机器学习和深度学习的hello world ~
注: “实现基于卷积神经网络和支持向量机的文本情感分类,并讨论数据量对这两种方式准确率的影响。”
1、通过网络爬虫从淘宝、京东爬取商品评论,对其进行人工分类、标注,得到数据集。
2、对数据集进行预处理,进行中文分词、去除停用词,标点符号。
3、分别使用 “卷积神经网络” 和 “支持向量机” 进行训练和预测,计算准确率。
4、改变用于训练的数据量大小,比较这两种方式下的准确率变化情况。
python=3.6
pandas=0.22.0
numpy=1.14.0
jieba=0.39
gensim=3.4.0
scikit-learn=0.19.1
keras=2.1.5
wordcloud=1.4.1
1、 原始数据爬取
创建商品评论页面的循环链接,使用Python的requests库循环抓取数据,使用正则表达式匹配查询,得到相关文本,将结果保存为.csv文档。
for url in urls:
content = requests.get(url).text
# 借助正则表达式使用findall进行匹配查询
nickname.extend(re.findall('"displayUserNick":"(.*?)"',content)) #用户名
ratecontent.extend(re.findall(re.compile('"rateContent":"(.*?)","rateDate"'),content)) #评论内容
ratedate.extend(re.findall(re.compile('"rateDate":"(.*?)","reply"'),content)) #评论时间
2、标注情感
正面:
负面:
在英文的行文中,单词之间是以空格作为自然分界符的,而中文只是字、句和段能通过明显的分界符来简单划界,但是词却没有一个形式上的分界符。要获得句子的语义特征,必须对句子进行分词。
使用”jieba分词”实现: words=jieba.lcut(text)
使用基于wordcloud生成的词云表示分词结果:
wc= WordCloud(font_path=font_path,
background_color='white',
max_words=2000,
mask=back_coloring,
max_font_size=100,
random_state=30,
width=600,height=400,margin=5,
relative_scaling=0.5
)
wc.generate(text)
最小词长为1时的词频:
最小词长为2时的词频:
由图可见,当最小词长选为1时,高频词出现了大量的标点符号、语气词等无关词语。虽然可以通过通用词将其剔除,但是这么做比较复杂,并且需要构建一个庞大的停用词表。选最小词长为2时,在高频词中明显可以看到很多表示情感的词,比如像”不错“、”满意“等等,已经满足了需求。所以最终选择的最小词长为2。
代码见 CNN.py
流程: 导入数据 -> 数据预处理(分词,统计词频、编号,标签转成独热码) -> 构建模型 -> 训练和预测 -> 计算准确率
1、分词(同上)
2、统计词频、编码
使用Keras的Tokenizer类 对文本中的词进行统计计数,生成文档词典,以支持基于词典位序生成文本的向量表示。
tokenizer = Tokenizer(num_words=2000) #初始化Tokenizer
tokenizer.fit_on_texts(texts=X_cut) #训练
counts=tokenizer.word_counts #词频
index=tokenizer.word_index #编号
注:在Keras官方文档中,Tokenizer被翻译成“分词器”,这个翻译其实不太恰当。它实现的功能并不是分词,而是统计词频,并且可以根据词频从高到低对词语依次编码为1,2,3……。
3、标签转成独热码
使用Pandas的get_dummies方法实现。
y_one_hot = pd.get_dummies(y)
y_one_hot_labels = np.asarray(y_one_hot)
模型来自博文(Implementing a CNN for Text Classification in TensorFlow :http://www.wildml.com/2015/12/implementing-a-cnn-for-text-classification-in-tensorflow/ )。因为要做的只是二分类,所以对其模型中平行的三个卷积层进行了简化,只使用一个卷积层。 因为发现过拟合严重,增加了两个Dropout层。
data_input = Input(shape=[maxlen])
word_vec = Embedding(input_dim=num_words+1,
input_length=maxlen,
output_dim=vec_size,
mask_zero=0)(data_input)
x = Conv1D(filters=128, kernel_size=[3], strides=1, padding='same', activation='relu')(word_vec)
x = GlobalMaxPool1D()(x)
x = Dropout(0.1)(x)
x = Dense(500, activation='relu')(x)
x = Dropout(0.1)(x)
x = Dense(output_shape, activation='softmax')(x)
model = Model(inputs=data_input, outputs=x)
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
model.summary()
#训练
model.fit(x=X_train, y=y_train, epochs=3, batch_size=64,verbose=2)
#预测
y_predict = model.predict(X_test)
#转换预测结果
y_predict_label = label2tag(predictions=y_predict, y=y)
#统计正确率
Y_test=label2tag(predictions=y_test,y=y)
print(sum([y_predict_label[i] == Y_test[i] for i in range(len(y_predict))]) / len(y_predict))
代码见 SVM.py
流程: 导入数据 -> 数据预处理(分词,词语转为词向量) -> 构建模型 -> 训练和预测 -> 计算准确率
1、分词,同上
2、词向量生成
使用中文词向量语料库(Shen Li, Zhe Zhao, Renfen Hu, Wensi Li, Tao Liu, Xiaoyong Du, Analogical Reasoning on Chinese Morphological and Semantic Relations, ACL 2018.)中的中文预训练词向量(sgns.weibo.word)对分词结果进行转换。
model = gensim.models.KeyedVectors.load_word2vec_format(word2vec_loadpath,binary=False)
text_vec = [[model[word] for word in text_cut if word in model] for text_cut in X_cut]
model_svc = SVC(C=10,kernel='linear',)
#C似乎越大准确率越高: score 0.819672(C=1) 0.83957(C=2) 0.850117(C=3) 0.862997(C=5)
#尝试了所有的kernel,最后得出linear的准确率最高。
model_svc.fit(X=X_train,y=y_train,)
y_predict = model_svc.predict(X_test)
print(sum(y_predict == np.array(y_test)) / len(y_predict))
数据量 | 卷积神经网络 | 支持向量机 |
---|---|---|
50 | 0.500 | 0.900 |
100 | 0.550 | 0.900 |
200 | 0.650 | 0.900 |
300 | 0.733 | 0.883 |
400 | 0.825 | 0.763 |
500 | 0.850 | 0.820 |
1000 | 0.875 | 0.844 |
2000 | 0.900 | 0.869 |
3000 | 0.901 | 0.875 |
4000 | 0.9175 | 0.886 |
可以看出,卷积神经网络随着数据量的增加,正确率也是不断地提高,最后收敛在0.90左右。而支持向量机的正确率却是经历了先减小后增大的过程。 说明对于卷积神经网络,用于训练的数据量越大,效果越好。而对于支持向量机,更重要的可能是参数的设置。