Python项目实战——朴素贝叶斯商品评价情感分析项目实战(附完整代码)
在电商数据分析场景中,评价的情感倾向分析是核心需求之一。本文将完整实现从苏宁商品评价爬取到朴素贝叶斯情感分类的全流程,帮助大家掌握爬虫、文本预处理、机器学习分类的完整过程。
一、项目目标
- 爬取苏宁商品的「优质评价」和「差评」数据
- 对评价文本进行分词、停用词过滤等预处理
- 基于朴素贝叶斯算法训练情感分类模型
- 实现单条评价的情感倾向预测
二、环境的安装
selenium网页自动化 / 爬取(操控浏览器)
pip install selenium
pandas数据处理(表格型数据操作)
pip install pandas
jieba中文分词(将中文文本拆分为词语)
pip install jieba
scikit-learn (sklearn)机器学习(数据分割、特征提取、模型训练、评估)
pip install scikit-learn
三、Selenium爬取苏宁商品优质评价
目前爬虫有两种方法,一种是request方法,一种是selenium方法
3.1爬虫方法介绍
3.1.1、request方法
Request 方法是基于 HTTP/HTTPS 协议直接向目标服务器发送请求、获取响应数据的爬虫方式,核心依赖requests库。属于无浏览器渲染的 “轻量级” 爬虫。
(1)核心原理
苏宁商品评价数据本质上存储在服务器中,前端页面展示评价时,会通过 AJAX(异步请求)从后端接口获取 JSON/HTML 格式的评价数据。Request 方法的核心是:
- 分析浏览器抓包(F12 开发者工具),找到返回评价数据的真实接口(通常是
https://xxx.com/comment/xxx形式); - 构造请求头(Headers,包含 User-Agent、Cookie、Referer 等)模拟浏览器请求;
- 向真实接口发送 GET/POST 请求,直接提取响应中的评价数据(如用户名、评价内容、评分、时间等)。
3.1.2、Selenium方法
Selenium 是一款浏览器自动化工具,核心是模拟人工操作浏览器(如打开页面、点击翻页、滚动加载),等待页面完全渲染后再提取评价数据,属于有浏览器渲染的 “重量级” 爬虫。
(1)核心原理
苏宁部分商品评价采用 “懒加载”(滚动到底部才加载更多)、“JS 动态渲染”(评价内容通过 JS 拼接生成),无法通过简单接口获取。Selenium 方法的核心是:
- 启动真实浏览器(Chrome/Edge/Firefox),加载苏宁商品评价页面;
- 模拟人工操作:等待页面加载完成、点击 “查看更多评价”、滚动页面加载更多内容;
- 通过 XPath/CSS 选择器定位评价元素(如评价内容的
<div>标签),提取文本数据。
接下来我们就分别使用Selenium方法爬取好评,然后用request方法爬取差评。
3.2 使用Selenium爬取苏宁商品优质评价数据
使用 Selenium 模拟浏览器操作,分别爬取优质评价,并保存为 txt 文件。
但是使用Selenium 模拟浏览器操作,需要我们下载msedgedriver.exe,因为浏览器本身是一个独立的应用程序(比如 Edge、Chrome),有严格的安全限制,不允许外部程序直接调用它的功能。而在我们下在浏览器驱动以后,我们就可以通过Python来访问浏览器了。
这里以edge浏览器为例,Chrome同理
3.2.1下载edge浏览器驱动
首先我们要查看浏览器的版本,驱动也需要下载对应版本

这里我们可以看到,我们的edge是146.0.3856.62最新版 (64 位),那在网页里面也下载最新版x64版本就可以了
edge浏览器驱动官网下载:
https://developer.microsoft.com/zh-cn/microsoft-edge/tools/webdriver/?form=MA13LH
下载自己电脑对应版本的驱动,我电脑是x64,之前看edge版本也可以看到电脑是x86还是x64。

解压以后我们需要msedgedriver.exe的路径,当然如果你想省事可以像我一样,直接把msedgedriver.exe,复制到Python文件当中,后面直接引用就行。


3.2.2找到自己的edge浏览器的路径
基本上edge路径都是
C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
但是如果有人不是,那就需要自己找到自己电脑上的edge路径

3.2.3、找到自己需要爬取网页的URL
这个就是我们需要爬取的URL,如果有需要,大家可以改成自己的,整个苏宁商品的评论代码逻辑是差不多的,如果你要爬京东或者其他网站,可以按照我的思路修改代码。
3.3Selenium爬取苏宁商品优质评价完整代码
from selenium import webdriver
from selenium.webdriver.edge.options import Options
from selenium.webdriver.edge.service import Service
from selenium.webdriver.common.by import By
import time
__browser_url = r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"# 定义Edge浏览器的安装路径
__driver_path = r"msedgedriver.exe"# 定义Edge驱动程序的路径(需确保驱动版本与浏览器匹配)
edge_options = Options()# 创建Edge浏览器的配置对象
edge_options.binary_location = __browser_url# 指定Edge浏览器的二进制文件路径
service = Service(executable_path=__driver_path)# 创建驱动服务对象,指定驱动程序的路径
driver = webdriver.Edge(service=service, options=edge_options)# 初始化Edge浏览器驱动,传入服务配置和浏览器选项
# 访问苏宁商品的优质评价页面(目标URL)
driver.get(
'https://review.suning.com/cluster_cmmdty_review/cluster-38249278-000000012389328846-0000000000-1-good.htm?originalCm')
yzpj_file = open('优质评价1.txt', 'w', encoding='gbk')# 打开文件用于保存爬取的评价内容,编码为gbk避免中文乱码,模式为写入
total_comments = 0# 初始化总评价数计数器,用于统计爬取的评价总数
def get_py_content(file): # 定义函数:获取当前页面的所有评价内容
global total_comments # 声明使用全局作用域的total_comments变量
pj_elements_content = driver.find_elements(by=By.CLASS_NAME, # 通过类名定位所有评价内容元素(body-content是评价内容的类名)
value='body-content')
current_page_count = len(pj_elements_content) # 获取当前页面的评价数量
total_comments += current_page_count # 将当前页面评价数累加到总评价数
for i in range(len(pj_elements_content)): # 遍历所有评价元素,将每个评价的文本写入文件
file.write(pj_elements_content[i].text + '\n')
print(f"爬取评价数{total_comments}")
get_py_content(yzpj_file)# 调用函数,获取第一页的评论内容
# 通过XPath定位下一页按钮元素(class为next rv-maidian 的元素)
next_elements = driver.find_elements(by=By.XPATH, value='//*[@class="next rv-maidian "]')
print(next_elements)# 打印定位到的下一页元素列表(用于调试)
# 循环判断:如果存在下一页按钮,则继续爬取
while next_elements != []:
# 取第一个下一页按钮元素
next_element = next_elements[0]
time.sleep(1) # 等待1秒,避免页面加载过快导致操作失效
next_element.click() # 点击下一页按钮
get_py_content(yzpj_file) # 爬取新页面的评价内容
# 重新定位下一页按钮,判断是否还有下一页
next_elements = driver.find_elements(by=By.XPATH, value='//*[@class="next rv-maidian "]')
yzpj_file.close()# 关闭保存评价的文件
driver.quit()# 关闭浏览器驱动,释放资源
3.4代码详解

我们第一步就是导入相关库,然后定义edge浏览器路径和我们之前下载的msedgedriver.exe

创建一个 Edge 浏览器的配置对象 edge_options。然后指定 Edge 浏览器的路径。之后创建一个 EdgeDriver的服务对象 service。初始化并启动 Edge 浏览器驱动,返回一个 driver 对象。

访问苏宁商品的优质评价页面,将爬取到的评价数据保存到yzpj_file,这里是用‘gbk’编码,那么全程用‘gbk’编码,如果用‘utf-8’那全程用‘utf-8’。total_comments = 0初始化总评论数计数器,初始值为 0

定义一个名为 get_py_content 的函数用于提取当前页面的评价并写入文件。声明函数内部使用的 total_comments 是全局变量,如果不使用 global 关键字,函数会将其视为局部变量,无法实现跨页面累加统计。通过 Selenium 定位当前页面中所有 class 为 body-content 的元素,这些元素对应商品评价的正文内容。
我们打开f12开发者工具,然后点开鼠标选择元素,然后把鼠标放到我们需要评论上,就可以看到评价正文的固定类名body-content,然后我们就可以通过body-content来获取评论正文。
后面就是使用一个for循环遍历所有评价元素。然后调用函数,获取第一页的评论内容。


通过 XPath 语法 定位页面中 class 为 next rv-maidian 的元素(即 “下一页” 按钮)。后面我们使用while循环持续执行翻页操作,如果next_elements为空,则结束翻页。

3.5运行结果
这里17733条数据太多了,爬个2000条够用了


四、request爬取差评
我先给大家Selenium爬取苏宁商品优质评价完整代码,原理一样的。
Selenium爬取苏宁商品差评完整代码
from selenium import webdriver
from selenium.webdriver.edge.options import Options
from selenium.webdriver.edge.service import Service
from selenium.webdriver.common.by import By
import time
__browser_url = r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" # edge浏览器的安装路径
__driver_path = r"msedgedriver.exe"
edge_options = Options() # 配置对象
edge_options.binary_location = __browser_url
service = Service(executable_path=__driver_path)
driver = webdriver.Edge(service=service, options=edge_options) # 驱动器
driver.get('https://review.suning.com/cluster_cmmdty_review/cluster-38249278-000000012389328846-0000000000-1-bad.htm?originalCmmdtyType=general&safp=d488778a.10004.loverRight.166')
yzpj_file = open('差评1.txt', 'w',encoding='gbk')
def get_py_content(file): # 获取当前这个页面的所有评价内容
pj_elements_content = driver.find_elements(by=By.CLASS_NAME, value='body-content') # 寻找标签元素
for i in range(len(pj_elements_content)):
file.write(pj_elements_content[i].text + '\n')
get_py_content(yzpj_file) # 获取第一页的评论内容
next_elements = driver.find_elements(by=By.XPATH, value='//*[@class="next rv-maidian "]')
print(next_elements)
while next_elements != []: # 是否获取到下一页的标签
next_element = next_elements[0]
time.sleep(1)
next_element.click() # 点击标签
get_py_content(yzpj_file)
next_elements = driver.find_elements(by=By.XPATH, value='//*[@class="next rv-maidian "]')
yzpj_file.close()
那么接下来我来介绍另一种request爬虫方法
4.1获取页面信息
相比较于Selenium用Python驱动edge爬取评论,request就原始多了,而且爬有反爬机制的网站非常容易被禁,而且代码逻辑更加复杂。
首先我们打开需要爬取的网页的开发工具(f12)
我们选择网络,然后找到第一列类型为document的数据点开,不同网站第一列名称不一样,找类型为document的数据就行。


这里我们至少需要复制两条请求头数据:
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0",
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",


在这里提醒一下,Cookie不是必须的请求头,如果你不用爬不了再用,Cookie是动态的,非常容易过期,添加以后每一次运行都要保证更新,非常麻烦,能不用就不用。
4.2request爬取苏宁商品差评完整代码
import requests
import time
CLUSTER_ID = "38249278" # cluster ID
COMMODITY_ID = "000000012389328846" # 商品ID
FIXED_PARAM = "0000000000" # URL中固定的参数段
REVIEW_TYPE = "bad" # 评论类型:bad(差评)
FILE_NAME = "差评1.txt" # 保存的文件名
# URL后缀参数(固定不变)
URL_SUFFIX = "?originalCmmdtyType=general&safp=d488778a.10004.loverRight.166&safpn=10009"
# 反爬配置
DELAY = 2 # 请求间隔(秒)
TIMEOUT = 15 # 请求超时时间
# ===================================================
# 完整请求头
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
}
def build_url(page_num):
"""构建指定页码的URL"""
base_url = f"https://review.suning.com/cluster_cmmdty_review/cluster-{CLUSTER_ID}-{COMMODITY_ID}-{FIXED_PARAM}-{page_num}-{REVIEW_TYPE}.htm"
full_url = base_url + URL_SUFFIX
return full_url
def get_page_reviews(page_num):
"""获取指定页码的评论内容"""
url = build_url(page_num)
response = requests.get(url=url, headers=HEADERS, timeout=TIMEOUT,
allow_redirects=True, stream=False)
response.encoding = "utf-8"
html_content = response.text
reviews = []
blocks = html_content.split('class="body-content"')
for block in blocks[1:]:
start_idx = block.find(">") + 1
end_idx = block.find("</div>", start_idx)
review_text = block[start_idx:end_idx].strip()
review_text = review_text.replace("\n", "").replace("\r", "").replace("\t", "")
# 过滤空评论(只保留有实际内容的评论)
if review_text and len(review_text) > 2:
reviews.append(review_text)
print(f"[第{page_num}页]爬取 {len(reviews)} 条评论")
return reviews
def crawl_all_bad_reviews():
all_reviews = []
page_num = 1
max_pages = 50
empty_page_count = 0 # 连续空页计数
max_empty_pages = 2 # 连续2页空就停止
while page_num <= max_pages and empty_page_count < max_empty_pages:
current_reviews = get_page_reviews(page_num)
if current_reviews:
all_reviews.extend(current_reviews)
empty_page_count = 0
else: # 无有效评论
empty_page_count += 1
print(f"[第{page_num}页]无有效评论,连续空页数:{empty_page_count}")
time.sleep(DELAY)
page_num += 1
with open(FILE_NAME, "w", encoding="gbk") as f:
for idx, review in enumerate(all_reviews, 1):
f.write(f"{review}\n")
print(f"总计爬取 {len(all_reviews)} 条有效差评")
print(f"评论已保存到:{FILE_NAME}")
crawl_all_bad_reviews()
4.3代码详解
request代码逻辑真的比Selenium复杂很多,翻页读取需要你自己去找规律,而且每个网站规律不一样,我之前写的爬的豆瓣短评、红楼梦全卷,他们代码翻页的逻辑都不同,都需要自己找规律。
https://blog.csdn.net/qq_74437448/article/details/157732998?spm=1001.2014.3001.5501爬取《葬送的芙莉莲》豆瓣短评:https://blog.csdn.net/qq_74437448/article/details/157732998?spm=1001.2014.3001.5501
爬取《红楼梦》全卷:
https://blog.csdn.net/qq_74437448/article/details/158705986?spm=1001.2014.3001.5501
先从请求头开始


