📊 第12章 Python 实现客户价值分析
📄 一句话概括

客户价值分析的产出不是数,是一张「分堆名单」加每堆的处置办法。 数据只有一张订单流水,9308 行 4 个字段,覆盖 1200 个客户——没有客户表,画像得自己算。 四个项目走到最后一个:这一章的重点是把模型输出翻译成业务动作。

📝 本章和前面几章的关系

第 9 章连库、第 10 章读 Excel、第 11 章带图表模块,这一章做客户分群。 前面三章的产出都是数或图,这一章的产出一张名单——它要直接指导花钱。

一、老板要的三个答案

一家公司有一堆客户,不可能一样对待。老板要三个答案:谁最值钱、谁快走了、钱该花在谁身上。 这三个问题可以合成一句话:把客户分成几堆,每堆用不同的办法对待。 分堆这件事,最笨的办法是按消费额排名,前两成当重要客户。这个办法有两个硬伤。

它看不见「最近还来不来」。去年买了十万、今年一单没下的,照样排在前面。 它也看不见「来了几次」。一次买十万和十次各买一万,价值完全不同。

二、只有流水,没有客户表

数据是一张订单流水表,9308 行、4 个字段,覆盖 1200 个客户。

字段 含义 这次的情况
订单编号 每单一个号 D000001 起
客户编号 谁下的单 C0001 到 C1200
订单日期 下单那一天 2023-01 到 2025-06
订单金额 这一单多少钱 元,几百到几千

没有客户表,没有年龄性别,没有注册渠道。客户的画像得从流水里自己算出来。 这是真实项目最常见的形态:业务系统只记「谁在什么时候花了多少」,剩下的全靠分析。 所以第一步不是建模,是把流水按客户聚一遍——聚完之后才有「客户」这个单位。

三、RFM:三个字母顶一张画像

R 是最近一次消费距今多少天,F 是一共买了几次,M 是一共花了多少钱。 三样合起来,才勉强算一张客户画像:多久没来、来得多不多、花了多少。 算完三个值再用聚类分成几堆,最后给每堆起一个业务上说得通的名字。

命名那一步是人做的,不是算法做的。聚类只告诉你「这几个人像」,不会告诉你「他们是谁」。 这句话听着简单,做错的人不少:直接把 0 号簇叫「重要客户」,其实 0 号可能正好是最差的一堆。

四、四步流程

步骤 做什么 产出
一 抽数、洗净、看分布 一份能算的流水
二 按客户聚出 R、F、M 每客户一行
三 标准化加聚类分堆 每客户一个堆号
四 给每堆起名、给策略 名单加处置办法

四步里第三步最容易出错:三个值的量纲差太远,不标准化,聚类只会看金额。 第 12.5 节会把这件事摊开算一遍:R 的标准差 182,M 的标准差 6750,差三十多倍。

五、项目准备:观察日要写死

要装 pandas、scikit-learn、matplotlib。本机这套都在。

pip install pandas scikit-learn matplotlib

本机 pandas 3.1.0、scikit-learn 1.9.1,够用。 观察日必须写死。R 是「距今多少天」,今天是哪天得固定,否则明天跑出来的数全变。 这次定在 2025-06-30,正好是数据最后一天之后。写成 pd.Timestamp.today() 是个坏习惯。

数据原样落成 订单流水.csv,脏的地方留着:负金额 6 条、客户编号空 4 条、重复 2 条。

六、动手 Demo:项目概述、效果与准备

这一节不建模:把三个问题、数据结构、RFM 三个字母、四步流程交代清楚。 最后把 9308 行流水原样落成 CSV,脏数据也一起留着。

import pandas as pd

df = pd.read_csv("订单流水.csv")
print("形状 %s" % (df.shape,))
print("客户数 %d" % df["客户编号"].nunique())
print("日期 %s 到 %s"
      % (df["订单日期"].min(), df["订单日期"].max()))

OBS = pd.Timestamp("2025-06-30")
print("观察日 %s" % OBS.date())
print("坏数据:负金额 %d,客户空 %d,重复 %d"
      % ((df["订单金额"] < 0).sum(), df["客户编号"].isnull().sum(),
         df.duplicated().sum()))

实跑输出:

--------------------------------------------------------------------
项目概述、效果与准备
--------------------------------------------------------------------

  ① 这个项目要回答什么
  --------------------------------------------------------------------
  一家公司有一堆客户,不可能一样对待。老板要三个答案:
  谁是最值钱的客户、谁快要走了、钱该花在谁身上。
  这三个问题用一句话概括:把客户分成几堆,每堆用不同的办法对待。
  这就是客户价值分析。它的产出不是一个数,是一张「分堆名单」加每堆的处置办法。

  ② 数据长什么样
  --------------------------------------------------------------------
  一张订单流水表,9308 行、4 个字段,覆盖 1200 个客户。

