2017年7月24日 星期一

機器學習_ML_文字分詞_

機器學習_ML-文字分詞

分成多步驟主要是因為自己在練習的時候沒有辦法一次性的把所有的流程處理掉,所以就自己把作業流程分一下。
主要參考了『Python機器學習 Sebastian Raschka著』,這是第八章的內容。
還有參考了『今天不學機器學習,明天就被機器取代:從Python入手+演算法』!

STEP-1_下載檔案,並且持久化檔案

#  範例檔請至http://ai.stanford.edu/~amaas/data/sentiment/下載
#  這邊主要是針對案例檔抽取50000筆來做使用,並且透過pickle持久化檔案。
import os
import pandas as pd
import pyprind
import pickle

def writeobj(path, bunchobj):
    file_obj = open(path, "wb")
    pickle.dump(bunchobj, file_obj)
    file_obj.close()

pBar = pyprind.ProgBar(50000)
labels = {'pos': 1, 'neg': 0}
df = pd.DataFrame()
for s in ('test', 'train'):
    for l in ('pos', 'neg'):
        path = 'D:\\python\\ML\\aclImdb\%s\%s' % (s, l)
        for file in os.listdir(path):
        #  os.path.join用來結合path與file
        #  案例來看會等於D:\python\ML\aclImdb\test\neg\xxx.txt
        #  所以該處利用join來結合連結與檔案名之後做檔案開啟的動作
            with open(os.path.join(path, file), encoding='utf8') as infile:
                txt = infile.read()
            #  ignore_index=True_重置 index
            #  labels內接的是小寫的L,不是1,對應上面第二層迴圈的L
            df = df.append([[txt, labels[l]]], ignore_index=True)
            pBar.update()

writeobj('D:\\python\\ML\\df.dat', df)

STEP-2_下載檔案,並且持久化檔案

#  這邊主要是測試讀取在01所做的檔案讀取測試。
#  試著用type去確認型態的話,會發現是pandas的物件型態。
import os
import pandas as pd
import pyprind
import pickle

def readobj(path):
    with open(path, "rb") as file:
        context = pickle.load(file)
    return context

path = 'D:\\python\\ML\\df.dat'

#  df = pd.DataFrame()
df = readobj(path)
print(df)
#  print(type(df))

STEP-3

#  將稍早透過pickle建置的持久檔讀出轉入csv
#  並且亂數排序過
import os
import pandas as pd
import numpy as np
import pickle

def readobj(path):
    with open(path, "rb") as file:
        context = pickle.load(file)
    return context


df = pd.DataFrame()
path = 'D:\\python\\ML\\df.dat'
df = readobj(path)

#  numpy.random.seed的部份,主要用來讓每次的亂數排序都是一致的。
#  如seed(0),不管執行幾次所得的結果都是一致的!
np.random.seed(0)
df = df.reindex(np.random.permutation(df.index))
#  header的部份是拿來定義欄位名稱使用
df.to_csv('D:\\python\\ML\\move_data.csv', index=False, header=('review', 'sentiment'))

STEP-4

# -*- coding: UTF-8 -*-
#  將稍早透過pickle建置csv讀出測試
import pandas as pd
import codecs

df = pd.DataFrame()
path = 'D:\\python\\ML\\move_data.csv'

#  目前很常遇到的就是編碼的問題,所以最後找到的解法是import codecs再透過with codecs來oepn。
with codecs.open(path, "r", encoding='utf-8', errors='ignore') as fdata:
    df = pd.read_csv(fdata)

print(df.head(3))

STEP-5

# -*- coding: UTF-8 -*-
import pandas as pd
import re
import codecs


def preprocessor(text):
    #  re.sub主要用來替代字串
    #  re.sub(正則式, 替代成什麼, 來源字串)
    text = re.sub('<[^>]*>', '', text)
    #  re.findall用來取得所有match的資料,是一個list
    emoticons = re.findall('(?::|;|=)(?:-)?(?:\)|\(|D|P)', text)
    #  把文字以外的符號去除之後,再把剛才的表情符號加到最後
    text = re.sub('[\W]+', ' ', text.lower()) +\
        ' '.join(emoticons).replace('-', '')
    return text

