← 返回 Skill 列表
extension
分类: 数据与分析无需 API Key

人群细分策略-市场调研

Turn raw brand-tracker / U&A crosstabs into a client-ready segmentation & targeting deck. Use when the user has survey data with demographic or behavioural breakdowns and asks for a segmentation, persona deck, target-audience definition, segment sizing, or 'which group should we prioritise'. Covers scheme selection (gender vs age vs skin type...), fixed-module persona cards, cross-market composition, rounding discipline, and a consistency QC pass that catches the classic errors (shares not summing to 100, a 'CORE TARGET' ranked #2, decimals in a client deck, small-base segments without a caveat). 关键词:分群、人群画像、Segmentation、目标人群、banner、交叉表、占比、persona、targeting、优先级。

person作者: user_82440845hubcommunity

交叉表分群画像 deck

把**交叉表(banner / crosstab)**做成一份能直接给客户讲的 segmentation & targeting deck: 选对分群维度 → 每群一张同题的画像卡 → 排优先级 → 过一遍一致性 QC。

这个 skill 真正值钱的地方不是画 PPT,是最后一关 QC。 客户最容易当场问倒你的三个问题——"这几个百分比加起来怎么是 101%?"、 "你写着 CORE TARGET 为什么排第二?"、"这个群才 108 个人你敢下这个结论?"—— 都由 validate_deck.py 在出片前拦住。

When to Use

触发场景:

  • 用户拿着调研数据(CSV / Excel / SPSS-Persig 导出 / 已有 banner JSON)要"做分群 / 做人群画像 / 定目标人群"
  • 需要回答"该打哪群人""这群人有什么特点""每个群的规模多大"
  • 已有 deck 需要复核一致性(可单独用 validate_deck.py)

不适用:

  • 只有单个总体、没有分组维度的数据分析 → 用普通 topline
  • 需要做统计建模(聚类 / 因子 / 潜类)→ 本 skill 假定分群口径已经定好,只做呈现与优先级
  • 定性深访/座谈会整理

五步工作流

① 解析    parse_banner.py     任何来源 -> 统一 banner.json
② 比选    plan_segments.py    用数据挑分群方案 + 群规模整数化 + 跨国构成反推
③ 取数    extract_persona.py  六模块固定人群卡
④ 出片    build_deck.py       PPTX(封面 / 框架 / 规模 / 人群卡 xN / 优先级)
⑤ QC      validate_deck.py    14 条一致性规则,FAIL 即回炉
          run_pipeline.py      上面五步一键串起来

出片版式(v2,13.33×7.5in 宽屏)

| 页 | 内容 | 关键设计 | |---|---|---| | 1 | 封面 | 深色底 0B1B2E + 底部每群主色色带,后面所有页的颜色都从这里取 | | 2 | How to read a persona card | 六个固定模块的读法,跨群可比 | | 3 | How the segments are defined | 左 THE SPLIT(分群维度)+ 右 SEGMENT SIZE(各群规模条,条色 = 该群主色)+ 小样本警示 | | 4..N+3 | 人群卡 xN | 顶部 tint 头带 + accent 竖条 + 占比 chip deep + 六模块 3×2 卡片 + KEY ACTION | | N+4 | Targeting Priority Summary | 深色双栏:左 SEGMENT PRIORITY RANKING / 右 WHAT WE DO ABOUT IT |

配色只需给 1 个 accent,其余四色自动派生(与 client deck 逐色吻合):

deep = accent × 0.75      # 深色文字、chip、编号底
tint = 白 + accent × 0.25 # 页面顶部头带
head = 白 + accent × 0.20 # 模块头背景
band = 白 + accent × 0.15 # Positioning 条

主色清单写在 assets/theme.json 的 accents,按人群顺序分配;单群可用 segment.accent 或 segment.palette 覆盖。 封面色带、metrics 页规模条、人群卡头带、summary 编号块四处同源,所以视觉上天然一一对应。

环境准备(第一次用必须先做)

pip3 install python-pptx          # 必需:生成 / 读取 PPTX
pip3 install openpyxl             # 可选:仅当输入是 .xlsx 时才需要
python3 scripts/smoke_test.py     # 期望 ALL PASS

没装 python-pptx 时,build_deck.py 会直接退出并提示安装命令; validate_deck.py 会把"deck 读不出来"记成 R00 FAIL(而不是崩溃), 其余不依赖 deck 的规则照常输出——避免 QC 静默失效。

smoke_test.py 的 D 项(打包)依赖本机的 skill-creator 插件,找不到会显示 [SKIP],不影响 A/B/C 的结论。

本机(macOS / WorkBuddy 托管环境)实测可用的确切命令:系统 python3 没装 python-pptx,且不建议往系统环境里装包,一律用托管 venv 的解释器:

PY=/Users/zhaoyijin/.workbuddy/binaries/python/envs/default/bin/python3
"$PY" -m pip install python-pptx openpyxl   # 已装:python-pptx 1.0.2 / openpyxl 3.1.5
"$PY" scripts/smoke_test.py                 # 实测 ALL PASS
"$PY" scripts/run_pipeline.py --config assets/testdata/demo_config.json --out /tmp/seg_out

用系统 python3 直跑会在 build_deck.py 处报缺依赖;validate_deck.py 虽不崩, 但会把"deck 读不出来"记成 R00 FAIL,deck 相关规则全部跳过。

关键原则(必须遵守,否则 deck 会被问倒)

1. 每群一张卡,模块题目必须跨群固定

一张卡片六个模块,所有人群页面的模块标题完全一致,否则无法横向对比:

| 模块 | 回答的问题 | 常用题 | |---|---|---| | WHO THEY ARE | 这群人是谁(人口/肤质/人生阶段) | 画像题 | | CATEGORY IMPORTANCE | 品类在他们生活里为什么重要 | 品类态度题 | | UNMET NEEDS | 现有产品还没解决的痛点 | 需求缺口题 | | USAGE OCCASION | 什么场景下用 | 使用场合题(固定维度)| | ATTITUDE & LIFESTYLE | 价值观与生活方式 | AIO 题 | | NEW OPPORTUNITY | Top 3 机会 + 显著高于其他群的机会 | 新品意愿题 |

2. 数字取整:整数 + 合计必须是 100

  • 对外材料不出现小数百分比(15.2% → 15%),用 ROUND_HALF_UP,别用 Python 默认的银行家舍入(79.5 会变成 79,客户对着 Excel 一算就说你错)。
  • 一组占比必须合计 100%,四舍五入会飘(41.6/14.9/34.7/8.9 → 42/15/35/9 = 101%),用最大余数法修正。脚本已内置 round_to_100()。

3. 显著性只留结论,不露标注

客户层面只写"该人群显著高于其他人群的特征 + 百分比",不要 (sig > B)。 validate_deck.py 的 R07 会扫描并拦下。

4. 角色标签与优先级排名不能互相打架

这是最容易翻车的地方。每群给一个角色标签(它对这个生意的角色)和一个优先级顺位(下一份资源投给谁),两者的隐含顺位必须一致:

| 标签 | 隐含顺位 | 含义 | |---|---|---| | SCALE BASE / VOLUME FRANCHISE / CORE TARGET | #1 | 量最大,守基本盘 | | GROWTH ENGINE | #2 | 最有增长空间,投新品/新claim | | SPECIALIST CONVERTER | #3 | 低卷入但可被单一场景转化 | | HIGH-VALUE NICHE | #4 | 小而精,控投入挖洞察 |

反面教材:写着 CORE TARGET 却在 summary 排 #2 → QC 直接 FAIL(R03)。 如果排名第一的不是最大人群,必须在 summary 页写明理由(R04 会 WARN 提醒)。

5. 小样本必须带 caveat

base < 100(默认阈值,可调)的人群页要显式写"方向性参考、投放前需验证"(R05)。

快速开始

# 一键跑通(用自带脱敏演示数据)
python3 scripts/run_pipeline.py \
    --config assets/testdata/demo_config.json \
    --out /tmp/seg_out --skip-deck   # 去掉 --skip-deck 会同时出 PPTX

# 只想复核已有 deck
python3 scripts/validate_deck.py \
    --persona /tmp/seg_out/persona.json \
    --deck    /tmp/seg_out/deck.pptx \
    --banner  /tmp/seg_out/banner.json

产物:banner.json(规范化数据)、plan.json(方案比选+人群规模)、persona.json(人群卡内容)、deck.pptx、qc.json(QC 明细)。

输入数据怎么给

方式 A — 长表 CSV / Excel(最干净,一行一个"选项 × 人群"):

| table_id | question | scheme | group_code | group_name | base | item | value | sig | |---|---|---|---|---|---|---|---|---| | Q27 | Usage occasion | need_gender | A | Oily-skin Female | 456 | spot first appears | 62.1 | BCD |

方式 B — 已是标准 banner JSON:--format json。 方式 C — Persig 的 tables.pkl:--format persig,多套 banner 并排时用 --persig-schemes "0-3=skintype_gender,4-7=skintype_age" 一次切开。 方式 D — Persig 导出的 Excel(客户最常给的形态):--format persig-xlsx, 用 --persig-groups "Traveler,Domestic" 挑出要用的那套分组。

方式 E — 逐受访者原始明细(raw data):当手头只有问卷原始数据(每行一个受访者、每列一个变量)时, 设置 raw_format: "raw" 并在配置中提供 schemes(分群变量与分组定义)和 codebook(选项文本映射)。 脚本会自动执行交叉分析生成 banner.json,后续步骤与 A-D 完全一致。

{
  "raw": "/path/to/raw_data.xlsx",
  "raw_format": "raw",
  "schemes": [{
    "code": "skintype_gender",
    "vars": [
      {"col": "q34", "label": "Skin type",
       "groups": {"Oily":["Oily skin"], "Non-oily":["Combination","Dry","Sensitive","Normal"]}},
      {"col": "q35", "label": "Gender",
       "groups": {"Female":["Female"], "Male":["Male"]}}
    ]
  }],
  "codebook": "/path/to/codebook.json"
}

raw 路线注意事项:

  • 原始数据不含选项文本,需提供 codebook.json(按题号 → 选项值→文本映射); 可先用 parse_raw.py --input ... --config ... --out banner.json --dump-codebook cb.json 自动生成初始映射再人工校对。
  • modules 中每个模块建议加 "question": "q27." 这样的题号前缀, 用于按题号定位表(比脆弱的 table id 更稳定)。
  • 百分比为未加权原始百分比,与 Persig 加权结果可能存在 <2pp 的正常差异。

四种/五种方式都归一到同一份 banner JSON,后续步骤完全一样。

真实数据一定是脏的(已实测,务必先看这节)

在 236 张真实 Persig 表 + 908 个 Persig Excel 表块上验证,下面四条是常态,脚本已内置处理:

  1. 同一张表里混着三种口径。0.1382(小数)、20.27(百分数)、101(频数)会出现在同一列。 整表一刀切会全表错位——实测整表判断吻合率 26.7%,逐单元格 80.6%。 % 号是唯一可靠信号;没 % 且数值 ≤1 才 ×100。
  2. 选项里混着统计行。Total mentions / Average No. of Mentions / Proportions/Means: Columns Tested / ____ 分隔线 / SF0002990406 表编号, 一个 908 表块的导出里剔掉了 1700 行。
  3. (NET) 汇总行会霸占 Top N。NET 是子项之和,必然最高,四个群的 Functional Benefit(NET) 都在 90% 左右——选它等于没说。默认剔除。
  4. 量表题的 Top N 是刻度。Q38 [SA-Grid] 这类题跑 top_own 会得到 4 43% · Strongly agree 34% · 3 20%。默认剔除,量表题请改用 T2B 汇总行。

另外两个坑:

  • Persig 导出里混着"表头行"(列是标题文字或汇总值,不是分组)。以出现次数最多的 列结构为基准自动剔除(实测 236 张里剔掉 6 张)。
  • 同一维度在不同表块可能落在不同列(age 在 A/B 列、也可能在 C/D 列)。 分组 code 用分组名而不是列字母,否则一个 2 群维度会被拆成 4 个群。

config 的 segments 块:键必须用分组 code

segments 是整份配置里唯一必须手写的部分(其他都能从数据算出来)。字段:

| 字段 | 必填 | 作用 | |---|---|---| | display | 否 | 卡片标题的人群名;不写就用数据里的原始分组名 | | role_label | 是 | 角色标签,见「关键原则 4」,R03 校验的就是它和排名的匹配 | | priority_rank | 是 | 1..N 且不重复,R04 / R12 校验 | | headline | 否 | 卡片顶部一句话结论 | | key_action | 否 | 卡片底部行动建议 | | caveat | 否 | 默认 true;设 false 会关掉小样本警示,进而触发 R05 FAIL | | share | 否 | 覆盖算出来的占比,一般不要动 |

⚠️ 最容易犯的错:拿人群名当键写。

"segments": { "Oily × Female": {"role_label": "..."} }   // ✗ 脚本按 code 查,一个都匹配不上
"segments": { "A": {"display": "Oily × Female", ...} }   // ✓

写错不会崩,但四群的 role_label / priority_rank / headline / key_action 全落空 —— 页面变成"无标签、无排名",R12 报「有 N 个人群没取到 priority_rank」。 看到这句提示,第一件事就是查键名。

分组 code 从哪来:跑完 parse_*.py 后看 banner.json 的 groups[].code(A/B/C/D…), 或一行打印出来:

python3 -c "import json;d=json.load(open('/tmp/seg_out/banner.json'));\
print([(g['code'],g['name']) for g in d['groups']])"

数据要满足什么才能做分群比选

plan_segments.py 会同时评估多个分群方案(比如 need_gender 4 群 vs age 3 群),按下面顺序排序:

  1. 有显著差异的题数(区分力,越多越好)
  2. 显著单元格占比
  3. 最小群样本量是否达标
  4. 组数少者优先(好落地)

经验值:如果两套方案的样本量差不多,就选显著差异题数更多的那套;如果其中一套最小群 < 100,直接把结论降到"方向性"。

一致性问题排查(QC 规则表)

| 规则 | 检查项 | 级别 | |---|---|---| | R01 | 各人群占比合计 = 100 | FAIL | | R02 | 各人群样本量合计 = 总样本 | FAIL | | R03 | 角色标签隐含顺位 = 实际优先级排名 | FAIL | | R04 | 排名 #1 ≠ 最大人群时需说明理由 | WARN | | R05 | base < 阈值的人群页带 caveat 措辞 | FAIL | | R06 | 不出现小数百分比(>1 位小数) | FAIL | | R07 | 不出现 sig / 显著性标注 | FAIL | | R08 | 各人群页模块标题集合一致 | FAIL | | R09 | deck 数字能回溯到 persona / 源表 | WARN | | R10 | 单页出现 ≥2 个互斥最高级 | WARN | | R11 | 角色标签不重复 | FAIL | | R12 | 优先级排名 1..N 连续 != summary 顺序一致 | FAIL | | R13 | 非最大人群却用 largest/biggest | FAIL | | R14 | persona 证据数字 = 源表数字 | FAIL |

交付前自检清单

  • [ ] smoke_test.py 全 PASS(环境正常)
  • [ ] validate_deck.py 0 FAIL;WARN 逐条人工确认
  • [ ] 每张人群卡六个模块都有数,且数字与源表一致
  • [ ] summary 页的排名顺序与顶层建议(投谁、守谁)逻辑自洽
  • [ ] 存在 n<100 的人群时,措辞已降级为"方向性"

文件说明

segmentation-deck/
├── SKILL.md
├── scripts/
│   ├── parse_banner.py      多来源 -> banner.json
│   ├── parse_raw.py         逐受访者原始明细 -> banner.json(raw 路线)
│   ├── plan_segments.py     方案比选 / 整数化 / 跨国构成反推
│   ├── extract_persona.py   六模块人群卡取数
│   ├── build_deck.py        PPTX 生成
│   ├── validate_deck.py     14 条一致性 QC
│   ├── run_pipeline.py      一键串流程
│   ├── make_demo_data.py    生成脱敏演示数据
│   └── smoke_test.py        自检
├── references/
│   ├── module-library.md    六模块取数口径与常见题号映射
│   ├── label-taxonomy.md    角色标签词典(含顺位约定)
│   └── qc-checklist.md      QC 逐条解释与修复动作
└── assets/
    ├── theme.json           配色
    └── testdata/            脱敏演示数据 + 干净/埋错两套配置
        ├── demo_banner.csv           长表演示数据
        ├── demo_config.json         干净配置(smoke_test A / 快速开始)
        └── demo_config_broken.json  埋错配置(smoke_test B)

testdata 是运行依赖,打包时不要排除。 SKILL.md 的「快速开始」和 smoke_test.py 的 A/B 两项都要读这三个文件,缺了会直接报错、自检跑不出来。 若 demo_banner.csv 不慎丢失,可一键重建: python3 scripts/make_demo_data.py --out assets/testdata/demo_banner.csv (两份 config 是手写配置、无法自动生成,丢了只能从仓库恢复。)

已在真实项目上验证

| 项目 | 数据 | 结果 | |---|---|---| | 某日系药妆品牌 · 祛痘膏(8 市场 n=809) | Persig tables.pkl,236 表 × 8 列 | 复现 38/9/42/11 = 100%,合计 n=809;Q27 base 299/73/325/90、Q41 46/50/46/43 与交付版逐项吻合;QC 0 FAIL / 0 WARN | | 某日系药妆品牌 · 祛痘膏 raw data(8 市场 n=809) | 逐受访者明细 xlsx(809×4441 列),raw 路线 | 复现 base 304/74/339/92 = 100%(与 Persig 加权差异 <2pp);codebook 覆盖六模块 98 条选项文本;QC 0 FAIL / 0 WARN;R14 证据数字与源表一致 | | 某日系药妆品牌 · 足部贴(5 市场 n=508) | Persig Excel,908 表块 × 28 列 | 复现 Traveler 52% / Domestic 48%;方案比选 travel_type(207 题显著) > work_status(170) > age(165) > gender(43),与业务判断一致;QC 0 FAIL / 0 WARN |

上面两个项目的 v2 版式均已跑通并渲染检查:祛痘项目 8 页(封面 4 群色带 / 框架 / 规模 / 4 张人群卡 / 优先级)、足部贴 6 页(2 群), 所有页面无文字溢出卡片、无底部裁切,四处主色同源一一对应。

细节规则见 references/;遇到 R0x 报错先查 references/qc-checklist.md。


这套东西做不到什么

脚本替你完成的是计算和一致性检查。下面三件事它给不出答案,只能靠人:

  1. 用哪个维度切分群 —— 性别×肤质、年龄×使用场景、还是购买频次×忠诚度? 同一份数据能切出十几套方案,哪一套能落进生意动作,取决于品类结构、渠道 和品牌所处阶段,不是卡方值能决定的。
  2. 人群叫什么名字 —— "油性肌肤女性"是描述,不是洞察。一个能让人记住、 愿意在内部反复引用的标签,要拿捏得住分寸,得看过足够多同类项目。
  3. 最后一页那句话 —— "所以我们下一步该做什么"。这是客户真正付钱买的东西, 也是脚本唯一不会碰的部分。

如果你正好卡在这三件事上,或者手上是多市场、多波次、需要横向比选的复杂项目:

MREJ — 市场调研分群与人群策略 承接:分群方案设计 / deck 交付 / 批量项目 / 团队方法培训 联系:https://73ea90f4292d4f75a9c6f516a84c98af.app.workbuddy.host (微信 EjayyyyyyZ / yj_zhao95@163.com)

免费版和付费服务的差别不在功能,在上面这三件事。