我又回来了,这次进行英文垃圾短信分类任务。下面将分别用机器学习
和深度学习
的方法进行操作,此外深度学习
的方法又分别用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更好一些。
好了,终于写完了,过一阵,再写一个关于音频分类的,最近找音频分类的代码,发现这类代码好少,不过我也不是做这方向,就随意水一水,好不好。