github star gitee star atomgit star PyPI Downloads AI 编程 AI 交流群

大家好,我是正在实战各种AI项目的程序员晚枫。

欢迎来到实战项目部分!这是第一个项目:销售数据分析报表自动化

很多公司每天/每周都要做销售报表,手工操作耗时耗力。这个项目教你用Python全自动完成,从数据读取到报表生成,一键搞定!


项目背景

需求场景

你是某电商公司的数据分析师,每天需要:

  1. 读取前一天的订单数据(CSV格式)
  2. 计算各项KPI指标
  3. 制作可视化图表
  4. 生成Excel报告并邮件发送给管理层

目标产出

一个Python脚本,运行后自动完成以上所有工作。


准备数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import pandas as pd
import numpy as np
from datetime import datetime, timedelta

# 生成模拟销售数据(实际项目中从数据库或文件读取)
np.random.seed(42)

def generate_sales_data(start_date, days=30):
"""生成模拟销售数据"""
dates = pd.date_range(start=start_date, periods=days, freq='D')

data = []
for date in dates:
n_orders = np.random.randint(50, 150)
for _ in range(n_orders):
data.append({
'订单ID': f"ORD{np.random.randint(100000, 999999)}",
'日期': date,
'产品类别': np.random.choice(['电子产品', '服装', '食品', '家居']),
'产品名称': np.random.choice(['iPhone', 'T恤', '零食', '杯子']),
'单价': np.random.randint(50, 5000),
'数量': np.random.randint(1, 5),
'地区': np.random.choice(['华北', '华东', '华南', '西南']),
'销售员': np.random.choice(['张三', '李四', '王五', '赵六'])
})

return pd.DataFrame(data)

# 生成数据
df = generate_sales_data('2024-01-01', 30)
df['金额'] = df['单价'] * df['数量']

# 保存为CSV(模拟真实数据源)
df.to_csv('sales_data.csv', index=False, encoding='utf-8-sig')
print(f"生成了 {len(df)} 条销售记录")

核心分析模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class SalesAnalyzer:
def __init__(self, data_path):
self.df = pd.read_csv(data_path, encoding='utf-8-sig')
self.df['日期'] = pd.to_datetime(self.df['日期'])
print(f"加载了 {len(self.df)} 条记录")

def calculate_kpis(self):
"""计算关键指标"""
kpis = {
'总销售额': self.df['金额'].sum(),
'总订单数': len(self.df),
'平均客单价': self.df['金额'].mean(),
'日均销售额': self.df.groupby('日期')['金额'].sum().mean(),
'最高单日销售': self.df.groupby('日期')['金额'].sum().max(),
'总销量': self.df['数量'].sum(),
}
return kpis

def category_analysis(self):
"""品类分析"""
return self.df.groupby('产品类别').agg({
'金额': ['sum', 'mean', 'count'],
'数量': 'sum'
}).round(2)

def region_analysis(self):
"""地区分析"""
return self.df.groupby('地区')['金额'].sum().sort_values(ascending=False)

def daily_trend(self):
"""日销售趋势"""
return self.df.groupby('日期')['金额'].sum()

def salesperson_performance(self):
"""销售员业绩"""
return self.df.groupby('销售员').agg({
'金额': 'sum',
'订单ID': 'count'
}).rename(columns={'订单ID': '订单数'}).sort_values('金额', ascending=False)

可视化模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import matplotlib.pyplot as plt
import seaborn as sns

class ReportVisualizer:
def __init__(self, analyzer):
self.analyzer = analyzer
plt.style.use('seaborn-v0_8')

def create_dashboard(self, save_path='sales_report.png'):
"""创建综合报表图"""
fig = plt.figure(figsize=(16, 12))

# 1. 日销售趋势
ax1 = plt.subplot(2, 3, 1)
daily = self.analyzer.daily_trend()
ax1.plot(daily.index, daily.values, marker='o', linewidth=2)
ax1.set_title('日销售趋势', fontsize=14, fontweight='bold')
ax1.set_ylabel('销售额')
ax1.grid(True, alpha=0.3)

# 2. 品类占比
ax2 = plt.subplot(2, 3, 2)
category = self.analyzer.category_analysis()['金额']['sum']
colors = plt.cm.Set3(np.linspace(0, 1, len(category)))
ax2.pie(category, labels=category.index, autopct='%1.1f%%', colors=colors)
ax2.set_title('品类销售占比', fontsize=14, fontweight='bold')

# 3. 地区对比
ax3 = plt.subplot(2, 3, 3)
region = self.analyzer.region_analysis()
bars = ax3.bar(region.index, region.values, color='skyblue', edgecolor='black')
ax3.set_title('地区销售排行', fontsize=14, fontweight='bold')
ax3.set_ylabel('销售额')
for bar in bars:
height = bar.get_height()
ax3.text(bar.get_x() + bar.get_width()/2., height,
f'{height:,.0f}', ha='center', va='bottom')

