销售数据可视化分析项目

销售数据可视化分析项目

一、课程目标

本资料旨在教授如何使用 Python 进行销售数据的模拟生成、加载、分析和可视化,通过一系列实际需求案例,让学员掌握 Pandas、NumPy、Matplotlib 和 Seaborn 等库的基本使用方法。

二、课程内容

1. 导入必要的库和设置

python 复制代码
import pandas as pd  # 导入 Pandas 库,用于数据处理和分析
import numpy as np  # 导入 NumPy 库,用于数值计算
import matplotlib.pyplot as plt  # 导入 Matplotlib 库,用于数据可视化
import os  # 导入 os 库,用于操作系统相关操作,如文件和目录管理
import seaborn as sns  # 导入 Seaborn 库,用于更美观的数据可视化
from datetime import datetime, timedelta  # 导入 datetime 和 timedelta 类,用于日期和时间处理

# 设置中文字体,确保图表中的中文正常显示
plt.rcParams["font.family"] = ["SimHei"]
plt.rcParams["axes.unicode_minus"] = False  # 解决负号显示问题

# 创建必要的目录
os.makedirs('data', exist_ok=True)  # 创建 data 目录,用于保存数据文件
os.makedirs('img', exist_ok=True)  # 创建 img 目录,用于保存图表文件

2. 需求 1: 模拟销售数据并保存为 CSV 文件

python 复制代码
def generate_sales_data():
    """生成模拟销售数据并保存为 CSV 文件"""
    # 设置随机种子,确保结果可重现
    np.random.seed(42)

    # 生成 1000 条销售记录
    n_samples = 1000

    # 生成日期数据(过去一年的随机日期)
    start_date = datetime.now() - timedelta(days=365)  # 计算一年前的日期
    dates = [start_date + timedelta(days=np.random.randint(0, 365)) for _ in range(n_samples)]  # 生成随机日期列表

    # 生成产品类别
    categories = ['电子产品', '服装', '食品', '家居', '图书']
    products = {
        '电子产品': ['手机', '笔记本电脑', '平板电脑', '耳机', '相机'],
        '服装': ['T恤', '牛仔裤', '连衣裙', '外套', '鞋子'],
        '食品': ['巧克力', '饼干', '水果', '饮料', '零食'],
        '家居': ['沙发', '餐桌', '床', '台灯', '吸尘器'],
        '图书': ['小说', '教材', '漫画', '传记', '工具书']
    }

    # 为每个类别设置基本价格范围
    base_prices = {
        '电子产品': (1000, 5000),
        '服装': (50, 500),
        '食品': (10, 100),
        '家居': (500, 3000),
        '图书': (20, 200)
    }

    # 生成销售数据
    data = []
    for _ in range(n_samples):
        category = np.random.choice(categories)  # 随机选择一个产品类别
        product = np.random.choice(products[category])  # 从选定类别中随机选择一个产品
        price = np.random.randint(base_prices[category][0], base_prices[category][1])  # 随机生成产品价格
        quantity = np.random.randint(1, 10)  # 随机生成销售数量
        region = np.random.choice(['华东', '华北', '华南', '西南', '西北', '东北', '中部'])  # 随机选择销售地区
        customer_type = np.random.choice(['个人', '企业'])  # 随机选择客户类型

        # 计算销售额
        revenue = price * quantity

        # 计算利润(电子产品和家居利润率较高,食品较低)
        if category in ['电子产品', '家居']:
            profit_rate = np.random.uniform(0.2, 0.4)  # 电子产品和家居的利润率在 20% - 40% 之间
        elif category == '食品':
            profit_rate = np.random.uniform(0.05, 0.15)  # 食品的利润率在 5% - 15% 之间
        else:
            profit_rate = np.random.uniform(0.1, 0.3)  # 其他类别的利润率在 10% - 30% 之间
        profit = revenue * profit_rate

        data.append({
            '日期': dates[_].strftime('%Y-%m-%d'),  # 将日期转换为字符串格式
            '类别': category,
            '产品': product,
            '价格': price,
            '数量': quantity,
            '销售额': revenue,
            '利润': profit,
            '地区': region,
            '客户类型': customer_type
        })

    # 创建 DataFrame
    df = pd.DataFrame(data)

    # 保存数据到 CSV 文件
    file_path = 'data/sales_data.csv'
    df.to_csv(file_path, index=False, encoding='utf-8-sig')  # 将 DataFrame 保存为 CSV 文件
    print(f"销售数据已保存到 {file_path}")

    return df
