情感分析系统(预测用户评论积极或消极的概率)

xiaoxiao2025-09-17  44

1.数据预处理

本部分将要完成数据的预处理过程,包括数据的读取,数据清洗,分词,以及把文本转换成tf-idf向量。在接下来的任务中,正面的情感我们标记为1, 负面的情感我们标记成0。

import re import jieba import numpy as np def process_line(line): new_line = re.sub('([a-zA-Z0-9])','',line) new_line = ''.join(e for e in new_line if e.isalnum()) new_line = ','.join(jieba.cut(new_line)) return new_line def process_train(file_path): comments = [] # 用来存储评论 labels = [] # 用来存储标签(正/负),如果是train_positive.txt,则所有标签为1, 否则0. with open(file_path) as file: # TODO 提取每一个评论,然后利用process_line函数来做处理,并添加到comments。 text = file.read().replace(' ','').replace('\n','') reg = '<reviewid=.*?</review>' result = re.findall(reg,text) for r in result: r = process_line(r) comments.append(r) if file_path == 'train.positive.txt': labels.append('1') else: labels.append('0') return comments, labels def process_test(file_path): comments = [] # 用来存储评论 labels = [] # 用来存储标签(正/负). with open(file_path) as file: # TODO 提取每一个评论,然后利用process_line函数来做处理,并添加到 # comments。 text = file.read().replace(' ','').replace('\n','') reg = '<reviewid=.*?</review>' result = re.findall(reg,text) for r in result: label = re.findall('label="(\d)"',r)[0] labels.append(label) r = process_line(r) comments.append(r) return comments, labels def read_file(): """ 读取所提供的.txt文件,并把内容处理之后写到list里面。 这里需要分别处理四个文件,“train_positive.txt", "train_negative.txt", "test_combined.txt" 并把每一个文件里的内容存储成列表。 """ # 处理训练数据,这两个文件的格式相同,请指定训练文件的路径 train_pos_comments, train_pos_labels = process_train("train.positive.txt") train_neg_comments, train_neg_labels = process_train("train.negative.txt") # TODO: train_pos_comments和train_neg_comments合并成train_comments, train_pos_labels和train_neg_labels合并成train_labels train_comments = train_pos_comments + train_neg_comments train_labels = train_pos_labels + train_neg_labels # 处理测试数据, 请指定测试文件的路径 test_comments, test_labels = process_test("test.combined.txt") return train_comments, train_labels, test_comments, test_labels

读取文本并校验数据长度

# 读取数据,并对文本进行处理 train_comments, train_labels, test_comments, test_labels = read_file() # 查看训练数据与测试数据大小 print (len(train_comments), len(train_labels), len(test_comments), len(test_labels))

把每一个文本内容转换成tf-idf向量

from sklearn.feature_extraction.text import TfidfVectorizer # 导入sklearn库 # TODO: 利用TfidfVectorizer把train_comments转换成tf-idf,把结果存储在X_train, 这里X_train是稀疏矩阵(Sparse Matrix) # 并把train_labels转换成向量 y_train. 类似的,去创建X_test, y_test。 把文本转换成tf-idf过程请参考TfidfVectorizer的说明 tfid_vec = TfidfVectorizer() X_train = tfid_vec.fit_transform(train_comments) y_train = np.array(train_labels) X_test = tfid_vec.transform(test_comments) y_test = np.array(test_labels) # 查看每个矩阵,向量的大小, 保证X_train和y_train, X_test和y_test的长度是一样的。 print (np.shape(X_train), np.shape(y_train), np.shape(X_test), np.shape(y_test))

第二部分: 利用逻辑回归模型搭建情感分析引擎

在本部分将会利用罗回归模型(logistic regressiion)来搭建情感分析引擎。

from sklearn.linear_model import LogisticRegression # TODO: 初始化模型model,并利用模型的fit函数来做训练,暂时用默认的设置。 lr = LogisticRegression().fit(X_train,y_train) # 打印在训练数据上的准确率 print ("训练数据上的准确率为:" + str(lr.score(X_train, y_train))) # 打印在测试数据上的准确率 print ("测试数据上的准确率为: " + str(lr.score(X_test, y_test))) # TODO: 利用自己提出的例子来做测试。随意指定一个评论,接着利用process_line来做预处理,再利用之前构建好的TfidfVectorizer来把文本转换 # 成tf-idf向量, 然后再利用构建好的model做预测(model.predict函数) test_comment1 = "这个很好" test_comment2 = "垃圾" test_comment3 = "评论区说不烂都是骗人的,超赞" a = [] a.append(process_line(test_comment1)) print(lr.predict(tfid_vec.transform(a)))