# 4. 销售员业绩
ax4 = plt.subplot(2, 3, 4)
sales_perf = self.analyzer.salesperson_performance()
ax4.barh(sales_perf.index, sales_perf['金额'], color='lightcoral')
ax4.set_title('销售员业绩排行', fontsize=14, fontweight='bold')
ax4.set_xlabel('销售额')

# 5. 品类箱线图
ax5 = plt.subplot(2, 3, 5)
sns.boxplot(data=self.analyzer.df, x='产品类别', y='金额', ax=ax5)
ax5.set_title('各品类订单金额分布', fontsize=14, fontweight='bold')
ax5.tick_params(axis='x', rotation=45)

# 6. KPI指标文本
ax6 = plt.subplot(2, 3, 6)
ax6.axis('off')
kpis = self.analyzer.calculate_kpis()
kpi_text = f"""
【关键指标】

总销售额: ¥{kpis['总销售额']:,.0f}
总订单数: {kpis['总订单数']:,}
平均客单价: ¥{kpis['平均客单价']:.0f}
日均销售额: ¥{kpis['日均销售额']:,.0f}
最高单日: ¥{kpis['最高单日销售']:,.0f}
总销量: {kpis['总销量']:,}
"""
ax6.text(0.1, 0.5, kpi_text, fontsize=12, verticalalignment='center',
family='monospace', bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))

plt.suptitle('销售数据分析报表', fontsize=18, fontweight='bold', y=0.98)
plt.tight_layout(rect=[0, 0, 1, 0.96])
plt.savefig(save_path, dpi=300, bbox_inches='tight')
plt.close()

return save_path

Excel报告生成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, PatternFill
from openpyxl.chart import BarChart, PieChart, Reference

def generate_excel_report(analyzer, output_path='sales_report.xlsx'):
"""生成Excel格式的详细报告"""
wb = Workbook()

# 删除默认sheet
wb.remove(wb.active)

# Sheet 1: 概览
ws_overview = wb.create_sheet("概览")
kpis = analyzer.calculate_kpis()

ws_overview['A1'] = '销售数据概览'
ws_overview['A1'].font = Font(size=16, bold=True)

row = 3
for key, value in kpis.items():
ws_overview[f'A{row}'] = key
ws_overview[f'B{row}'] = value
if isinstance(value, float):
ws_overview[f'B{row}'].number_format = '#,##0.00'
row += 1

# Sheet 2: 品类分析
ws_category = wb.create_sheet("品类分析")
category_df = analyzer.category_analysis()
category_df.to_excel(output_path, sheet_name='品类分析', startrow=0)

# 保存
wb.save(output_path)
return output_path

主程序整合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import os
from datetime import datetime

def main():
"""主程序"""
print("="*50)
print("销售数据分析报表自动生成系统")
print("="*50)

# 1. 读取数据
print("\n[1/4] 读取销售数据...")
analyzer = SalesAnalyzer('sales_data.csv')

# 2. 计算KPI
print("[2/4] 计算关键指标...")
kpis = analyzer.calculate_kpis()
print(f" ✓ 总销售额: ¥{kpis['总销售额']:,.0f}")
print(f" ✓ 总订单数: {kpis['总订单数']:,}")

# 3. 生成可视化
print("[3/4] 生成可视化图表...")
visualizer = ReportVisualizer(analyzer)
chart_path = visualizer.create_dashboard()
print(f" ✓ 图表已保存: {chart_path}")

# 4. 生成Excel
print("[4/4] 生成Excel报告...")
excel_path = generate_excel_report(analyzer)
print(f" ✓ Excel已保存: {excel_path}")

print("\n" + "="*50)
print("报表生成完成!")
print("="*50)

if __name__ == "__main__":
main()

定时自动运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import schedule
import time

def job():
print(f"[{datetime.now()}] 开始执行日报任务...")
main()
print("任务完成\n")

# 每天早上9点执行
schedule.every().day.at("09:00").do(job)

print("定时任务已启动,每天早上9点自动生成报表...")
while True:
schedule.run_pending()
time.sleep(60)

项目总结

学到的技能

  • ✅ 数据读取与清洗
  • ✅ 多维度数据分析(时间、品类、地区、人员)
  • ✅ 数据可视化(Matplotlib + Seaborn)
  • ✅ Excel报告生成
  • ✅ 自动化任务调度

扩展方向

  • 连接数据库实时读取
  • 添加邮件自动发送功能
  • 部署到服务器定时运行
  • 制作Web版数据看板

进阶:报表自动化全流程

定时任务方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 使用schedule库实现定时执行
import schedule
import time