python 复制代码
generate_sales_data()
复制代码
销售数据已保存到 data/sales_data.csv

| | 日期 | 类别 | 产品 | 价格 | 数量 | 销售额 | 利润 | 地区 | 客户类型 |
| 0 | 2024-10-21 | 食品 | 水果 | 42 | 6 | 252 | 15.987250 | 华北 | 企业 |
| 1 | 2025-06-24 | 服装 | 外套 | 435 | 8 | 3480 | 525.229896 | 华北 | 企业 |
| 2 | 2025-04-07 | 图书 | 小说 | 36 | 9 | 324 | 62.958137 | 华南 | 个人 |
| 3 | 2024-10-25 | 食品 | 巧克力 | 78 | 2 | 156 | 19.201533 | 东北 | 个人 |
| 4 | 2024-09-20 | 电子产品 | 笔记本电脑 | 3635 | 3 | 10905 | 3797.384136 | 华南 | 个人 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 995 | 2024-08-17 | 电子产品 | 笔记本电脑 | 1132 | 6 | 6792 | 1398.024382 | 中部 | 个人 |
| 996 | 2025-04-29 | 食品 | 巧克力 | 27 | 2 | 54 | 7.623330 | 西北 | 企业 |
| 997 | 2024-11-26 | 图书 | 小说 | 173 | 1 | 173 | 27.368579 | 华东 | 企业 |
| 998 | 2025-07-01 | 服装 | 牛仔裤 | 265 | 2 | 530 | 105.190907 | 华南 | 个人 |

999 2025-06-08 服装 T恤 296 6 1776 342.128440 东北 企业

1000 rows × 9 columns

3. 需求 2: 加载销售数据

python 复制代码
def load_sales_data():
    """加载销售数据"""
    try:
        df = pd.read_csv('data/sales_data.csv', encoding='utf-8-sig')  # 尝试读取 CSV 文件
        # 转换日期列
        df['日期'] = pd.to_datetime(df['日期'])  # 将日期列转换为 Pandas 的日期时间类型
        print("数据加载成功")
        return df
    except FileNotFoundError:
        print("数据文件不存在,正在生成模拟数据...")
        return generate_sales_data()  # 如果文件不存在,调用 generate_sales_data 函数生成模拟数据
python 复制代码
# 加载数据
df = load_sales_data()
复制代码
数据加载成功

4. 需求 3: 按产品类别分析销售情况,生成透视表并保存为 CSV

python 复制代码
def analyze_sales_by_category(df):
    """按产品类别分析销售情况"""
    # 创建透视表
    pivot_table = pd.pivot_table(
        df,
        index='类别',  # 以产品类别为行索引
        values=['销售额', '利润', '数量'],  # 分析的数值列
        aggfunc={
            '销售额': 'sum',  # 对销售额进行求和
            '利润': 'sum',  # 对利润进行求和
            '数量': 'sum'  # 对数量进行求和
        }
    )

    # 计算利润率
    pivot_table['利润率'] = (pivot_table['利润'] / pivot_table['销售额']).map(lambda x: f"{x:.2%}")  # 计算利润率并转换为百分比格式

    # 保存透视表到 CSV
    file_path = 'data/category_analysis.csv'
    pivot_table.to_csv(file_path, encoding='utf-8-sig')  # 将透视表保存为 CSV 文件
    print(f"类别分析数据已保存到 {file_path}")

    # 可视化
    fig, axes = plt.subplots(1, 3, figsize=(18, 6))  # 创建包含 3 个子图的图形

    # 销售额柱状图
    pivot_table['销售额'].plot(kind='bar', ax=axes[0], title='按类别销售额', color='skyblue')  # 绘制销售额柱状图
    for p in axes[0].patches:
        axes[0].annotate(f'{p.get_height():,.0f}',  # 在柱子上添加销售额数值注释
                         (p.get_x() + p.get_width() / 2., p.get_height()),
                         ha='center', va='center',
                         xytext=(0, 10),
                         textcoords='offset points')

    # 利润柱状图
    pivot_table['利润'].plot(kind='bar', ax=axes[1], title='按类别利润', color='lightgreen')  # 绘制利润柱状图
    for p in axes[1].patches:
        axes[1].annotate(f'{p.get_height():,.0f}',  # 在柱子上添加利润数值注释
                         (p.get_x() + p.get_width() / 2., p.get_height()),
                         ha='center', va='center',
                         xytext=(0, 10),
                         textcoords='offset points')

    # 利润率饼图
    profit_rate = pivot_table['利润'] / pivot_table['销售额']
    profit_rate.plot(kind='pie', ax=axes[2], title='按类别利润率', autopct='%1.2f%%', ylabel='')  # 绘制利润率饼图

    plt.tight_layout()  # 调整子图布局
    plt.savefig('img/category_analysis.png')  # 保存图形为 PNG 文件
    plt.show()
    plt.close()  # 关闭图形

    return pivot_table