这里我们可以看到,我们将URL拆解为
"https://review.suning.com/cluster_cmmdty_review/cluster-{CLUSTER_ID}-{COMMODITY_ID}-{FIXED_PARAM}-{page_num}-{REVIEW_TYPE}.htm"
原URL:
"https://review.suning.com/cluster_cmmdty_review/cluster-38249278-000000012389328846-0000000000-1-bad.htm?originalCm&"
注意到规律:
38249278就是CLUSTER_ID一个id
000000012389328846就是COMMODITY_ID商品id
0000000000就是FIXED_PARAM固定参数
-1-就是page_num第一页
bad.htm就是REVIEW_TYPE差评
然后把后面不变的参数单独提取:URL_SUFFIX = "?originalCmmdtyType=general&safp=d488778a.10004.loverRight.166&safpn=10009"

定义一个名为 build_url 的函数,接收参数 page_num(目标页码),用于生成对应页码的苏宁商品评价页面 URL。

定义一个名为get_page_reviews的函数。
url = build_url(page_num):调用之前定义的 build_url 函数,生成目标页码的完整 URL。
requests.get(...):发起 HTTP GET 请求,携带请求头、超时时间等配置:
headers=HEADERS:模拟浏览器请求头,避免被服务器识别为爬虫。
timeout=TIMEOUT:设置请求超时时间,防止程序长时间挂起。
allow_redirects=True:允许自动跟随重定向。
stream=False:不使用流式下载,直接获取完整响应。
response.encoding = "utf-8":指定响应内容编码为 UTF-8,避免中文乱码。
html_content = response.text:获取页面的 HTML 源码文本。
分割 HTML 定位评论块,reviews = []:初始化空列表,用于存储提取到的评论。
blocks = html_content.split('class="body-content"'):
以评论内容的 class 标识 class="body-content" 为分割点,将 HTML 拆分成多个片段。
分割后,blocks[0] 是页面头部内容,blocks[1:] 每个元素都对应一条评论的 HTML 片段。
这里和Selenium不同,我们除了知道评论正文存储在class=body-content里面,我们还需要找到评论内容开始标签。
我们先复制部分差评,然后搜索他的位置,双击搜索位置,可以看到评论正文就在
<div class="topic-body">
<p class="body-content">
退不了货的,别买!!!手机被拆开过的后封机,二手的,还在手机贴了一大张贴纸,很丑
</p>
<div class="body-images clearfix">


