amz_review_analyse/VOC分析方法论与报告生成逻辑.md
OnesvmWhoops cb6692c0c0 新增 voc_业务_2 报告流水线,并完善聚类与词频模块。
包含 Persona 锚定聚类、LLM 报告生成、方法论文档及 .gitignore 更新,便于在 Gitee 独立部署。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 17:12:39 +08:00

815 lines
33 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# VOC 数据清洗、分析与报告生成通用方法论
> 文档版本:v1.0 · 2026-06-11
> 适用范围:亚马逊任意品类竞品 VOC 分析
> 数据来源:卖家精灵 / Shulex 导出的实时评论 CSV
> 报告输出:双层结构 HTML 报告(描述层 What + 分析层 Why)
---
## 目录
1. [原始数据结构](#1-原始数据结构)
2. [数据清洗规则](#2-数据清洗规则)
3. [描述层 What — 分析逻辑](#3-描述层-what--分析逻辑)
- 3.1 有效评论统计
- 3.2 用户画像(Persona)识别
- 3.3 正负反馈主题提取
- 3.4 情感关键词分析
4. [分析层 Why — 分析逻辑](#4-分析层-why--分析逻辑)
- 4.1 KANO 模型需求分类
- 4.2 JTBD 动机框架
- 4.3 人群 × 场景 × 需求矩阵
- 4.4 痛点根因分析
5. [报告生成逻辑](#5-报告生成逻辑)
- 5.1 HTML 整体结构
- 5.2 可视化组件
- 5.3 使用场景字段写入规则(核心规则)
6. [执行 SOP(逐步操作流程)](#6-执行-sop逐步操作流程)
7. [关键阈值与判断规则速查表](#7-关键阈值与判断规则速查表)
8. [新品类接入清单](#8-新品类接入清单)
---
## 1. 原始数据结构
### 文件命名规则
```
{ASIN}_realtime.csv
```
每个竞品 ASIN 对应一个独立文件,分析时批量读取同一目录下的全部文件。
### CSV 字段说明
| 字段名 | 类型 | 说明 |
|---|---|---|
| `asin` | string | 亚马逊标准识别号,文件可能带 BOM 头(`\ufeffasin`),读取时须用 `utf-8-sig` 编码 |
| `rating` | float(字符串形式) | 评分,取值 `1.0` / `2.0` / `3.0` / `4.0` / `5.0`,须用 `float()` 转换,**不能用 `int()`** |
| `title` | string | 评论标题 |
| `content` | string | 评论正文(主要分析字段) |
| `verified` | string | `"True"` / `"False"`,是否已验证购买 |
| `vine` | string | `"True"` / `"False"`,是否为 Vine 评测 |
| `review_date` | string | ISO 8601 格式,如 `2026-05-28T00:00:00+00:00` |
---
## 2. 数据清洗规则
### 2.1 有效评论筛选(不可更改的核心规则)
**只保留以下两类评论,其余全部排除:**
```python
def is_valid(row):
return (
row.get('verified', '').strip().lower() == 'true'
or
row.get('vine', '').strip().lower() == 'true'
)
```
**排除理由**:未验证且非 Vine 的评论可能包含刷评、竞品恶意差评或未实际购买的猜测,会干扰真实用户体验数据。
### 2.2 差评 / 好评 / 中性评论定义
| 分类 | 星级 | 用途 |
|---|---|---|
| 好评(Positive) | ★★★★★ / ★★★★ | 提取正向主题、魅力型需求、用户满意点 |
| 中性(Neutral) | ★★★ | 单独记录,不进入主题频次统计 |
| 差评(Negative) | ★★ / ★ | 主要分析对象,提取痛点主题和根因 |
### 2.3 新买家 vs 复购买家区分规则
| 类型 | content 字段识别关键词 |
|---|---|
| **新买家** | `first time` / `just got` / `just bought` / `new to` |
| **复购买家** | `reorder` / `bought again` / `second time` / `repurchase` / `keep buying` |
> 两类买家的差评重点通常不同:
> - 新买家 → 效果不符预期、开箱即坏、使用门槛高
> - 复购买家 → 某个功能在长期使用后失效、品质下降
---
## 3. 描述层 What — 分析逻辑
### 3.1 有效评论统计
对每个 ASIN 分别计算,再汇总全市场数据:
| 指标 | 计算公式 |
|---|---|
| 有效评论数 | 通过 `is_valid()` 筛选后的总行数 |
| 加权平均评分 | `Σ(各ASIN均分 × 各ASIN有效评论数) / 全市场有效评论总数` |
| 差评率 | `≤2星评论数 / 有效总数` |
| 正评率 | `≥4星评论数 / 有效总数` |
| 各星级分布 | 1–5 星各自数量及占比 |
**市场竞争状态判断**:
| 加权均分 | 判断 |
|---|---|
| < 3.5 | 市场存在严重系统性缺陷,是新品进入的明确窗口期 |
| 3.5 – 4.0 | 市场有改进空间,部分功能存在普遍短板 |
| > 4.0 | 市场整体较成熟,需通过差异化或细分切入 |
### 3.2 用户画像(Persona)识别
#### 识别方法
在评论 `title + content` 字段中搜索特征词,将评论人归入对应 Persona。一条评论可同时归入多个 Persona。
#### Persona 识别词的建立原则
1. **阅读全部差评(≤2星)**,找出用户描述自身处境的词汇("I have... / I am... / As a...")
2. **阅读全部好评(≥4星)**,找出用户描述自身需求背景的词汇
3. 从中归纳出 4–6 个差异化的用户群体
4. 每个群体设定 5–10 个识别关键词
#### ⚠️ Persona 必须覆盖的三个分类维度(缺一不可)
在最终确认 Persona 列表前,必须检查是否已从以下三个维度进行了覆盖,**不能只按其中一个维度拆分就停止**:
| 维度 | 说明 | 典型信号词 |
|---|---|---|
| **A. 物理/生理特征** | 用户身体特征决定了产品对他们的效果上限(最易被遗漏) | `thick/dark/coarse hair` / `sensitive skin` / `pregnant` / `curly` / `Latina` / `Type 4 hair` |
| **B. 行为/场景** | 用户在什么情境下使用产品 | `travel` / `in the shower` / `gift` / `daily` |
| **C. 购买动机/背景** | 用户为何从其他方案切换过来 | `switched from razor` / `too expensive` / `saw on TikTok` / `first time` |
> **关键原则**:如果你的 Persona 列表里只有场景类和动机类群体,而没有任何一个群体是按身体特征定义的,说明维度 A 被遗漏了,必须重新检查差评中的自我标注词汇。
#### 自我标注信号强制检查步骤
在完成初步 Persona 归纳后,**必须**额外执行以下搜索,确认是否有被遗漏的物理特征用户群:
```
搜索差评中所有含以下模式的句子:
"I have [adj] [noun]"(如 I have thick hair / I have sensitive skin)
"My [noun] is/are [adj]"(如 My skin is super sensitive)
"As a [noun/adj person]"(如 As a Latina / As a curly-haired person)
"[族裔/肤色/发质形容词]"(如 Latina / dark hair / coarse / Type 4)
若上述词汇出现 ≥ 5 条,则该物理特征代表一个独立 Persona,必须单独列出。
```
#### Persona 识别词模板格式
```python
PERSONA_KEYWORDS = {
'{群体名称A}': ['{关键词1}', '{关键词2}', ...],
'{群体名称B}': ['{关键词1}', '{关键词2}', ...],
# 根据实际品类补充
}
```
#### Persona 占比估算规则
```
占比 = 命中该Persona识别词的评论数 / 有效评论总数
四舍五入至整5%
```
> 因一条评论可被多个 Persona 命中,各 Persona 占比之和可超过 100%。
#### Persona 卡片内容规格(每个群体输出以下信息)
| 字段 | 来源 | 说明 |
|---|---|---|
| 群体名称 | 自定义 | 简洁描述身份特征,≤6 字 |
| 占比 | 统计计算 | 见上方公式 |
| 核心痛点 | 该群体差评 | ≤3 条,原文语义概括 |
| 核心需求 | 该群体好评+诉求 | ≤3 条 |
| 购买动机 | JTBD 分析 | 用"雇佣产品做什么"句式 |
| 代表性引用 | 真实评论原文 | 必须来自实际评论,注明 ASIN |
### 3.3 正负反馈主题提取
#### 主题识别关键词组的建立方法
1. 阅读**全部差评(≤2星)**,记录用户描述问题时的高频词
2. 将语义相近的词归为同一主题,形成关键词组
3. 每个主题设定 5–10 个关键词
4. 覆盖 80%+ 的差评内容(长尾主题可合并为"其他")
#### ⚠️ 主题拆分规则:相近但机制不同的问题必须独立成主题
语义相近不等于根因相同。以下情况**必须拆分为独立主题,不得合并**:
| 合并后失真的典型例子 | 应该如何拆分 | 原因 |
|---|---|---|
| "剃效差"(笼统) | ① 留茬/剃不干净 ② 拉扯/扯毛而非切断 | 机制不同:留茬=刀头贴肤不足;拉扯=刀片咬不断粗硬毛,影响人群完全不同 |
| "皮肤问题"(笼统) | ① 割伤/出血 ② 摩擦热/灼烧感 ③ 剃须疹/内生毛 | 根因不同,对应不同的工程解决方案 |
| "产品损坏"(笼统) | ① 充电失效 ② 配件断裂/脱落 | 分属电气系统和结构系统,受影响时间节点不同(充电=使用初期;断裂=一段时间后) |
> **判断是否需要拆分的问题**:
> "同一主题下的差评,是否描述的是同一个物理/工程原因?"
> 如果不是,必须拆开。
**通用差评主题模板格式**:
```python
NEGATIVE_THEMES = {
'{主题名称}': ['{关键词1}', '{关键词2}', ...],
# 品类相关主题
}
```
**通用好评主题模板格式**:
```python
POSITIVE_THEMES = {
'{主题名称}': ['{关键词1}', '{关键词2}', ...],
}
```
#### 频次统计规则
1. 在 `title + content` 中搜索关键词
2. 同一评论中同一关键词出现多次,仍计为 1 次(避免重复计数)
3. 差评主题只统计 ≤2 星评论;好评主题只统计 ≥4 星评论
4. **频次 = 命中该主题的评论条数**(非词语出现总次数)
#### 主题优先级判定规则
| 优先级 | 差评频次门槛 | 涉及竞品范围 |
|---|---|---|
| **P0(立即处理)** | ≥ 总有效差评数的 20% | 80%+ 竞品均出现 |
| **P1(短期处理)** | 总有效差评数的 10–20% | 60%+ 竞品出现 |
| **P2(中期关注)** | 总有效差评数的 3–10% | 40%+ 竞品出现 |
> **频次门槛的动态计算**:
> `P0 绝对门槛 = 全市场有效差评数 × 20%`
> 例:1123 条有效评论,差评率 35% ≈ 393 条差评,P0 门槛 ≈ 79 条
### 3.4 情感关键词分析
对所有有效评论进行词频统计,提取高频情感词。
**输出字段规格**:
| 字段 | 说明 | 规则 |
|---|---|---|
| 词汇 | 英文原词或词组 | 保留原文,不翻译 |
| 出现频次 | 在有效评论中出现的条数 | 同一评论多次出现计1次 |
| 情感极性 | 正面 / 负面 / 中性 | 根据语境判断,同一词在不同语境可有不同极性 |
| 含义/使用场景 | 该词汇在评论中的具体语境 | **只写评论中明确出现的内容,不推断** |
| 主要关联人群 | 对应的 Persona 名称 | 可多个 |
---
## 4. 分析层 Why — 分析逻辑
### 4.0 Persona 完整性验证(进入分析层前的强制关卡)
**在开始 KANO / JTBD 分析之前,必须完成以下交叉验证,发现遗漏立即返回 3.2 节补充。**
#### 验证方法:每个 P0/P1 主题 → 强制归因到 Persona
为每一个 P0/P1 差评主题填写下表:
| 差评主题 | 频次 | 该主题的典型描述 | 主要影响哪类用户? | 对应已有 Persona? |
|---|---|---|---|---|
| {主题1} | {N条} | {原文特征} | {用户特征描述} | {Persona名 / ❌未覆盖} |
| {主题2} | ... | ... | ... | ... |
**如果某个 P0/P1 主题在"对应已有 Persona"列填写了 ❌,说明存在遗漏的用户群体,必须新增 Persona。**
#### 常见漏洞场景
| 被遗漏的情况 | 漏洞原因 | 补救方式 |
|---|---|---|
| 身体特征群体(如粗硬发质用户) | 只按场景/动机分群,未检查维度 A(物理特征) | 返回 3.2 节执行自我标注信号强制检查 |
| 长期使用复购用户 | 只看差评内容,未注意时间轴("after months of use") | 检查含 `months` / `after a while` / `second bottle` 的差评是否形成独立群体 |
| 特定人群的特殊需求 | 该群体占比较小但痛点极具体 | 即使占比低(~5%),若痛点独特且无法被其他 Persona 代表,必须单独列出 |
### 4.1 KANO 模型需求分类
#### 四种类型定义与判断标准
| 类型 | 定义 | 判断标准 | 常见错误 |
|---|---|---|---|
| **基本型(Must-be)** | 不满足→强烈差评;满足→用户不会特别提及或表扬 | ① 差评频次达 P0 级别 ② 80%+ 竞品均出现该缺陷 ③ 好评中几乎不出现"因为做到了 X 所以好评" | 把"剃净度"归为基本型——剃净度好坏都会被用户提及,属期望型 |
| **期望型(Performance)** | 做得越好评分越高,做得越差评分越低,线性关系 | ① 好评中被作为"这款优于竞品"的主要理由 ② 差评中作为"原本期待但未达到"的失望点 ③ 用户用程度词描述(`better/worse/not as good as`) | 把"电池续航"归为基本型——续航差才差评,续航超长会被用户特别称赞 |
| **魅力型(Attractive)** | 满足→产生超预期惊喜和好评;不满足→用户不会差评 | ① 好评中出现强情感词 `love` / `obsessed` / `amazing` / `didn't expect` / `bonus` ② 该功能在差评中几乎不出现 ③ 竞品普遍缺失,属市场空白 | 把"附赠收纳袋"归为期望型——用户从未因为"没有收纳袋"而差评,属意外惊喜 |
| **反向型(Reverse)** | 某些用户认为该功能是负担,反而差评 | ① 差评中出现对某个"功能"的明确抱怨 ② 该内容在好评中也受另一部分人喜爱(说明用户分歧) | 把"产品损坏"归为反向型——没有用户"希望产品能损坏" |
#### 各类型的输出格式要求
每个 KANO 条目必须包含以下 5 个字段,缺一不可:
```
需求项:[具体需求描述,动词+名词形式]
评论频次证据:[支撑该分类的评论条数及代表性原文片段]
主要影响 Persona:[哪类用户群对该需求最敏感]
分类原因:[用一句话解释为什么是这个 KANO 类型,而不是其他类型]
竞品现状:[现有竞品是否满足,满足程度如何]
```
**示例(基本型)**:
```
需求项:充电后可正常启动
评论频次证据:118条差评(P0级别),"stopped working after a few uses" / "won't charge at all"
主要影响 Persona:所有群体,尤其是复购用户(第二台也坏后彻底失去信任)
分类原因:充电失效是"有就正常、坏了就1星"的底线需求,好评中没有人因"能充电"而特别表扬
竞品现状:全部5款竞品均有此问题,说明是行业普遍工程缺陷
```
**示例(魅力型)**:
```
需求项:LCD 电量显示
评论频次证据:好评中 28条提及,"love that I can see the battery level" / "so convenient",差评中0条因缺少LCD而差评
主要影响 Persona:旅行护理族(出行前确认电量)/ 所有群体
分类原因:用户不会因为"没有电量显示"而差评,但有了之后会主动提及并作为推荐理由
竞品现状:仅1款(FANKRUAI)有此功能,属差异化空白
```
#### KANO 归类操作步骤
**步骤一:基本型识别**
- 列出所有 P0/P1 差评主题
- 检查每个主题对应的好评:如果好评中几乎没有人因"做到了这点"而表扬,确认为基本型
- 每个基本型需求必须注明:频次(条数)+ 出现该问题的竞品数量
**步骤二:期望型 vs 魅力型区分**
在好评中对每个高频好评主题做以下判断:
| 判断问题 | 若"是"→ | 若"否"→ |
|---|---|---|
| 差评中有人因该功能**不够好**而差评? | 期望型 | 魅力型候选 |
| 好评用程度词描述(`better/works great/very`)? | 期望型 | 魅力型候选 |
| 好评中出现 `love/obsessed/amazing/bonus/didn't expect`? | 魅力型 | 继续判断 |
| 竞品普遍缺失,属市场新鲜感? | 魅力型 | 继续判断 |
**步骤三:反向型搜索(不得以"未发现"一笔带过)**
必须主动在差评中搜索以下关键词,并记录每个词的出现频次:
```
搜索词组(在全部有效评论 title+content 中搜索):
过于复杂:too many parts / too complicated / confusing / hard to use
过于嘈杂:too loud / so loud / noise / noisy
功能多余:don't need / unnecessary / didn't ask for / useless feature
操作繁琐:takes too long / too many steps / annoying to clean
```
**结果处理规则**:
- 若任意词组频次 ≥ 5 条 → 该功能为反向型,单独列出并附引用
- 若所有词组总频次 < 5 条 → 填写:"反向型:经主动搜索 [列出搜索词],出现频次共 [N] 条,低于阈值,本品类暂无明确反向需求"(**禁止直接写"无"或"未发现"**)
### 4.2 JTBD 动机框架
> JTBD(Jobs To Be Done):用户"雇佣"产品来完成什么任务。分析维度:功能性动机、情感性动机、社会性动机。
**输出格式(每个 Persona 一行)**:
| 字段 | 说明 | 填写规则 |
|---|---|---|
| 用户群 | Persona 名称 | — |
| 核心 Job | 用户想完成的任务 | 动词+宾语形式,如"用电动工具替代传统方式" |
| 功能性动机 | 实用层面的驱动因素 | 必须能从评论中找到佐证句子 |
| 情感性动机 | 情绪/心理层面的驱动因素 | 必须能从评论中找到佐证句子 |
| 社会性动机 | 他人视角/社交驱动(如无评论佐证则留空) | 可选 |
| 购买触发时机 | 什么具体事件让用户决定购买 | 来自评论中的具体描述 |
### 4.3 人群 × 场景 × 需求矩阵
矩阵将 Persona、使用场景、KANO 需求分层和当前满意度整合为一张全景视图。
**列结构**:
| 列 | 填写来源 |
|---|---|
| 用户群 | Persona 名称 + 占比 |
| 使用场景(When/Where) | **严格遵守场景字段规则(见 5.3 节)** |
| 基本型需求 | KANO 基本型 + 该群体 P0 差评 |
| 期望型需求 | KANO 期望型 + 该群体 P1 差评 |
| 魅力型需求 | KANO 魅力型 + 该群体好评加分点 |
| 当前满意度 | 该群体对应评论的均分和好评率综合判断 |
**满意度评级标准**:
| 当前满意度 | 对应均分参考 | 显示样式 |
|---|---|---|
| 高 | ≥ 4.0 | 绿色 |
| 中等 | 3.3 – 3.9 | 黄色 |
| 低 ⚠ | < 3.3 | 红色 |
### 4.4 痛点根因分析
**适用条件**:差评主题达到 P0 或 P1 级别时,必须进行根因分析。
**分析框架**:
```
根因 N:[工程/设计/材料/体验设计问题名称]
→ 导致后果:[差评主题名称] × [频次]
→ 失效机制:[从产品结构或工作原理层面解释为什么会出现这个问题]
→ 关键引用:[2-3条真实评论原文(英文)— 所属ASIN品牌]
```
**根因分析的层次要求**:
| 层次 | 示例(错误 → 正确) |
|---|---|
| 停留在现象层(❌) | "产品质量差" |
| 到达机制层(✅) | "充电口防水胶圈未达到IP67标准,浴室蒸汽渗入导致腐蚀" |
---
## 5. 报告生成逻辑
### 5.1 HTML 整体结构
报告采用**纯 HTML 内嵌 CSS + JS**,无外部文件依赖,单文件可直接分享。
```
{产品关键词}-voc-v{版本号}.html
├── <head>
│ ├── Chart.js CDN(可视化依赖)
│ │ └── https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js
│ └── <style> 内嵌 CSS
│
├── <nav class="top-nav">(固定顶部导航,支持锚点跳转)
│ ├── [描述层 What] → 数据总览 / 受众画像 / 正负反馈 / 各ASIN主题分布 / 情感词频
│ └── [分析层 Why] → KANO模型 / JTBD动机 / 人群矩阵 / 痛点根因
│
└── <div class="page">(主体内容)
├── 标题 + 副标题 + 阅读指引 callout
├── ── 描述层 What ──
│ ├── #sec-overview:KPI 总览卡片
│ ├── #sec-persona:Persona 卡片网格
│ ├── #sec-feedback:全市场差评/好评主题柱状图(汇总)
│ ├── #sec-asin-theme:各 ASIN 差评/好评主题频次分布(新增)
│ └── #sec-keyword:情感词频表格
├── ── 分析层 Why ──
│ ├── #sec-kano:KANO 四象限卡片
│ ├── #sec-jtbd:JTBD 动机表格
│ ├── #sec-matrix:人群×场景×需求矩阵
│ └── #sec-rootcause:痛点根因分析块
└── <footer>(数据来源声明)
```
**文件存放路径**:`{产品文件夹}/分析报告 HTML/`
**文件命名**:`{产品关键词(连字符)}-voc-v{版本号}.html`
示例:`dog-calming-chews-voc-v1.html`
### 5.2 可视化组件规格
#### KPI 卡片(4 个,固定布局)
| 位置 | 指标 | 颜色规则 |
|---|---|---|
| 卡片1 | 有效评论总数 | 蓝色(中性) |
| 卡片2 | 加权平均评分 | < 3.5 红色 / 3.5–4.0 黄色 / > 4.0 绿色 |
| 卡片3 | 正评率(≥4星占比) | 绿色 |
| 卡片4 | 差评率(≤2星占比) | 红色 |
#### 柱状图(使用 Chart.js,水平条形图)
**差评主题柱状图(全市场汇总)**:
```javascript
new Chart(document.getElementById('negChart'), {
type: 'bar',
data: {
labels: ['主题1', '主题2', ...], // 按频次降序排列
datasets: [{
data: [频次1, 频次2, ...],
// 颜色按优先级:P0 = '#ef4444',P1 = '#f97316',P2 = '#eab308'
backgroundColor: ['#ef4444', '#ef4444', '#f97316', '#f97316', '#eab308', '#eab308'],
}]
},
options: {
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: { x: { beginAtZero: true } }
}
});
```
**好评主题柱状图(全市场汇总)**:配色统一使用绿色系(`#22c55e`)。
---
#### 各 ASIN 主题频次分布图(新增,ID: sec-asin-theme)
**用途**:揭示同一痛点在不同竞品间的严重程度差异,帮助判断哪款竞品在哪个维度最弱/最强。
**图表类型**:**分组柱状图(Grouped Bar Chart)**,每个主题一组,每组内各 ASIN 一根柱子。
**差评版 — 数据结构**:
```javascript
new Chart(document.getElementById('asinNegChart'), {
type: 'bar',
data: {
labels: ['主题1', '主题2', ...], // x轴:差评主题(P0/P1 主题,按全市场频次降序)
datasets: [
// 每个 ASIN 一个 dataset
{ label: 'ASIN1(品牌名)', data: [主题1频次, 主题2频次, ...], backgroundColor: '#色值' },
{ label: 'ASIN2(品牌名)', data: [...], backgroundColor: '#色值' },
// ...
]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: true, position: 'bottom' }
},
scales: {
x: { beginAtZero: true },
y: { beginAtZero: true }
}
}
});
```
**好评版 — 与差评版结构完全相同**,labels 换成好评主题,颜色使用绿色系渐变。
**ASIN 配色规则(固定,每次分析保持一致)**:
| ASIN 序号 | 差评图颜色 | 好评图颜色 |
|---|---|---|
| ASIN 1 | `#ef4444`(红) | `#22c55e`(绿) |
| ASIN 2 | `#f97316`(橙) | `#86efac`(浅绿) |
| ASIN 3 | `#eab308`(黄) | `#4ade80`(草绿) |
| ASIN 4 | `#8b5cf6`(紫) | `#2dd4bf`(青绿) |
| ASIN 5 | `#3b82f6`(蓝) | `#60a5fa`(浅蓝绿) |
**数据提取逻辑(Python)**:
```python
def count_theme_per_asin(all_reviews, themes, neg=True):
"""
按 ASIN 分别统计各主题的差评/好评频次
返回格式:{asin: {theme: count}}
"""
from collections import defaultdict
result = defaultdict(lambda: defaultdict(int))
for r in all_reviews:
if neg and r['rating'] > 2: continue
if not neg and r['rating'] < 4: continue
text = (r['title'] + ' ' + r['content']).lower()
for theme, keywords in themes.items():
if any(kw.lower() in text for kw in keywords):
result[r['asin']][theme] += 1
return dict(result)
# 转为 Chart.js datasets 格式
def to_chartjs_datasets(per_asin_data, asin_labels, theme_order):
"""
asin_labels: {asin: '品牌名'} 映射
theme_order: 主题列表(按全市场频次排序)
"""
colors = ['#ef4444', '#f97316', '#eab308', '#8b5cf6', '#3b82f6']
datasets = []
for i, (asin, label) in enumerate(asin_labels.items()):
datasets.append({
'label': label,
'data': [per_asin_data.get(asin, {}).get(t, 0) for t in theme_order],
'backgroundColor': colors[i % len(colors)],
})
return datasets
```
**图表尺寸**:高度建议 `360px`(主题数 ≤ 8)或 `480px`(主题数 > 8)。
**图表标题规则**:
- 差评版:`各竞品差评主题频次对比(≤2星评论)`
- 好评版:`各竞品好评主题频次对比(≥4星评论)`
#### 表格通用样式规则
| 元素 | CSS 类 | 用途 |
|---|---|---|
| P0 行 | `.row-r` | 红色背景底色(`#fff5f5`) |
| P1 行 | `.row-y` | 黄色背景底色(`#fffbeb`) |
| P2 行 | `.row-b` | 蓝色背景底色(`#eff6ff`) |
| 机会行 | `.row-g` | 绿色背景底色(`#f0fdf4`) |
| 优先级徽章 | `.pill pill-danger` / `.pill-warn` / `.pill-info` | 红/黄/蓝圆角标签 |
### 5.3 使用场景字段写入规则(核心规则)
**这是本方法论中最容易出错、最需要严格执行的规则:**
```
【强制规则】
所有涉及"使用场景(When/Where)"的字段,
只允许填写在评论 content 中能找到原词佐证的场景描述。
如果找不到评论佐证,一律填写 "—"。
禁止基于产品功能、品类常识或逻辑推断填写任何场景描述。
```
#### 执行步骤
```
Step 1:确定该 Persona 的特征词组
Step 2:在该 Persona 对应的评论中搜索场景类词汇
(地点词:shower / bathroom / office / car / gym...)
(时间词:morning / night / before / after / daily...)
(情境词:traveling / pregnant / postpartum / gift...)
Step 3:统计每个场景词在该 Persona 评论中的出现条数
Step 4:按以下规则决定是否填写
```
| 出现条数 | 处理方式 |
|---|---|
| ≥ 5 条 | 可以填写该场景 |
| 2 – 4 条 | 慎重填写,建议留空或标注"少数提及" |
| < 2 条 | 必须留空,填写 `—` |
#### 常见错误示例
| 错误写法(❌ 推断) | 正确写法(✅ 仅来自评论) |
|---|---|
| 夏季前突击整理 | —(无评论提及"before summer"作为使用时机) |
| 日常护理 | —("daily"在评论中属产品使用频率描述,非场景) |
| 坐姿/斜靠操作 | —(用户姿势属推断,评论未明确提及) |
| 任何场所 | —(无具体场景词,不可用"泛化"代替留空) |
| 浴室/淋浴 | ✅(评论中出现 `in the shower` / `bathroom` ≥5条) |
| 旅行途中 | ✅(评论中出现 `travel` / `on a trip` ≥5条) |
| 孕期护理 | ✅(评论中出现 `pregnant` / `37 weeks pregnant` ≥5条) |
---
## 6. 执行 SOP(逐步操作流程)
### Step 1:数据读取
```python
import csv
import os
def load_reviews(filepath):
"""读取单个ASIN的评论CSV,返回有效评论列表"""
reviews = []
with open(filepath, encoding='utf-8-sig') as f: # utf-8-sig 处理BOM头
for row in csv.DictReader(f):
if (row.get('verified', '').strip().lower() == 'true' or
row.get('vine', '').strip().lower() == 'true'):
reviews.append({
'asin': row.get('asin', '').strip(),
'rating': float(row.get('rating', 0) or 0),
'title': row.get('title', ''),
'content': row.get('content', ''),
'date': row.get('review_date', ''),
})
return reviews
def load_all_reviews(directory):
"""批量读取目录下所有ASIN的评论"""
all_reviews = []
for fname in os.listdir(directory):
if fname.endswith('_realtime.csv'):
all_reviews.extend(load_reviews(os.path.join(directory, fname)))
return all_reviews
```
### Step 2:基础统计
```python
def basic_stats(reviews):
"""计算有效评论的基础统计指标"""
ratings = [r['rating'] for r in reviews if r['rating'] > 0]
total = len(ratings)
if not total:
return {}
return {
'total': total,
'avg': round(sum(ratings) / total, 2),
'pos_rate': round(sum(1 for r in ratings if r >= 4) / total, 3),
'neg_rate': round(sum(1 for r in ratings if r <= 2) / total, 3),
'dist': {i: ratings.count(float(i)) for i in range(1, 6)},
}
```
### Step 3:主题频次统计
```python
# 根据品类自定义主题关键词(见第3.3节)
NEGATIVE_THEMES = {
'{主题名称}': ['{关键词1}', '{关键词2}', ...],
}
POSITIVE_THEMES = {
'{主题名称}': ['{关键词1}', '{关键词2}', ...],
}
def count_themes(reviews, themes, neg=True):
"""
统计各主题频次
neg=True 时只统计差评(≤2星),neg=False 时只统计好评(≥4星)
"""
result = {}
for theme, keywords in themes.items():
count = 0
for r in reviews:
if neg and r['rating'] > 2: continue
if not neg and r['rating'] < 4: continue
text = (r['title'] + ' ' + r['content']).lower()
if any(kw.lower() in text for kw in keywords):
count += 1
result[theme] = count
return dict(sorted(result.items(), key=lambda x: x[1], reverse=True))
```
### Step 4:Persona 识别
```python
# 根据品类自定义(见第3.2节)
PERSONA_KEYWORDS = {
'{群体名称}': ['{关键词1}', '{关键词2}', ...],
}
def identify_personas(reviews, persona_keywords):
"""统计各Persona的命中评论数量"""
result = {p: 0 for p in persona_keywords}
for r in reviews:
text = (r['title'] + ' ' + r['content']).lower()
for persona, kws in persona_keywords.items():
if any(kw.lower() in text for kw in kws):
result[persona] += 1
total = len(reviews)
return {p: {'count': c, 'pct': round(c / total * 100)} for p, c in result.items()}
```
### Step 5:场景词验证(填写矩阵前必须执行)
```python
def verify_scene(persona_reviews, scene_keywords, min_count=5):
"""
验证某个场景词是否在该Persona评论中出现足够多次
返回 (是否可填写, 实际出现条数)
"""
count = 0
for r in persona_reviews:
text = (r['title'] + ' ' + r['content']).lower()
if any(kw.lower() in text for kw in scene_keywords):
count += 1
return count >= min_count, count
# 示例用法
persona_reviews = [r for r in all_reviews if '粗硬发质' in identify_personas_for_review(r)]
can_fill, cnt = verify_scene(persona_reviews, ['shower', 'bathroom', 'in the shower'])
scene_text = '浴室/淋浴' if can_fill else '—'
```
### Step 6:报告组装流程
1. **准备数据**:运行 Step 1–5,收集所有统计结果
2. **起草 Canvas**(在 IDE 中生成 `.canvas.tsx` 文件),等待用户确认内容无误
3. **用户确认后**:生成 HTML 文件,保存至 `分析报告 HTML/` 目录
4. **Canvas 与 HTML 内容必须保持同步**,修改 Canvas 后须同步更新 HTML
---
## 7. 关键阈值与判断规则速查表
| 决策点 | 规则 |
|---|---|
| **有效评论筛选** | `verified == True` 或 `vine == True` |
| **差评定义** | rating ≤ 2.0 |
| **好评定义** | rating ≥ 4.0 |
| **P0 主题门槛** | 频次 ≥ 有效差评数 × 20%,且 80%+ 竞品出现 |
| **P1 主题门槛** | 频次为有效差评数的 10–20%,60%+ 竞品出现 |
| **P2 主题门槛** | 频次为有效差评数的 3–10%,40%+ 竞品出现 |
| **Persona 占比** | 命中评论数 / 有效总数,四舍五入至整5% |
| **场景词可填写门槛** | ≥ 5 条 Persona 评论中出现该场景词,否则填 `—` |
| **市场整体判断** | 均分 < 3.5 = 系统性缺陷,新品窗口期 |
| **KANO 基本型判断** | P0 级差评,且与低评分强相关 |
| **KANO 魅力型判断** | 好评中出现 `love`/`amazing`/`didn't expect`,非差评主题 |
| **新买家识别** | content 含 `first time`/`just got`/`just bought`/`new to` |
| **复购买家识别** | content 含 `reorder`/`bought again`/`second time`/`repurchase` |
| **根因分析触发** | 差评主题达到 P0 或 P1 级别 |
| **Persona 引用合规** | 只能引用 content 中确实存在的原文,禁止改写或虚构 |
---
## 8. 新品类接入清单
每次分析新品类时,依次完成以下配置,其余分析框架直接复用:
```
□ 1. 确认 CSV 文件路径和 ASIN 列表
□ 2. 阅读**全部差评和全部好评**,按三个维度(A物理特征 / B行为场景 / C购买动机)归纳 Persona,编写 PERSONA_KEYWORDS
□ 3. 执行**自我标注信号强制检查**(搜索 "I have [adj]..." / "As a [noun]..." 等模式),确认无遗漏的物理特征群体
□ 4. 阅读**全部差评(≤2星)**,归纳差评主题,注意根因不同的问题必须拆分为独立主题,编写 NEGATIVE_THEMES
□ 5. 阅读**全部好评(≥4星)**,归纳 4–6 个好评主题,编写 POSITIVE_THEMES
□ 6. 运行 Step 1–3,验证频次统计结果与人工阅读印象一致;同时用 count_theme_per_asin() 生成各 ASIN 的主题频次分布数据,用于 #sec-asin-theme 图表
□ 7. **Persona 完整性验证**:为每个 P0/P1 主题强制归因到 Persona,有 ❌ 则返回步骤 2 补充
□ 8. 对每个 Persona 执行 verify_scene(),确认使用场景字段
□ 9. 完成 KANO 归类(基于统计结果,无需额外数据)
□ 10. 完成 JTBD 框架(基于 Persona 评论,无需额外数据)
□ 11. 撰写根因分析(P0/P1 主题,每条根因附 2-3 条原文引用)
□ 12. 生成 Canvas → 用户确认 → 生成 HTML
```
---
*本文档为通用框架,无品类特定数据。新品类分析时,只需填写第 8 节清单中的品类相关配置,其余规则和代码模板均可直接复用。*