python 复制代码
print("\n执行需求 3: 按产品类别分析销售情况")
category_analysis = analyze_sales_by_category(df)
复制代码
执行需求 3: 按产品类别分析销售情况
类别分析数据已保存到 data/category_analysis.csv

5. 需求 4: 按地区分析销售情况,生成交叉表并保存为 CSV

python 复制代码
def analyze_sales_by_region(df):
    """按地区分析销售情况"""
    # 创建交叉表 - 地区与产品类别的销售额
    cross_tab = pd.crosstab(
        index=df['地区'],  # 以地区为行索引
        columns=df['类别'],  # 以产品类别为列索引
        values=df['销售额'],  # 分析的数值列
        aggfunc='sum',  # 对销售额进行求和
        margins=True,  # 显示总计行和列
        margins_name='总计'
    ).fillna(0)  # 将缺失值填充为 0

    # 保存交叉表到 CSV
    file_path = 'data/region_analysis.csv'
    cross_tab.to_csv(file_path, encoding='utf-8-sig')  # 将交叉表保存为 CSV 文件
    print(f"地区分析数据已保存到 {file_path}")

    # 可视化 - 热力图
    plt.figure(figsize=(12, 8))  # 创建图形
    sns.heatmap(cross_tab.iloc[:-1, :-1], annot=True, fmt='.0f', cmap='YlGnBu', cbar=True)  # 绘制热力图
    plt.title('地区与产品类别的销售额交叉表')  # 设置图形标题
    plt.tight_layout()  # 调整图形布局
    plt.savefig('img/region_heatmap.png')  # 保存图形为 PNG 文件
    plt.show()
    plt.close()  # 关闭图形

    return cross_tab
python 复制代码
print("\n执行需求 4: 按地区分析销售情况")
region_analysis = analyze_sales_by_region(df)
复制代码
执行需求 4: 按地区分析销售情况
地区分析数据已保存到 data/region_analysis.csv

6. 需求 5: 按季度分析销售趋势

python 复制代码
def analyze_sales_trend(df):
    """按季度分析销售趋势"""
    # 提取季度信息
    df['季度'] = df['日期'].dt.to_period('Q')  # 从日期列中提取季度信息

    # 创建透视表
    trend_pivot = pd.pivot_table(
        df,
        index='季度',  # 以季度为行索引
        values=['销售额', '利润', '数量'],  # 分析的数值列
        aggfunc='sum'  # 对销售额、利润和数量进行求和
    ).reset_index()  # 重置索引

    # 转换季度为字符串格式
    trend_pivot['季度'] = trend_pivot['季度'].astype(str)  # 将季度列转换为字符串类型

    # 保存趋势数据到 CSV
    file_path = 'data/sales_trend.csv'
    trend_pivot.to_csv(file_path, index=False, encoding='utf-8-sig')  # 将透视表保存为 CSV 文件
    print(f"销售趋势数据已保存到 {file_path}")

    # 可视化 - 折线图
    plt.figure(figsize=(12, 6))  # 创建图形

    # 销售额趋势
    plt.subplot(2, 1, 1)  # 创建第一个子图
    plt.plot(trend_pivot['季度'], trend_pivot['销售额'], marker='o', color='skyblue', label='销售额')  # 绘制销售额折线图
    for x, y in zip(trend_pivot['季度'], trend_pivot['销售额']):
        plt.annotate(f'{y:,.0f}', (x, y), textcoords='offset points',  # 在折线上添加销售额数值注释
                     xytext=(0, 10), ha='center')
    plt.title('季度销售趋势', loc = 'right')  # 设置子图标题
    plt.ylabel('销售额')  # 设置 y 轴标签
    plt.legend()  # 显示图例

    # 利润率趋势
    plt.subplot(2, 1, 2)  # 创建第二个子图
    profit_rate = trend_pivot['利润'] / trend_pivot['销售额']
    plt.plot(trend_pivot['季度'], profit_rate, marker='o', color='lightgreen', label='利润率')  # 绘制利润率折线图
    for x, y in zip(trend_pivot['季度'], profit_rate):
        plt.annotate(f'{y:.2%}', (x, y), textcoords='offset points',  # 在折线上添加利润率数值注释
                     xytext=(0, 10), ha='center')
    plt.xlabel('季度')  # 设置 x 轴标签
    plt.ylabel('利润率')  # 设置 y 轴标签
    plt.legend()  # 显示图例

    plt.tight_layout()  # 调整子图布局
    plt.savefig('img/sales_trend.png')  # 保存图形为 PNG 文件
    plt.show()
    plt.close()  # 关闭图形

    return trend_pivot