这一块我们用for循环,从 blocks[1:] 开始遍历,跳过页面头部片段。
start_idx = block.find(">") + 1:找到评论内容开始标签 > 的位置,+1 跳过标签本身。
end_idx = block.find("</div>", start_idx):从 start_idx 开始,找到结束标签 </div> 的位置。
block[start_idx:end_idx].strip():截取标签之间的文本并去除首尾空白。
调用 replace 方法,移除文本中的换行符 \n、回车符 \r、制表符 \t。
然后用if条件过滤无效评论
只保留非空且长度大于 2 的评论,避免空字符串或无意义短文本。
将符合条件的评论被添加到 reviews 列表中。

用request让程序停下也是老大难,因为我们从第一页开始for循环,我们打开的网页差评就两页,但是实际上后面网页也有,只不过么有评论,用request也会去读取,所以我们就要另外想办法让他读取完停下。

这里我们就使用了一个while循环,同时满足未超过最大页数和未超过连续空页数限制才继续爬取。我们这里只要读取了2页空数据,代码就会停下。
4.4运行结果


五、文本预处理:分词与停用词过滤
爬取到评价数据后,需要对文本进行分词(将连续文本拆分为独立词语)和停用词过滤(移除无意义的虚词),为后续机器学习建模做准备。
5.1完整代码
import pandas as pd
cp_content = pd.read_table(r"差评1.txt",header=None, names=['content'],encoding='gbk')
yzpj_content = pd.read_table(r"优质评价1.txt",header=None, names=['content'],encoding='gbk')
import jieba
cp_segments = []
contents = cp_content.content.values.tolist() # 将content列数据取出并转化为list格式,目的是分别 jieba.lcut分词
for content in contents:
results = jieba.lcut(content)
if len(results) > 1: # 当分词之后,这条评论如果只有1个内容,
cp_segments.append(results) # 将分词后的内容添加到列表segments中
cp_fc_results = pd.DataFrame({'content': cp_segments})
cp_fc_results.to_excel('cp_fc_results.xlsx', index=False)
yzpj_segments = []
contents = yzpj_content.content.values.tolist() # 将content列数据取出并转化为list格式
for content in contents:
results = jieba.lcut(content)
if len(results) > 1:
yzpj_segments.append(results) # 将分词后的内容添加到列表segments中
# ## 分词结果储存在新的数据框中
yzpj_fc_results = pd.DataFrame({'content': yzpj_segments})
yzpj_fc_results.to_excel('yzpj_fc_results.xlsx', index=False)
stopwords = pd.read_csv(r".\StopwordsCN.txt", encoding='utf8', engine='python', index_col=False)
# 定义去除停用词函数
def drop_stopwords(contents, stopwords):
segments_clean = []
for content in contents:
line_clean = []
for word in content:
if word in stopwords:
continue
line_clean.append(word)
segments_clean.append(line_clean)
return segments_clean
# 调用去除停用词函数
contents = cp_fc_results.content.values.tolist() # DataFrame格式转为List格式
stopwords = stopwords.stopword.values.tolist() # 停用词转为List格式
cp_fc_contents_clean_s = drop_stopwords(contents, stopwords)
contents = yzpj_fc_results.content.values.tolist() # DataFrame格式转为List格式
yzpj_fc_contents_clean_s = drop_stopwords(contents, stopwords)
5.2代码解析

