设想一下,部门同事甩给你一份电商订单导出表。表格内容不多,也就几千行,但字段倒是齐全——订单号、下单时间、顾客ID、商品类目、单价、数量、实付金额、所在城市、订单状态,全都列好了。对方只留下一句话:“帮我分析分析,看看最近卖得怎么样。”你打开表格,转了几圈,最直观的结论只有一个:总销售额好像还行。然后呢?没了。这是很多刚开始接触数据分析的人的真实起点,也是我写这篇内容的动机:借一份最简单的电商零售数据集,把一套完整的数据分析流程走一遍。不是给你堆算法,也不是炫图表,而是讲清楚从需求定义、数据清洗到探索分析和结论落地,每一步到底在做什么、为什么这么做、遇到坑怎么绕。
这篇文章适合刚入门数据分析的运营、产品和开发,也适合带新人的团队作为培训素材。看完之后你可以直接拿自己手头的订单表、用户表、流量表套用同样的思路。
1. 先读懂电商零售数据集的结构:别急着写代码
1.1 看一眼字段,先搞清“每行是什么”
拿到数据之后,人总是忍不住想马上开始统计,尤其是看到“销售额”这种字样,手已经想去点SUM了。我建议你先忍一忍,把表结构当回事。一份典型的电商零售订单表,至少包含这几类信息:谁买的(顾客ID)、买了什么(商品名称、类目)、买了多少(数量、单价)、花了多少钱(实付金额)、什么时候买(下单时间)、从哪买(所在城市)、这笔订单现在处于什么状态(订单状态)。
用一份示例数据来说,常见字段和它们能回答的问题如下表:
| 字段 | 类型 | 回答什么问题 | 常见坑 |
|---|---|---|---|
| 订单号 | 字符串/数字 | 订单唯一性、订单量 | 重复、格式不统一 |
| 下单时间 | 时间/字符串 | 趋势、活动效果 | 时区、格式、Excel序列号 |
| 顾客ID | 字符串/数字 | 用户行为、复购 | 游客账号、空值 |
| 商品类目 | 字符串 | 品类结构、爆款 | 类目改名、大小类混杂 |
| 单价 | 数值 | 价格带、客单价 | 是否含运费、含税不清 |
| 数量 | 数值 | 销量规模 | 负数、超过合理值 |
| 实付金额 | 数值 | GMV、利润率 | 含优惠分摊、含退款 |
| 订单状态 | 枚举字符串 | 有效订单口径 | 状态含义不统一 |
还有一件更关键的事:这张表的每一行,到底代表什么?有的导出表一行是一笔订单,有的导出表一行是订单里的一个商品明细(同一订单占多行),也有的导出表一行是一个顾客的汇总。我在实际项目中见过不少分析结论失准,源头就是这里没看清。拿这份数据来说,先确认订单号是否能唯一标识每一行;如果不能,说明是多商品明细表,后面算客单价、复购率时就要先做去重或聚合。
1.2 用“扫数据”代替“开始分析”
确认完“每行是一笔订单”之后,下一步不是马上画图,而是对整张表做一次快速扫描,建立参照系。我习惯用Python的Pandas做这一步,因为代码少、反馈直接:
import pandas as pd df = pd.read_csv("order_data.csv", encoding="utf-8") print(df.shape) # 总行数、总列数 print(df.head(3)) # 前3行,看格式 print(df.info()) # 各列非空数量与类型 print(df.describe(include="all")) print(df["订单状态"].value_counts()) # 状态分布这段代码不是炫技,而是回答几个基础问题:数据一共多少行多少列?时间范围是什么?金额字段有没有空值或异常?订单状态有哪些取值、各自占比多少?把这些记在一张便签纸上,后面不管做趋势还是做分层,心里先有一张“数据集地图”。
我特别提醒一点:describe输出的平均值、最值先不要当真,因为这里是探索,不是结论。比如“实付金额”最大值如果是几万元,而店铺平均客单价只有一百多,那八成是混入了批发订单或异常单,后面清洗时要去查,而不是直接拿来统计。我见过有人拿这种没清洗的数据做客单价对比,最后给运营出一份“高客单价城市分析”,结论完全被两条异常订单带偏了。先扫后析,不是形式主义,是防跑偏的第一道闸。
2. 数据分析流程第一步:把业务问题翻译成数据问题
2.1 数据不回答,问题才回答
每次有人拿一堆数据来问我“帮我分析一下”,我都会反过来先问一句:你想解决什么?这不是抬杠,是因为数据分析的第一步不是工具和技术,而是把业务需求翻译成具体问题。
拿“帮我看看最近卖得怎么样”这句话来说,它太模糊了。到底是想知道:
- 这个月跟上个月比,销售额涨了还是跌了?
- 哪个品类是增长引擎,哪个品类在拖后腿?
- 是买的人变多了,还是单笔买得更贵了?
- 不同城市的消费者表现有没有差异?
这些是四个完全不同的问题,分析路径也不一样。如果你不拆解,直接跑一个“销售额趋势图”,顶多得到一个“似乎还行”的结论,老板听完还是不知道怎么决策。数据分析最怕的就是这种“看起来分析了,实际上没结论”的状态。
2.2 把模糊需求翻译成可执行的数据问题
我在处理数据前有个习惯:把业务问题写在纸面,然后对着数据表翻译,直到每个问题都能对应到“某个字段+某种计算方法+某张结果表”。下面这个翻译表是我常用的形式:
| 原始业务需求 | 可执行的数据问题 | 分析手段 | 预期产出物 |
|---|---|---|---|
| 最近卖得怎么样 | 近30天销售额、订单量的日趋势如何 | 时间序列聚合、趋势图 | 趋势线+涨跌判断 |
| 什么好卖什么难卖 | 各品类销售额、销量占比和环比变化 | 分组聚合、帕累托分析 | 品类结构表 |
| 谁在买 | 不同客单区间、不同地域的下单特征 | 交叉表、用户分层 | 用户画像简表 |
| 复购情况怎么样 | 用户90天内二次购买占比是多少 | 同期群分析简化版 | 复购率表 |
把这些翻译完后,后续的清洗、探索、建模才有具体的检验标准。如果连“分析出来给谁看、要解决什么动作”都没想清楚,再漂亮的图表也只是一张“看起来有用的废纸”。我自己踩过的坑是:前两年接了一份用户行为数据,拿到后立刻做了一堆聚类,结果跑了三天,发现运营真正想要的是“找出最近一个月流失风险最高的用户名单”,聚类结果根本没法用。从那以后,我给自己立了条规矩:先写问题,再写代码;问题没写清,不开IDE。
3. 数据清洗与预处理:真正花时间的环节
3.1 重复值、缺失值、异常值的处理思路
真正做过项目的人会告诉你,一份数据里真正“干净”的很少。这份电商零售数据集也不例外,我拿到手时先做了三件事:查重复、查缺失、查异常。
查重复:订单表最怕两种重复,一种是完全一模一样的行(可能是导出时重复发送),另一种是同一订单号出现了多次。第一种直接用drop_duplicates()删掉;第二种要看业务,如果是同一订单下的多商品明细,那就不能删,只能按订单号去重后再做用户级分析。判断方法很简单:先看df["订单号"].nunique()和df.shape[0]是否一致,不一致再查明细。
df = df.drop_duplicates() df["订单号重复标记"] = df.duplicated(subset=["订单号"], keep=False)查缺失:缺失值不能无脑填0。要看缺失集中在哪一列、为什么缺失。比如顾客ID缺失,可能是游客未登录,这类订单在算复购时就不能计入用户维度;城市缺失,可能是渠道下单,分析地域时直接剔除并单独标记。处理原则是:能根据业务推断的就推断,不能推断的就标记成“未知”,尽量不要让缺失值悄悄影响后面的聚合结果。
查异常:异常值最典型的两种,金额为负(退款单)和数量为0(赠品或异常单)。处理这类数据,我一般不会直接删除,而是新增一个状态列,把“有效订单”和“非有效订单”分开:
df["订单标记"] = "" df.loc[df["实付金额"] < 0, "订单标记"] = "退款单" df.loc[df["数量"] <= 0, "订单标记"] = "异常单" df["是否有效订单"] = df["订单标记"] == ""这样做的好处是,后面分析时既能做“全量GMV口径”,也能做“有效订单口径”,两条口径互不干扰。我见过不少人在第一步就把负金额删掉,结果问老板“退款算不算销售额”时才发现口径搞反了,还得回头重新处理。清洗数据和做饭前洗菜切菜很像,环节不惊艳,但直接影响成菜质量。
3.2 新增字段与口径统一:让数据更好用
清洗完脏数据,下一步是加工字段,让后续分析少写很多重复代码。针对这份零售数据,我认为必加的三个字段是:月份、星期几、是否有效订单。
- 月份:把下单时间转成
YYYY-MM,用于月度趋势对比。 - 星期几:用于发现周中周末的销售规律,很多促销活动都需要看这个维度。
- 件单价:用实付金额除以数量,看不同时段的购买力变化。
参考代码:
df["下单时间"] = pd.to_datetime(df["下单时间"]) df["订单月份"] = df["下单时间"].dt.strftime("%Y-%m") df["星期几"] = df["下单时间"].dt.dayofweek # 0代表周一 df.loc[df["数量"] > 0, "件单价"] = df["实付金额"] / df["数量"]口径统一是另一个容易被忽略的点。同一份数据里,“销售额”可能有三种口径:订单金额、实付金额、有效订单实付金额。如果在分析时各写各的,最后对不上账很正常。我的做法是:每个统计结果都带一列“口径说明”,哪怕只是在列名后缀_有效、_全量,都能避免后期争论。
做完清洗和加工之后,再做一次总量验证:全表实付金额之和等于分月份汇总之和,也等于分品类汇总之和。这个检查看起来蠢,但能挡住九成以上的返工。数据量越大越值得做。
4. 数据探索与可视化:让销售规律自己浮出水面
4.1 单维度观察:先看趋势、结构、分布
清洗完成,现在可以进入探索性分析了。探索分析的目的不是证明某个假设,而是发现值得深挖的规律。我会先做三张图:
- 第一张:日销售额/订单量趋势线,看大盘有没有周期性、有没有突然的尖峰。
- 第二张:各品类销售额占比的柱状图,看收入结构是否过度集中。
- 第三张:实付金额直方图,看客单价的分布形态,如果出现长尾,说明少数高客单订单占了大头。
参考代码:
import matplotlib.pyplot as plt daily = df.groupby(df["下单时间"].dt.date)["实付金额"].sum() daily.plot(figsize=(12, 4), title="每日销售额趋势") plt.show() category = df.groupby("商品类目")["实付金额"].sum().sort_values() category.plot(kind="barh", figsize=(8, 5)) plt.show()看趋势图的时候,如果出现“周末反而下降”,先别急着怀疑数据,要想想业务:这个店铺的主要客户是不是企业用户?如果不清楚,就先备注“待业务确认”,而不是直接写成结论。单维度图的真正价值是帮你建立直觉,同时暴露异常。比如某个日期销售额变成0,很可能是那天数据没导出,后续统计时要排除。
4.2 多维度交叉:找出值得深挖的反常点
单维度看的是全貌,多维度看的是结构变化。我建议你至少做两个交叉分析:
- 月份 × 品类:观察每个月的品类结构变化。有的品类平时占比平稳,一到某个月突然暴涨,背后往往藏着某次活动或某个爆款。
- 城市 × 客单价:观察不同城市的人均购买力。高客单价城市可能是重点运营区,也可能只是某位大客户在“抬价”。
参考代码:
pivot = df.pivot_table(index="订单月份", columns="商品类目", values="实付金额", aggfunc="sum", fill_value=0) pivot.plot(kind="bar", stacked=True, figsize=(10, 5)) plt.show()看透视表时,我会把“绝对值”和“占比”双看:绝对值展示规模,占比展示结构变化。占比提升但绝对值很小的品类,可能是分母下降造成的“声东击西”。这种坑我在实际中见过好几次。比如某月总销售额下滑,某个类目占比从8%涨到25%,看起来像“逆势上涨”,实际只是因为其他类目降得更狠,这个类目的绝对值并没有增长。所以,交叉分析里一定要保留一列绝对值,不要只盯着比例看。
5. 量化分析与用户分层:从“发生了什么”到“该怎么办”
5.1 RFM用户分层:把用户变成可执行的清单
探索分析回答“发生了什么”,接下来要回答“可以做什么”。对于电商零售数据,最容易落地且不依赖复杂算法的分析就是RFM用户分层。R表示最近一次购买时间(Recency),F表示购买频次(Frequency),M表示累计金额(Monetary)。思路很简单:用这三个维度给每个顾客打分,然后把人分成若干群体,每个群体做不同运营动作。
具体做法,我按三步走:先按顾客ID聚合,得到每个用户的R、F、M;再用四分位给每个维度打分;最后按分数段把用户归为几类。
| 用户层 | R(最近购买) | F(频次) | M(金额) | 运营建议 |
|---|---|---|---|---|
| 高价值活跃用户 | 近30天内 | 高频 | 高金额 | VIP维护、专属优惠 |
| 潜力用户 | 近90天内 | 中频 | 中金额 | 提升频次、组合购买 |
| 沉睡用户 | 90天前 | 低频 | 曾高金额 | 召回短信、发放激励 |
| 新客 | 首次购买 | 低频 | 低金额 | 产品教育、培养复购 |
操作时,我不建议直接套固定阈值,因为不同店铺的消费分布完全不同。比如卖家具的店铺,五年买一次很正常,如果套用“30天内购买”作为高价值活跃,整个用户群可能全是沉睡用户。所以我习惯先看R、F、M的分布,再用分位数切分,让数据落在哪个区间就对应哪个分数:
rfm = df.groupby("顾客ID").agg( R=("下单时间", "max"), F=("订单号", "count"), M=("实付金额", "sum"), ).reset_index() reference_date = pd.Timestamp("2024-06-30") # 实际使用可用 df["下单时间"].max() rfm["R天数"] = (reference_date - pd.to_datetime(rfm["R"])).dt.days # R天数越小越好,所以最好的区间给4分 rfm["R分"] = pd.qcut(rfm["R天数"], 4, labels=[4, 3, 2, 1], duplicates="drop") rfm["F分"] = pd.qcut(rfm["F"], 4, labels=[1, 2, 3, 4], duplicates="drop") rfm["M分"] = pd.qcut(rfm["M"], 4, labels=[1, 2, 3, 4], duplicates="drop")注意:如果同一订单时间或金额的值过多,pd.qcut可能因为分箱边界重复而报错,这时候可以退一步,用quantile()手动算阈值再切分。RFM真正的价值不是模型多高级,而是把几千个用户压缩成五六个可操作的分桶。运营拿到名单就能直接发券,不用再问“所以我该干嘛”。
5.2 一个不用算法的销量预测方法:先跟基准对齐
很多初学者一提到预测,就想用机器学习,把数据丢进去训练一个模型,然后拿着误差到处说。我的建议是:至少在建模之前,先做一版简单的基准预测。对这份电商零售数据来说,最简单的基准就是用“过去4周同星期几的平均值”预测下一周。
为什么用星期几?因为电商零售数据的周内波动往往很明显,工作日和周末的销售可能差一倍以上。用“最近4周的周一平均值”预测下周一,比用“最近30天平均值”预测下周一要靠谱得多。基准预测的作用,是给复杂模型划定一条及格线:如果复杂模型连基准都跑不赢,那就没有上线的必要。
操作步骤:
- 按周和星期几聚合历史销售额。
- 算每个星期几在过去4周的平均值。
- 与最新一期真实值对比,计算相对误差。
- 如果误差能稳定在10%以内,这个基准已经够日常排期用了。
我试过不少项目后发现一个反直觉现象:对中小型店铺来说,这种朴素基准预测往往比复杂模型更实用。因为数据量少、变量波动大,复杂模型容易过拟合。所以做预测前,先别急着上机器学习,先跟基准对齐,很多时候你会发现“最朴素的方法已经够用了”。
6. 常见问题与排查技巧:数据分析师的避坑实录
6.1 时间字段“看不懂”:字符串、时区、Excel序列号
电商数据集最常见的时间坑有三个:时间存成字符串,且格式混用;时间带时区但没说明;Excel导出的时间被读成序列号。比如"2024/6/30 15:22"和"2024-06-30 15:22:00"混在一起,直接用字符串排序就会出错。
解决办法是先把所有时间统一转成标准格式:
df["下单时间"] = pd.to_datetime(df["下单时间"], errors="coerce")errors="coerce"很有用:遇到无法解析的值会变成空值,而不是直接报错中断,方便你事后排查。转换完成后,再看一眼info(),确认该列类型是datetime64。如果有多时区数据,先统一成同一时区再分析,跨时区订单不要直接按字符串比较时间。
6.2 销售额算来算去对不上:命中了“口径陷阱”
对不上账在数据分析里很常见,原因通常不是算错,而是不同人用了不同的“销售额”定义。有的统计把含运费金额算进去了,有的没算;有的把退款单直接删了,有的保留;有的把未支付订单也算作销售。排查口诀是:先定位字段,再看筛选条件,最后核对主键。
建议把口径维护成一张清单,写清楚这个指标里包含哪些订单状态、是否包含退款、是否包含运费。分析结论后面加一段“本数据口径说明”,能省掉很多扯皮时间。我在团队里带人的时候,会要求所有人在周报里都带上这一行,看起来多了一个字,实际上把大量跨岗位沟通成本砍掉了。
6.3 数据量小,结论到底可不可信
只有几千行订单时,很多统计结论看起来“很明显”,但实际经不起推敲。这时候我的处理方式是:看波动范围,不要看单一数值。比如近30天客单价是120元,上个月是115元,看起来很稳,但如果你去算每日客单价的波动,标准差可能超过30%,那这个5元的差异就毫无统计意义。
小样本分析的结论尽量以“趋势方向”为主,而不是给精确值。可以说“某品类近两个月销量在持续下滑”,而不是“某品类销量下降了17.3%”。同时,对任何违反常识的结论做一次合理性检查。比如分析结果说“某城市的客单价远超其他城市,但订单量极少”,那很可能只是几笔大额订单造成的假象,需要剔除后再验证。
7. 结论如何落地:别让分析死在最后一公里
7.1 按“决策”组织结论,而不是按“表”组织
分析工作真正见功力的地方,是最后把结论讲清楚。很多同学前面明明做得挺好,一到汇报就把Excel表格密密麻麻贴满一屏,老板看了血压升高。结论应该按“决策点”来组织,而不是按数据表来组织。
我常用的模板是三列:发现了什么、影响什么、建议做什么。
| 发现 | 对业务的影响 | 建议动作 |
|---|---|---|
| 近4周销售额环比下滑12%,主要来自某个品类 | 该品类可能进入需求低谷,也可能是价格竞争力下降 | 跟进该品类价格与库存,不要全店促销 |
| 高价值用户的复购率环比下滑5% | 核心存量用户活跃度在下降 | 圈选RFM高价值用户,定向发放召回权益 |
| 某地区贡献了整体销售额的35%且增速最快 | 可复制该地区的打法 | 将该地区设为下季度重点运营区域 |
每页只讲一件核心发现,细节放到附录。如果老板只问一个问题:“你觉得我现在该做什么?”你要能指着建议动作那一列直接回答出来。
7.2 图表要服务阅读者:一张图只讲一个结论
可视化表达有一个简单原则:一张图只讲一句话。“销售额下跌”用一张折线图加一根参考线;“品类占比过高”用一张水平柱状图,把前三名排好序;不要试图在一张图里塞进所有信息,那只会让读者找不到重点。
图表的配色、坐标轴标签这些细节,也会影响信息传达。坐标轴一定要写清楚单位和时间范围,饼图不要超过5个切片,折线图不要堆超过3条线。我在交付分析报告前,会做一次“地铁测试”:想象对方在地铁上只用30秒扫一眼你的图表,能不能看懂你想说什么。看不懂,就再删再改。
最后说点个人体会。用一份简单的电商零售数据集练一遍完整的数据分析流程,收获的绝不只是几个函数用法。你会发现真正的难点不是清洗、建模那些技术环节,而是每一步都要有业务判断:这行该不该删?这个字段的口径是什么?这个结论能不能指导下一步动作?建议你把整条流程亲手做一遍,从写问题清单开始,到用RFM分用户,再到出三页汇报结论。做完之后,换一份完全不同的数据集,再问自己一遍:如果只剩三分钟跟老板说话,我会讲哪三句?这个能力,就是从这种小项目里一点点磨出来的。