简介:基于机器学习的网络新闻评论情感分类研究是一份面向自然语言处理与文本挖掘方向研究者的学术论文PDF,针对网络新闻评论的短文本、口语化等特点,系统解决了如何自动判别评论情感倾向的问题。资源包内共有1个PDF文件,大小仅392KB,内容为全文完整排版,下载后可离线阅读或作为课题参考文献;该资源已有169人学习浏览。论文归纳了网络新闻评论数据特征,并围绕特征集、特征维度、权重计算方法和词性选择展开多组分类实验与对比。核心结论包括:情感词与论据词语搭配使用时分类效果优于仅用情感词;TF-IDF权重计算方法优于布尔型权重;名词和动词作为特征比形容词和副词取得更好效果。这些分析结论对构建中文短文本情感分类模型、选取有效特征及权重策略具有直接参考价值。
1. 重温一篇 2010 年的论文:网络新闻评论情感分类的四个反直觉结论
这份《基于机器学习的网络新闻评论情感分类研究》是《计算机应用》2010 年第 4 期的一篇短文,研究的是网络新闻跟帖这种口语化短文本的情感分类。它给我的第一印象是结论足够反直觉:情感词和论据词语搭配使用效果更好;特征维度对准确率的影响比长文本小得多;TF-IDF 权重压过布尔权重——这和当时电影评论情感分类的主流结论正好相反;词性上名词、动词比形容词、副词更能打。对正在做短文本分类、舆情分析的人,尤其当你发现模型在口语化数据上飘忽不定时,这篇论文值得细读。机器学习入门阶段的读者,也可以把它当特征工程的课后阅读,比对着吴恩达的课程和周志华的西瓜书,能更快理解特征选择在真实数据里的价值。
2. 数据和预处理先行:网络跟帖的清洗、去重与三粒度标注
情感分类的第一步从来不是选模型,而是搞清楚语料长什么样。论文用的语料是三个新闻事件的网民跟帖:「超市禁止免费提供塑料袋」「央视停播 NBA」「刘翔退赛」。这类数据最大的特点就是又短又脏,直接建模结果会很惨,所以原文把数据处理放在实验之前,这一步非常关键。
2.1 数据特点:又短又脏,特征稀疏到离谱
网络新闻跟帖和产品评论有本质区别。产品评论有明确的评价对象(比如某款手机的屏幕、续航),而且很多平台自带评分等级,标注成本很低。新闻跟帖没有属性列表,评论者可以围绕任何一个点发散,所以论文里统一表述为「情感分析」而不是「观点挖掘」。
具体到数据形态,论文归纳了三个特点。第一是长度极短,一般只有几十个字符,包含的词典词语可能就三五个,特征向量极其稀疏。第二是表达不规范,口语化严重,错别字、网络用语、特殊分隔符大量出现。第三是思维发散,指代不明确,评论者经常通过其他对象来论证自己的观点。比如有网友在塑料袋话题下写「那岂不是要提供纸袋了,又要有多少森林被砍了」,这里的「森林」不是评价对象,而是支撑反对观点的一个论据词。这类词恰恰是后面特征实验里的关键变量,先记住这个例子。
2.2 去重与规范化:五步清洗让语料可建模
原始评论不能直接用,论文做了两件事:去重和规范化。去重的规则是「同一评论者短时间内发表的相同评论」,这类重复内容信息量几乎为零,留在语料里只会拉高某些特征的权重。规范化处理则包括简繁转换、全角半角转换、字母大小写转换、不规范分隔号识别去除、特殊符号去除。现在复现这一步用 Python 很容易,下面是一个常见做法的清洗函数:
import re def normalize_comment(text: str) -> str: # 全角标点转半角,避免同一个词因标点形态被拆成两个特征 text = text.replace(",", ",").replace("。", ".").replace("!", "!") \ .replace("?", "?").replace(":", ":") # 字母统一小写,“NBA”和“nba”不应该成为两个特征 text = text.lower() # 去除特殊分隔符和表情符号,这类噪声对情感判断没有正向贡献 text = re.sub(r"[【】\[\]()()#@\-_]", "", text) # 压缩连续空白 text = re.sub(r"\s+", " ", text).strip() return text这个函数的执行顺序是有讲究的:先转全角再转半角,否则全角英文字母在大小写转换时容易漏掉;特殊符号要在大小写转换之后再去,因为有些符号在半角状态下会和连字符混淆。论文里还提到「支一持一封一杀一NBA」这种用「一」做分隔符的写法,规范化阶段需要单独处理这类模式,否则分词阶段会被切得七零八落。当年用规则脚本做,现在用正则加自定义词典就能覆盖大部分情况。
2.3 三粒度情感标注:文档、句子、词语各标什么
规范化之后是情感标注。论文采用文档、句子、词语三种粒度同时标注,这是一个工作量不小但信息量很高的方案。标注流程是先确定整条评论的情感倾向,再拆解句子,提取每个句子的评价对象和情感词,最后给每个情感词标注倾向和强度。表格里是三个粒度的标注内容:
| 标注粒度 | 标注内容 | 用途 |
|---|---|---|
| 文档级 | 整条评论的情感倾向(正面/负面) | 分类实验的标签 |
| 句子级 | 每个句子的评价对象、情感词 | 提取论据词语、构建特征集 |
| 词语级 | 情感词的倾向和强度 | 情感词典构建、词语级分析 |
三个粒度不是各做各的,而是层层约束:文档倾向决定句子分析的基调,句子级提取的情感词又回过来校验文档倾向是否标错。标注完还要做一致性检查,否则后续的特征对比实验会积累大量噪声。我复现时一般会先用文档级结果跑一版基线,再决定要不要投入句子级和词语级的标注,因为后两者的标注成本高出一个量级,但对特征实验是必需的。
3. 特征工程定上限:特征集、特征维度与词性选择怎么搭
在短文本场景里,模型能发挥多少取决于特征工程做到什么程度。论文的特征实验分三条线:特征集构成、特征维度、词性选择。三条线的结论互相印证,指向同一个判断——网络新闻评论里真正有判别力的不只是情感词,还有那些承载论证逻辑的论据词语。
3.1 特征集对比:纯情感词覆盖不足,加上论据词语才稳
论文的第一组实验是人工挑选特征词。从标注好的语料里提取所有情感词和评价对象信息,先只挑情感词构成「特征集一」;再把评价对象里能支撑观点的论据词语合并进情感词集,构成「特征集二」。然后用 SVM 分类器、TF-IDF 权重、50% 训练 50% 测试的方式跑三个事件。结果很能说明问题:
| 特征集 | 前两个事件准确率 | 无特征样本情况 |
|---|---|---|
| 仅情感词 | 低于 60% | 约占全部语料一半 |
| 情感词 + 论据词语 | 明显上升 | 无特征样本急剧减少 |
纯情感词特征集表现差的主要原因有两个:一是特征维度太低,人工挑的情感词覆盖不了口语化短评;二是人工选词时倾向于选关联性强的词,比如提到「支持」就很容易联想到「赞同」,这些词在语料里高度共现,特征间的冗余度很高。加入论据词语后,「森林」「垃圾袋」「奥运」这类词进入特征集合,评论里原本无特征的样本大幅减少,准确率跟着上来了。
特殊现象出现在「刘翔退赛」事件里。「加油」这个情感词对分类的贡献大得惊人,删掉它之后准确率从 77.64% 直接掉到 53.89%,差了将近 24 个百分点。这说明短文本情感分类里,个别高频强情感词可以主导整个模型的决策,后面第 5 章会专门讲这个坑。另外,原文提到在去除无特征样本后,三个事件重新分类的结果都超过 75%,说明人工特征本身是有判别力的,问题是覆盖范围不够。
3.2 特征维度:2000 维封顶,低了也不慌
第二个实验比较不同特征维度下的分类准确率。长文本分类通常靠高维特征取胜,维度从几千涨到几万,准确率跟着涨,超过峰值后才会回落。网络新闻评论不一样,特征最高维度只有 2000 左右,远低于正式语料,而且准确率随维度变化的曲线非常平缓——维度降低到一定程度,依然能保持不错的准确率。
论文给的解释是网络新闻评论用词相对集中,这些出现频率高的词恰好对情感类别有较强的表征能力,所以维度压缩不会立刻伤到分类器。另一个角度看,短文本里特征本身少,维度从 2000 压到几百,损失的只是低频词,而低频词在几十字的评论里本来就很难出现第二次。这个结论对我复现时的直接指导是:不需要追求高维向量,max_features设 300 到 800 之间就够用,超过 2000 基本没什么收益。
3.3 词性选择:名词和动词比形容词副词更能打
第三个实验看词性对分类的影响。论文用 ICTCLAS30 分词系统做词性标注,分别用形容词、名词、动词、副词单独构建特征跑分类。原文表 5 的数据很有参考价值:
| 词性 | 塑料袋政策 | 停播 NBA | 刘翔退赛 | 词语所占比例 |
|---|---|---|---|---|
| 形容词+名词+动词+副词 | 88.19% | 81.53% | 86.83% | 67.77% |
| 形容词 | 71.24% | 60.13% | 72.26% | 4.78% |
| 名词 | 84.96% | 74.39% | 81.04% | 20.63% |
| 动词 | 83.65% | 76.56% | 82.63% | 30.44% |
| 副词 | 78.76% | 63.06% | 72.06% | 11.92% |
这个结果和「形容词最能表征情感」的直觉相反。原因有两条:第一,形容词和副词在网络新闻评论里占比太小,四类词性合计占 67.77%,形容词只占 4.78%,单独作为特征时覆盖范围严重不足;第二,前面反复提到的论据词语,词性上绝大多数是名词和动词,比如「森林」「砍」这类词,本身不直接表达情感,但能支撑评论者的立场,名词和动词把这部分信息带进了特征集合。
复现时我用 jieba.posseg 做词性筛选,效果可以对齐:
import jieba.posseg as pseg def filter_by_pos(text: str, allowed_pos: set) -> list: words = [] for word, flag in pseg.cut(text): if flag in allowed_pos and word.strip(): words.append(word.strip()) return words # 对应论文结论:名词(n)和动词(v)优先,形容词(a)、副词(d)视数据量决定是否保留 allowed = {"n", "v"} tokens = filter_by_pos("现在不提供了,要去买专门的垃圾袋", allowed)这里要注意的是,jieba 的词性标签体系和 ICTCLAS 不同,但「名词优先、动词次之」这个策略在短文本情感分类里是通用的。如果标注语料充足,可以按论文的方式做一次词性对比,确认自己的数据分布是否和 2010 年这批新闻评论一致。我一般会保留名词和动词,形容词只在词典覆盖不足时加入,副词基本不考虑。
4. 权重计算方法对比:TF-IDF 为何在短文本里压过布尔权重
特征确定了,权重怎么算又是另一个影响结果的因素。文献里有个被反复引用的结论:情感分类中布尔权重优于词频权重,理由是情感倾向词在一条文本里通常只出现一次,出现一次就足以决定倾向,重复出现没有额外信息。论文用网络新闻评论数据重新测了这个假设,结果和文献相反。
4.1 TF-IDF、TF、布尔:三种权重的差异在短文本里被抹平
先明确三种计算方式。TF 权重是词频,词语在文档里出现几次就记几分,衡量的是局部的显著性。布尔权重只看出现与否,出现记 1,不出现记 0。TF-IDF 在 TF 基础上乘一个逆文档频率因子,IDF 越大说明词语在语料里越稀有,从而抑制「的」「了」「是」这类高频虚词,放大那些在少量文档中出现的信息词。
TF-IDF 的计算公式可以写成:
TF-IDF(t, d) = TF(t, d) × IDF(t) IDF(t) = log(总文档数 N / 包含词语 t 的文档数 df(t))在长文本主题分类里,TF-IDF 压制常见词的效果非常明显。但情感分类和主题分类的信息分布不同:主题由关键词决定,情感倾向经常由少量词甚至一个词决定。所以 Pang 等人在电影评论上得出的结论是布尔权重更好,因为情感词重复出现的情况本来就少,词频带来的区分度十分有限。
4.2 实验结果:TF-IDF 略优,但差距不明显
论文用 TF-IDF、TF、布尔型三种权重分别测试三个数据集,结论是 TF-IDF 获得较优准确率,但三种方法的差距并不大。原文给了两个原因。第一,网络新闻评论长度极短,同一条评论里情感倾向词重复出现的概率大大降低,三种权重计算出的数值实际很接近。第二,评论里出现次数较多的词语主要是评价对象和论据词语,这些词对情感倾向有较好的表征能力,用 TF-IDF 能进一步放大它们在分类中的作用。
这个结论对我的提示是:权重策略要跟着数据特性走,不要照搬其他领域的结论。在短文本场景里,如果你不确定该用哪种权重,直接跑一组对比就行,成本很低。Scikit-learn 里几分钟就能出结果:
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer from sklearn.svm import SVC from sklearn.pipeline import Pipeline # TF-IDF 权重 pipe_tfidf = Pipeline([ ("vec", TfidfVectorizer(max_features=800)), ("clf", SVC(kernel="linear")) ]) # 布尔权重:CountVectorizer 加 binary=True pipe_bool = Pipeline([ ("vec", CountVectorizer(binary=True, max_features=800)), ("clf", SVC(kernel="linear")) ])跑完之后不要只盯着准确率,还要看两份预测结果的错误样本是否重合。如果重合度高,说明两种权重下的特征空间差异不大,选哪个都行;如果不重合,就值得分析哪些样本被 TF-IDF 救回来了,这才是实验的价值所在。
4.3 我复现时的参数设置
基于论文的实验结论,我在复现时固定了一组参数:max_features=2000对应论文里的特征维度上限,实际测试时先在 300、500、800、1200 各跑一遍,取交叉验证均值最高的值。min_df设 1,因为短文本里很多信息词只出现一两次,设 2 会把「垃圾袋」「森林」这类论据词过滤掉。ngram_range保持(1, 1),不升 bigram 是刻意为之——短文本里相邻词组合几乎都是重复信息,扩大 n-gram 只会让矩阵更稀疏。sublinear_tf可以试,论文时代没有这个参数,但它是 TF 取对数的一种平滑方式,在某些数据上能小幅提升稳定性,这属于现代实现的改良,不是论文原结论。
5. 复现避坑:四个高频问题与对应的处理办法
论文里有一些结论是显式的,有一些是隐含的,复现时最容易翻车的都是隐含的部分。下面四个问题是我自己踩过坑之后沉淀下来的,每条都按「现象、原因、解决」来写。
5.1 分词翻车:网络用语和人名被切得七零八落
现象:用普通分词器处理「不播就不播有什么大不了的,电视台有权选择放什么节目」这类评论,分词结果还算正常,但遇到「支一持一封一杀一NBA」这种插字写法,输出变成「支」「持」「封」「杀」,特征是四个单字,信息完全丢失。遇到网络人名和别称,同样容易被切碎。
原因:当年论文用的 ICTCLAS30 基于书面语训练,对网络口语的覆盖很弱。现在的主流分词器虽然进步很大,但面对口语化短文本,依然会栽在特殊分隔符和网络新词上。
解决:在分词前先做一层正则预处理,把「一」「~」这类插入的分隔符替换掉,再加载自定义用户词典。比如上面那条评论,预处理后变成「支持封杀NBA」,分词器能正确输出完整词语。词典里要包含事件相关的人名、机构名和网络热词,这一步是中文短文本情感分类绕不开的脏活。
5.2 无特征样本过多:纯情感词典覆盖不住口语评论
现象:只用情感词构建特征时,三个事件里前两个的准确率低于 60%,检查特征矩阵发现近半数评论没有任何特征词命中,分类器等于在拿一半样本硬猜。
原因:网络新闻评论太短,一条评论可能就一个词加一个标点。情感词典覆盖的词语集中在正式表达上,口语化短评里的高频词多数不在词典里。
解决:照论文的做法把论据词语加进特征集。论据词语从句子级标注的评价对象里提取,词性上以名词和动词为主。加入之后无特征样本数量急剧减少,准确率随之上升。如果标注语料不足,可以退而求其次,把新闻原文里的高频名词提前拉出来做成候选论据词表,也能覆盖一部分。
5.3 「加油」效应:单一强特征词绑架整个模型
现象:刘翔退赛数据集里,保留「加油」时准确率 77.64%,把它从特征集合里删掉,准确率掉到 53.89%,模型几乎瘫痪。
原因:短文本里特征稀疏,一个高频强情感词可能出现在大量正样本里,SVM 的决策函数在训练过程中把大量权重压在这个词上。删掉它,模型缺少了最主要的判别依据。
解决:做特征稳定性检查。具体操作是从特征集合里逐个删除高频特征词,观察交叉验证准确率的波动幅度;凡是删除后准确率掉超过 3 个百分点的特征,都要警惕模型对它的过度依赖。缓解办法是保留相对多样的特征来源(情感词、论据词混合),以及用 5 折交叉验证取均值,而不是用单次划分的结果下结论。
5.4 权重结论照搬:文献说布尔好,你的数据不一定
现象:在电影评论领域,布尔权重优于词频权重是常见结论。直接把这个结论搬过来用到网络新闻评论上,发现布尔权重并没有优势,甚至略差。
原因:电影评论长度适中,情感词重复出现的概率比几十字的新闻跟帖高,布尔权重能发挥「出现即决定性」的优势。网络新闻评论里论据词语是重要特征,这类词需要用 TF-IDF 的逆文档频率来强化区分度,布尔权重给所有出现的词相同的权重,反而抑制了论据词的作用。
解决:权重方案必须在自己数据上重新验证。我在实验里固定跑三组:TF-IDF、TF、布尔,每组 5 折交叉验证,最后看均值再选。多个数据集上如果 TF-IDF 稳定领先,就不必纠结文献结论。
6. 一个验证技巧:用最小样本十分钟跑通情感分类全流程
论文里那些实验结论,自己动手复现一遍才会真正变成自己的东西。完整复现三个事件、多种特征组合的代价很高,我一般先做一个最小复现:单选一个事件,正负样本各几十条,用 TF-IDF 加线性 SVM,把全流程跑通,确认数据和参数没问题再扩展。
import jieba from sklearn.pipeline import Pipeline from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.svm import SVC from sklearn.metrics import accuracy_score # 自定义词典:覆盖事件相关的人名、网络用语 jieba.load_userdict("userdict.txt") def tokenize(text: str): # 先清洗再分词,顺序不能反过来 text = normalize_comment(text) return [w for w in jieba.cut(text) if w.strip()] # 论文结论:短文本里低维度就能保持较好准确率,500维足够起步 pipe = Pipeline([ ("vec", TfidfVectorizer(tokenizer=tokenize, max_features=500)), ("clf", SVC(kernel="linear", C=1.0)) ]) # 50%训练 / 50%测试,和论文实验的切分比例保持一致 split = int(len(comments) * 0.5) pipe.fit(comments[:split], labels[:split]) preds = pipe.predict(comments[split:]) print("acc:", accuracy_score(labels[split:], preds))跑完先看两个指标:准确率是否在 75% 附近,以及无特征样本占比是多少。论文在去除无特征样本后三个事件都能超过 75%,如果你的结果明显低于这个区间,优先检查分词和清洗,而不是调 SVM 参数。如果无特征样本占比超过 20%,说明特征集合覆盖不足,回到第 3 章的思路补论据词语。从那以后,我每拿到一批新的文本数据,第一件事就是跑一遍这个最小流程,确认当前特征方案能稳定在合理区间,再去谈调参数、换模型的事。这个习惯帮我挡掉了至少三次在错误数据分布上做无用优化的时间浪费,希望帮到你。
本文还有配套的精品资源,点击获取