导入我们的优质评价和差评,这里如果导出的是“gbk”那就都用“gbk”,用“utf-80”就都用“utf-80”,然后让所有列都命名为content

定义空列表 cp_segments,用于存储差评的评论结果,每条评论对应一个词语列表。cp_content 是之前读取的 DataFrame,content 列存储原始评论文本。
.values.tolist():将 DataFrame 的 content 列转换为Python 列表,便于逐行遍历分词。
然后使用for循环遍历每一条原始评论,jieba.lcut(content):对单条评论执行精确模式分词,返回词语列表(results)。
if len(results) > 1:过滤掉分词后只有 1 个词语的评论(如 “差”“好” 这类无分析价值的单字短评)。
cp_segments.append(results):将符合条件的分词结果存入列表。
将分词后的结果 cp_segments 封装为 pandas.DataFrame
将 DataFrame 导出为 Excel 文件 cp_fc_results.xlsx。

定义空列表 yzpj_segments,用于存储优质评价的分词结果,和上面的差评类似就不多介绍了。
pd.DataFrame({'content': yzpj_segments}):将分词结果封装为 DataFrame,列名为 content。
.to_excel('yzpj_fc_results.xlsx', index=False):导出为 Excel 文件。
读取中文停用词表StopwordsCN.txt(存储在当前目录下),用于后续过滤无意义虚词(如 “的”“了”“很” 等)。
这一块资源我也上传了有需要可以下载。

