客户消费数据分析
程序主要功能模块说明:
-
数据生成模块
- 使用Faker库生成真实感的用户信息
- 通过正态分布模拟收入和消费金额等连续变量
- 设置合理的业务逻辑关系(如会员才有会员等级)
-
数据处理模块
- 缺失值处理:针对不同字段特点采用不同填充策略
- 异常值过滤:移除不符合实际业务场景的极端值
- 特征工程:创建衍生变量"购买活跃度"用于分层分析
-
数据分析模块
- 描述性统计:获取数据整体概况
- 分组分析:对比会员与非会员、不同地区的消费差异
- 相关性分析:识别影响消费金额的关键因素
-
数据可视化模块
- 多张子图布局:一次性展示多个维度的分析结果
- 统计图表:直方图、柱状图、散点图、热图、饼图等
- 图表保存:将结果保存为图片文件便于后续使用
所有核心步骤都有详细的错误处理和进度提示,确保程序运行的稳定性和可维护性。
数据结构说明:
这个程序实现了完整的数据处理流程,包括模拟数据生成、数据保存、数据清洗、数据分析和可视化。以下是数据结构说明:
字段名称 | 字段描述 | 数据类型 |
---|---|---|
用户ID | 唯一标识用户的ID | 字符串 |
性别 | 用户性别 | 字符串 |
年龄 | 用户年龄 | 整数 |
教育程度 | 用户教育水平 | 字符串 |
收入 | 用户月收入 | 整数 |
地区 | 用户所在地区 | 字符串 |
是否会员 | 用户是否为会员 | 布尔值 |
会员天数 | 用户成为会员的天数 | 整数 |
会员等级 | 用户的会员等级 | 字符串 |
上次购买日期 | 用户上次购买的日期 | 日期 |
购买频率 | 用户在一定时期内的购买次数 | 整数 |
总消费金额 | 用户的总消费金额 | 整数 |
平均订单金额 | 用户平均每次订单的金额 | 浮点数 |
是否响应促销 | 用户是否对促销活动做出响应 | 布尔值 |
折扣力度 | 用户使用的折扣比例 | 浮点数 |
购买活跃度 | 根据购买频率划分的活跃度等级 | 分类变量 |
程序运行后会生成以下分析结果:
- 保存模拟数据到CSV文件
- 输出基本统计信息和关键分析指标
- 生成多张子图展示用户特征分布、地区消费差异、消费行为模式和相关性分析
- 生成会员等级分布图
所有图表都会保存为PNG文件,方便进一步分析和展示。
代码
import pandas as pd # 数据处理和分析库
import numpy as np # 数值计算库
import matplotlib.pyplot as plt # 数据可视化库
import seaborn as sns # 高级数据可视化库
from faker import Faker # 生成模拟数据
import random # 随机数生成
from datetime import datetime, timedelta # 日期时间处理
# 配置matplotlib支持中文字体和LaTeX数学符号
plt.rcParams.update({
# 优先使用中文字体,同时保留serif用于LaTeX数学符号
"font.family": ["SimHei", "serif"],
"mathtext.fontset": "cm", # 使用Computer Modern字体渲染数学符号
"axes.unicode_minus": False, # 解决负号显示问题
"text.usetex": False, # 不强制使用外部LaTeX,依赖matplotlib内置渲染
})
# 设置随机种子确保结果可复现
np.random.seed(42)
random.seed(42)
# 模拟数据生成函数
def generate_sample_data(n=1000):
fake = Faker('zh_CN') # 创建中文数据生成器
data = [] # 存储生成的数据
for _ in range(n): # 生成n条记录
# 用户基本信息
user_id = fake.uuid4() # 生成唯一用户ID
gender = random.choice(['男', '女']) # 随机选择性别
age = random.randint(18, 70) # 随机生成18-70岁的年龄
education = random.choice(['高中及以下', '本科', '硕士', '博士']) # 随机教育程度
income = max(0, int(np.random.normal(8000, 3000))) # 收入符合正态分布
region = random.choice(['华东', '华南', '华北', '西南', '西北', '东北', '华中']) # 随机地区
# 会员信息
is_member = random.choice([True, False]) # 是否为会员
member_days = random.randint(0, 365) if is_member else None # 会员天数
membership_level = random.choice(['普通会员', '银卡会员', '金卡会员', '钻石会员']) if is_member else None # 会员等级
# 消费信息
last_purchase_date = (datetime.now() - timedelta(days=random.randint(0, 180))).strftime('%Y-%m-%d') # 上次购买日期
purchase_frequency = max(0, int(np.random.normal(5, 3))) # 购买频率符合正态分布
total_spend = max(0, int(np.random.normal(2000, 1000))) # 总消费金额符合正态分布
avg_order_value = total_spend / max(1, purchase_frequency) # 平均订单金额
# 促销响应
responded_to_promo = random.choices([True, False], weights=[0.3, 0.7])[0] # 30%概率响应促销
discount_used = round(random.uniform(0.05, 0.3), 2) if responded_to_promo else None # 折扣力度
# 将生成的数据添加到列表
data.append({
'用户ID': user_id,
'性别': gender,
'年龄': age,
'教育程度': education,
'收入': income,
'地区': region,
'是否会员': is_member,
'会员天数': member_days,
'会员等级': membership_level,
'上次购买日期': last_purchase_date,
'购买频率': purchase_frequency,
'总消费金额': total_spend,
'平均订单金额': avg_order_value,
'是否响应促销': responded_to_promo,
'折扣力度': discount_used
})
return pd.DataFrame(data) # 转换为DataFrame返回
# 数据保存函数
def save_to_csv(df, filename='customer_data.csv'):
try:
df.to_csv(filename, index=False, encoding='utf-8-sig') # 保存为CSV文件
print(f"数据已成功保存到 {filename}")
except Exception as e:
print(f"保存文件时出错: {e}") # 异常处理
# 数据清洗函数
def clean_data(df):
cleaned_df = df.copy() # 复制数据避免修改原始数据
# 处理缺失值:将会员相关的缺失值填充为合理值
cleaned_df['会员天数'] = cleaned_df['会员天数'].fillna(0)
cleaned_df['会员等级'] = cleaned_df['会员等级'].fillna('非会员')
cleaned_df['折扣力度'] = cleaned_df['折扣力度'].fillna(0)
# 处理异常值:过滤掉收入和消费金额过高的异常记录
cleaned_df = cleaned_df[(cleaned_df['收入'] < 50000) & (cleaned_df['总消费金额'] < 100000)]
# 转换数据类型:将日期字符串转换为日期类型
cleaned_df['上次购买日期'] = pd.to_datetime(cleaned_df['上次购买日期'])
# 添加派生特征:根据购买频率创建分类特征
cleaned_df['购买活跃度'] = pd.cut(cleaned_df['购买频率'],
bins=[0, 2, 5, 10, float('inf')],
labels=['低', '中', '高', '极高'])
return cleaned_df
# 数据分析函数
def analyze_data(df):
# 输出基本统计信息
print("\n数据基本统计信息:")
print(df.describe()) # 描述性统计
# 分析会员与非会员消费差异
member_stats = df.groupby('是否会员')['总消费金额'].mean()
print("\n会员与非会员平均消费金额对比:")
print(member_stats)
# 分析不同地区消费差异
region_stats = df.groupby('地区')['总消费金额'].mean().sort_values(ascending=False)
print("\n各地区平均消费金额:")
print(region_stats)
# 相关性分析:计算数值列与总消费金额的相关性
numeric_cols = ['年龄', '收入', '会员天数', '购买频率', '总消费金额', '平均订单金额', '折扣力度']
correlation = df[numeric_cols].corr()
print("\n变量相关性分析:")
print(correlation['总消费金额'].sort_values(ascending=False))
return correlation # 返回相关系数矩阵
# 数据可视化函数
def visualize_data(df, correlation):
plt.figure(figsize=(15, 10)) # 设置图表大小
# 1. 年龄分布直方图
plt.subplot(2, 2, 1) # 创建2x2网格的第1个子图
sns.histplot(df['年龄'], bins=20, kde=True) # 绘制直方图和核密度估计
plt.title('用户年龄分布') # 设置标题
# 2. 不同地区消费金额对比
plt.subplot(2, 2, 2)
region_spend = df.groupby('地区')['总消费金额'].mean().reset_index()
# 修复FutureWarning:添加hue参数并设置legend=False
sns.barplot(x='地区', y='总消费金额', data=region_spend, palette='viridis',
hue='地区', legend=False)
plt.title('各地区平均消费金额对比')
# 3. 消费金额与购买频率散点图
plt.subplot(2, 2, 3)
sns.scatterplot(x='购买频率', y='总消费金额', hue='是否会员', data=df) # 绘制散点图
plt.title('购买频率与总消费金额关系')
# 4. 相关性热图
plt.subplot(2, 2, 4)
sns.heatmap(correlation, annot=True, cmap='coolwarm', fmt='.2f', square=True) # 绘制热图
plt.title('变量相关性热图')
plt.tight_layout() # 自动调整子图布局
plt.savefig('data_visualization.png', dpi=300, bbox_inches='tight') # 保存图表
plt.show() # 显示图表
# 5. 会员等级分布饼图
plt.figure(figsize=(8, 6)) # 创建新图表
member_levels = df[df['是否会员']]['会员等级'].value_counts() # 统计会员等级分布
plt.pie(member_levels, labels=member_levels.index, autopct='%1.1f%%', startangle=90) # 绘制饼图
plt.title('会员等级分布')
plt.axis('equal') # 使饼图为正圆形
plt.savefig('member_distribution.png', dpi=300, bbox_inches='tight')
plt.show()
# 主函数:程序入口点
def main():
# 1. 生成模拟数据
print("正在生成模拟数据...")
df = generate_sample_data(1000)
# 2. 保存数据
save_to_csv(df)
# 3. 读取数据
print("\n正在读取数据...")
loaded_df = pd.read_csv('customer_data.csv')
# 4. 数据清洗
print("\n正在进行数据清洗...")
cleaned_df = clean_data(loaded_df)
# 5. 数据分析
print("\n正在进行数据分析...")
correlation = analyze_data(cleaned_df)
# 6. 数据可视化
print("\n正在生成数据可视化图表...")
visualize_data(cleaned_df, correlation)
if __name__ == "__main__":
main()
运行结果
正在生成模拟数据...
数据已成功保存到 customer_data.csv
正在读取数据...
正在进行数据清洗...
正在进行数据分析...
数据基本统计信息:
年龄 收入 会员天数 上次购买日期 \
count 1000.000000 1000.000000 1000.000000 1000
mean 44.775000 8166.665000 94.670000 2025-02-27 21:15:50.400000256
min 18.000000 0.000000 0.000000 2024-12-05 00:00:00
25% 32.000000 6246.000000 0.000000 2025-01-13 00:00:00
50% 45.000000 8170.000000 21.000000 2025-02-28 12:00:00
75% 58.000000 9992.500000 188.000000 2025-04-11 00:00:00
max 70.000000 19778.000000 365.000000 2025-06-03 00:00:00
std 15.287841 2904.390826 117.978184 NaN
购买频率 总消费金额 平均订单金额 折扣力度
count 1000.000000 1000.000000 1000.000000 1000.000000
mean 4.560000 2054.679000 739.530832 0.050890
min 0.000000 0.000000 0.000000 0.000000
25% 2.000000 1395.750000 263.900000 0.000000
50% 4.000000 2041.500000 455.137500 0.000000
75% 7.000000 2679.250000 874.750000 0.080000
max 14.000000 5852.000000 4445.000000 0.300000
std 2.898068 961.284906 779.612809 0.089239
会员与非会员平均消费金额对比:
是否会员
False 2035.957983
True 2071.685115
Name: 总消费金额, dtype: float64
各地区平均消费金额:
地区
西南 2141.916667
西北 2079.544828
华南 2067.291045
华北 2058.568345
华东 2029.803150
东北 2016.153333
华中 1984.161074
Name: 总消费金额, dtype: float64
变量相关性分析:
总消费金额 1.000000
平均订单金额 0.446292
购买频率 0.030452
会员天数 0.024801
折扣力度 0.010037
年龄 -0.006626
收入 -0.019257
Name: 总消费金额, dtype: float64
正在生成数据可视化图表...