python 复制代码
print("\n执行需求 5: 按季度分析销售趋势")
sales_trend = analyze_sales_trend(df)
复制代码
执行需求 5: 按季度分析销售趋势
销售趋势数据已保存到 data/sales_trend.csv

7. 需求 6: 分析不同客户类型的购买偏好

python 复制代码
def analyze_customer_preference(df):
    """分析不同客户类型的购买偏好"""
    # 创建交叉表 - 客户类型与产品类别的购买数量
    preference_crosstab = pd.crosstab(
        index=df['客户类型'],  # 以客户类型为行索引
        columns=df['类别'],  # 以产品类别为列索引
        values=df['数量'],  # 分析的数值列
        aggfunc='sum',  # 对购买数量进行求和
        margins=True,  # 显示总计行和列
        margins_name='总计'
    ).fillna(0)  # 将缺失值填充为 0

    # 计算占比 - 使用 DataFrame.map 替代已弃用的 applymap
    preference_percentage = preference_crosstab.div(preference_crosstab['总计'], axis=0)  # 计算每个客户类型对各产品类别的购买数量占比
    for col in preference_percentage.columns:
        preference_percentage[col] = preference_percentage[col].map(lambda x: f"{x:.2%}")  # 将占比转换为百分比格式

    # 保存数据到 CSV
    file_path = 'data/customer_preference.csv'
    preference_percentage.to_csv(file_path, encoding='utf-8-sig')  # 将数据保存为 CSV 文件
    print(f"客户偏好数据已保存到 {file_path}")

    # 可视化 - 堆叠柱状图
    plt.figure(figsize=(12, 6))  # 创建图形
    preference_crosstab.iloc[:-1, :-1].plot(kind='bar', stacked=True, ax=plt.gca())  # 绘制堆叠柱状图
    plt.title('不同客户类型的购买偏好')  # 设置图形标题
    plt.xlabel('客户类型')  # 设置 x 轴标签
    plt.ylabel('购买数量')  # 设置 y 轴标签
    plt.legend(title='产品类别')  # 显示图例
    plt.tight_layout()  # 调整图形布局
    plt.savefig('img/customer_preference.png')  # 保存图形为 PNG 文件
    plt.show()
    plt.close()  # 关闭图形

    return preference_percentage
python 复制代码
print("\n执行需求 6: 分析不同客户类型的购买偏好")
customer_preference = analyze_customer_preference(df)
复制代码
执行需求 6: 分析不同客户类型的购买偏好
客户偏好数据已保存到 data/customer_preference.csv

8. 需求 7: 分析销售额最高的前10个产品