定义函数对分词后的文本进行停用词过滤,移除无实际语义的虚词(如 “的”“了”“很” 等),保留核心情感词汇。
segments_clean = [] 用于存储过滤后的干净文本结果。
for content in contents:遍历每一条已经分词的评论。
for word in content:遍历当前评论中的每一个词语。

contents = ...:将差评分词结果 cp_fc_results(DataFrame 格式)的 content 列提取出来,转为 Python 列表。
stopwords = ...:将停用词表 stopwords(DataFrame 格式)的 stopword 列提取出来,转为 Python 列表。
cp_fc_contents_clean_s = ...:调用 drop_stopwords 函数,传入差评分词列表和停用词列表,得到过滤后的差评数据。
同理yzpj_fc_contents_clean_s = ...:复用已转换好的 stopwords 列表,调用 drop_stopwords 函数,得到过滤后的优质评价数据。
5.3运行结果



六、建立朴素贝叶斯商品评价情感分析模型
经过文本预处理后,我们得到了干净的分词结果。接下来通过朴素贝叶斯算法构建情感分类模型,实现对商品评价的 “差评 / 优质评价” 自动分类,核心步骤包括:数据标签化、数据平衡(过采样)、特征向量化、模型训练与评估。
6.1原代码
import pandas as pd
import jieba
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn import metrics
# 1. 数据读取与处理
cp_content = pd.read_table(r"差评1.txt", header=None, names=['content'], encoding='gbk')
yzpj_content = pd.read_table(r"优质评价1.txt", header=None, names=['content'], encoding='gbk')
# 过滤空行
cp_content = cp_content[cp_content['content'].notna() & (cp_content['content'].str.strip() != '')]
yzpj_content = yzpj_content[yzpj_content['content'].notna() & (yzpj_content['content'].str.strip() != '')]
# 2. jieba分词
cp_segments = []
contents = cp_content.content.values.tolist()
for content in contents:
if isinstance(content, str):
results = jieba.lcut(content)
if len(results) > 1:
cp_segments.append(results)
# 2.2 优质评价分词
yzpj_segments = []
contents = yzpj_content.content.values.tolist()
for content in contents:
if isinstance(content, str):
results = jieba.lcut(content)
if len(results) > 1:
yzpj_segments.append(results)
# 保存分词结果
cp_fc_results = pd.DataFrame({'content': cp_segments})
cp_fc_results.to_excel('cp_fc_results.xlsx', index=False)
yzpj_fc_results = pd.DataFrame({'content': yzpj_segments})
yzpj_fc_results.to_excel('yzpj_fc_results.xlsx', index=False)
# 3. 移除停用词
stopwords = pd.read_csv(r".\StopwordsCN.txt", encoding='utf8', engine='python', index_col=False)
stopwords_set = set(stopwords.stopword.values.tolist())
# 定义去停用词函数
def drop_stopwords(contents, stopwords):
segments_clean = []
for content in contents:
line_clean = []
for word in content:
if word.strip() and word not in stopwords:
line_clean.append(word)
if line_clean:
segments_clean.append(line_clean)
return segments_clean
# 调用函数去停用词
contents = cp_fc_results.content.values.tolist()
cp_fc_contents_clean_s = drop_stopwords(contents, stopwords_set)
contents = yzpj_fc_results.content.values.tolist()
yzpj_fc_contents_clean_s = drop_stopwords(contents, stopwords_set)
# 4. 朴素贝叶斯分类
# 4.1 添加标签(1=差评,0=优质评价)
cp_train = pd.DataFrame({'segments_clean': cp_fc_contents_clean_s, 'label': 1})
yzpj_train = pd.DataFrame({'segments_clean': yzpj_fc_contents_clean_s, 'label': 0})
pj_train = pd.concat([cp_train, yzpj_train])
pj_train.to_excel('pj_train.xlsx', index=False)
#过采样
# 确定多数类(优质评价)样本数量
majority_count = len(pj_train[pj_train['label'] == 0])
# 对少数类(差评)进行随机过采样,数量匹配多数类
minority_upsampled = pj_train[pj_train['label'] == 1].sample(n=majority_count, replace=True, random_state=0)
# 合并过采样后的少数类和原始多数类,得到平衡数据集
pj_train_balanced = pd.concat([minority_upsampled, pj_train[pj_train['label'] == 0]])
# 打乱数据顺序(可选,提升训练效果)
pj_train_balanced = pj_train_balanced.sample(frac=1, random_state=0).reset_index(drop=True)
# 4.2 数据切分(使用平衡后的数据集)
x_train, x_test, y_train, y_test = train_test_split(
pj_train_balanced['segments_clean'].values, # 平衡数据集
pj_train_balanced['label'].values, # 平衡数据集
random_state=0
)
# 转换为词向量可识别格式
words = []
for line_index in range(len(x_train)):
words.append(' '.join(x_train[line_index]))
# 词向量转换
vec = CountVectorizer(max_features=4000, lowercase=False, ngram_range=(1,3))
vec.fit(words)
x_train_vec = vec.transform(words)
# 4.3 朴素贝叶斯分类训练
classifier = MultinomialNB(alpha=0.1)
classifier.fit(x_train_vec, y_train)
# 训练集预测与评估
train_pr = classifier.predict(x_train_vec)
print("\n训练集分类报告")
print(metrics.classification_report(y_train, train_pr))
# 测试集预测与评估
test_words = []
for line_index in range(len(x_test)):
test_words.append(' '.join(x_test[line_index]))
test_pr = classifier.predict(vec.transform(test_words))
print("\n测试集分类报告")
print(metrics.classification_report(y_test, test_pr))
6.2代码详解

