背景介绍
对于小型企业或店铺而言,快速分析产品销售表现是优化库存、制定营销策略的关键。本文将带你用Python开发一个销售数据统计与可视化工具,通过读取CSV销售数据,自动统计各产品的销量与销售额,并以直观的柱状图展示结果。该工具不仅能帮助初学者掌握文件处理+数据统计+可视化的完整流程,还能解决matplotlib中文乱码等常见问题。
思路分析
我们的工具将分三步实现:
1. 数据读取:使用csv模块读取CSV文件,处理每行数据的产品名称、销售数量和单价。
2. 数据统计:通过字典按产品名称分组,累加总销量、计算总销售额(销量×单价)。
3. 可视化展示:利用matplotlib绘制双柱状图(子图布局),并配置中文显示、图表美化(如标签旋转、颜色设置)。
代码实现
下面是完整的代码实现,包含详细注释:
import csv
import matplotlib.pyplot as plt
def read_and_analyze(csv_path):
"""读取CSV文件并按产品统计销量和销售额"""
product_stats = {} # 存储结构:{产品名: (总销量, 总销售额)}
with open(csv_path, 'r', encoding='utf-8') as f:
reader = csv.reader(f)
next(reader) # 跳过表头行
for row in reader:
# 处理数据不完整的情况(空值、列数不足)
if len(row) < 3 or not row[1].strip() or not row[2].strip():
print(f"警告:数据行{row}不完整/有空值,已跳过")
continue
product = row[0]
try:
quantity = int(row[1]) # 转换为整数(销量)
price = float(row[2]) # 转换为浮点数(单价)
except ValueError:
print(f"警告:数据行{row}的数量/单价格式错误,已跳过")
continue
# 累加销量和销售额
if product in product_stats:
prev_q, prev_r = product_stats[product]
product_stats[product] = (prev_q + quantity, prev_r + quantity * price)
else:
product_stats[product] = (quantity, quantity * price)
return product_stats
def visualize(product_stats, save_path=None):
"""绘制销量和销售额的双柱状图"""
# 提取数据
products = list(product_stats.keys())
quantities = [stats[0] for stats in product_stats.values()]
revenues = [stats[1] for stats in product_stats.values()]
# 配置matplotlib中文显示(需系统有对应字体,如SimHei)
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题
# 创建1行2列的子图,调整画布大小
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))
# 绘制销量对比图(左子图)
ax1.bar(products, quantities, color='#5DA5DA', edgecolor='black', zorder=3)
ax1.set_title('各产品销量对比')
ax1.set_xlabel('产品名称')
ax1.set_ylabel('销量(件)')
ax1.tick_params(axis='x', rotation=45) # 旋转x轴标签防止重叠
ax1.grid(axis='y', linestyle='--', alpha=0.7) # 添加水平网格线
# 绘制销售额对比图(右子图)
ax2.bar(products, revenues, color='#FAA43A', edgecolor='black', zorder=3)
ax2.set_title('各产品销售额对比')
ax2.set_xlabel('产品名称')
ax2.set_ylabel('销售额(元)')
ax2.tick_params(axis='x', rotation=45)
ax2.grid(axis='y', linestyle='--', alpha=0.7)
# 隐藏左右上三边的边框,使图表更简洁
for ax in [ax1, ax2]:
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
# 调整布局,防止标签被截断
plt.tight_layout()
if save_path:
plt.savefig(save_path, dpi=300, bbox_inches='tight')
print(f"图表已保存至:{save_path}")
else:
plt.show()
def main():
"""主函数:处理用户输入,调用数据读取和可视化"""
try:
csv_path = input("请输入CSV文件路径(例如:sales_data.csv):")
# 读取并分析数据
stats = read_and_analyze(csv_path)
if not stats:
print("错误:未统计到有效数据,请检查CSV文件格式。")
return
# 打印统计结果
print("\n===== 销售统计结果 =====")
for product, (q, r) in stats.items():
print(f"{product}:总销量={q},总销售额={r:.2f}")
# 可视化
save_choice = input("\n是否需要保存图表?(y/n) ")
if save_choice.lower() == 'y':
save_path = input("请输入保存路径(例如:sales_chart.png):")
visualize(stats, save_path)
else:
visualize(stats)
except FileNotFoundError:
print(f"错误:文件{csv_path}不存在,请检查路径。")
except Exception as e:
print(f"发生未知错误:{e}")
if __name__ == "__main__":
main()
代码解析
- 数据读取与统计:
read_and_analyze函数通过csv.reader逐行读取数据,跳过表头后处理每行数据。使用字典product_stats按产品名称分组,累加销量、计算销售额,并处理空值和格式错误(如非数字的销量/单价)。 -
可视化配置:
visualize函数中,我们通过plt.rcParams配置中文显示(需系统安装对应字体,如SimHei),创建1行2列的子图(subplots),分别绘制销量和销售额的柱状图。通过grid添加网格线、spines隐藏多余边框,使图表更美观。 -
用户交互:
main函数处理用户输入的CSV路径,调用统计和可视化函数,并支持选择是否保存图表(需用户输入保存路径)。
运行示例
假设CSV文件sales_data.csv内容如下:
产品名称,销售数量,单价
产品A,10,20.5
产品B,5,30.0
产品C,8,15.7
运行程序后,控制台输出:
===== 销售统计结果 =====
产品A:总销量=10,总销售额=205.00
产品B:总销量=5,总销售额=150.00
产品C:总销量=8,总销售额=125.60
同时弹出双柱状图,左图展示销量对比,右图展示销售额对比(x轴标签旋转45度,图表带网格线和简洁边框)。
拓展挑战
- 主题切换:可通过
plt.style.use('dark_background')或自定义颜色配置实现深色主题。 - 异常处理增强:对CSV中“销售数量”或“单价”为空的情况,可设置默认值(如0)或提示用户修正。
- 批量处理:支持读取多个CSV文件,合并统计结果后可视化。
总结
本项目通过Python的csv、matplotlib库,实现了“文件读取→数据统计→可视化”的完整流程。核心难点在于中文显示配置(解决matplotlib乱码)和数据异常处理(空值、格式错误)。通过该项目,初学者可系统掌握文件处理、数据聚合、可视化的实践技巧,为更复杂的数据分析项目打下基础。
如果需要进一步优化,可尝试引入pandas简化数据处理(如df.groupby().agg()),或用seaborn美化图表风格。
希望这篇教程能帮助你掌握Python数据处理与可视化的核心技能!