python 复制代码
def analyze_top_products(df):
    """分析销售额最高的前10个产品"""
    # 按产品分组并计算总销售额
    top_products = df.groupby('产品')['销售额'].sum().sort_values(ascending=False).head(10).reset_index()  # 按产品分组,计算总销售额,排序并取前 10 个产品

    # 保存数据到 CSV
    file_path = 'data/top_products.csv'
    top_products.to_csv(file_path, index=False, encoding='utf-8-sig')  # 将数据保存为 CSV 文件
    print(f"Top 10 产品数据已保存到 {file_path}")

    # 可视化 - 水平柱状图
    plt.figure(figsize=(10, 6))  # 创建图形
    top_products.plot(kind='barh', x='产品', y='销售额', ax=plt.gca(), legend=False)  # 绘制水平柱状图
    plt.title('销售额最高的前10个产品')  # 设置图形标题
    plt.xlabel('销售额')  # 设置 x 轴标签
    plt.ylabel('产品')  # 设置 y 轴标签
    for i, v in enumerate(top_products['销售额']):
        plt.text(v + 1000, i, f'{v:,.0f}', va='center')  # 在柱子上添加销售额数值注释
    plt.tight_layout()  # 调整图形布局
    plt.savefig('img/top_products.png')  # 保存图形为 PNG 文件
    plt.show()
    plt.close()  # 关闭图形

    return top_products
python 复制代码
print("\n执行需求 7: 分析销售额最高的前10个产品")
top_products = analyze_top_products(df)
复制代码
执行需求 7: 分析销售额最高的前10个产品
Top 10 产品数据已保存到 data/top_products.csv

9. 需求 8: 分析各地区的客户类型分布

python 复制代码
def analyze_region_customer_type(df):
    """分析各地区的客户类型分布"""
    # 创建透视表
    region_customer_pivot = pd.pivot_table(
        df,
        index='地区',  # 以地区为行索引
        columns='客户类型',  # 以客户类型为列索引
        values='销售额',  # 分析的数值列
        aggfunc='sum',  # 对销售额进行求和
        fill_value=0  # 将缺失值填充为 0
    )

    # 计算各地区客户类型占比
    region_customer_percentage = region_customer_pivot.div(region_customer_pivot.sum(axis=1), axis=0)  # 计算每个地区不同客户类型的销售额占比

    # 保存数据到 CSV
    file_path = 'data/region_customer_type.csv'
    region_customer_percentage.to_csv(file_path, encoding='utf-8-sig')  # 将数据保存为 CSV 文件
    print(f"地区客户类型分布数据已保存到 {file_path}")

    # 可视化 - 饼图
    fig, axes = plt.subplots(2, 4, figsize=(16, 8))  # 创建包含 8 个子图的图形
    axes = axes.flatten()  # 将子图数组展平

    regions = region_customer_percentage.index.tolist()  # 获取地区列表
    for i, region in enumerate(regions):
        if i < len(axes):
            region_customer_percentage.loc[region].plot(
                kind='pie',
                ax=axes[i],
                autopct='%1.1f%%',
                title=f'{region} 客户类型分布',
                ylabel=''
            )  # 为每个地区绘制客户类型分布饼图

    plt.tight_layout()  # 调整子图布局
    plt.savefig('img/region_customer_type.png')  # 保存图形为 PNG 文件
    plt.show()
    plt.close()  # 关闭图形

    return region_customer_percentage
python 复制代码
print("\n执行需求 8: 分析各地区的客户类型分布")
region_customer_type = analyze_region_customer_type(df)
复制代码
执行需求 8: 分析各地区的客户类型分布
地区客户类型分布数据已保存到 data/region_customer_type.csv

10. 需求 9: 分析价格与销售额、利润的关系

python 复制代码
def analyze_price_relationship(df):
    """分析价格与销售额、利润的关系"""
    # 计算每个产品的平均价格、总销售额和总利润
    product_stats = df.groupby('产品').agg({
        '价格': 'mean',  # 计算每个产品的平均价格
        '销售额': 'sum',  # 计算每个产品的总销售额
        '利润': 'sum'  # 计算每个产品的总利润
    }).reset_index()  # 重置索引

    # 保存数据到 CSV
    file_path = 'data/price_relationship.csv'
    product_stats.to_csv(file_path, index=False, encoding='utf-8-sig')  # 将数据保存为 CSV 文件
    print(f"价格关系数据已保存到 {file_path}")

    # 可视化 - 散点图矩阵
    g = sns.pairplot(product_stats, vars=['价格', '销售额', '利润'], hue='产品', palette='husl')  # 绘制散点图矩阵
    plt.suptitle('价格、销售额和利润的关系', y=1.02)  # 设置图形总标题
    plt.tight_layout()  # 调整图形布局
    plt.savefig('img/price_relationship.png')  # 保存图形为 PNG 文件
    plt.show()
    plt.close()  # 关闭图形

    # 计算相关系数矩阵
    correlation = product_stats[['价格', '销售额', '利润']].corr()  # 计算价格、销售额和利润之间的相关系数矩阵

    return correlation
