销售数据可视化分析项目

销售数据可视化分析项目

一、课程目标

本资料旨在教授如何使用 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%
最畅销类别         电子产品
最畅销地区           西南
相关推荐
川石课堂软件测试8 分钟前
自动化测试的基本概念及常用框架
数据库·python·功能测试·测试工具·单元测试·自动化·流程图
灰勒塔德11 分钟前
jetson orin nano super开发指南
linux·服务器·python
82782093719 分钟前
python scp 备份
开发语言·python
poggioxay30 分钟前
JAVA零基础入门知识3(持续更新中)
java·开发语言·python
serve the people40 分钟前
TensorFlow 基础训练循环(简化版 + 补全代码)
人工智能·python·tensorflow
木里先森41 分钟前
解决报错:/lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32‘ not found
linux·python
爱打代码的小林44 分钟前
numpy库数组笔记
笔记·python·numpy
Misnice1 小时前
pip 查看当前包列表
windows·python·pip
qq_356196951 小时前
day29异常处理@浙大疏锦行
python
互亿无线明明1 小时前
如何为全球业务构建可扩展的“群发国际短信接口”?
java·c++·python·golang·eclipse·php·erlang