「AI Python 系列」第 02 栏 · AI+数据可视化
全栏 15 篇 · 零成本跟完 🍃
作者:梅雅达编程笔记
首发:CSDN


摘要: 前面学了数据处理、可视化库、AI 辅助分析,这篇全部串起来。模拟一份真实电商销售数据,走完从数据加载→清洗→探索→可视化→生成报告的全流程。最终产出一份包含 6 张图表的完整分析报告(HTML 格式),以及一个可复用的自动化脚本。这就是数据可视化的完整闭环。


这是本栏最重要的实战篇。

前 13 篇都是碎片化的工具和技巧。今天把它们全部串起来,走完一个完整的数据可视化项目。

目标:拿到一份电商销售数据,从零做出一份可交付的可视化分析报告。


一、项目目标

输入:一份包含 1000 行订单记录的 CSV 文件
输出:
  1. 清洗后的干净数据
  2. 6 张核心图表
  3. 一份 HTML 格式的分析报告
  4. 一个可以反复使用的自动化脚本

用到的技能:

  • pandas 数据清洗(Day 03-04)
  • matplotlib/seaborn 静态图表(Day 05-07)
  • pyecharts 交互图表(Day 08-09)
  • AI 辅助分析(Day 11-12)

二、导入依赖 + 配置

import pandas as pd, numpy as np, matplotlib.pyplot as plt, seaborn as sns, base64, glob
from datetime import datetime, timedelta
from pyecharts.charts import Line
from pyecharts import options as opts

sns.set_theme(style='whitegrid')
plt.rcParams.update({'font.family':'sans-serif','font.sans-serif':['Microsoft YaHei','SimHei','DejaVu Sans'],'axes.unicode_minus':False})
np.random.seed(42)

三、Step 1:生成模拟数据

生成 1000 条模拟电商订单数据,包含商品、价格、渠道、地区等字段,并刻意加入缺失值和重复行来模拟真实脏数据。

n=1000; bd=datetime(2025,1,1)
dates=sorted([bd+timedelta(days=int(np.random.uniform(0,365))) for _ in range(n)])
prods=np.random.choice(['蓝牙耳机','机械键盘','无线鼠标','移动电源','手机壳','数据线','充电宝','屏幕清洁套装'],n,p=[0.15,0.12,0.12,0.15,0.13,0.13,0.10,0.10])
pm={'蓝牙耳机':129,'机械键盘':299,'无线鼠标':89,'移动电源':79,'手机壳':29,'数据线':19,'充电宝':149,'屏幕清洁套装':39}
pr=np.array([pm[p] for p in prods])
dp=(pr*np.random.choice([1.0,0.9,0.85,0.8],n,p=[0.6,0.2,0.15,0.05])).astype(int)
qt=np.random.randint(1,5,n)
ch=np.random.choice(['天猫','京东','拼多多','抖音','快手'],n,p=[0.30,0.25,0.20,0.15,0.10])
rg=np.random.choice(['华东','华南','华北','华中','西南','东北','西北'],n,p=[0.25,0.20,0.18,0.12,0.10,0.08,0.07])
rets=np.random.binomial(1,np.where(np.isin(ch,['抖音','快手']),0.18,0.08))
df=pd.DataFrame({'订单日期':dates,'商品':prods,'原价':pr,'实付价格':dp,'数量':qt,'渠道':ch,'地区':rg,'已退货':rets})
mi=np.random.choice(n,5,replace=False)
df.loc[mi[:2],'渠道']=None;df.loc[mi[2:4],'地区']=None;df.loc[mi[4],'数量']=None
df=pd.concat([df,df.iloc[:3]],ignore_index=True)
df.to_csv('orders_raw.csv',index=False,encoding='utf-8-sig')
print(f'原始数据:{len(df)} 行')

四、Step 2:数据清洗 + 探索

对原始数据进行去重、补全缺失值、计算衍生字段,并按渠道和商品汇总关键统计指标。