| 字段 | 含义 | 这次的情况 |
|---|---|---|
| 订单编号 | 每单一个号 | D000001 起 |
| 客户编号 | 谁下的单 | C0001 到 C1200 |
| 订单日期 | 下单那一天 | 2023-01-01 到 2025-06 |
| 订单金额 | 这一单多少钱 | 元,几十到几千 |

  注意:这里没有「客户表」,只有流水。客户的画像得从流水里自己算出来。
  这是真实项目最常见的形态:业务系统只记「谁在什么时候花了多少」,剩下的全靠分析。
  ! 数据是造的:四类客户各有各的下单节奏,忠诚客户买得多买得勤,流失客户很久没来。

  ③ RFM:三个字母代替一张画像
  --------------------------------------------------------------------
  R 是最近一次消费距今多少天,F 是一共买了几次,M 是一共花了多少钱。
  三个维度合起来,才勉强算一张客户画像。只看 M,会把「一次买很多但再也不来」的人当宝贝。
  算完三个值之后用聚类分成几堆,再给每堆起个业务上说得通的名字。
  命名那一步是人做的,不是算法做的。聚类只告诉你「这几个人像」,不会告诉你「他们是谁」。

  ④ 四步流程
  --------------------------------------------------------------------

| 步骤 | 做什么 | 产出 |
|---|---|---|
| 一 | 抽数、洗净、看分布 | 一份能算的流水 |
| 二 | 按客户聚出 R、F、M | 每客户一行 |
| 三 | 标准化 + 聚类分堆 | 每客户一个堆号 |
| 四 | 给每堆起名、给策略 | 一张名单加处置办法 |

  四步里第三步最容易出错:三个值的量纲差太远,不标准化,聚类只会看金额。
  第 12.5 节会把这件事摊开算一遍。

  ⑤ 项目准备
  --------------------------------------------------------------------

  [本沙箱已装齐]
  | pip install pandas scikit-learn matplotlib
  numpy 是 pandas 的依赖,会一起装上。

  本机 pandas 3.1.0、scikit-learn 1.9.1。
  观察日要写死:R 是「距今多少天」,今天是哪天必须固定,否则明天跑出来的数就变了。
  这次把观察日定在 2025-06-30,和数据最后一天对齐。

  ⑥ 把流水落成 CSV
  --------------------------------------------------------------------
  原样存成 订单流水.csv,9308 行 4 列,UTF-8 带 BOM。
  脏的地方留在里面:负金额 6 条、客户编号空 4 条、完全重复 2 条。
  ! 不提前洗。下一篇专门讲怎么查、怎么洗。

nunique() 数的是「不同值的个数」,比 len() 少掉重复——数客户必须用它。 观察日写成字符串再转 Timestamp,比直接写 (2025, 6, 30) 好读,也不容易记错顺序。 这一节故意不洗数据。isnull().sum() 和 duplicated().sum() 只是先看一眼,下一篇才动手。

30 秒实验

  1. 把观察日改成 2025-03-31,想想 R 会整体变大还是变小。
  2. 把 nunique() 换成 len(),看那个数差多少,想想差在哪。
  3. 想一想:如果公司还有一张客户表(年龄、城市、注册渠道),第一步该做什么?

常见误区

  1. 只用消费额排名:看不见「最近还来不来」和「来了几次」,会把睡着的客户当宝贝。
  2. 把观察日写成今天:明天跑出来的结果和今天不一样,没人敢拿它做决策。
  3. 以为有客户表:这份数据只有流水,客户画像是从流水里聚出来的。
  4. 直接给簇号贴业务名:0 号簇是什么,得看均值表,不能想当然。
自测三问(点开对答案) 1. 为什么「按消费额排名」不够? —— 它看不见最近是否还来、也看不见来了几次。一次买很多但再也不来的客户,照样排前面。 2. 观察日为什么必须写死? —— R 是距今多少天,基准日一变,全表 R 都变。写死才能复现,别人才敢用。 3. 这一章和前面三个项目最大的不同是什么? —— 产出不是数或图,是一张分堆名单加每堆的处置办法,要直接指导花钱。

问题清楚了。下一篇把 RFM 三个字母和聚类这两件事讲透,尤其是标准化那个坑。

相关笔记