python 复制代码
print("\n执行需求 9: 分析价格与销售额、利润的关系")
price_relationship = analyze_price_relationship(df)
复制代码
执行需求 9: 分析价格与销售额、利润的关系
价格关系数据已保存到 data/price_relationship.csv

11. 需求 10: 综合分析报告 - 生成摘要统计信息

python 复制代码
def generate_summary_report(df):
    """生成综合分析报告"""
    # 计算关键指标
    total_sales = df['销售额'].sum()  # 计算总销售额
    total_profit = df['利润'].sum()  # 计算总利润
    total_quantity = df['数量'].sum()  # 计算总销售量
    average_price = df['价格'].mean()  # 计算平均价格
    profit_rate = total_profit / total_sales  # 计算利润率

    # 找出最畅销的产品类别和地区
    top_category = df.groupby('类别')['销售额'].sum().idxmax()  # 找出销售额最高的产品类别
    top_region = df.groupby('地区')['销售额'].sum().idxmax()  # 找出销售额最高的地区

    # 创建摘要数据
    summary_data = {
        '指标': ['总销售额', '总利润', '总销售量', '平均价格', '利润率', '最畅销类别', '最畅销地区'],
        '数值': [
            f'{total_sales:,.2f}',
            f'{total_profit:,.2f}',
            f'{total_quantity:,}',
            f'{average_price:,.2f}',
            f'{profit_rate:.2%}',
            top_category,
            top_region
        ]
    }

    # 创建 DataFrame
    summary_df = pd.DataFrame(summary_data)

    # 保存摘要报告
    file_path = 'data/summary_report.csv'
    summary_df.to_csv(file_path, index=False, encoding='utf-8-sig')  # 将摘要报告保存为 CSV 文件
    print(f"摘要报告已保存到 {file_path}")

    return summary_df
python 复制代码
print("\n执行需求 10: 生成综合分析报告")
summary_report = generate_summary_report(df)

print("\n数据分析项目完成!")
print("数据文件已保存到 data 目录")
print("图表已保存到 img 目录")

# 打印摘要报告
print("\n项目摘要报告:")
print(summary_report.to_string(index=False))
复制代码
执行需求 10: 生成综合分析报告
摘要报告已保存到 data/summary_report.csv

数据分析项目完成!
数据文件已保存到 data 目录
图表已保存到 img 目录

项目摘要报告:
   指标           数值
 总销售额 4,839,533.00
  总利润 1,377,496.93
 总销售量        5,023
 平均价格       978.16
  利润率       28.46%
最畅销类别         电子产品
最畅销地区           西南
相关推荐
在努力的韩小豪37 分钟前
如何从0开始构建自己的第一个AI应用?(Prompt工程、Agent自定义、Tuning)
人工智能·python·llm·prompt·agent·ai应用·mcp
linT_T1 小时前
数字化管理新趋势:权限分级看板如何筑牢安全防线
信息可视化
Leo.yuan1 小时前
数据清洗(ETL/ELT)原理与工具选择指南:企业数字化转型的核心引擎
大数据·数据仓库·数据挖掘·数据分析·etl
Otaku love travel2 小时前
实施运维文档
运维·windows·python
测试老哥2 小时前
软件测试之单元测试
自动化测试·软件测试·python·测试工具·职场和发展·单元测试·测试用例
presenttttt3 小时前
用Python和OpenCV从零搭建一个完整的双目视觉系统(六 最终篇)
开发语言·python·opencv·计算机视觉
测试19984 小时前
软件测试之压力测试总结
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·压力测试
isNotNullX5 小时前
实时数仓和离线数仓还分不清楚?看完就懂了
大数据·数据库·数据仓库·人工智能·数据分析
烛阴5 小时前
带参数的Python装饰器原来这么简单,5分钟彻底掌握!
前端·python