def clean_data(df):
    """数据清洗"""
    initial_len = len(df)
    
    # 1. 去重
    df = df.drop_duplicates()
    print(f"去重:{initial_len}{len(df)} 行(删除 {initial_len - len(df)} 条重复)")
    
    # 2. 处理缺失值
    missing_before = df.isnull().sum().sum()
    df['渠道'] = df['渠道'].fillna('未知')
    df['地区'] = df['地区'].fillna('未知')
    df['数量'] = df['数量'].fillna(df['数量'].median()).astype(int)
    missing_after = df.isnull().sum().sum()
    print(f"缺失值:{missing_before}{missing_after}")
    
    # 3. 日期处理
    df['订单日期'] = pd.to_datetime(df['订单日期'])
    df['月份'] = df['订单日期'].dt.month
    df['月份名'] = df['订单日期'].dt.strftime('%Y-%m')
    df['星期'] = df['订单日期'].dt.dayofweek  # 0=周一
    
    # 4. 计算衍生字段
    df['销售额'] = df['实付价格'] * df['数量']
    df['折扣率'] = df['实付价格'] / df['原价']
    
    # 5. 异常值检查
    neg_qty = (df['数量'] < 0).sum()
    if neg_qty > 0:
        df = df[df['数量'] > 0]
        print(f"异常值:删除 {neg_qty} 条负数量记录")
    
    print(f"清洗完成:{len(df)} 行")
    return df

df = pd.read_csv('orders_raw.csv')
df_clean = clean_data(df)

在这里插入图片描述


五、Step 3:可视化

