我又回來了,這次進行英文垃圾短信分類任務。下面將分別用機器學習
和深度學習
的方法進行操作,此外深度學習
的方法又分別用RNN
和CNN
的方法進行展示,Let’s go!!!
充滿活力的衝啊!!!
一、英文垃圾短信分類
這次的任務很簡單,就是一個二分類的任務。不過屬於nlp的二分類的任務。給出短信內容,判別該短信是否是垃圾短信。
那麼,那麼,那麼,重點來了!既然要做本次實驗,怎麼能沒有數據集呢?
數據集纔是驅動力呀!
數據集是kaggle下載的,來判別短信內容是否爲垃圾短信。
二、機器學習方法進行英文垃圾短信分類
1.數據集
首先先讀取數據集,我們先看一下數據集的模樣。
不對,應該是這樣的。
之後,統計一下,數據的分佈情況。從圖中我們看到短信的類別存在不平衡的情況。
# 以圖方式表示
sns.countplot(sms_data["label"])
plt.xlabel("Label")
plt.title("Number of ham of spam messages")
既然存在樣本不平衡的情況,那麼下面對數據預處理的時候,我們就需要對這情況進行處理,這裏的處理在深度學習的部分。
2.數據預處理
a.分割數據
爲了評估效果,我們需要對數據集進行分割,來劃出一部分,用來測試。
b.文本特徵提取
這裏將短信的內容,將文本數據轉爲特徵向量。
比較常用的文本特徵表示法爲詞袋法
。
詞袋法:
- 不考慮詞語出現的順序,每個出現過的詞彙單獨作爲一列特徵
- 這些不重複的特徵詞彙集合爲詞表
- 每一個文本都可以在很長的詞表上統計出一個很多列的特徵向量
- 如果每個文本都出現的詞彙,一般被標記爲停用詞 不計入特徵向量
主要有兩個api來實現CounterVectorizer
和TfidfVectorizer
CountVectorizer:
- 只考慮詞彙在文本中出現的頻率
TfidfVectorizer:
- 除了考量某詞彙在文本出現的頻率,還關注包含這個詞彙的所有文本的數量
- 能夠消減高頻沒有意義的詞彙出現帶來的影響,挖掘更有意義的特徵。
這裏給出TfidfVectorizer的部分代碼,
3.機器學習大雜燴
a.模型滿漢全席
將常見的模型,拿出來,進行評估,廢話不多講,直接上代碼
models = {
"SVC":SVC(kernel="linear"),
"MultinomialNB":MultinomialNB(),
"LogisticRegression":LogisticRegression(),
"KNeighborsClassifier":KNeighborsClassifier(),
"DecisionTreeClassifier":DecisionTreeClassifier(),
"RandomForestClassifier":RandomForestClassifier(),
"AdaBoostClassifier":AdaBoostClassifier(),
"BaggingClassifier":BaggingClassifier(),
"ExtraTreesClassifier":ExtraTreesClassifier()
}
prediction = dict()
score_map = {}
for model_name in models:
model = models[model_name]
model.fit(x_train_df,y_train)
prediction[model_name]=model.predict(x_test_df)
score=accuracy_score(y_test,prediction[model_name])
score_map[model_name]=score
result = pd.DataFrame()
result["model"] = score_map.keys()
result["score" ]=score_map.values()
result["score"]=result["score"].apply(lambda x : x*100)
最後讓我們看一下結果,可以看到支持向量機的效果很好,而且這只是默認參數的情況下,下面調一下參,在看一下。
def plot_model_performace(result):
sns.set_style("ticks")
figsize=(22,6)
ticksize=12
titlesize=ticksize+8
labelsize=ticksize+5
xlabel="Model"
ylabel="Score"
title="Model Performance"
params={"figure.figsize":figsize,
"axes.labelsize":labelsize,
"axes.titlesize":titlesize,
"xtick.labelsize":ticksize,
"ytick.labelsize":ticksize}
plt.rcParams.update(params)
col1="model"
col2="score"
sns.barplot(x=col1,y=col2,data=result)
plt.title(title.title())
plt.xlabel(xlabel)
plt.ylabel(ylabel)
plt.xticks(rotation=90)
plt.grid()
plt.plot()
plt.show()
print(result)
b.超參數調參
現在就由最偉大的煉丹師出場了。
from sklearn.model_selection import GridSearchCV
param_grid = {
"alpha":np.concatenate(
[
np.arange(0.0001,0.001,0.0001),
np.arange(0.001,0.01,0.001),
np.arange(0.01,0.1,0.01),
np.arange(0.1,1,0.1),
np.arange(1,10,1),
np.arange(10,100,5)
]
)
}
model = MultinomialNB()
grid_cv_model = GridSearchCV(model,param_grid,n_jobs=-1,verbose=3,cv=3)
grid_cv_model.fit(x_train_df,y_train)
#對指標評價
print("{}{}".format("Best Estimator: ",grid_cv_model.best_estimator_))
print("{}{}".format("Besr Params: ",grid_cv_model.best_params_))
print("{}{}".format("Bset Scores: ",grid_cv_model.best_score_))
並用混淆矩陣來評價一下
# 混淆矩陣
def plot_confusion_matrix(y_test,y_pred,title=""):
conf_mat=confusion_matrix(y_test,y_pred)
conf_mat_normalized=conf_mat.astype("float")/conf_mat.sum(axis=1)[:,np.newaxis]
figsize=(22,5)
ticksize=18
titlesize=ticksize+8
labelsize=ticksize+5
xlabel="Predicted label"
ylabel="True label"
params={"figure.figsize":figsize,
"axes.labelsize":labelsize,
"axes.titlesize":titlesize,
"xtick.labelsize":ticksize,
"ytick.labelsize":ticksize}
plt.rcParams.update(params)
plt.subplot(121)
sns.heatmap(conf_mat,annot=True)
plt.title(title)
plt.xlabel(xlabel)
plt.ylabel(ylabel)
plt.subplot(122)
sns.heatmap(conf_mat_normalized,annot=True)
plt.title(title)
plt.xlabel(xlabel)
plt.ylabel(ylabel)
plt.show()
print("Confusion Matrix:\n")
print(conf_mat)
print("\n\nConfusion Matrix Normalized:\n")
print(conf_mat_normalized)
終於終於終於才寫了一半,好想拆開,這樣就能水兩篇了。(其實這篇也是來水的)
三、深度學習英文垃圾短信分類
在本節,將分別用CNN和RNN模型進行操作,準備好了麼,讓我們出發!
1.數據集
數據集可參照上部分,並沒有多大變化,都是驅動力。
2.數據預處理
a.樣本不均衡
我們在上述數據集的觀察下,發現樣本數據存在不均衡的情況,這裏處理一下。
使用sklearn.utils.class_weight樣本均衡操作。當我們的數據,有多個類別,每個類別的數據量有很大差距時,這時需要對每個類別的樣本做一次均衡,這樣會讓每個類別的特徵都在一定程度上被模型學習。
# 計算各個類別的weights
def get_weight(y):
class_weight_current = cw.compute_class_weight("balanced",np.unique(y),y)
return class_weight_current
class_weight = get_weight(y_train.flatten())
b.文本數據處理
使用分詞器Tokenier進行文本數據處理。分詞器Tokenizer Tokenizer是一個用於向量化文本,或將文本轉換爲序列(即單詞在字典中的下標構成的列表,從1算起)的類方法
# 分詞器Tokenizer Tokenizer是一個用於向量化文本,或將文本轉換爲序列(即單詞在字典中的下標構成的列表,從1算起)的類方法
# fit_on_texts(texts) :texts用於訓練的文本列表
# texts_to_sequences(texts):texts待轉爲序列的文本列表 返回值:序列的列表,列表中的每個序列對應於一段輸入文本
# 填充序列pad_sequences 將長爲nb_smaples的序列轉換爲(nb_samples,nb_timesteps)2Dnumpy attay.如果提供maxlen,nb_timesteps=maxlen,否則其值爲最長序列的長度。
# 其它短於該長度的序列都會在後部填充0以達到該長度。長與nb_timesteps的序列會被階段,以使其匹配該目標長度。
#max_words = 1000
#max_len = 150
max_words = len(set(" ".join(x_train).split()))
max_len = x_train.apply(lambda x:len(x)).max()
tok = Tokenizer(num_words=max_words)
tok.fit_on_texts(x_train)
sequences = tok.texts_to_sequences(x_train)
sequences_matrix = sequence.pad_sequences(sequences,maxlen=max_len)
c.超參數的設置
-
ModelCheckpoint:
- 作用:該回調函數將在每個epoch後保存模型到filepath
- 參數:
- filename:字符串,保存模型的路徑,filepath可以是格式化的字符串,裏面的
- monitor:需要監視的值,通常爲:val_acc或val_loss或acc或loss
- verbose:信息展示模型,0或1。默認爲0表示不輸出該信息,爲1表示輸出epoch模型保存信息。
- save_best_only:當設置爲Trur時,將只保存在驗證集上性能最好的模型
- mode:“auto”,“min”,"max"之一,在save_best_only=True時決定性能最佳模型的評判準則。
- save_weights_only:若設置爲True時,則只保存模型權重,否則將保存整個模型(包括模型結構,配置信息等)
- period:CheckPoint之間的間隔的epoch數
-
EarlyStopping:
- 作用:當監測值不再改善時,該回調函數將中止訓練
- 參數:
- monitor:需要監視的量,通常爲val_acc或val_loss或acc或loss
- patience:當early stop被激活(如發現loss相比上patience個epoch訓練沒有下降),則經過patience個epoch後停止訓練。
- verbose:信息展示模型
- mode:“auto”,“min”,"max"之一,在min模式下,如果檢測值停止下降則中止訓練。在max模式下,當檢測值不再上升則停止訓練。
-
ReduceLROnPlateau:
- 作用:當評價指標不再提升時,減少學習率。當學習停滯時,減少2倍或10倍的學習率通常能夠獲得較好的效果。該回調函數檢測指標的情況,如果在patience個epoch中看不到模型性能提升,則減少學習率。
- 參數:
- monitor:被監測的量
- factor:每次減少學習率的因子,學習率將以lr=lr*factor的形式被技術那好
- patience:當patience個epoch過去而模型性能不提升時,學習率減少的動作會被觸發
- mode:“auto”,“min”,"max"之一,在min模式下,如果檢測值觸發學習率減少。在max模式下,當檢測值不再上升則觸發學習率減少
- epsilon:閾值,用來確定是否進入檢測值的“平原區”
- cooldown:學習率減少後,會經過cooldown個epoch才重新進行正常操作
- min_lr:學習率的下限。
print("Setting Callbacks")
checkpoint = ModelCheckpoint("model.hdf5",
monitor="val_acc",
save_best_only=True,
mode="max")
early_stopping = EarlyStopping(monitor="val_loss",
patience=2,
verbose=1,
restore_best_weights=True,
mode="min")
reduce_lr = ReduceLROnPlateau(monitor="val_loss",
factor=0.6,
patience=1,
verbose=1,
mode="min")
callbacks=[checkpoint,early_stopping,reduce_lr]
print("Set Callbacks at",date_time(1))
3.深度學習模型
下面,分別定義一個CNN模型和RNN模型,然後進行訓練和測試。
a.定義RNN模型
# 定義RNN模型
def RNN():
model = Sequential()
model.add(Embedding(max_words,50,input_length=max_len))
model.add(LSTM(64))
model.add(Dropout(0.5))
model.add(BatchNormalization())
model.add(Dropout(0.5))
model.add(Dense(256,activation="relu"))
model.add(Dropout(0.5))
model.add(BatchNormalization())
model.add(Dropout(0.5))
model.add(Dense(1,activation="sigmoid"))
model.summary()
return model
給出最後的曲線結果圖。
b.定義CNN模型
# 定義CNN模型
def CNN():
model=Sequential()
model.add(Embedding(max_words,50,input_length=max_len))
model.add(Conv1D(64,3,padding="valid",activation="relu",strides=1))
model.add(GlobalMaxPooling1D())
model.add(Dropout(0.5))
model.add(BatchNormalization())
model.add(Dropout(0.5))
model.add(Dense(256,activation="relu"))
model.add(Dropout(0.5))
model.add(BatchNormalization())
model.add(Dropout(0.5))
model.add(Dense(1,activation="sigmoid"))
model.summary()
return model
效果的話,還是RNN更好一些。
好了,終於寫完了,過一陣,再寫一個關於音頻分類的,最近找音頻分類的代碼,發現這類代碼好少,不過我也不是做這方向,就隨意水一水,好不好。