df = pd.DataFrame()
path = 'D:\\python\\ML\\move_data.csv'
with codecs.open(path, "r", encoding='utf-8', errors='ignore') as fdata:
    df = pd.read_csv(fdata)

#  dd ='is seven.<br /><br />Title (Brazil): Not Available :)'
#  print(preprocessor(dd))
#  將欄位資料做清除整理不必要的符號。
df['review'] = df['review'].apply(preprocessor)
print(df)

STEP-6

import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer

#  實做CountVectorizer的時候可以透過ngram_range來做分詞的長度設置
#  ngram_range(2,2)表示從2到2,如果是(2,3)的話,即表示字串從2~3長。
count = CountVectorizer(ngram_range=(1, 1))
docs = np.array([
    'The sun is shining',
    'The weather is sweet',
    'The sun is shining and the weather is sweet'
])
bag = count.fit_transform(docs)
#  列印詞彙的內容
#  {'the': 5, 'sun': 3, 'is': 1, 'shining': 2, 'weather': 6, 'sweet': 4, 'and': 0}
print(count.vocabulary_)
#  列印出相對應的索引值
#  and的索引是0 在第1句中,and沒有出現,故首值為0,依此下去列出三個文本的狀態
print(bag.toarray())

#  實做tfidf
tfidf = TfidfTransformer()
np.set_printoptions(precision=2)
#  print(tfidf.fit_transform(count.fit_transform(docs)).toarray())
#  上句與下句一樣
print(tfidf.fit_transform(bag).toarray())

STEP-7

#  波特詞幹還原演算法
#  可透過nltk.download('stopwords')來下載停用詞
from nltk.stem.porter import PorterStemmer
from nltk.corpus import stopwords

porter = PorterStemmer()
stop = stopwords.words('english')

def tokenizer_porter(text):
    return[porter.stem(word) for word in text.split()]

print([w for w in tokenizer_porter('runners like running and thus they run')[-10:] if w not in stop])

STEP-8

from sklearn.model_selection  import GridSearchCV
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd
import codecs
from nltk.stem.porter import PorterStemmer
from nltk.corpus import stopwords



def tokenizer_porter(text):
    return[porter.stem(word) for word in text.split()]


def tokenizer(text):
    return text.split()

df = pd.DataFrame()
path = 'D:\\python\\ML\\move_data.csv'
porter = PorterStemmer()
stop = stopwords.words('english')

#  目前很常遇到的就是編碼的問題,所以最後找到的解法是import codecs再透過with codecs來oepn。
with codecs.open(path, "r",encoding='utf-8', errors='ignore') as fdata:
    df = pd.read_csv(fdata)


x_train = df.loc[:500, 'review'].values
y_train = df.loc[:500, 'sentiment'].values
x_test = df.loc[500:, 'review'].values
y_test = df.loc[500:, 'sentiment'].values

tfidf = TfidfVectorizer(strip_accents=None,
                        lowercase=False,
                        preprocessor=None)

param_grid = [{'vect__ngram_range': [(1, 1)],
               'vect__stop_words': [stop, None],    
               'vect__tokenizer': [tokenizer, tokenizer_porter],
               'clf__penalty': ['l1', 'l2'],
               'clf__C': [1.0, 10.0, 100.0]},
              {'vect__ngram_range': [(1, 1)],
               'vect__stop_words': [stop, None],
               'vect__tokenizer': [tokenizer, tokenizer_porter],
               'vect__use_idf':[False],
               'vect__norm':[None],
               'clf__penalty': ['l1', 'l2'],
               'clf__C': [1.0, 10.0, 100.0]},
              ]

lr_tfidf = Pipeline([('vect', tfidf),
                     ('clf', LogisticRegression(random_state=0))])

gs_lr_tfidf = GridSearchCV(lr_tfidf, param_grid,
                           scoring='accuracy',
                           cv=5,
                           verbose=1,
                           n_jobs=-1)