def daily_report():
# 1. 读取最新数据
df = pd.read_csv('sales_today.csv')

# 2. 计算KPI
kpi = {
'total_sales': df['amount'].sum(),
'order_count': len(df),
'avg_order': df['amount'].mean()
}

# 3. 生成图表
fig, ax = plt.subplots(figsize=(10, 6))
df.groupby('category')['amount'].sum().plot.bar(ax=ax)
fig.savefig('daily_chart.png')

# 4. 发送邮件
send_email(
to='boss@company.com',
subject=f'日报 {date.today()}',
body=f"今日销售: ¥{kpi['total_sales']:,.0f}",
attachments=['daily_chart.png']
)

# 每天早上9点执行
schedule.every().day.at("09:00").do(daily_report)

while True:
schedule.run_pending()
time.sleep(60)

邮件发送实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage

def send_email(to, subject, body, attachments=None):
msg = MIMEMultipart()
msg['From'] = 'data@company.com'
msg['To'] = to
msg['Subject'] = subject

msg.attach(MIMEText(body, 'html'))

if attachments:
for filepath in attachments:
with open(filepath, 'rb') as f:
img = MIMEImage(f.read())
msg.attach(img)

with smtplib.SMTP('smtp.company.com', 587) as server:
server.starttls()
server.login('user', 'password')
server.send_message(msg)

避坑指南

❌ 坑1:报表数据不一致

1
2
3
4
# 多个数据源的时间范围不同导致数据不一致
# 解决方案:统一时间过滤条件
start_date = pd.Timestamp('today') - pd.Timedelta(days=1)
df = df[df['date'] >= start_date]

❌ 坑2:定时任务中断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 方案1:使用系统cron(Linux/Mac)
# crontab -e
# 0 9 * * * /path/to/python /path/to/report.py

# 方案2:使用Windows任务计划程序

# 方案3:加入异常处理和日志
import logging
logging.basicConfig(filename='report.log', level=logging.INFO)

try:
daily_report()
logging.info(f"报告生成成功: {date.today()}")
except Exception as e:
logging.error(f"报告生成失败: {e}")

销售分析KPI体系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 电商销售核心KPI
kpi_system = {
'营收类': {
'GMV': '总成交额(含退款)',
'净收入': 'GMV - 退款金额',
'客单价': '净收入 / 订单数',
'件单价': '净收入 / 商品件数',
},
'用户类': {
'DAU': '日活跃用户数',
'新客占比': '新客订单 / 总订单',
'复购率': '购买2次以上用户 / 总用户',
'留存率': 'N日后仍活跃的用户占比',
},
'效率类': {
'转化率': '下单用户 / 访问用户',
'退货率': '退货订单 / 总订单',
'发货时效': '下单到发货的平均时间',
'库存周转率': '销售成本 / 平均库存',
}
}

for category, kpis in kpi_system.items():
print(f"\n{category}:")
for name, desc in kpis.items():
print(f" {name}: {desc}")

报表自动化架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# 完整的报表自动化系统架构
class ReportGenerator:
def __init__(self, config):
self.data_source = config['data_source']
self.report_type = config['report_type']
self.recipients = config['recipients']

def fetch_data(self):
'''从数据源获取数据'''
if self.data_source == 'csv':
return pd.read_csv('latest_data.csv', parse_dates=['date'])
elif self.data_source == 'database':
engine = create_engine(self.config['db_url'])
return pd.read_sql(self.config['query'], engine)

def calculate_kpi(self, df):
'''计算KPI'''
return {
'gmv': df['amount'].sum(),
'orders': len(df),
'avg_order': df['amount'].mean(),
'refund_rate': df['refunded'].mean()
}

def generate_charts(self, df):
'''生成图表'''
charts = []
# 趋势图
fig, ax = plt.subplots(figsize=(12, 5))
df.groupby('date')['amount'].sum().plot(ax=ax)
fig.savefig('trend.png', dpi=150, bbox_inches='tight')
charts.append('trend.png')
return charts

def send_report(self, kpi, charts):
'''发送报告'''
body = '<h2>销售日报</h2>' + f"<p>GMV: {kpi['gmv']:,.0f}</p>" + f"<p>订单数: {kpi['orders']:,}</p>" + f"<p>客单价: {kpi['avg_order']:,.0f}</p>"
send_email(self.recipients, f'销售日报 {date.today()}', body, charts)

def run(self):
df = self.fetch_data()
kpi = self.calculate_kpi(df)
charts = self.generate_charts(df)
self.send_report(kpi, charts)

# 使用
config = {
'data_source': 'csv',
'report_type': 'daily',
'recipients': ['boss@company.com']
}
report = ReportGenerator(config)
report.run()

