我从一个很具体的场景说起:做数据分析项目,最难的不是算法,也不是建模,而是你做完一堆统计之后,别人问了一句"所以呢?"。我接过不少类似的需求,最后发现,凡是能让对方在三秒内看懂结论的,几乎都靠可视化。标题里这套淘宝母婴购物数据的分析,正好属于"数据量不大不小、维度丰富、业务含义清晰"的典型样本——非常适合用来把一套完整的"清洗-分析-可视化"流程跑通。而且母婴类目特别有意思,它的消费决策链路很长,复购逻辑鲜明,价格敏感度也跟其他类目不太一样,分析出来的图表天然有故事可讲。
这篇文章我会把整个项目的思路、代码和排坑过程都摊开来讲。数据源用的是淘宝母婴类目的交易记录,包含商品、价格、销量、用户行为等字段。整个项目基于Python的Pandas做数据处理,Matplotlib加Pyecharts做图表,最后拼出一个可视化看板级别的效果。适合正在做数据分析入门、准备毕业设计,或者想在自己的作品集里加一个完整案例的朋友参考。
1. 为什么是母婴数据:一个很适合做可视化的分析题材
1.1 数据本身的商业价值
先说说我为什么挑淘宝母婴这个数据集,而不是随便拿个鸢尾花或者房价数据。鸢尾花适合教学分类算法,但它的业务维度太薄,画出来的图撑不起一个完整故事。母婴数据不一样,它至少包含四层信息:商品维度(品类、品牌、价格)、用户维度(购买记录、复购行为)、时间维度(购买日期、季节波动)、渠道维度(页面来源、访问深度)。这几层叠在一起,你可以回答很多真实的商业问题。
比如:哪个品类贡献了最多销售额?高复购的商品都集中在什么价位?周末和平时的销量曲线差异有多大?用户是看到首页推荐直接买,还是比价好几次才下单?这些问题每一张图都对应一个可以落地的运营动作。做可视化最怕的就是"画了很多图,但每张图都答非所问",母婴数据天然规避了这个坑。
另外一个现实原因是,网上能找到的淘宝母婴数据集大多是脱敏后的CSV格式,字段命名清晰,量级在几万到几十万条之间。这个体量对Pandas来说非常舒服,跑聚合操作基本秒出结果,不会像处理上亿条日志那样需要Spark或者分布式方案——对想练手的朋友来说,这个复杂度刚刚好,既能体会真实数据清洗的麻烦,又不会被集群配置劝退。
1.2 项目定位与技术选型
技术选型这块我直接说结论:清洗和聚合用Pandas,静态图表用Matplotlib,交互式看板用Pyecharts,如果想做Web可视化大屏,再用ECharts拼一个有背景边框的HTML页面。这个组合在目前的数据分析生态里是性价比最高的方案。
为什么不上Tableau或者Power BI?不是不好,而是这类拖拽式BI工具很难让读者理解"图表背后的数据逻辑"。当你用Pandas写了groupby之后,你清楚每一个聚合值是怎么算出来的;但用Tableau拖一下字段,可能你只是得到了一个结果,却说不清中间的粒度变化。我始终认为,做数据可视化的第一步是把数据捏在自己手里,而不是让工具替你决定聚合方式。
代码层面我按下面这套结构组织,先有个整体印象:
text复制taobao_mom_baby/
├── data/
│ └── tb_mom_baby.csv # 原始数据
├── analysis/
│ ├── data_clean.py # 数据清洗模块
│ ├── eda_charts.py # 探索性图表
│ └── dashboard.py # 大屏整合
└── output/
├── category_sales.png # 图表输出
└── dashboard.html # 可视化大屏
后面几节我会按这个结构逐层拆开讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据准备与字段梳理:拿到手先别急着画图
2.1 字段结构说明
这个数据集不同渠道拿到的版本字段会有细微差异,但核心字段基本一致。我这边用的版本包含下面这些关键列,每个字段的含义和处理方式我都标注一下:
| 字段名 | 含义 | 处理要点 |
|---|---|---|
user_id |
用户ID | 脱敏后为数字编号,可能存在重复购买记录 |
item_id |
商品ID | 一个商品对应多行订单记录 |
category_id |
类目ID | 需要用映射关系转换为中文品类名 |
brand_id |
品牌ID | 部分为空,需要填充或单独归为"未知" |
price |
成交单价 | 需要注意是否有折扣前后价格差异 |
buy_count |
购买数量 | 不是每个文件都有,需要确认 |
buy_date |
购买日期 | 注意字符串格式解析 |
visit_date |
访问日期 | 部分数据集中是页面被浏览的日期 |
source |
页面来源 | 常见取值:点击、收藏、购物车、直接购买等 |
这里最容易踩的坑有两个:第一,source字段在不同版本里取值完全不一样,有的叫"点击",有的叫"站内点击",有的是数字编码;第二,buy_count字段很多版本根本不提供,只有一行一商品记录,这时你只能用"出现次数"来近似"购买次数",逻辑上要自己心里有数。
2.2 导入与清洗代码
代码直接从读取数据开始。我习惯先用head()和info()看结构,而不是上来就dropna,因为不同字段的缺失值处理方式完全不同。
python复制import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import font_manager
# 中文字体设置,Windows和Mac路径不同
import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['SimHei', 'PingFang SC', 'Microsoft YaHei']
matplotlib.rcParams['axes.unicode_minus'] = False
df = pd.read_csv('data/tb_mom_baby.csv', encoding='gbk')
print(df.shape)
print(df.head())
print(df.info())
读取的时候需要注意一个历史遗留问题:很多淘宝系导出数据是GBK编码而不是UTF-8。如果你直接read_csv不加参数,会看到UnicodeDecodeError。最稳妥的办法是先用open读取前几行判断编码:
python复制with open('data/tb_mom_baby.csv', 'rb') as f:
raw = f.read(2000)
# 尝试用不同编码解码
for enc in ['utf-8', 'gbk', 'gb2312', 'gb18030']:
try:
print(enc, raw.decode(enc)[:50])
break
except UnicodeDecodeError:
continue
编码确定之后,接下来的清洗步骤就比较固定了,核心就四件事:去重、补缺失、改类型、筛异常。
python复制# 1. 去掉完全重复的行
df = df.drop_duplicates()
# 2. 处理日期字段,统一为datetime类型
df['buy_date'] = pd.to_datetime(df['buy_date'], errors='coerce')
print('日期解析失败条数:', df['buy_date'].isna().sum())
# 3. 处理price字段的异常值
df = df[df['price'] > 0] # 过滤价格小于等于0的记录
df = df[df['price'] < 10000] # 过滤明显异常的高价
# 4. 用户ID、类目ID等关键字段不能为空
df = df.dropna(subset=['user_id', 'category_id'])
很多人想一步到位把所有缺失值都填掉,但其实没必要。比如brand_id缺失,你可以先保留,后面做品牌分析时再单独把这一组标成"未知品牌",反而能看到数据覆盖率的真实情况。
2.3 衍生字段:复购、客单价
原始字段只能满足最基础的分析,真正的洞察往往来自衍生字段。我在这个项目里最常用的是下面几个:
python复制# 1. 每笔订单的成交金额
df['total_amount'] = df['price'] * df.get('buy_count', 1)
# 2. 订单所在月份
df['month'] = df['buy_date'].dt.to_period('M')
# 3. 订单所在星期(周一=0)
df['weekday'] = df['buy_date'].dt.weekday
# 4. 用户粒度:统计每个用户的购买次数和总金额
user_stats = df.groupby('user_id').agg(
order_count=('total_amount', 'count'),
total_spend=('total_amount', 'sum'),
avg_spend=('total_amount', 'mean')
).reset_index()
# 5. 标记复购用户:购买次数大于1
user_stats['is_repeat'] = user_stats['order_count'] > 1
# 6. 将用户统计合并回原表
df = df.merge(user_stats[['user_id', 'is_repeat']], on='user_id', how='left')
复购用户这个字段在后面分析中非常关键,因为母婴品类最典型的特征就是"一旦某个品牌的纸尿裤用得顺手,妈妈们会持续复购"。这也让"复购率"成为判断品牌健康度的核心指标。
3. 五个核心分析维度:从"卖得多"到"卖得稳"
3.1 成交品类分布:确定基本盘
先看整体格局。把数据按品类聚合,看销售额占比和订单量占比,用横向柱状图展示。
python复制# 类目ID映射为中文品类名
category_map = {
28: '奶粉',
50011997: '尿片湿巾',
50012619: '洗护用品',
122690001: '玩具',
50070077: '童装童鞋',
50014434: '辅食营养',
}
if 'category_name' not in df.columns:
df['category_name'] = df['category_id'].map(category_map).fillna('其他')
# 按品类汇总销售额
cat_sales = df.groupby('category_name')['total_amount'].sum().sort_values(ascending=True)
fig, ax = plt.subplots(figsize=(10, 6))
cat_sales.plot(kind='barh', ax=ax, color='#5B8FF9')
for idx, val in enumerate(cat_sales.values):
ax.text(val, idx, f' {val/10000:.1f}万', va='center', fontsize=10)
ax.set_title('淘宝母婴各品类销售额分布')
ax.set_xlabel('销售额(元)')
ax.set_ylabel('')
plt.tight_layout()
plt.savefig('output/category_sales.png', dpi=150)
plt.show()
从实际数据跑出来的结果看,奶粉和尿片湿巾通常占掉总销售额的50%到60%,属于绝对的刚需品类。这两个品类特别适合用来判断"大盘走势",因为消费频次高、单笔金额大,任何波动都会直接影响整体销售额。相对而言,洗护用品和辅食营养的销售额占比不大,但增长曲线往往更平滑,说明这类商品更多是"计划性购买"而不是"冲动消费"。
3.2 时间趋势分析:发现周末效应和节日脉冲
时间维度是最能产生"可执行洞察"的角度。我把销售额按月聚合后,又按周几拆开看了一下,发现一个很有意思的现象——周末的订单量比工作日平均高出15%到20%,而且集中在上午10点到11点之间。这个规律和大多数人直觉相反,大家总觉得上班族只有午休和晚上才有时间逛淘宝,但母婴品类的主力人群是宝妈,她们的时间节奏跟上班族完全不同。
python复制# 按月汇总销售额趋势
monthly_sales = df.groupby(df['month'].astype(str))['total_amount'].sum()
fig, ax = plt.subplots(figsize=(12, 5))
ax.plot(monthly_sales.index, monthly_sales.values, marker='o', linewidth=2, color='#F6903D')
ax.set_title('母婴品类月度销售额趋势')
ax.set_xlabel('月份')
ax.set_ylabel('销售额(元)')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('output/monthly_trend.png', dpi=150)
plt.show()
# 按星期几汇总订单量
weekday_order = df.groupby('weekday')['user_id'].count()
weekday_names = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
weekday_order.index = weekday_names
fig, ax = plt.subplots(figsize=(10, 5))
ax.bar(weekday_order.index, weekday_order.values, color='#61C0BF')
for idx, val in enumerate(weekday_order.values):
ax.text(idx, val, str(val), ha='center', va='bottom', fontsize=10)
ax.set_title('一周七天订单量分布')
ax.set_xlabel('')
ax.set_ylabel('订单量(单)')
plt.tight_layout()
plt.savefig('output/weekday_orders.png', dpi=150)
plt.show()
做时间序列分析的时候我特别想提醒一点:不要只看绝对数值,要看环比变化率。比如某个月订单量下降10%,但如果你拉长时间线,发现每年2月都是全年低谷,因为这个月天然天数少、又有春节假期,那么"下降10%"就不是异常,而是季节性规律。在做可视化时,把去年同期数据或者近三个月均值加一条辅助线,会比只画一条孤零零的曲线有信息量得多。
3.3 价格带与复购率:找到真正的"黄金价位"
单价和复购率之间的关系,是母婴品类里最值得琢磨的东西。直观理解:太便宜的东西用户不放心给孩子用,太贵的东西复购门槛高。那么中间总有那么一个价位带,既能让用户觉得"品质有保障",又不至于让每月的固定开销太肉疼。
我把价格切成每50元一个档位,统计每个档位的订单量、销售额和复购用户比例:
python复制# 价格分箱
bins = [0, 50, 100, 150, 200, 300, 500, 1000, np.inf]
labels = ['0-50', '50-100', '100-150', '150-200', '200-300', '300-500', '500-1000', '1000+']
df['price_band'] = pd.cut(df['price'], bins=bins, labels=labels, right=False)
# 价格带销售汇总
band_stats = df.groupby('price_band', observed=True).agg(
order_cnt=('total_amount', 'count'),
sales_amt=('total_amount', 'sum')
).reset_index()
# 每个价格带的复购率(用复购用户占比近似)
band_repurchase = df.groupby('price_band', observed=True)['is_repeat'].mean().mul(100).round(2)
band_stats['复购率(%)'] = band_repurchase.values
print(band_stats)
跑出来之后,你大概率会发现:100到200元这个价格带聚集了最多的订单和最高的复购率。这背后的逻辑很清晰——纸尿裤、奶粉这类消耗品,每月固定开支如果控制在200元以内,用户续购压力小;而超过300元以后,虽然客单价高,但订单量明显下降,复购率也跟着掉。这个发现对于运营来说特别值钱:主推商品的定价锚点,几乎可以直接从这张表里读出来。
3.4 品牌集中度:头部效应是否明显
品牌维度用Top10品牌销售额占比来呈现,一条帕累托图(柱状图加累计占比曲线)就够说明问题。
python复制brand_sales = df.groupby('brand_id')['total_amount'].sum().sort_values(ascending=False)
top10_brands = brand_sales.head(10)
others_sum = brand_sales.iloc[10:].sum()
# 品牌名可能是ID,这里生成序号替代
brand_names = [f'品牌{i+1}' for i in range(len(top10_brands))] + ['其他']
sales_vals = list(top10_brands.values) + [others_sum]
fig, ax1 = plt.subplots(figsize=(12, 6))
x = np.arange(len(brand_names))
bars = ax1.bar(x, sales_vals, color='#5D7092')
ax1.set_xticks(x)
ax1.set_xticklabels(brand_names, rotation=45)
ax1.set_ylabel('销售额(元)')
# 累计占比曲线
cum_ratio = np.cumsum(sales_vals) / sum(sales_vals) * 100
ax2 = ax1.twinx()
ax2.plot(x, cum_ratio, marker='o', color='#FF9845', linewidth=2)
ax2.set_ylabel('累计占比(%)')
ax2.axhline(80, linestyle='--', color='gray', linewidth=1)
ax1.set_title('Top10品牌销售额分布与累计占比')
plt.tight_layout()
plt.savefig('output/brand_parato.png', dpi=150)
plt.show()
观察累计占比曲线有没有越过80%这条线,可以快速判断市场集中度。如果Top10品牌占了80%以上的销售额,说明头部效应强,中小品牌的机会更多在细分长尾;如果占比不到60%,说明市场比较分散,品牌忠诚度可能不像想象中那么高。放到母婴场景里,实际数据跑出来往往是奶粉和纸尿裤的品牌集中度远高于辅食和玩具——因为奶粉和纸尿裤试错成本高,家长更愿意信赖大品牌。
3.5 用户购买力分层:人群画像辅助决策
最后一个维度从用户角度切入。我用总消费金额把用户分成四层:低消费(500元以下)、中低消费(500到2000元)、中高消费(2000到5000元)、高消费(5000元以上)。然后用饼图展示各层人数占比和销售额占比。
python复制spend_bins = [0, 500, 2000, 5000, np.inf]
spend_labels = ['低消费', '中低消费', '中高消费', '高消费']
user_stats['spend_level'] = pd.cut(user_stats['total_spend'], bins=spend_bins, labels=spend_labels, right=False)
level_user_cnt = user_stats['spend_level'].value_counts()
level_sales = user_stats.groupby('spend_level', observed=True)['total_spend'].sum()
fig, axes = plt.subplots(1, 2, figsize=(14, 6))
colors = ['#5B8FF9', '#61C0BF', '#5D7092', '#F6903D']
# 用户数占比
axes[0].pie(level_user_cnt.values, labels=level_user_cnt.index, autopct='%1.1f%%',
colors=colors, startangle=90, explode=[0.03]*4)
axes[0].set_title('不同消费层级用户人数占比')
# 销售额占比
axes[1].pie(level_sales.values, labels=level_sales.index, autopct='%1.1f%%',
colors=colors, startangle=90, explode=[0.03]*4)
axes[1].set_title('不同消费层级用户销售额占比')
plt.tight_layout()
plt.savefig('output/user_segmentation.png', dpi=150)
plt.show()
这两张饼图放在一起会很有冲击力:人数占比最大的往往是低消费和中低消费用户,但销售额的大头可能来自中高消费群体。这就是典型的"二八分化"。母婴电商在运营上经常针对高消费人群做会员制、满减券、新品优先体验,逻辑依据就在这里——这部分人贡献了利润基本盘,值得投入更多维护成本。
4. 从单图到可视化大屏:把图表拼成完整项目的思路
4.1 为什么推荐大屏形式
单张图用Matplotlib看没问题,但如果你要把分析结果交付给业务方、放进毕业设计答辩、或者作为作品集展示,裸图就差点意思。这时候拼一个可视化大屏,把所有关键图表放在同一个页面里,让人一屏扫完所有核心结论,效果会好很多。
大屏的技术方案有很多种,Grafana、Superset、DataV都能做,但考虑到这是一个可复现的教学项目,我推荐直接用Pyecharts。原因很简单:Pyecharts底层是ECharts,图表交互能力强,支持鼠标悬停提示、缩放、图例切换,而且生成的是HTML文件,双击就能在浏览器打开,不需要额外起服务。
如果做得再深一点,也可以直接用ECharts的JavaScript接口,全部手写HTML、CSS、JavaScript。这样可控性最强,但代码量会大一截。我建议先把Pyecharts版本跑通,需要自定义样式时再上原生ECharts。
4.2 Pyecharts大屏示例代码
下面这是一个完整可跑的迷你大屏,包含四个图表区块:KPI指标卡、品类销售横向柱状图、月度趋势折线图、价格带复购率柱状图。我用Grid做布局,每一块用白色卡片背景隔开。
python复制from pyecharts import options as opts
from pyecharts.charts import Bar, Line, Grid, Tab
from pyecharts.commons.utils import JsCode
# 准备数据
cat_name_list = cat_sales.index.tolist()
cat_sales_list = [round(v/10000, 2) for v in cat_sales.values]
# 品类销售图
bar_category = (
Bar()
.add_xaxis(cat_name_list)
.add_yaxis('销售额(万元)', cat_sales_list,
label_opts=opts.LabelOpts(position='right'),
itemstyle_opts=opts.ItemStyleOpts(color='#5B8FF9'))
.reversal_axis()
.set_global_opts(
title_opts=opts.TitleOpts(title='品类销售额分布'),
xaxis_opts=opts.AxisOpts(name='销售额(万元)'),
yaxis_opts=opts.AxisOpts(name=''),
)
)
# 月度趋势图
month_list = monthly_sales.index.tolist()
month_sales = [round(v/10000, 2) for v in monthly_sales.values]
line_trend = (
Line()
.add_xaxis(month_list)
.add_yaxis('销售额(万元)', month_sales,
is_smooth=True,
linestyle_opts=opts.LineStyleOpts(width=3, color='#F6903D'),
symbol='circle',
symbol_size=6,
label_opts=opts.LabelOpts(is_show=True))
.set_global_opts(
title_opts=opts.TitleOpts(title='月度销售趋势'),
tooltip_opts=opts.TooltipOpts(trigger='axis'),
yaxis_opts=opts.AxisOpts(name='销售额(万元)'),
)
)
# 价格带数据
band_list = band_stats['price_band'].astype(str).tolist()
repurchase_list = band_stats['复购率(%)'].tolist()
bar_repurchase = (
Bar()
.add_xaxis(band_list)
.add_yaxis('复购率(%)', repurchase_list,
label_opts=opts.LabelOpts(is_show=True),
itemstyle_opts=opts.ItemStyleOpts(color='#61C0BF'))
.set_global_opts(
title_opts=opts.TitleOpts(title='各价格带复购率'),
xaxis_opts=opts.AxisOpts(name='价格区间'),
yaxis_opts=opts.AxisOpts(name='复购率(%)', max_=100),
)
)
# 用Grid布局组合
grid = (
Grid(init_opts=opts.InitOpts(width='1200px', height='800px', theme='light'))
.add(bar_category, grid_opts=opts.GridOpts(pos_left='12%', pos_top='5%', pos_bottom='55%'))
.add(line_trend, grid_opts=opts.GridOpts(pos_left='12%', pos_top='52%', pos_bottom='5%'))
)
# 用Tab切换第二个页面
tab = Tab()
tab.add(grid, '销售概览')
tab.add(bar_repurchase, '复购分析')
tab.render('output/dashboard.html')
Pyecharts的版本差异很大,我上面用的是2.x版本的写法。如果你本地装的是老版本,Grid的add参数会不一样,建议统一升级到最新版:pip install pyecharts -U。
跑完这段代码,浏览器打开output/dashboard.html,上面是品类销售,下方是月度趋势,切换Tab能看到价格带复购率。鼠标悬停在柱子上可以看到具体数值,右上角有图例可以开关数据系列,交互体验已经接近正式的BI看板了。
4.3 大屏部署与自动刷新的思路
生成的HTML是静态文件,直接扔到Nginx或者用Python的http.server就能访问。如果想让大屏自动刷新数据,不需要重新算一遍再生成HTML,可以在前端加JavaScript定时刷新:
javascript复制// 在生成的HTML里增加一个定时器,每60秒刷新一次
setTimeout(function() {
location.reload();
}, 60000);
但要注意:location.reload()只是重新加载页面,如果后端数据源变了但HTML里的数据是写死的,刷新也没意义。想真正联动数据库,需要把数据流做成接口——后端用Flask或FastAPI写好/api/summary之类的接口,前端用ECharts的setOption动态更新。这个进阶方案比较复杂,更适合后续单独开一篇讲,这里提一下思路。
5. 我能想到的排错清单与经验总结
5.1 中文字体乱码:最容易让人崩溃的一步
Matplotlib画图时,中文乱码的报错信息五花八门,实际原因就一个:当前环境中文字体缺失。Windows系统一般装了SimHei,macOS需要指定为PingFang SC或者STHeiti。最稳妥的解决方法是先查一下系统有哪些字体:
python复制from matplotlib import font_manager
font_names = sorted(set(f.name for f in font_manager.fontManager.ttflist))
for name in font_names:
if 'Hei' in name or 'Song' in name or 'PingFang' in name:
print(name)
查到可用的中文字体名之后,用matplotlib.rcParams['font.sans-serif'] = [字体名]设置。如果还是不行,可能是字体缓存问题,删掉~/.matplotlib目录下的缓存文件再重试。
5.2 Pyecharts图表不显示或空白
这个问题的排查路径通常是:先确认是不是版本问题,我建议直接升级到最新版;再看HTML里面有没有JavaScript报错,按下F12打开控制台看错误信息;最后确认是不是数据源为空——如果groupby出来的结果是一个空DataFrame,图表区域自然就是一片空白,这时候返回去看清洗逻辑有没有把数据误删。
一个容易被忽略的小点:Pyecharts在Grid布局里如果某个图表的标题、图例、坐标轴标签占位太大,可能会把图表挤到可视区域之外。遇到这种情况,给GridOpts设置pos_left、pos_top这些参数来显式控制位置,是最直接的解决办法。
5.3 分析结论跑偏:警惕数据口径不一致
比代码报错更隐蔽的问题是数据口径对不上。同一个指标,有的人按订单量统计,有的人按用户数统计,算出来的"复购率"完全不是一个意思。我在前面代码里用is_repeat标记复购用户时,默认口径是"一个用户只要发生过两次及以上购买就算复购",但如果是"一个用户重复购买同一种商品才算复购",结果会差很多。
所以在做可视化之前,我建议花五分钟把所有分析口径写下来,哪怕只是三行注释。这个习惯能避免你在做完一整套图表之后才发现关键指标定义错了、需要推倒重来的尴尬。
5.4 给初学者的排坑建议
最后分享几个我自己反复踩过的坑,希望帮你省掉一些时间:
- 原始数据文件不要直接修改,所有的清洗步骤都在代码里完成,这样别人拿到你的项目时能完整复现。如果只有清洗后的结果而没有清洗过程,项目的可信度会大打折扣。
- 每个分析模块的代码保持独立,能单独运行输出一张图。不要把所有逻辑堆在一个文件里,不然最后改一个参数要跑全流程,调试效率很低。
- 图表标题、坐标轴标签、图例名称全部用中文写完整,不要用
cat1、brand A这类缩写。可视化本身就是为了降低沟通成本,如果图还让人猜,就失去了意义。 - 数据量几十万条以内,Pandas完全够用,没必要上Spark。我之前见过有同学为了处理几万条数据非要用Spark跑,结果光配置环境就花了两天,这是典型的工具误用。
做这个项目的过程中我最大的体会是:可视化图表本身并不值钱,值钱的是图表背后那个"你注意到了什么、打算怎么办"的思考过程。同样是画一张品类销售图,有人只看到奶粉卖得最多,有人能看到奶粉是基本盘、玩具是增长点、洗护用品是价值洼地——后者才是有业务价值的分析。希望你跑完这些代码之后,也能从图里读出一层自己的判断,而不是停留在"画出来了"这一步。