if __name__ == '__main__':
    gs_lr_tfidf.fit(x_train, y_train)
    print('Best parameter set: %s ' % gs_lr_tfidf.best_params_)
    print('CV Accuracy: %.3f' % gs_lr_tfidf.best_score_)

STEP-9

import numpy as np
import re
from nltk.corpus import stopwords
from sklearn.feature_extraction.text import HashingVectorizer
from sklearn.linear_model import SGDClassifier
import pyprind


stop = stopwords.words('english')
path = "D:\\python\\ML\\move_data.csv"

def tokenizer(text):
    text = re.sub('<[^>]*>', '', text)
    emoticons = re.findall('(?::|;|=)(?:-)?(?:\)|\(|D|P)', text)
    text = re.sub('[\W]+', ' ', text.lower()) +\
        ' '.join(emoticons).replace('-', '')
    tokenized = [w for w in text.split() if w not in stop]
    return tokenized


def stream_docs(path):
    with open(path, 'r') as csv:
        #  pass掉第一行標題行
        next(csv)
        for line in csv:
            text, label = line[:-3], int(line[-2])
            #  yield用法就如同return,不同的是值會留著下次呼叫的時候繼續用!
            #  再另篇來說明!
            yield text, label


#  內建函數 (function) next() ,回傳參數 (parameter) 迭代器中下一個數值
#  測試是否有成功呼叫!記得要做一點點就測試一下才會好除錯!
#  print(next(stream_docs(path)))


#  定義函數來處理串流
def get_minibatch(doc_stream, size):
    docs, y = [], []
    try:
        for _ in range(size):
            text, label = next(doc_stream)
            docs.append(text)
            y.append(label)
    except StopIteration:
        return None, None
    return docs, y

vect = HashingVectorizer(decode_error='ignore',
                         n_features=2**21,
                         preprocessor=None,
                         tokenizer=tokenizer)

clf = SGDClassifier(loss='log', random_state=1, n_iter=1)

doc_stream = stream_docs(path=path)

pbar = pyprind.ProgBar(45)
classes = np.array([0,1])

for _ in range(45):
    x_train, y_train = get_minibatch(doc_stream, size=1000)
    if not x_train:
        break
    x_train = vect.transform(x_train)
    clf.partial_fit(x_train, y_train, classes=classes)
    pbar.update()

x_test, y_test = get_minibatch(doc_stream, size=5000)
x_test = vect.transform(x_test)
print('Accuracy: %.3f' % clf.score(x_test, y_test))

#  再透過最後的這5000筆來更新模型
clf = clf.partial_fit(x_test, y_test)

SSRS_多選傳值子報表參數

SSRS_多選傳值子報表參數

操作說明

子報表的參數設置為『允許多個值』

母報表的參數設定

一般來說,直接選擇參數設定的時候會預設帶入value(0),這時候只要將(0)拿掉即可。
子報表的dataset設置條件式要調整為xxx in (:xxx)

SAP_ABAP_邊學邊記錄_INTERNAL TABLE(內表)

SAP_ABAP_邊學邊記錄_INTERNAL TABLE(內表)

INTERNAL TABLE(內表)說明

INTERNAL TABLE如另篇文中說明,是存放資料的介質,從DB取出資料之後就是放在INTERNAL TABLE處理之後才顯示在畫面上的。
宣告的方式有三種,另篇的說明是標準的,這邊重新介紹過!

宣告方式_STANDARD

可參照DB或是參照WORK AREA,下述方式即參照了WORK AREA。其STANDARD是可有可無的!
DATA LINE_TABLE TYPE STANDARD TABLE OF LINE.

STANDARD說明

宣告為STANDARD的部份,其資料取出是從第一筆開始按序讀取。(如透過ASP.NET的DATA READER)
取資料的方式一般來說是透過LOOP來依序取得載入。
在寫入資料的時候,可以將資料寫到最後,也可以依指定位址寫入

宣告方式_SORTED

DATA LINE_TABLE TYPE SORTED TABLE OF LINE WITH NON-UNIQUE KEY CELL1 CELL2.

SORTED說明

查詢的時候會依KEY值排序,再透過二分法來做查詢。

宣告方式_HASHED

