這篇教程裏,咱們會使用FastText來作分類html
import pandas as pd import numpy as np from sklearn.metrics import roc_auc_score from datetime import date
咱們先讀入數據。這裏我提供了一個已經combine好了的數據。python
data = pd.read_csv('../input/Combined_News_DJIA.csv')
這時候,咱們能夠看一下數據長什麼樣子web
data.head()
其實看起來特別的簡單直觀。若是是1,那麼當日的DJIA就提升或者不變了。若是是1,那麼DJIA那天就是跌了。數組
這下,咱們能夠先把數據給分紅Training/Testing data網絡
train = data[data['Date'] < '2015-01-01'] test = data[data['Date'] > '2014-12-31']
而後,咱們把每條新聞作成一個單獨的句子,集合在一塊兒:app
X_train = train[train.columns[2:]] corpus = X_train.values.flatten().astype(str) X_train = X_train.values.astype(str) X_train = np.array([' '.join(x) for x in X_train]) X_test = test[test.columns[2:]] X_test = X_test.values.astype(str) X_test = np.array([' '.join(x) for x in X_test]) y_train = train['Label'].values y_test = test['Label'].values
這裏咱們注意,咱們須要三樣東西:dom
corpus是所有咱們『可見』的文本資料。咱們假設每條新聞就是一句話,把他們所有flatten()了,咱們就會獲得list of sentences。ide
同時咱們的X_train和X_test可不能隨便flatten,他們須要與y_train和y_test對應。oop
corpus[:3]
X_train[:1]
y_train[:5]
來,咱們再把每一個單詞給分隔開:
一樣,corpus和X_train的處理不一樣
from nltk.tokenize import word_tokenize corpus = [word_tokenize(x) for x in corpus] X_train = [word_tokenize(x) for x in X_train] X_test = [word_tokenize(x) for x in X_test]
tokenize完畢後,
咱們能夠看到,雖然corpus和x都是一個二維數組,可是他們的意義不一樣了。
corpus裏,第二維數據是一個個句子。
x裏,第二維數據是一個個數據點(對應每一個label)
X_train[:2]
corpus[:2]
咱們進行一些預處理來把咱們的文本資料變得更加統一:
小寫化
刪除中止詞
刪除數字與符號
lemma
咱們把這些功能合爲一個func:
# 中止詞
from nltk.corpus import stopwords stop = stopwords.words('english') # 數字 import re def hasNumbers(inputString): return bool(re.search(r'\d', inputString)) # 特殊符號 def isSymbol(inputString): return bool(re.match(r'[^\w]', inputString)) # lemma from nltk.stem import WordNetLemmatizer wordnet_lemmatizer = WordNetLemmatizer() def check(word): """ 若是須要這個單詞,則True 若是應該去除,則False """ word= word.lower() if word in stop: return False elif hasNumbers(word) or isSymbol(word): return False else: return True # 把上面的方法綜合起來 def preprocessing(sen): res = [] for word in sen: if check(word): # 這一段的用處僅僅是去除python裏面byte存str時候留下的標識。。以前數據沒處理好,其餘case裏不會有這個狀況 word = word.lower().replace("b'", '').replace('b"', '').replace('"', '').replace("'", '') res.append(wordnet_lemmatizer.lemmatize(word)) return res
把咱們三個數據組都來處理一下:
corpus = [preprocessing(x) for x in corpus] X_train = [preprocessing(x) for x in X_train] X_test = [preprocessing(x) for x in X_test]
咱們再來看看處理以後的數據長相:
print(corpus[553]) print(X_train[523])
有了這些乾淨的數據集,咱們能夠作咱們的NLP模型了。
咱們這裏要用的是FastText。
原理,我在課件上已經講過了,這裏咱們來進一步看看具體的使用。
因爲這篇paper剛剛發佈,不少社區貢獻者也都在給社區提供代碼,儘早實現python版本的開源編譯(我也是其中之一)。
固然,由於Facebook團隊自己已經在GitHub上放出了源代碼(C++),
因此,咱們能夠用一個python wrapper來造個interface,方便咱們調用。
首先,咱們講過,FT把label也看作一個元素,帶進了word2vec的網絡中。
那麼,咱們就須要把這個label塞進咱們的「句子」中:
for i in range(len(y_train)): label = '__label__' + str(y_train[i]) X_train[i].append(label) print(X_train[49])
而後,咱們把數據存成文件的形式。由於咱們這裏的FastText只是個python的interface。調用起來還得用C++的接口。
咱們須要存三個東西:
含有label的train集
不含label的test集
label單獨放一個文件
X_train = [' '.join(x) for x in X_train] print(X_train[12])
同理,test集也這樣。
X_test = [' '.join(x) for x in X_test] with open('../input/train_ft.txt', 'w') as f: for sen in X_train: f.write(sen+'\n') with open('../input/test_ft.txt', 'w') as f: for sen in X_test: f.write(sen+'\n') with open('../input/test_label_ft.txt', 'w') as f: for label in y_test: f.write(str(label)+'\n')
import fasttext clf = fasttext.supervised('../input/train_ft.txt', 'model', dim=256, ws=5, neg=5, epoch=100, min_count=10, lr=0.1, lr_update_rate=1000, bucket=200000)
訓練完咱們的FT模型後,咱們能夠測試咱們的Test集了
y_scores = [] # 咱們用predict來給出判斷 labels = clf.predict(X_test) y_preds = np.array(labels).flatten().astype(int) # 咱們來看看 print(len(y_test)) print(y_test) print(len(y_preds)) print(y_preds) from sklearn import metrics # 算個AUC準確率 fpr, tpr, thresholds = metrics.roc_curve(y_test, y_preds, pos_label=1) print(metrics.auc(fpr, tpr))
同理,這裏,咱們經過parameter tuning或者是resampling,可讓咱們的結果更加好。
固然,由於FT自己也是一個word2vec。而且自帶了一個相似於二叉樹的分類器在後面。
這樣,在小量數據上,是跑不出很理想的結論的,還不如咱們本身帶上一個SVM的效果。
可是面對大量數據和大量label,它的效果就體現出來了。