将过滤后的差评分词结果 cp_fc_contents_clean_s 封装为 DataFrame,并添加情感标签 label=1。
然后将优质评价添加情感标签 label=0
使用 pd.concat() 纵向合并差评 DataFrame 和优质评价 DataFrame,得到完整的训练数据集 pj_train。之后出为 Excel 文件。

做模型一定不要忘记了数据不匹配的这个大问题。
这里采用了过采样法,好评2000多条,差评12条,用下采样,那好评也变成12条,会导致准确率也不高。

这里就是数据切分为训练集测试集。

这里就是词向量转换,将分词后的列表格式转换为机器学习模型可识别的数值型词向量。
使用for循环遍历每条评论的分词列表,用 ' '.join() 将词语拼接为空格分隔的字符串。
CountVectorizer:统计每个词在文本中出现的次数。
vec.fit(words):统计所有出现的词语 / 短语,确定特征维度;
vec.transform(words):将训练集文本转换为稀疏矩阵格式的词向量,每行对应一条评论,每列对应一个词汇,值为该词汇在当前评论中出现的次数;

使用朴素贝叶斯来进行训练,最后得到训练集和测试集的准确率。
6.3代码结果

七、实现单条评价的情感倾向判断(好评 / 差评)
训练完成的朴素贝叶斯模型最终要落地为可交互的工具,最终实现 “输入任意电商评价文本,自动判断是好评还是差评” 的功能。
7.1原代码
def predict_single_sentence(sentence):
seg_list = jieba.lcut(sentence)
seg_clean = [word for word in seg_list if word.strip() and word not in stopwords_set]
seg_str = ' '.join(seg_clean)
vec_sentence = vec.transform([seg_str])
pred_label = classifier.predict(vec_sentence)[0]
result = "差评" if pred_label == 1 else "好评"
return result
# 交互预测逻辑
if __name__ == "__main__":
user_input = input("\n请输入要预测的评价语句:")
pred_result = predict_single_sentence(user_input)
print(f"\n预测结果:{user_input} {pred_result}")
7.2代码详解
这里定义predict_single_sentence函数,接收单条原始评论文本 sentence,使用 jieba.lcut() 进行精确分词,得到词语列表 seg_list。
然后通过列表推导式过滤无意义词语,将过滤后的词语列表拼接为空格分隔的字符串,适配 CountVectorizer 的输入格式。
使用之前模型拟合好的vec,将预处理后的文本转换为词向量矩阵。
然后调用训练好的朴素贝叶斯分类器 classifier,对词向量进行预测,得到标签 pred_label。标签为1是差评,0为好评。
7.3结果展示


这里可以看出来,不管是好评还是差评,模型都有效的识别出来了,说明这个模型的准确率还是非常高的。
以上就是这个项目的完整内容了,希望能对你有所帮助。
更多推荐
所有评论(0)