DATA LINE_TABLE TYPE HASHED TABLE OF LINE WITH UNIQUE KEY CELL.

HASHED說明

透過HASH表來查詢,KEY值必填,只能讀取。
WITH NON-UNIQUE與UNIQUE的說明
此參數決定了具相同關鍵字的數據是否重覆出現!在STANDARD中是不允許UNIQUE的宣告,且不需特別設定WITH NON-UNIQUE,而在HASHED中是不允許設置WITH NON-UNIQUE,且必需設置UNIQUE。
INITIAL SIZES n說明
n可以為0或是任意正整數值,設置與否皆不影響執行,只會影響效率,如n小於需求,則在執行程序的時候會去自行擴增,此時會影響效率,而n設置過大的時候會導致資源浪費。
如n為0或不指定,則預設給予8kb的空間。

其它宣告方式

DATA <INTERNAL TABLE> TYPE <結構類型> WITH [UNIQUE|NON-UNIQUE] [INITIAL SIZE n] [WITH HEADER LINE].
DATA <INTERNAL TABLE> LIKE TABLE OF <内表或者透明表> WITH [UNIQUE|NON-UNIQUE] [INITIAL SIZE n] [WITH HEADER LINE]。

其它宣告方式範例

TABLES:SOURCE_TABLE. //來源為透明表的時候必需要先IMPORT進來
TYPES:BEGIN OF INTERNAL_TABLE.
      NAME LIKE SOURCE_TABLE-CELL1.
      TEL LIKE SOURCE_TABLE-CELL2.
      ADD LIKE SOURCE_TABLE-CELL3.      
END OF INTERNAL_TABLE.
//賦值
MOVE 'A' TO INTERNAL_TABLE.NAME.
MOVE 'B' TO INTERNAL_TABLE.TEL.
MOVE 'C' TO INTERNAL_TABLE.ADD.
//顯示
WRITE INTERNAL_TABLE.

透明表說明

所謂的透明表泛指SAP系統中跟資料庫中定義完全相同的表,且任何對透明表的操作都會對資料庫直接的影響。

SAP_ABAP_邊學邊記錄_賦值(MOVE TO)

SAP_ABAP_邊學邊記錄_賦值(MOVE TO)

說明

相同的結構之間可以透過MOVE TO來做賦值,如存在結構差異的話,可以透過MOVE-CORRESPONDING TO來將相同字段給值。

MOVE TO範例

//定義結構
TYPES:BEGIN OF ADDS.
      FLAG, //沒指定會預設為C且長度為1
      ID LIKE AA-ID,
      NAME LIKE AA-NAME,
      CITY LIKE AA-CITY,
END OF ADDS.
//實作,產生WORD AREA
DATA ADDRESS TYPE ADDS.
//賦值
MOVE:'Y'      TO ADDRESS-FLAG,
     '0001'   TO ADDRESS-ID,
     'MARTY'  TO ADDRESS-NAME,
     'TAIWAN' TO ADDRESS-CITY.
//顯示
WRITE ADDRESS.

MOVE-CORRESPONDING TO範例

TABLES: EMPLOYEE.
 
DATA: BEGIN OF ADDS,
        FLAG,
        ID      LIKE EMPLOYEE-ID,
        NAME    LIKE EMPLOYEE-NAME1,
        CITY    LIKE EMPLOYEE-CITY,
      END OF ADDS.
 
SELECT * FROM EMPLOYEE.
 
     MOVE-CORRESPONDING EMPLOYEE TO ADDS.
     
     CLEAR ADDS.
ENDSELECT.

MOVE-CORRESPONDING TO說明

TABLE:EMPLYOEE
ID NAME1 CITY
0001 MARTY TAIWAN
ADDS
FLAG ID NAME CITY
透過MOVE-CORRESPONDING TO來賦值的話,只會針對欄位名稱相同的來賦值!
以案例來看,即ID與CITY在這個執行上會有值而以。

SAP_ABAP_邊學邊記錄_結構宣告

SAP_ABAP_邊學邊記錄_結構宣告

