本文主要是介绍【基于机器学习的餐馆评论文本分类分析】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
餐馆评论的文本分析
- 0 引言
- 1 数据预处理
- 1.1 数据集描述
- 1.2 缺失值处理
- 1.3 异常值处理
- 1.4 短句及特殊字符删除
- 1.5 中文分词、去停用词
- 1.6 水军数据处理
- 2 描述性统计分析
- 2.1 词云图
- 2.2 不同餐馆的好评/差评 ratio[按照总体评分],排序 top10,柱状图可视化
- 2.3 Top10 餐馆随时间变化的好评/差评[按照总体评分]线图
- 2.4 雷达图
- 3 特征工程
- 3.1 数据集划分
- 3.2 特征提取
- 4 模型与预测
- 4.1 建立模型
- 4.2 模型预测
- 4.3 模型检验
- 5 总结
- 6 参考文献
0 引言
本文利用python语言,对餐馆的大众点评评论文本进行分析。首先,通过数据清洗、中文分词以及特征工程完成数据的预处理。对完成预处理的数据作了描述统计说明。
其次,构建了逻辑回归、支持向量机和朴素贝叶斯三个分类器模型,计算召回率、精确度、F1和准确率等指标来评价它们的实际性能。逻辑回归模型表现最好,准确率为85%,可以用于实现对餐馆评论文本的精确分类。
最后,基于处理好的数据利用关键字查询餐馆的名称,并通过可视化手段展示某个餐馆的评论、好评/差评比例、环境评分、口味评分、服务评分以及随时间变化的好评/差评线图等指标。
1 数据预处理
1.1 数据集描述
本文研究使用的餐馆大众点评评论文本包含3个数据集:restaurants.csv、ratings.csv、links.csv。数据集字段信息及部分示例数据如表1-3。
restaurant数据集包含 243247条餐馆数据
餐馆数目(有名称): 209132
餐馆数目(没有名称):34115
餐馆数目(总计): 243247
ratings数据集包含 4422473条评论数据、542706个用户
用户数目:542706
评分/评论数目(总计): 4422473
总体评分数目([1,5]): 3293878
环境评分数目([1,5]): 4076220
口味评分数目([1,5]): 4093819
服务评分数目([1,5]): 4076220
评论数目: 4107409
links数据集包含243247条数据
1.2 缺失值处理
对缺失值的处理主要是删除数据中的空值。
- 查看restaurant数据集的缺失值。
print(restaurants.isnull().sum(axis=0))
restaurant数据集name列有34115条缺失值。因为后文有可视化分析,没有餐馆名称的数据直接删掉。
- 查看ratings数据集的数据集
print(ratings.isnull().sum(axis=0))
ratings数据集总共4422473条数据
评分有1128580条缺失值
环境评分有346253条缺失值
口味评分有328654缺失值
服务评分有346253条缺失值
评论内容有315064条缺失值
首先删除restaurant数据集中餐馆名称为nan的restId,对应的ratings数据集数据。然后再删除评论内容中的缺失值。
# 删除餐馆名称为nan的restId,对应的ratings数据,要删除的id→id_with_missing_values# 根据id删除行
data = ratings.set_index('restId').drop(id_with_missing_values).reset_index()# 删除评论内容为nan的值
data.dropna(axis=0, subset='comment', inplace=True)
处理完之后再查看ratings数据集的缺失值。
处理之后发现rating_env、rating_flavor、rating_service均有55个缺失值,对缺失值进行具体探查。
# 查看rating_env列有缺失值的行
null_rating_env = data[data['rating_env'].isna()]
print(null_rating_env)
从图中可以看出rating_env、rating_flavor、rating_service是一起缺失的,所以直接删掉就好了。
然后rating列还存在1013107条缺失值,因为缺失值占据数据集的1/4,所以不能直接删除,初步的想法是对rating列进行填充。
因为数据量太大了,对于我个人的电脑来说要运行很久,所以直接删除好了。
1.3 异常值处理
同时呢我们观察到在ratings数据集中存在环境、口味、服务的评分与总评分不符合的情况,例如对环境、口味、服务评分只有1-2分,但是总评分却是4分及以上。可能是因为该餐馆在其他方面得到了更高的评价,例如价格、装修或者地理位置等。这些低分的评价可能是由于个别顾客对某些方面的不满意而导致的,不能完全反映该餐厅的整体评价,或者是某些用户的评分标准与其他用户存在很大差异,导致他们给的评分与整体评分相差较大。会影响对评论文本的情感分析,需要进行处理。
# 筛选rating_env、rating_flavor、rating_service评分为3分以下,rating评分为3分及以上的数据
data1 = known_rating[(known_rating['rating_env'] < 3) & (known_rating['rating_flavor'] < 3)& (known_rating['rating_service'] < 3) & (known_rating['rating'] >= 4)]
# 筛选rating_env、rating_flavor、rating_service评分为3分以上,rating评分为3分以下的数据
data2 = known_rating[(known_rating['rating_env'] >= 3) & (known_rating['rating_flavor'] >= 3)& (known_rating['rating_service'] >= 3) & (known_rating['rating'] < 4)]
所以对于rating列异常值和异常值本文采取的处理方法是对所有维度的评分进行加权,并将其作为综合评分使用。这样可以更准确地反映顾客的整体评价,避免过于依赖单个维度(例如总评分)而导致评估不准确或误导。
权值的设置是自定义的,该赋权过程可以用公式表示如下:
rating_2=0.4×rating+0.2×rating_env+0.2×rating_flavor+0.2×rating_service
其中rating_2表示计算出的综合评分,其为0-5的数值。
利用综合评分的分值可以划分评论数据为好评数据和差评数据,设置rating_2值为[0,3]的评论为差评,rating_2值为[4,5]的评论为好评,将结果保存到evaluation列,其中“1”代表好评,“0”代表差评。
# 计算总的得分rating_2
data['rating_2'] = data['rating_env']*0.2 + data['rating_flavor']*0.2 + data['rating_service']*0.2 + data['rating']*0.4
# 划分好评和差评
data['evaluation'] = data['rating_2'].apply(lambda x: 0 if x < 4 else 1)
1.4 短句及特殊字符删除
评论字段中字符长度较小的数据,利用价值小。将评论文本中字符长度小于10的数据删除。
data = data[data['comment'].apply(len) >= 10]
还有一些特殊字符如英文、数字、表情符号、字符串等,对于特殊字符采用正则表达式re进行剔除,这个在去停用词部分处理。
1.5 中文分词、去停用词
中文文本与英文文本之间的差别很大,在中文表达中没有作为分隔符的空格出现,同时具体的汉字表达的意思也是极不明确的,单个词语更不能十分准确地表达意思。因此需要先对文本进行分词操作,然后对分词后的结果逐一进行表示。本文使用的是jieba分词技术来进行中文文本分词。
文本在经过分词之后存在很多像“的”、“了”、“吧”、“啊”、“这”等一些无实际意义的语气词、代词、介词等,还有标点符号、特殊符号等都称为停用词。这类词不仅会提升模型的复杂性还会影响分类效果,所以需要过滤这些无意义的词,从而减少文本的噪音,增大关键词密度,提高文本分类的准确率和主题分析的效率。
基于前人的研究成果,本文搜集了一些停用词典,主要包括哈工大停用词典、百度停用词典、四川大学机器智能实验室停用词库以及中文停用词表,将它们合并去重最后得到包含 1893个停用词的停用词典。
值得注意的是,由于本研究的数据量过大,在分词过程中将数据集划分为10个批次,对每个批次都进行了去停用词的处理,将结果依次保存为文件,最后将10个文件合并。
import jieba
import re
from sklearn.model_selection import KFold# 加载停用词表
stop_words = set()
with open('D:/课程/数据挖掘技术与实践/作业/tc-corpus-answer/停用词表/stopwords.txt', encoding=encoding) as f:for line in f:stop_words.add(line.strip())def preprocess_text(text):# 去除空白字符text = re.sub(r'\s+', '', text)# 分词seg_list = jieba.lcut(text)# 去除停用词和非中文字符seg_list = [token for token in seg_list if token not in stop_words and re.match(r'^[\u4e00-\u9fa5]+$', token)]return ' '.join(seg_list)# 划分数据集为 10 个批次,并对每个批次中的 comment 列进行预处理,并单独保存到文件中
kfold = KFold(n_splits=10, shuffle=True, random_state=42)
for i, (train_idx, test_idx) in enumerate(kfold.split(df)):df_batch = df.iloc[test_idx].copy()df_batch['comment'] = df_batch['comment'].apply(preprocess_text)df_batch.to_csv(f'batches_{i+1}.csv', encoding='utf-8', index=False)# 读取第 1 个数据集文件
batch_data = pd.read_csv('batches_1.csv')# 读取其他 9 个数据集文件,并与第 1 个数据集合并
for i in range(2, 11):batch_data_i = pd.read_csv(f'batches_{i}.csv')batch_data = pd.concat([batch_data, batch_data_i], ignore_index=True)# 将合并后的数据集保存为一个文件
batch_data.to_csv('without_data.csv', index=False)batch_data = pd.read_csv('without_data.csv')
在进行分词和去停用词操作后,评论文本中出现了缺失值和重复值,删除这些数据。
将restaurants数据集和ratings数据集根据restId合并数据集。
batch_data = pd.merge(batch_data, restaurants[['restId', 'name']], on='restId', how='left'
原始文本经过分词和去停用词操作后的结果如下表所示
原始文本 | 整体感觉还是不错的了,,比较安静惬意,,坐坐喝喝茶真的是挺舒服的,,,四周的环境绿化也挺不错 |
---|---|
分词、去停用词 | 整体 感觉 不错 安静 惬意 坐坐 喝 喝茶 真的 挺舒服 四周 环境 绿化 挺不错 感觉 |
可以看出处理效果是非常明显的,许多符号和无意义文本都被去除,为后文建立模型提供了优质的数据基础。
1.6 水军数据处理
统计comment列的字段长度,绘制箱线图如下:
import pandas as pd
import matplotlib.pyplot as pltfig, ax = plt.subplots(figsize=(8, 6))
ax.boxplot(data['comment_length'],vert=False, widths=0.4, patch_artist=True, boxprops=dict(facecolor='LightBlue'))
ax.set_title('Comment Length Boxplot', fontsize=14)
ax.set_xlabel('Comment Length', fontsize=12)
plt.show()
从上图我们可以看出,居然有评论内容的长度有2000字!that‘s amazing!
在数据预处理的过程中,试图筛选出网络水军发表的评论,并进行清除,但是在实际操作过程中没有确定的标准来进行辨别。
根据同一userId号在相近的时间内以相似的内容进行评论,被高度怀疑是网络水军的做法,数据预处理时仅根据这一实践经验进行了部分高度疑似水军数据的删除。
from difflib import SequenceMatcher
import mathdata = batch_data.copy()# 将数据集分成20个批次
num_batches = 20
batch_size = math.ceil(len(data) / num_batches)for i in range(num_batches):start_idx = i * batch_sizeend_idx = min((i+1) * batch_size, len(data))# 取出当前批次的数据batch_data = data.iloc[start_idx:end_idx]# 删除高度疑似水军数据idx_to_drop = []for j in range(1, len(batch_data)):# 判断userId是否相同if batch_data.iloc[j]['userId'] == batch_data.iloc[j-1]['userId']:# 判断时间间隔是否小于等于1分钟if pd.Timestamp(batch_data.iloc[j]['timestamp']) - pd.Timestamp(batch_data.iloc[j-1]['timestamp']) <= pd.Timedelta(minutes=1):# 计算相似度similarity = SequenceMatcher(None, batch_data.iloc[j]['comment'], batch_data.iloc[j-1]['comment']).ratio()if similarity > 0.8:idx_to_drop.append(j)# 删除高度疑似水军数据batch_data = batch_data.drop(idx_to_drop)print(idx_to_drop)# 保存处理后的数据到文件batch_data.to_csv(f'batch_data_processed_{i}.csv', index=False)
# 将数据进行汇总
# 读取第 1 个数据集文件
batch = pd.read_csv('batch_data_processed_0.csv')# 读取其他 9 个数据集文件,并与第 1 个数据集合并
for i in range(1, 19):batch_i = pd.read_csv(f'batch_data_processed_{i}.csv')batch = pd.concat([batch, batch_i], ignore_index=True)# 将合并后的数据集保存为一个文件
batch.to_csv('drop_water_data.csv', index=False)
2 描述性统计分析
2.1 词云图
经过上文对数据进行预处理后,本节分别统计好评和差评评论文本中各个词语出现的频次并绘制相应词云图,最后绘制所有评论的词云图。词云图中,词频越高,词的字号就越大,词频越低,词的字号就越小。
from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号def generate_wordcloud_batches(batch_data, num_batches, save_path):# 每批次处理数据的大小batch_size = int(len(batch_data) / num_batches)batch_data['comment'] = batch_data['comment'].astype(str)# 定义生成词云图函数def generate_wordcloud(text_list, output_file):text = " ".join(text_list)wc = WordCloud(font_path='simkai.ttf', background_color='white', width=800, height=600, max_words=100, collocations=False)wc.generate(text)wc.to_file(output_file)# 分批次处理数据并生成词云图for i in range(num_batches):start = i * batch_sizeend = start + batch_size if i != (num_batches - 1) else len(batch_data)batch_text_list = batch_data.iloc[start:end, :]["comment"].tolist()output_file = f"{save_path}batch_wordcloud_f_{i}.png"generate_wordcloud(batch_text_list, output_file)# 合并所有词云图all_text_list = batch_data["comment"].tolist()output_file = f"{save_path}all_f.png"generate_wordcloud(all_text_list, output_file)
将数据集划分为好评数据集和差评数据集,分别绘制好评、差评和总的评论词云图如下:
df = a_data.copy()
final_wordcloud = generate_wordcloud_batches(df, num_batches=10, save_path='a/')
df = c_data.copy()
final_wordcloud = generate_wordcloud_batches(df, num_batches=10, save_path='c/')
df = batch_data.copy()
final_wordcloud = generate_wordcloud_batches(df, num_batches=10, save_path='all_data/')
观察图可以看出,不错、味道、好吃、吃、喜欢、感觉、环境、价格、服务等词语较为醒目,可以知道在评论中大部分消费者经常使用这些词汇对餐馆做出评价,观察好评词云图高频词是一些正面评价的词汇,而在差评词云图中出现了一些负面高频词,如:贵、少、不好等词汇。其中在差评词云图中,关于服务的词汇出现了两个:服务员、服务,说明做出负面评价的消费者对餐馆的服务质量并不满意。建议餐馆管理者加强对服务员的培训、提高服务质量。
2.2 不同餐馆的好评/差评 ratio[按照总体评分],排序 top10,柱状图可视化
对预处理操作完成后的数据进行统计,筛选出餐馆的评论量大于50的数据,过滤掉评论量较少的餐馆,集中分析有更多评论量的餐馆,按照餐馆的好评/差评数据占比总数据的比例降序排列,查看好评评论和差评评论中top10餐馆。统计情况如下图。
import pandas as pd
import matplotlib.pyplot as plt# 读取数据
data = batch_data.copy()
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False# 筛选出评论数量大于50的餐馆数据
filtered_data = data.groupby('restId').filter(lambda x: len(x) > 50)# 计算每个餐馆的总评数目、好评数目和差评数目
grouped = filtered_data.groupby(['restId', 'evaluation']).size().reset_index(name='count')
good_counts = grouped[grouped['evaluation'] == 1]
bad_counts = grouped[grouped['evaluation'] == 0]
total_counts = grouped.groupby('restId')['count'].sum().reset_index(name='total_count')
good_ratios = good_counts.merge(total_counts, on='restId')
good_ratios['good_ratio'] = good_ratios['count'] / good_ratios['total_count']
bad_ratios = bad_counts.merge(total_counts, on='restId')
bad_ratios['bad_ratio'] = bad_ratios['count'] / bad_ratios['total_count']
ratios = good_ratios.merge(bad_ratios, on='restId').merge(data[['name','restId']].drop_duplicates(), on='restId')# 按照好评/总评比例或者差评/总评比例大小排序,并取出前10名餐馆
top10_good = good_ratios.sort_values(by='good_ratio', ascending=False).head(10)
top10_bad = bad_ratios.sort_values(by='bad_ratio', ascending=False).head(10)# 横向柱状图可视化好评/差评比例
plt.subplots(figsize=(10, 7))
plt.suptitle('Restaurants Rating Ratio - Top 10 Good Rating vs. Top 10 Bad Rating', fontsize=16, y=1)plt.subplot(1, 2, 1)
plt.barh(y=ratios.nlargest(10,'good_ratio')['name'], width=ratios.nlargest(10,'good_ratio')['good_ratio'], color='green')
plt.xticks(rotation=0)
plt.xlabel('Good Rating Ratio')
plt.ylabel('Restaurant Name')
plt.title('Top 10 Restaurants by Good Rating Ratio')plt.subplot(1, 2, 2)
plt.barh(y=ratios.nlargest(10,'bad_ratio')['name'], width=ratios.nlargest(10,'bad_ratio')['bad_ratio'], color='red')
plt.xticks(rotation=0)
plt.xlabel('Bad Rating Ratio')
plt.ylabel('Restaurant Name')
plt.title('Top 10 Restaurants by Bad Rating Ratio')plt.subplots_adjust(wspace=1)
plt.show()
2.3 Top10 餐馆随时间变化的好评/差评[按照总体评分]线图
随着时间推移,餐馆的服务水平、菜品质量、环境卫生等方面可能发生变化,对应的好评/差评率也会有所反应。整个数据中时间跨度为2009-07-04 00:16:00到2012-02-08 14:04:00,总共有32个月,137个周,950个日,数据量比较大。绘制按照周的时间粒度的随时间变化的餐馆的好评/差评率线图如下。
def plot_evaluation_by_week(top10, filtered_data, ratios, is_good_evaluation=True):# 绘制每个餐馆的评分随时间变化的线图for restId in top10['restId']:rest_data = filtered_data[filtered_data['restId'] == restId]rest_data['date'] = pd.to_datetime(rest_data['timestamp'])rest_data = rest_data.set_index('date').resample('W').mean()rest_name = ratios.loc[ratios['restId'] == restId, 'name'].iloc[0]fig, ax = plt.subplots()ax.plot(rest_data.index, rest_data['rating_2'], label=rest_name, color='blue')ax.set_xlabel('时间')ax.set_ylabel('评分')title = '好评排名top10的餐厅' if not is_good_evaluation else '差评排名top10的餐厅'plt.title(title)plt.xticks(rotation=45)ax.legend(loc='best')plt.show()
2.4 雷达图
筛选出好评评论和差评评论中top10餐馆后,为更深入地了解好评评论量较高的餐馆和差评评论量较高的餐馆的综合表现,绘制每个餐馆的环境、口味、服务评分雷达图如下。
def draw_radar_chart(top_restids, data):"""
绘制top_restids中餐厅的雷达图
:param top_restids: 需要绘制雷达图的餐厅列表
:param data:所有餐厅的评分数据
"""# 选择对应的restid数据top_restaurants_data = data[data['restId'].isin(top_restids)]# 计算rating_env,rating_flavor,rating_service的平均值avg_ratings = top_restaurants_data.groupby('name').mean()[['rating_env', 'rating_flavor', 'rating_service']]# 绘制雷达图attributes = ['rating_env', 'rating_flavor', 'rating_service']for name, row in avg_ratings.iterrows():values = row.values.flatten().tolist()values += values[:1]angles = [n / float(len(attributes)) * 2 * pi for n in range(len(attributes))]angles += angles[:1]ax = plt.subplot(111, polar=True)plt.xticks(angles[:-1], attributes,rotation=90,ha='left')ax.set_rlabel_position(0)plt.yticks([1.0, 2.0, 3.0, 4.0,5.0], ["1.0", "2.0", "3.0", '4.0','5.0'], color="grey",size=9, rotation=90, ha='center')plt.ylim(1, 5)ax.plot(angles, values, linewidth=1, linestyle='solid')ax.fill(angles, values, 'b', alpha=0.1)#添加数值标记(保留两位数)for i in range(len(attributes)):angle_rad = i / float(len(attributes)) * 2 * piif values[i] >= 3:ha = 'left'else:ha = 'right'plt.text(angle_rad, values[i]+0.2, format(values[i], '.2f'), ha=ha, va='center')plt.title('Ratings for Restaurant {}'.format(name))plt.show()
观察好评率top10餐馆可以发现,大部分好评餐馆在环境、服务、口味3各方面中环境和服务评分比口味高,由于好评率是所有维度的综合体现,环境和服务评分可能对总体的好评率产生更大的影响。
观察差评率top10餐馆可以发现大部分差评餐馆在环境、服务、口味3各方面中环境和服务评分比口味低,这与上文得出的结论相同,环境和服务评分可能对总体的好评率产生更大的影响。餐馆经营者需要注意维护餐厅的整体形象,提高服务质量、卫生和环境等方面的表现,并尽可能提高各方面的综合表现,以获得更高的好评率和更多的客户支持。
3 特征工程
3.1 数据集划分
餐馆的评论文本数据经过预处理后,已经具备构建分类器的条件。将评论文本分成训练数据集和测试数据集,首先在训练数据集上建立预测模型,构建文本分类器,然后用训练出来的分类器模型在测试数据集上进行预测,根据预测情况对分类器性能进行评估。
把预处理后的数据的comment列作为特征值,evaluation列作为目标值。采用随机抽样的方式来抽取训练数据集和测试数据集,以8:2的比例划分训练集和测试集。
from sklearn. model_selection import train_test_splitX = batch_data['comment']
y = batch_data['evaluation']
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=22)
3.2 特征提取
采用Count Vectorizer文本特征提取方法,将原始文本数据转化为数字特征向量。该方法将每个文档表示为一个向量,其中向量的每个元素表示该文档中相应单词(或特征)出现的次数。
设置Count Vectorizer方法中的两个参数max_df=0.9,min_df=3, 当某个单词在文档中出现的频率达到max_df这个阈值时,某个单词在所有文档中出现的频率小于min_df这个阈值时,就会被认为是停用词(即被过滤掉),可以帮助减小特征空间的维度并提高向量化后数据的质量和可解释性。
将评论文本数据转换为特征向量后,用TfidfTransformer文本特征转换方法,将CountVectorizer输出的词频矩阵转换为TF-IDF矩阵。TF-IDF矩阵可以将常见的词语的权重降低,同时却保留那些区分度较高的词语的权重,以优化文本特征表示的效果。
from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer# 使用Count Vectorizer提取文本特征
count_vect = CountVectorizer(max_df = 0.9,min_df = 3)
X_train_counts = count_vect.fit_transform(X_train)
X_test_counts = count_vect.transform(X_test)from sklearn.feature_extraction.text import TfidfVectorizer
# 使用TF-IDF Vectorizer调整特征权重
tfidf_transformer = TfidfTransformer()
X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)
X_test_tfidf = tfidf_transformer.transform(X_test_counts)
4 模型与预测
4.1 建立模型
接下来就可以使用 Python 语言进行模型构建,首先在训练数据集上构建文本分类模型,然后在测试数据集上进行预测,根据预测情况计算模型评价指标对分类模型性能进行评估。
本研究选取了朴素贝叶斯、逻辑回归、支持向量机共3个算法,建立中文文本二值分类模型。各模型主要参数如下:
(1)逻辑回归模型。首先考虑加入正则化项来防止模型出现过拟合现象,比较常见的有参数向量的范数 𝐿1、𝐿2 等,这里选择 𝐿2 的正则化,正则惩罚项系数 𝐶 设为 1。
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
from sklearn.metrics import classification_reportlogistic_reg = LogisticRegression(penalty='l2', C=1.0)
logistic_reg.fit(X_train_tfidf, y_train)y_pred_l = logistic_reg.predict(X_test_tfidf)print(classification_report(y_test, y_pred_l))
(2)支持向量机模型。直接使用线性核,直接实例化 LinearSVC 对象。
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import accuracy_score
from sklearn.metrics import classification_report
# 建立朴素贝叶斯模型
naive_bayes = MultinomialNB(alpha=0.1 )
naive_bayes.fit(X_train_tfidf, y_train)y_pred_s = naive_bayes.predict(X_test_tfidf)print(classification_report(y_test, y_pred_s))
(3)朴素贝叶斯模型。查阅 Sklearn 的官网介绍发现朴素贝叶斯的主要参数是平滑项参数 (𝐴𝑙𝑝ℎ𝑎),且当 𝐴𝑙𝑝ℎ𝑎 = 0.1 时,其运行效果最佳。
from sklearn.svm import LinearSVC
from sklearn.metrics import accuracy_score
from sklearn.metrics import classification_report
# 建立SVM分类模型并进行训练
svc = LinearSVC()
svc.fit(X_train_tfidf, y_train)# 对测试集进行预测并输出评估结果
y_pred = svc.predict(X_test_tfidf)print(classification_report(y_test, y_pred))
4.2 模型预测
本小节的实验参数依照上节参数设置,分类模型分别采用机器学习朴素贝叶斯、支持向量机、逻辑回归模型进行训练,根据训练出来的各分类模型,对测试集中的数据进行预测,评价指标选择的是accuracy、precision、recall、F1。
各模型测试结果的评价指标如下表
模型 | accuracy | precision | recall | F1 |
---|---|---|---|---|
逻辑回归 | 0.8502 | 0.81 | 0.85 | 0.81 |
支持向量机 | 0.8483 | 0.81 | 0.85 | 0.79 |
朴素贝叶斯 | 0.8458 | 0.81 | 0.85 | 0.79 |
根据测试集上的指标,可以选择逻辑回归模型作为最终的预测模型。虽然三个模型的精度和其他指标都相近,但逻辑回归的F1得分达到了0.81,是三个模型中的最高值。在这种情况下,我们可以选择在测试集上表现最好的模型,这个模型能在未知数据上更可靠地进行分类。
4.3 模型检验
经过上文对模型的训练,我们最终选择了表现效果更好的逻辑回归模型,为了验证和评估训练好的分类模型在真实场景下的表现,通过用户输入新的评论,我们可以将模型应用于没有包含在训练集和测试集中的数据,这样可以更全面地评估模型的泛化能力和真实世界中的应用效果。
输入新评论,对新评论作同前文一致的文本预处理,进行特征提取和处理,使用训练好的分类模型进行预测,得到分类结果如下。
新评论 | 分类结果 |
---|---|
我在上海尝试了一家新开的法式餐馆,感觉非常惊艳!从前菜到主菜再到甜品,每一道菜都很讲究,味道和口感都非常出色,让我直呼过瘾。服务也非常周到,服务员们知道如何处理每一个细节,让整个用餐过程非常愉快。虽然价格有点贵,但绝对值得一尝 | 好评 |
这家餐厅真是太失望了!除了位置好以外,其他都非常不行。我们点了几道菜,但味道都太油腻了,而且肉的质量也很差。虽然服务员很友好,但是等待时间太长了,甚至比正常情况下还要糟糕。餐厅的氛围也不好,很吵,感觉不适合用餐。总之,这是一次糟糕的体验,不会再来了 | 差评 |
从新评论在逻辑回归模型上训练的分类结果看,逻辑回归模型的预测结果准确,具有良好的拟合效果。
5 总结
本次研究所使用的数据量较大,但在处理缺失值时,采取了删除空值的措施,这导致了数据量的大量损失,是本研究的不足之一。为此,可以采用决策树预测等方法对rating评分的缺失值进行填充,以提高数据的覆盖面和模型的拟合效果。
在计算综合评分时,权值是自定义的,可以采用网格搜索来确定权值,以实际分类模型的分类效果来确定最优权值。
为了筛选水军数据,我们采用了SequenceMatcher方法来计算相似度。未来,我们可以探索其他更有效的筛选方法,以提高数据的可靠性和准确性。
在本次研究中,因为安装问题所以没有使用Elasticsearch服务器,在未来的研究中,我们可以考虑使用Elasticsearch来进行数据索引和检索。这样可以更快速和准确地查询数据,并提高数据的处理效率和精度。同时,Elasticsearch还能够提供强大的搜索和分析能力,帮助我们更好地理解数据,发现数据中的规律和趋势,为研究提供更深入的支持和指导。
6 参考文献
[1] 张东红,马一凡,刘丹.基于文本分类方法的新闻主题识别系统[J].信息技术与信息
化, 2021(10):163-165.
[2] Shen F, Luo X, Chen Y. Text classification dimension reduction algorithm for Chinese web page based on deep learning [C], International Conference on. IET, 2013:451-456.
[3] 张紫琼. 在线中文评论情感分类问题研究[D].哈尔滨工业大学,2010.
[4] 丁照银. 基于机器学习的评论文本分析[D].安徽师范大学,2019.
[5] 王浩然. 基于机器学习的微博网约车话题评论文本分析[D].南开大学,2021.
[6]郑明明. 基于机器学习的冰雪旅游评论文本分析[D].燕山大学,2022.
这篇关于【基于机器学习的餐馆评论文本分类分析】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!