情感分析算法说明
概述
WeLink 使用基于规则的句子级情感评分,对每条文本消息打 0~1 分,按月聚合后展示情感趋势曲线。
评分的核心思路:先把句子 tokenize 成词元列表,再用滑动窗口否定和局部程度副词加权对情感词定向打分,最后加权平均。
该方法不依赖模型服务,响应快,可完全本地运行,但对复杂语境的准确率有限。
评分流程
1. Tokenize
tokenize(text) → []string对句子做贪心最长匹配(优先识别多字词),把文本拆成 token 列表:
- 从当前位置起,从最长(6字符)向最短(2字符)尝试匹配已知词(否定词 / 程度副词 / 情感词)
- 匹配成功则取整词作为一个 token
- 无匹配则取单字符
示例:"今天不开心" → ["今", "天", "不", "开心"]
2. 滑动窗口否定
遍历 token 列表时,遇到否定词后,对接下来 4 个 token 内的情感词翻转极性。
"今天不开心"
→ tokens: [今, 天, 不, 开心]
→ "不" 触发否定窗口,窗口计数 = 4
→ "开心" 在窗口内 → 翻转为负向
→ 最终得分 < 0.5"不难过"
→ tokens: [不, 难过]
→ "不" 触发否定,"难过" 被翻转为正向
→ 最终得分 > 0.53. 局部程度副词加权
情感词打分时,检查其前一个 token 是否为程度副词。是则乘以对应权重:
| 程度副词 | 权重 |
|---|---|
| 极其 | 1.7 |
| 非常 / 超级 | 1.6 |
| 特别 / 太 / 超 / 极 | 1.4~1.5 |
| 十分 / 相当 / 格外 / 尤为 / 异常 | 1.3~1.4 |
| 真的 / 好 / 挺 / 蛮 / 很 | 1.2 |
程度副词本身不参与情感计分,仅作修饰。
4. 加权平均 → 分数
收集所有有极性的 token(正向 +1,负向 -1),按程度权重做加权平均:
ratio = Σ(polarity × weight) / Σ(weight) ∈ [-1, 1]
score = 0.5 + ratio × 0.4 ∈ [0.1, 0.9]无任何情感词命中 → 返回 (0.5, false),该消息不计入月度 score,但仍计入 count。
词典
积极词(~50 个)
情感明确的正向词,去除了口语填充词("好"、"可以"、"行"、"哈哈"等):
开心 高兴 快乐 幸福 愉快 欢喜 喜悦 欣慰 心情好
喜欢 爱 爱你 宝贝 亲爱 心动
棒 厉害 牛 太棒了 很棒 好棒 优秀 出色 聪明 能干
完美 漂亮 好看 帅 美 可爱 赞 666 6666
感谢 谢谢 感激 感动 暖 暖心 贴心 温柔 体贴
成功 顺利 通过 搞定 完成 达成 实现 进步 提升
期待 惊喜 好期待 太好了 太棒了 好激动 激动 兴奋
满意 舒服 舒适 享受 放松 轻松 愉悦
加油 支持 鼓励 相信 祝贺 恭喜 庆祝 欢迎
有趣 好玩 好笑 开怀
甜 甜蜜 幸运 美好 美妙 好幸福消极词(~50 个)
难过 伤心 哭 哭了 哭泣 流泪 委屈 心疼 痛苦 心碎 想哭 好难受 难受 难受死了
焦虑 担心 害怕 恐惧 紧张 忐忑 不安 惶恐 慌
愤怒 生气 发火 火大 气死 气死我了 好气 烦死
讨厌 恶心 恨 滚 闭嘴 滚开
失望 沮丧 遗憾 后悔 可惜 无奈 心灰意冷
累 累死了 好累 疲惫 疲倦 精疲力竭
头疼 头痛 胃疼 不舒服 生病 发烧
烦 烦恼 烦透了 烦死了 烦人 无聊 厌烦 厌倦
孤独 寂寞 孤单 好孤独 一个人
崩溃 绝望 心塞 好绝望 撑不住 坚持不下去
失败 失去 分手 离开 完了 糟糕 糟透了
倒霉 运气差 坏运气否定词(11 个)
不 没 别 莫 勿 未 非 无 没有 从未 从来不程度副词(18 个)
非常 特别 超级 极其 十分 太 真的 真 好 超
相当 挺 蛮 很 极 格外 尤为 异常月度聚合
月度统计的 count 字段反映该月全部文本消息数(含中性),使图表消息量更准确:
for each text message:
if isSys(text) or len < 2: skip
bucket[month].total++ ← 全部消息都计入 count
score, valid = scoreSentence(text)
if not valid:
totalNeutral++
continue ← 不影响月度 score
bucket[month].scoreSum += score
bucket[month].scored++
if score >= 0.6: totalPos++
elif score <= 0.4: totalNeg++
else: totalNeutral++
monthly[month].score = scoreSum / scored (无情感词的月份默认 0.5)
monthly[month].count = total
overall = totalScoreSum / totalScored分数解读
| 分数范围 | 分类 | 含义 |
|---|---|---|
| ≥ 0.6 | 积极 | 正面情绪 |
| 0.4 ~ 0.6 | 中性 | 无明显情绪倾向 |
| ≤ 0.4 | 消极 | 负面情绪 |
= 0.5,valid=false | 无效 | 未命中情感词,计入 count 但不影响 score |
与历史版本(v1)的区别
| v1 | v2(当前) | |
|---|---|---|
| 否定检测 | 只看文本前 6 字节 | 滑动窗口,作用于后 4 个 token |
| 程度副词 | 对整句 Contains,与否定词逻辑互相干扰 | 只检查情感词前一个 token |
| 词典 | 含"好"、"哈哈"、"可以"等歧义词 | 去除口语填充词,只保留极性明确的词 |
| 月度 count | 仅含情感词的消息数 | 全部文本消息数 |
| 分词方式 | 无,直接 strings.Contains 整句 | 贪心最长词匹配后逐 token 判断 |
局限性
- 短句:2~4 字的短消息通常不命中完整情感词(如"好的"、"嗯")
- 反讽:无法识别,如讽刺性的"太棒了"会被算为正向
- 方言 / 网络新词:词典覆盖有限,持续扩充中
- 否定窗口固定:4 token 的否定作用域是经验值,对长句可能不够准确(如"我不是很高兴但还好")
与词云的关系
词云和情感分析共享相同的数据源(local_type=1 文本消息),都支持 include_mine 控制是否包含自己发的消息。
| 词云 | 情感分析 | |
|---|---|---|
| 处理单元 | 全文分词(GSE) | 句子级 tokenize + 情感词匹配 |
| 输出 | 词频分布 | 月度情感趋势分 |
| 过滤 | 停用词 / 标点 / 表情符号 | 无效句(< 2 字符或无情感词命中) |