打印结果如下,能看到测试评论“这个很好”的预测值为1,即“积极”

第三部分: 利用决策树,神经网络,SVM来训练模型。

决策树模型
from sklearn import tree # TODO: 初始化决策树模型,并利用模型的fit函数来做训练并打印在训练和测试数据上的准确率,利用决策树默认的参数设置 dtc1 = tree.DecisionTreeClassifier().fit(X_train,y_train) # 打印在训练数据上的准确率 print ("训练数据上的准确率为:" + str(dtc1.score(X_train, y_train))) # 打印在测试数据上的准确率 print ("测试数据上的准确率为: " + str(dtc1.score(X_test, y_test))) # TODO: 初始化决策树模型,并利用模型的fit函数来做训练并打印在训练和测试数据上的准确率,设置max_depth参数为3 dtc2 = tree.DecisionTreeClassifier(max_depth=3).fit(X_train,y_train) # 打印在训练数据上的准确率 print ("训练数据上的准确率为:" + str(dtc2.score(X_train, y_train))) # 打印在测试数据上的准确率 print ("测试数据上的准确率为: " + str(dtc2.score(X_test, y_test))) # TODO: 初始化决策树模型,并利用模型的fit函数来做训练并打印在训练和测试数据上的准确率,设置max_depth参数为5 dtc3 = tree.DecisionTreeClassifier(max_depth=5).fit(X_train,y_train) # 打印在训练数据上的准确率 print ("训练数据上的准确率为:" + str(dtc3.score(X_train, y_train))) # 打印在测试数据上的准确率 print ("测试数据上的准确率为: " + str(dtc3.score(X_test, y_test)))
支持向量机(SMV)模型
from sklearn import svm # TODO: 初始化SVM模型,并利用模型的fit函数来做训练并打印在训练和测试数据上的准确率,SVM模型的kernel设置成“rbf”核函数 svc = svm.SVC(kernel='rbf').fit(X_train,y_train) # 打印在训练数据上的准确率 print ("训练数据上的准确率为:" + str(svc.score(X_train, y_train))) # 打印在测试数据上的准确率 print ("测试数据上的准确率为: " + str(svc.score(X_test, y_test)))
线性支持向量机(LinearSVM)
from sklearn.svm import LinearSVC # TODO: 初始化LinearSVC模型,并利用模型的fit函数来做训练并打印在训练和测试数据上的准确率,使用模型的默认参数。 clf = LinearSVC() clf.fit(X_train,y_train) # 打印在训练数据上的准确率 print ("训练数据上的准确率为:" + str(clf.score(X_train, y_train))) # 打印在测试数据上的准确率 print ("测试数据上的准确率为: " + str(clf.score(X_test, y_test)))
神经网络模型
from sklearn.neural_network import MLPClassifier # TODO: 初始化MLPClassifier模型,并利用模型的fit函数来做训练并打印在训练和测试数据上的准确率,设置为hidden_layer_sizes为100, # 并使用"lbfgs" solver mlp = MLPClassifier(solver='lbfgs',hidden_layer_sizes=100) mlp.fit(X_train,y_train) # 打印在训练数据上的准确率 print ("训练数据上的准确率为:" + str(mlp.score(X_train, y_train))) # 打印在测试数据上的准确率 print ("测试数据上的准确率为: " + str(mlp.score(X_test, y_test)))

第四部分: 通过交叉验证找出最好的超参数

调用一个sklearn模型本身很简单,只需要2行代码即可以完成所需要的操作。但这里的关键点在于怎么去寻找最优的超参数(hyperparameter)。 比如对于逻辑回归 来说,我们可以设定一些参数的值如“penalty”, C等等,这些我们可以理解成是超参数。通常情况下,超参数对于整个模型的效果有着举足轻重的作用,这就意味着 我们需要一种方式起来找到一个比较合适的参数。其中一个最常用的方法是grid search, 也就在一个去区间里面做搜索,然后找到最优的那个参数值。

