Python电商数据分析实战:从数据清洗到可视化全流程

发布时间:2026/9/30 17:39:30
Python电商数据分析实战:从数据清洗到可视化全流程 拿到一份电商订单数据几十万行摆在那里你打算从哪里下手我是那种喜欢先把数据盘明白再写代码的人这份项目从环境准备到最终的可视化图表完整走了一遍用Python分析电商销售数据的流程。这篇文章就记录我在这个项目里踩过的坑、验证过的思路以及可以直接照抄的实现方式。不管你是刚接触Python的数据分析新手还是已经写过不少分析脚本但想看看别人怎么处理细节的同行这篇文章应该都能给你一些参考。1. 数据准备阶段环境搭建与数据集结构确认1.1 分析环境怎么选做电商数据分析Python不是唯一选择Excel、SQL甚至现在各种AI工具都能出结果。但我最终选择Python核心原因是它能把数据处理-统计计算-可视化串在同一条流水线上尤其是面对几十万行级别的订单明细时Excel已经明显吃力而Python的pandas处理起来非常轻松。我的本机环境是Windows 11安装了Python 3.10版本。这里建议你用3.9以上的版本太老的版本在部分库的兼容性上容易出问题。数据分析离不开的几件套是pandas、numpy和matplotlib另外为了方便读取和导出Excel格式的数据我额外装了openpyxl。安装命令很简单pip install pandas numpy matplotlib openpyxl如果你还在纠结装哪个Python发行版我的建议是直接去官网下载安装包安装时记得勾选Add Python to PATH。Anaconda当然也行但对于只想做数据分析不想被一堆预装库拖累的朋友干净的原生Python再加pip安装就够了。1.2 模拟数据集的结构说明因为是项目演示我用脚本模拟了一份结构贴近真实业务的电商订单数据总共2023年1月1日到2023年12月31日的5万条订单记录。字段设计参考了大多数电商后台能导出的明细表包含的信息如下表所示字段名含义示例order_id订单编号OD202301010001order_date下单日期2023-03-15category商品类目数码、女装、美妆、家居、食品product_name商品名称无线蓝牙耳机unit_price商品单价199quantity购买数量2total_amount订单金额398customer_id客户IDC1000234province收货省份广东payment_method支付方式支付宝这里我特意把缺失值、重复记录和少量异常值混合进去了因为真实拿到的数据永远不可能干净。如果你要复现这个项目自己生成模拟数据时也要注意嵌入这些问题后面的清洗步骤才有意义。1.3 数据加载的基本操作数据文件是csv格式读取用pandas一行代码就能完成。这里有个经验如果源文件有中文建议编码用utf-8-sig而不是默认的utf-8否则读入的中文可能是乱码Windows环境下尤其明显。import pandas as pd df pd.read_csv(sales_data.csv, encodingutf-8-sig) print(df.shape) print(df.head())输出结果能看到数据是50000行乘10列。先不要急着写分析逻辑这时候最重要的事情是了解数据的基本面貌有哪些列、各列是什么类型、哪些字段明显有问题。我通常会在加载之后紧接着执行df.info()和df.describe()前者能看出每列的非空数量和数据类型后者能快速发现数值列的分布是否合理。2. 数据清洗过程缺失、重复和异常值的处理思路2.1 缺失值怎么处理才能不翻车先看一遍缺失值的情况用df.isnull().sum()统计各列的缺失数量。我这份数据里缺失主要出现在total_amount和customer_id两列缺失量都不算大加起来不到总数据量的3%。这种比例我一般不会直接删除整行而是看缺失字段在业务上是否有可替代的信息。total_amount缺失时好在unit_price和quantity都在所以直接相乘补齐即可。customer_id缺失处理起来就要小心因为客户ID丢了但订单本身是有效的可以用UNKNOWN占位不影响销售数据的统计只是在复购分析时需要排除这部分样本。这里补充一条实操原则缺失值处理没有一个固定公式关键是理解字段的业务含义。销量字段缺失如果发生在有支付记录的订单上更可能是录入异常而非真实为0两者的处理策略完全不同。# 用单价和数量回填缺失的订单金额 mask df[total_amount].isnull() df[unit_price].notnull() df[quantity].notnull() df.loc[mask, total_amount] df.loc[mask, unit_price] * df.loc[mask, quantity] # 客户ID缺失用UNKNOWN占位 df[customer_id] df[customer_id].fillna(UNKNOWN)2.2 重复记录要区分完全重复和部分重复重复数据是电商明细里常出现的脏数据主要来源是数据同步时的重复导出。清洗前先查一下重复情况print(df.duplicated().sum()) # 完全重复行数 print(df.duplicated(subset[order_id]).sum()) # 订单号重复行数完全重复的行直接drop_duplicates()删除即可。但如果只是order_id重复就不能盲删了——因为同一条订单可能包含多个商品每行代表一个商品子项这类重复是业务允许的。我这边的数据是每个订单固定一行所以order_id重复就判定为异常保留第一条。有个坑提醒一下drop_duplicates()默认保留第一条记录如果你希望保留最新的数据可以在删除前先按时间字段排序再执行去重。df df.sort_values(order_date).drop_duplicates(subset[order_id], keepfirst)2.3 异常值检查负数和离谱的数字都要搜出来数值异常在这个数据里主要表现为两类一类是quantity出现负数另一类是unit_price高得离谱。负数数量大多是退单标记错误或者手工录入时误输但仔细看之后发现这些订单并没有对应的退款标记所以直接判定为脏数据。对单价异常我用了科学的界定方法——看unit_price的分布。正常情况下客单价集中在几十到几百之间个别商品几千块也合理但如果单价超过10万就很可能是录错了。这部分不需要一棒子打死全部删除我会先用条件筛选出来查看具体是哪些商品再决定是否删除。# 去除负数销量 df df[df[quantity] 0] # 查看单价超过一定阈值的记录 unusual_price df[df[unit_price] 10000] print(unusual_price[product_name].value_counts())实际操作中我发现很多异常值其实是真实数据。就拿单价超过1万的记录来说如果商品名称显示是高档家具或者专业设备那价格高是完全合理的。所以我宁可多花时间逐条看也不愿意为了省事一刀切。清洗完成后别忘了重置索引df df.reset_index(dropTrue)3. 核心业务指标计算从订单明细到经营洞察3.1 整体销售趋势怎么看数据清洗干净后第一件事当然是看大盘。月度销售额GMV和月度订单量是最基础的两个指标它们能直观反映业务的节奏感。这里我建议先把订单日期标准化再提取出月份字段做分组聚合df[order_date] pd.to_datetime(df[order_date]) df[month] df[order_date].dt.strftime(%Y-%m) monthly_gmv df.groupby(month)[total_amount].sum() monthly_orders df.groupby(month)[order_id].nunique()order_id的统计我特意用了nunique()而不是count()因为去重后的数据虽然一条订单一行但用nunique()计算出的订单数更稳妥即使后面继续往数据里追加多行同订单的子项也不会算错。从2023年的模拟数据看月度GMV整体呈现逐季抬升的走势其中6月和11月出现两次高峰。6月是年中大促11月则是双十一的影响这两波峰值和电商行业的真实节奏吻合。分析到这一步业务的基本盘已经清晰了。3.2 类目维度分析谁在贡献收入谁是潜力股总体趋势只能看到水涨船高想知道哪条业务线在赚钱就必须拆到类目维度。我做了两个层面的统计各类目的总销售额和销售占比、各类目的SKU数和平均客单价。category_stats df.groupby(category).agg( sales(total_amount, sum), orders(order_id, nunique), avg_amount(total_amount, mean) ).sort_values(sales, ascendingFalse) category_stats[sales_share] category_stats[sales] / category_stats[sales].sum()从结果来看数码类贡献了超过35%的销售额排名第一美妆和女装紧随其后。家居类的单量其实不小但平均客单价偏低属于走量型类目。数码类则恰恰相反订单量仅次于女装但高单价把销售额推得很高。这种分析的价值在于它能直接引导运营方向数码类适合做利润冲刺和高客单用户运营家居类更适合做复购和连带销售。如果只看整体销售额这些结构性差异就会被掩盖。3.3 客户复购分析新客、老客与忠诚用户电商分析里复购率是衡量用户质量的重要指标。为了计算它我先把客户按首单时间和后续购买次数做了标签。customer_data df.groupby(customer_id).agg( order_count(order_id, nunique), total_spend(total_amount, sum), first_order_date(order_date, min) ) customer_data[repeated] customer_data[order_count] 1 repeat_rate customer_data[repeated].mean()这个思路很简单把每个客户的订单聚合起来看订单次数是否大于1。模拟数据算出来的整体复购率大约为38%但不同类目的复购率差异很大——食品和家居类目复购明显高于数码类。这其实很符合消费逻辑消耗品天然有复购需求耐用品的复购周期更长因此给数码类客户做复购激励时不能用和食品类相同的策略。这里要用到前面清洗时做的占位逻辑customer_id为UNKNOWN的客户在复购分析中自然会被排除因为聚合后没有区分意义。这种操作能保证最终指标不受脏数据干扰。3.4 价格带划分客单价与用户消费力客单价是电商运营常挂嘴边的词但很多人只看全店平均值。平均值有个天然缺陷它会被少数高价订单拉高。所以我习惯用分位数来看价格结构price_bins [0, 50, 100, 200, 500, float(inf)] price_labels [50以下, 50-100, 100-200, 200-500, 500以上] df[price_band] pd.cut(df[total_amount], binsprice_bins, labelsprice_labels) price_band_stats df.groupby(price_band, observedFalse).agg( orders(order_id, nunique), sales(total_amount, sum) )分段结果很能说明问题客单价在100到200元之间的订单量最大是店铺的主力价格带500元以上的高价订单虽然单量占比不高却贡献了显著比例的销售额。这就是典型的金字塔结构说明产品定价梯度是合理的同时高客单价区有进一步提升的空间。用pd.cut做分段时observedFalse这个参数在pandas 2.0版本以后建议加上否则按分类变量分组时容易出警告。4. 数据可视化把分析结论画成图4.1 让matplotlib正常显示中文Python数据可视化最容易劝退新手的不是画图逻辑而是中文乱码。默认情况下matplotlib的字体配置不支持中文图形上的所有中文标签都会变成方框。我的解决办法是在画图前统一设置字体参数import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, Arial Unicode MS] plt.rcParams[axes.unicode_minus] False这个配置对Windows环境下的SimHei黑体和Mac的Arial Unicode MS都有覆盖。axes.unicode_minus必须设置成False否则坐标轴上的负号会显示成乱码。更省事的方式是把这段配置放进一个sales_analysis.py文件头部之后所有画图脚本都复用这个配置。4.2 月度销售趋势折线图画趋势图要选对图表类型连续时间序列用折线图最直观。plt.figure(figsize(10, 5)) plt.plot(monthly_gmv.index, monthly_gmv.values, markero, linewidth2) plt.title(2023年月度销售额趋势) plt.xlabel(月份) plt.ylabel(销售额) plt.grid(True, linestyle--, alpha0.6) plt.tight_layout() plt.savefig(monthly_sales_trend.png, dpi120, bbox_inchestight)bbox_inchestight这个参数很关键它会把画布外的边缘空白裁掉保存出来的图片不会出现坐标轴标签被截断的问题。dpi120是导出图片的经验值清晰度够用在报告里文件也不会太臃肿。从图上看两个销售高峰的曲线特征非常明显。配合前面的月度数据基本可以确定促销节点的爆发力和淡季期的平稳节奏。4.3 类目销售额对比柱状图类目对比适合用柱状图一眼扫过去就能看出顺序plt.figure(figsize(8, 5)) plt.bar(category_stats.index, category_stats[sales], color#4C72B0) plt.title(各品类销售额对比) plt.xlabel(类目) plt.ylabel(销售额) plt.xticks(rotation45) plt.tight_layout() plt.savefig(category_sales.png, dpi120, bbox_inchestight)这里有一个容易忽略的细节如果类目名称较长横向排列会导致标签重叠给xticks加一个rotation45能有效避开这个问题。柱状图呈现出来的层级关系很清晰数码遥遥领先美妆和女装位于第二梯队食品和家居垫底。再结合3.2节的客单价数据就能解释为什么销售额排名和订单量排名不完全一致。4.4 客单价分布直方图直方图用来观察数据分布形态非常合适可以直观看出客单价集中在哪个区间plt.figure(figsize(9, 5)) plt.hist(df[total_amount], bins50, edgecolorwhite, color#55A868) plt.title(订单金额分布) plt.xlabel(订单金额) plt.ylabel(订单数量) plt.tight_layout() plt.savefig(order_amount_distribution.png, dpi120, bbox_inchestight)bins50是我试出来的合适粒度区间太细会显得锯齿严重太粗则看不清分布细节。从直方图看订单金额呈现明显的右偏分布大量订单集中在100到200元区域尾部逐渐拖长到千元级别。这种长尾分布意味着店铺的主要消费者是中等客单价用户提升这部分客群的购买频次是增长的关键。5. 分析复盘与扩展方向5.1 从数据结果到建议动作整个项目做完数据分析本身并不难难的是让结论真正能指导决策。我最后把分析结果整理成了几条可执行建议比如数码类维持高客单价优势配合大促节点做高价单品或套装推广家居类提升连带率在订单完成后推荐相关配件或高频消耗品针对复购率低的类目设计周期性的客户召回活动利用会员日等方式唤醒沉默用户这层转换很关键因为拿出去给业务方看的时候别人关心的不是你用了什么算法清洗数据而是数据告诉我们应该在哪个方向多投入资源。5.2 更进阶的分析方向这次项目算是一个完整但基础的分析闭环实际上电商数据分析还有很多扩展空间。我复盘时想到的几个方向供你继续探索用户分群用RFM模型给客户分层找出高价值、高潜力和流失风险客户ABC分析按类目销量贡献划分重点商品、普通商品和长尾商品优化库存策略促销效果评估对比大促前后的销售日数据测算活动带来的增量效果时间序列预测基于月度销售数据训练模型尝试预测未来几个月的销售额这些方向我在后续项目里会逐步实践等跑通了再回来分享。建议你在复现这个项目时不要停留在把代码跑完的层面。试着改改数据字段、换换分组维度、调整可视化展示方式看结论会发生什么变化。比如我把month换成week维度重新分析时就发现了月度趋势掩盖掉的周中和周末销售差异。这种二次挖掘的过程才是数据分析最有趣的部分。