【實戰】英文垃圾短信分類

我又回來了,這次進行英文垃圾短信分類任務。下面將分別用機器學習深度學習的方法進行操作,此外深度學習的方法又分別用RNNCNN的方法進行展示,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來實現CounterVectorizerTfidfVectorizer

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更好一些。

好了,終於寫完了,過一陣,再寫一個關於音頻分類的,最近找音頻分類的代碼,發現這類代碼好少,不過我也不是做這方向,就隨意水一水,好不好。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章