举个例子,对于逻辑回归模型,它拥有一个超参数叫做C,在文档里面解释叫做“Inverse of regularization strength“, 就是正则的权重,而且这种权重的取值 范围可以认为通常是(0.01, 1000)区间。这时候,通过grid search的方式我们依次可以尝试 0.01, 0.1, 1, 10, 100, 1000 这些值,然后找出使得 模型的准确率最高的参数。当然,如果计算条件资源允许的话,可以尝试更多的值,比如0.01,0.05,0.1, 0.5, 1, 5, 10 …。 当我们尝试越多值的时候,找到 最优参数的概率就会越大。

逻辑回归模型
from sklearn.linear_model import LogisticRegression from sklearn.model_selection import KFold params_c = np.logspace(-3,3,7) # 对于参数 “C”,尝试几个不同的值 best_c = params_c[0] # 存储最好的C值 best_acc = 0 kf = KFold(n_splits=5,shuffle=False) for c in params_c: # TODO: 编写交叉验证的过程,对于每一个c值,计算出在验证集中的平均准确率。 在这里,我们做5-fold交叉验证。也就是,每一次把20% # 的数据作为验证集来对待,然后准确率为五次的平均值。我们把这个准确率命名为 acc_avg avg = 0 for train_index, test_index in kf.split(X_train): lr = LogisticRegression(C=c).fit(X_train[train_index],y_train[train_index]) avg += lr.score(X_train[test_index],y_train[test_index]) acc_avg = avg/5 if acc_avg > best_acc: best_acc = acc_avg best_c = c print ("最好的参数C值为: %f" % (best_c)) # TODO 我们需要在整个训练数据上重新训练模型,但这次利用最好的参数best_c值 # 提示: model = LogisticRegression(C=best_c).fit(X_train, y_train) lr = LogisticRegression(C=best_c).fit(X_train, y_train) # 打印在训练数据上的准确率 print ("训练数据上的准确率为:" + str(lr.score(X_train, y_train))) # 打印在测试数据上的准确率 print ("测试数据上的准确率为: " + str(lr.score(X_test, y_test)))
神经网络模型

注意:这个模型训练时间较久,在做交叉验证的情况下计算时间可能长达几十个小时

from sklearn.neural_network import MLPClassifier import numpy as np param_hidden_layer_sizes = np.linspace(10, 200, 20) # 针对参数 “hidden_layer_sizes”, 尝试几个不同的值 param_alphas = np.logspace(-4,1,6) # 对于参数 "alpha", 尝试几个不同的值 best_hidden_layer_size = param_hidden_layer_sizes[0] best_alpha = param_alphas[0] for size in param_hidden_layer_sizes: for val in param_alphas: # TODO 编写交叉验证的过程,需要做5-fold交叉验证。 avg = 0 for train_index, test_index in kf.split(X_train, y_train): mlp = MLPClassifier(alpha=int(val),hidden_layer_sizes=int(size)) mlp.fit(X_train[train_index],y_train[train_index]) avg += mlp.score(X_train[test_index],y_train[test_index]) acc_avg = avg/5 if acc_avg > best_acc: best_acc = acc_avg best_hidden_layer_size = size best_alpha = val print ("最好的参数hidden_layer_size值为: %f" % (best_hidden_layer_size)) print ("最好的参数alpha值为: %f" % (best_alpha)) # TODO 我们需要在整个训练数据上重新训练模型,但这次使用最好的参数hidden_layer_size和best_alpha mlp = MLPClassifier(alpha=best_alpha,hidden_layer_sizes=best_hidden_layer_size).fit(X_train,y_train) # 打印在训练数据上的准确率 print ("训练数据上的准确率为:" + str(mlp.score(X_train, y_train))) # 打印在测试数据上的准确率 print ("测试数据上的准确率为: " + str(mlp.score(X_test, y_test)))

完整代码及训练数据已上传至github,点击此处可直接查看,有疑问的同学请提issues或博客下方留言~

转载请注明原文地址: https://www.6miu.com/read-5036510.html

最新回复(0)