销售分析报告模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
def generate_sales_report(df, period='daily'):
'''生成销售分析报告'''
import pandas as pd
from datetime import date

report = "================================
"
report += f"销售分析报告 - {date.today()}
"
report += "================================

"
report += "📊 核心指标
"
report += f"- 总销售额: ¥{df['amount'].sum():,.0f}
"
report += f"- 订单数: {len(df):,}
"
report += f"- 客单价: ¥{df['amount'].mean():,.0f}
"
report += "- 退货率: {:.1f}%

".format(df.get('returned', pd.Series([False]*len(df))).mean()*100)
report += "品类分析
"

# 品类汇总
category_summary = df.groupby('category').agg(
sales_sum=('amount', 'sum'),
order_cnt=('order_id', 'count'),
avg_amount=('amount', 'mean')
).sort_values('sales_sum', ascending=False)

report += category_summary.to_string()
report += "

Top 5 products
"

top_products = df.groupby('product')['amount'].sum().nlargest(5)
report += top_products.to_string()

# 保存报告
filename = 'sales_report_{}_{}.txt'.format(period, date.today())
with open(filename, 'w') as f:
f.write(report)

return report

# 使用
report = generate_sales_report(df)
print(report)

销售数据分析完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import date

plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False

# ===== 1. 数据读取 =====
np.random.seed(42)
n = 10000
df = pd.DataFrame({
'order_id': range(10001, 10001 + n),
'date': pd.date_range('2025-01-01', periods=n, freq='1H'),
'product': np.random.choice(['手机', '电脑', '平板', '耳机', '手表'], n),
'channel': np.random.choice(['线上', '线下'], n, p=[0.7, 0.3]),
'city': np.random.choice(['北京', '上海', '广州', '深圳', '成都'], n),
'amount': np.random.exponential(1000, n).round(2),
'quantity': np.random.randint(1, 5, n)
})

# ===== 2. KPI计算 =====
gmv = df['amount'].sum()
orders = len(df)
avg_order = df['amount'].mean()
refund_rate = 0.05 # 模拟

print('=' * 40)
print(f'销售KPI报告 - {date.today()}')
print('=' * 40)
print(f'GMV: ¥{gmv:,.0f}')
print(f'订单数: {orders:,}')
print(f'客单价: ¥{avg_order:,.0f}')
print(f'退货率: {refund_rate*100:.1f}%')

# ===== 3. 品类分析 =====
cat_summary = df.groupby('product').agg(
销售额=('amount', 'sum'),
订单数=('order_id', 'count'),
客单价=('amount', 'mean')
).sort_values('销售额', ascending=False)
print(f'\n品类分析:')
print(cat_summary.round(0))

# ===== 4. 可视化 =====
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 月度趋势
monthly = df.set_index('date').resample('M')['amount'].sum()
monthly.plot(ax=axes[0,0], title='月度销售额趋势')
axes[0,0].set_ylabel('销售额(万元)')

# 品类占比
df.groupby('product')['amount'].sum().plot.pie(ax=axes[0,1], autopct='%1.1f%%', title='品类占比')

# 渠道对比
df.groupby('channel')['amount'].sum().plot.bar(ax=axes[1,0], title='渠道对比', rot=0)

# 城市排行
df.groupby('city')['amount'].sum().sort_values().plot.barh(ax=axes[1,1], title='城市排行')

plt.tight_layout()
plt.savefig('sales_report.png', dpi=150, bbox_inches='tight')
print('\n图表已保存: sales_report.png')

下节预告

下一项目是用户行为分析,学习RFM模型、留存分析等经典方法。

👉 继续阅读:项目2-用户行为分析与RFM模型


💬 加入学习交流群

扫码加入Python学习交流群,和数千名同学一起进步:

👉 点击加入交流群

群里不定期分享:

  • 数据分析实战案例
  • Python学习资料
  • 求职面试经验
  • 行业最新动态

推荐:AI Python数据分析实战营

🎁 限时福利:送《利用Python进行数据分析》实体书

👉 点击了解详情


课程导航

上一篇: 数据分布分析-正态分布与QQ图

下一篇: 项目2-用户行为分析与RFM模型


PS:自动化报表是数据分析师的核心技能。把这个项目做出来,你就超过了80%的同行。



📚 推荐教材

主教材《Excel+Python 飞速搞定数据分析与处理(图灵出品)》

💬 联系我

平台账号/链接
微信扫码加好友
微博@程序员晚枫
知乎@程序员晚枫
抖音@程序员晚枫
小红书@程序员晚枫
B 站Python 自动化办公社区

主营业务:AI 编程培训、企业内训、技术咨询

🎓 AI 编程实战课程

想系统学习 AI 编程?程序员晚枫的 AI 编程实战课 帮你从零上手!