图 1:月度销售趋势(matplotlib

用面积图 + 折线图展示各月份销售额变化,并标注最高销售月份。

m=df_clean.groupby('月份名')['销售额'].sum().reset_index()
fig,ax=plt.subplots(figsize=(12,5))
ax.fill_between(range(len(m)),m['销售额'],alpha=0.3,color='#2196F3')
ax.plot(range(len(m)),m['销售额'],marker='o',color='#2196F3',linewidth=2)
ax.set_xticks(range(len(m)));ax.set_xticklabels(m['月份名'],rotation=45)
ax.set_title('月度销售额趋势',fontsize=14,fontweight='bold');ax.set_ylabel('销售额(元)');ax.grid(True,alpha=0.3)
mi2=m['销售额'].idxmax()
ax.annotate(f"最高:{m.loc[mi2,'销售额']:,.0f}元",xy=(mi2,m.loc[mi2,'销售额']),xytext=(mi2+2,m.loc[mi2,'销售额']*1.1),fontsize=11,color='#D32F2F',arrowprops=dict(arrowstyle='->',color='#D32F2F'))
plt.tight_layout();plt.savefig('chart_01_monthly_trend.png',dpi=150,bbox_inches='tight');plt.show()

在这里插入图片描述

图 2:渠道销售额对比(seaborn

按渠道横向柱状图对比,颜色深浅区分销售额高低。

fig,ax=plt.subplots(figsize=(10,5))
c=cs.sort_values('总销售额',ascending=True)
sns.barplot(data=c.reset_index(),x='总销售额',y='渠道',hue='渠道',palette=['#2196F3' if v<c['总销售额'].median() else '#1565C0' for v in c['总销售额']],ax=ax,legend=False)
ax.set_title('各渠道销售额对比',fontsize=14,fontweight='bold');ax.set_xlabel('销售额(元)')
for i,v in enumerate(c['总销售额']):ax.text(v+1000,i,f'{v:,.0f}',va='center',fontsize=10)
plt.tight_layout();plt.savefig('chart_02_channel_sales.png',dpi=150,bbox_inches='tight');plt.show()

在这里插入图片描述

图 3:商品销售占比(matplotlib 饼图)

饼图展示各商品销售额在总销售额中的占比。

fig,ax=plt.subplots(figsize=(8,8))
p=ps.sort_values('总销售额',ascending=False)
ax.pie(p['总销售额'],labels=p.index,autopct='%1.1f%%',startangle=90,colors=plt.cm.Set3(np.linspace(0,1,len(p))),textprops={'fontsize':11})
ax.set_title('各商品销售额占比',fontsize=14,fontweight='bold')
plt.tight_layout();plt.savefig('chart_03_product_pie.png',dpi=150,bbox_inches='tight');plt.show()

在这里插入图片描述

图 4:价格-销量关系(seaborn 散点图)

散点图展示商品实付价格与购买数量之间的关系,不同商品用颜色区分。

fig,ax=plt.subplots(figsize=(10,6))
sns.scatterplot(data=df_clean,x='实付价格',y='数量',hue='商品',alpha=0.6,s=50,ax=ax)
ax.set_title('实付价格 vs 购买数量',fontsize=14,fontweight='bold');ax.legend(bbox_to_anchor=(1.05,1),loc='upper left')
plt.tight_layout();plt.savefig('chart_04_price_vs_qty.png',dpi=150,bbox_inches='tight');plt.show()

在这里插入图片描述

图 5:地区销售热力图(seaborn heatmap

热力图展示各地区在不同渠道的销售额分布,颜色越深销售额越高。

pv=pd.pivot_table(df_clean,values='销售额',index='地区',columns='渠道',aggfunc='sum',fill_value=0)
fig,ax=plt.subplots(figsize=(10,6))
sns.heatmap(pv,annot=True,fmt=',.0f',cmap='YlOrRd',linewidths=0.5,ax=ax)
ax.set_title('地区 × 渠道销售额热力图',fontsize=14,fontweight='bold')
plt.tight_layout();plt.savefig('chart_05_region_channel_heatmap.png',dpi=150,bbox_inches='tight');plt.show()

在这里插入图片描述

图6 交互式月度趋势

pyecharts 生成支持缩放、悬停交互的多渠道月度销售折线图。

mbc=df_clean.groupby(['月份名','渠道'])['销售额'].sum().unstack(fill_value=0)
line=Line().add_xaxis(mbc.index.tolist())
for i,col in enumerate(mbc.columns):
    line.add_yaxis(col,mbc[col].tolist(),is_smooth=True,itemstyle_opts=opts.ItemStyleOpts(color=['#2196F3','#FF5722','#4CAF50','#FFC107','#9C27B0'][i%5]))
line.set_global_opts(title_opts=opts.TitleOpts(title='各渠道月度销售趋势(交互式)'),tooltip_opts=opts.TooltipOpts(trigger='axis'),legend_opts=opts.LegendOpts(pos_top='8%'),datazoom_opts=[opts.DataZoomOpts(type_='slider',range_start=0,range_end=100)])
line.render('chart_06_interactive_trend.html')
print('交互图表已生成')

在这里插入图片描述


六、Step 4:生成 HTML 报告

import base64, glob

charts = {}
for i in range(1,6):
    f = glob.glob(f'chart_0{i}_*.png')
    if f:
        charts[i] = base64.b64encode(open(f[0],'rb').read()).decode()

html = f'''
<!DOCTYPE html><html><head><meta charset='utf-8'><title>电商销售数据分析报告</title>
<style>
body{{font-family:'PingFang SC','Microsoft YaHei',sans-serif;max-width:1000px;margin:0 auto;padding:20px;background:#f5f5f5;color:#333}}
h1{{color:#1565C0;border-bottom:3px solid #1565C0;padding-bottom:10px}}
h2{{color:#1976D2;margin-top:30px}}
.summary{{background:#fff;padding:20px;border-radius:8px;box-shadow:0 2px 4px rgba(0,0,0,.1);margin:20px 0}}
.metric{{display:inline-block;margin:10px 20px;text-align:center}}
.metric .value{{font-size:28px;font-weight:bold;color:#1565C0}}
.metric .label{{font-size:13px;color:#666}}
.chart{{background:#fff;padding:15px;border-radius:8px;box-shadow:0 2px 4px rgba(0,0,0,.1);margin:20px 0}}
table{{border-collapse:collapse;width:100%;margin:10px 0}}
th,td{{border:1px solid #ddd;padding:8px 12px;text-align:right}}
th{{background:#1976D2;color:white}}
.footer{{text-align:center;color:#999;margin-top:40px}}
</style></head><body>
<h1>📊 电商销售数据分析报告</h1>
<p>分析时间:{df_clean['订单日期'].min().date()} ~ {df_clean['订单日期'].max().date()}</p>
<div class='summary'>
<h2>核心指标</h2>
<div class='metric'><div class='value'>{len(df_clean):,}</div><div class='label'>总订单数</div></div>
<div class='metric'><div class='value'>¥{df_clean['销售额'].sum():,.0f}</div><div class='label'>总销售额</div></div>
<div class='metric'><div class='value'>¥{df_clean['销售额'].mean():,.0f}</div><div class='label'>平均客单价</div></div>
<div class='metric'><div class='value'>{df_clean['已退货'].mean():.1%}</div><div class='label'>退货率</div></div>
</div>
<div class='chart'><h2>📈 月度销售趋势</h2>{'<img src="data:image/png;base64,'+charts.get(1,'')+'" />' if 1 in charts else ''}</div>
<div class='chart'><h2>📊 渠道销售额对比</h2>{channel_stats.to_html(classes='table')}{'<img src="data:image/png;base64,'+charts.get(2,'')+'" />' if 2 in charts else ''}</div>
<div class='chart'><h2>🥧 商品销售占比</h2>{'<img src="data:image/png;base64,'+charts.get(3,'')+'" />' if 3 in charts else ''}</div>
<div class='chart'><h2>🔍 价格与销量关系</h2>{'<img src="data:image/png;base64,'+charts.get(4,'')+'" />' if 4 in charts else ''}</div>
<div class='chart'><h2>🗺️ 地区×渠道热力图</h2>{'<img src="data:image/png;base64,'+charts.get(5,'')+'" />' if 5 in charts else ''}</div>
<div class='chart'><h2>📱 交互式图表</h2><p>请查看同目录下的 <code>chart_06_interactive_trend.html</code></p></div>
<div class='footer'><p>本报告由 Python 自动生成</p></div>
</body></html>'''

open('sales_report.html','w',encoding='utf-8').write(html)
print('报告已生成:sales_report.html')

七、完整脚本(自动化版)

把上面的流程封装成一个可以反复使用的脚本:

# 从生成数据到生成报告的最简封装
def run_pipeline(input_file='orders_raw.csv'):
    df = pd.read_csv(input_file)
    df = df.drop_duplicates()
    df['渠道'] = df['渠道'].fillna('未知')
    df['地区'] = df['地区'].fillna('未知')
    df['数量'] = df['数量'].fillna(df['数量'].median()).astype(int)
    df['订单日期'] = pd.to_datetime(df['订单日期'])
    df['月份名'] = df['订单日期'].dt.strftime('%Y-%m')
    df['销售额'] = df['实付价格'] * df['数量']
    df = df[df['数量'] > 0]
    df.to_csv('orders_clean.csv', index=False, encoding='utf-8-sig')
    print(f'✅ 完成!共 {len(df)} 行')
    return df

# run_pipeline()  # 取消注释即可一键重跑

此为精简版代码,完整代码请评论区留言领取


八、小结

一个完整的数据可视化项目包含这些步骤:

步骤 内容 对应本栏
1. 数据加载 读 CSV/Excel Day 03
2. 数据清洗 去重、补缺、异常值 Day 04
3. 数据探索 统计摘要、找规律 Day 11
4. 可视化 静态图 + 交互图 Day 05-10
5. 报告 整合成可交付文档 本篇

关键经验:

  1. 先清洗再分析:脏数据出来的结论是错的
  2. 多种图表组合:不要只用一种图,趋势/对比/占比/关系都覆盖到
  3. 静态+交互:报告用静态图,演示用交互图
  4. 自动化:做完一次就封装成脚本,下次换个数据源直接跑

下一篇是本栏最后一篇——用 AI 做一个对话式的数据分析助手,把前面所有东西整合成一个完整产品。

往期回顾

Day 01 · 数据可视化到底在干啥?为什么 AI 让它变简单了

Day 02:环境搭建 Python 数据分析零成本工具包

Day 03 · Pandas 快速上手:读取、清洗、整理数据 文章已被快递鸟社区收录

Day 04 · 数据清洗:缺失值、异常值、重复值一站式处理

Day 05 · Matplotlib 基础:折线图、柱状图、饼图、散点图

Day 06 · 图表美化:配色、标注、子图布局、中文显示

Day 07 · Seaborn 进阶:统计图表一行代码搞定

Day 08 · Pyecharts 入门:可交互的中文图表

Day 09 · Pyecharts 进阶:地图、时间线、组合图表

Day 10 · Plotly:Web 级交互式数据展示

Day 11 · 用 AI 做数据探索:GLM-4.7-Flash 自动分析数据集

Day 12 · 自然语言做数据透视:不用写代码,问 AI 就行

Day 13 · AI 视觉模型提取图片数据:GLM-4.6V-Flash 实战


下期预告: Day 15 用 AI 做数据分析助手——一个可以对话出图的完整工具,输入数据文件后用自然语言分析+可视化。


专栏

资源领取

  • 关注作者获取本栏完整代码和数据集

原创声明:本文为梅雅达编程笔记原创作品,未经允许不得转载。

Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