WORK AREA(工作區)、INTERNAL TABLE(內表)、HEADER LINE(標題行)
INTERNAL TABLE是SAP中實在處理資料的部份,從DB把資料取回的時候,也是會進入INTERNAL TABEL中,而去執行的部份要透過WORK AREA去取INTERNAL TABLE的值。

建置INTERNAL TABLE(內表)

在另一篇變數宣告中提到,TYPES定義的部份要透過DATA實做才行!
這其中的一些作業又跟ABAP的行家話有關,像WORK AREA、INTERNAL TABLE…
一步一步來操作記錄!

宣告一個結構(想像中是一個CLASS)

TYPES: BEGIN OF LINES.
       CELL1 TYPE I,
       CELL2 TYPE I
       END OF LINES.

宣告一個WORD AREA(想像成實做CLASS成OBJ)

DATA WA TYPE LINES.

宣告一個INTERNAL TABLE(想像成宣告一個TABLE,他的資料結構是LINES)

//舊式宣告方法
DATA LINE_TABLE TYPE LINES OCCURS 0 WITH HEADER LINE.
//目前建議作法
DATA LINE_TABLE TYPE STANDARD TABLE OF LINE.

關於OCCURS 0

OCCURS主要是宣告這個TABLE的行數,0即表示沒有限制,當超過定義的時候會自動擴展,不過網路上看前輩們的討論是舊的作法了,現在都不建議再OCCURS了!

關於WITH HEADER LINE

WITH HEADER LINE可當做一個WORK AREA使用,不過網路看前輩們在說,效能上不宣告WITH HEADER LINE是較好的!

建置INTERNAL TABLE操作說明

我們透過TYPES宣告了一個LINES,這個LINES有著兩個欄位,CELL1與CELL2,就是每一行的記錄!
接著再透過DATA來實做這個LINES,就是ABAP中說的WORD AREA!
最後宣告一個TABLE,就是ABAP中說的INTERNAL TABLE!
就跟在ASP.NET一樣,宣告ROW、然後宣告CELL,將CELL給ADD進去ROW,然後再宣告一個TABLE,將這個ROW也ADD進去TABLE!(欄組成行,行加入資料表)

操作INTERNAL TABLE

方式一

WA-CELL1=1.
WA-CELL2=2.
APPEND WA TO LINE_TABLE.
//這WA是稍早所宣告的,不宣告WITH HEADER LINE的作法

方式二

LINE_TABLE-CELL1=1.
LINE_TABLE-CELL2=2.
APPEND LINE_TABLE.
//宣告了WITH HEADER LINE的作法兩種皆可行

操作方式說明

宣告了WITH HEADER LINE的時候同時也算是宣告了一個隱性的WORK AREA(LINE_TABLE),所以以方式二的方式可以直接執行!
理解上可以把WITH HEADER LINE的作法想成在INTERNAL TABLE的第0行變成是WORK AREA,待執行之後再寫入INTERNAL TABLE,所以我才會把這個動作解釋成是一個隱性的WORK AREA,而不宣告的時候還是必需透過另一個WORK AREA來做中介執行,即方式一。
//完整操作步驟
//定義結構
TYPES:BEGIN OF ADDS.
      FLAG, //沒指定會預設為C且長度為1
      ID LIKE AA-ID,
      NAME LIKE AA-NAME,
      CITY LIKE AA-CITY,
END OF ADDS.
//實作,產生WORD AREA
DATA ADDRESS TYPE ADDS.
//賦值
MOVE:'Y'      TO ADDRESS-FLAG,
     '0001'   TO ADDRESS-ID,
     'MARTY'  TO ADDRESS-NAME,
     'TAIWAN' TO ADDRESS-CITY.
//顯示
WRITE ADDRESS.

      

SAP_ABAP_邊學邊記錄_宣告變數

SAP_ABAP_邊學邊記錄_宣告變數

abap在vscode上面也有套件可以下載,不無小補,作業起來應該會比較sap上操作來的好一點。

宣告方式

SAP的結尾是用『.』一定要記得點上,如javascript的var『;』

TYPES

如用系統內建的型態無法滿足的時候,可以透過TYPES來做自定義!
也可以用於宣告一個結構,但無法直接使用,還是需要透過DATA來實體化。
感覺起來像是類別實做成物件…用法的話,可用於重覆需要宣告的資料結構!

DATA

用於宣告變數的前贅詞,如javascript的var、let或是vb的dim…

TYPE

用於宣告的變數的時候指定資料型別

LIKE

用法同TYPE,不同的是,LIKE是用於有值的資料。

CONSTANT

宣告常數,常數部份無法更動。如javascript的const

STATICS

宣告一個臨時變數,用完了就自動釋放了!

變數類型

類型 說明 備註
C 字串
D 日期 YYYYMMDD_‘2017/07/24’
F 浮點數 長度8
I 整數
N 數值組成的字串 ‘123’
P 小數點數值 1.0123456
T 時間 HHMMSS_‘08:50:00’
X 16進制數 FFF0

宣告方式

DATA 變數名稱(長度) TYPE 變數型別 VALUE 初始值

DATA宣告範例

DATA ABC TYPE C. --宣告ABC是一個字串,但是未給長度,初始值為1
DATA ABC(10) TYPE C. --宣告ABC是一個長度10的字串
DATA ABC TYPE P DECIMALS 5 VALUE '3.14159'. --宣告變數ABC為P且小數點五位...
DATA DEF LIKE SY-UNAME. -- 宣告DEF的值為當前系統帳號(SY-UNAME為系統變數)

CONSTANT宣告範例

CONSTANT GHI TYPE P DECIMALS 5 VALUE '3.14159'.

STATIC宣告範例

STATIC JKL TYPE C VALUE 'HELLO WORLD!'.

TYPES宣告範例

TYPES:NAMES(10) TYPE C,
      COUNTS(20) TYPE C
      .
DATA:PLAYER TYPE NAMES VALUE 'HELLO HEY'     

其他說明

如果要一次宣告多變數的話,可以透過DATA:的作法
DATA: ABC TYPE C
      DEF TYPE C
      GHI TYPE F
      . <---這個點很重要,如javascript中的結尾分號,沒了,就錯了!

宣告方式(引入TABLE-COLUMN型別)

在為了避免宣告的類別與TABLE取出有差異的情況下,我們可以直接去宣告成該TABLE欄位的型別!
這部份跟鼎新的TT、T100系列開發的時候還蠻像的!(ORACLE內也可以這樣處理)
DATA 變數名稱 TYPE TABLE-COLUMN

宣告範例

DATA ABC TYPE CTABLE-ACOLUMN --宣告ABC的型別為CTABLE的ACOLUMN

系統變數說明

變數 說明 備註
SY-SUBRC 系統執行某指令後,表示執行成功與否的變數,'0’表示成功
SY-UNAME 當前使用者登入SAP的USERNAME
SY-DATUM 當前系統日期
SY-UZEIT 當前系統時間
SY-TCODE 當前執行程式的Transaction code
SY-INDEX 當前LOOP循環過的次數
SY-TABIX 當前處理的是internal table的第幾筆
SY-TMAXL Internal table的總筆數
SY-SROWS 螢幕總行數
SY-SCOLS 螢幕總列數
SY-MANDT CLIENT NUMBER
SY-VLINE 畫豎線
SY-ULINE 畫橫線
SY-REPID 當前程序的程序名 不能更改
SY-CPROG 調用程序的程序名 可修改

2017年7月8日 星期六

藤原栗子週末碎念-0708

不知不覺已經好長一段時間沒有更新了,快一個月前跟泡泡先生一起看迪士尼,然後筆電就死了,是的,筆電就死了,很安詳的噗的一聲然後就無法開機了,拿去聯想得到的回應是太久了,沒有料可以修,只能再買台新的了!
新工作開始,SAP不虧是SAP,即使你看的懂中文也不知道他是幹嘛的!!
花了兩天的時間才些許的知道怎麼建BOM...而且還不少欄位不知道該怎麼處理!
總之要摸熟SAP看來不是之前T100一般三個月就可以上手了,不管如何,這是一個很好的機會,讓自己可以好好的了解一下SAP了。