# 勤奋的凯尔森同学10000h刻意练习Day5:综合应用案例——Kaggle电商客户行为分析
所属专栏: 凯尔森的10000h刻意练习
Slogan: 一个36岁程序员, 研究生(学硕),前世界500强top20软件开发Java工程师,用10000小时深耕AI, 目标Top10 AI资深工程师, 全程日更记录。
tips: 文章末尾附有jupyter完整代码
在学习了NumPy、Pandas以及多种可视化工具后,我们通过一个真实的Kaggle数据集来串联所有知识点。本案例将使用E-Commerce Customer Behavior & Sales Dataset - TR(土耳其电商客户行为数据集),该数据集包含5000条真实交易记录,涵盖了客户demographics、购买行为、产品偏好和engagement指标等多个维度。
# 1.1 案例背景与目标
数据集来源:Kaggle平台上的"E-Commerce Customer Behavior & Sales Analysis -TR"数据集,我们使用的是ecommerce_customer_behavior_dataset.csv这个文件,还有一个ecommerce_customer_behavior_dataset_v2.csv的版本,数据量有1.7W+。
数据集概览:
- 记录数:5000条交易记录
- 时间范围:2023年1月至2024年3月
- 字段数:18列
- 数据质量:无缺失值,格式一致
字段说明:
| 字段名 | 类型 | 说明 |
|---|---|---|
| Order_ID | 字符串 | 唯一订单标识 |
| Customer_ID | 字符串 | 唯一客户标识 |
| Date | 日期 | 交易日期 |
| Age | 整数 | 客户年龄(18-75岁) |
| Gender | 字符串 | 性别(Male/Female/Other) |
| City | 字符串 | 客户所在城市 |
| Product_Category | 字符串 | 产品类别(8类) |
| Unit_Price | 浮点数 | 单价 |
| Quantity | 整数 | 购买数量(1-5) |
| Discount_Amount | 浮点数 | 折扣金额 |
| Total_Amount | 浮点数 | 最终支付金额 |
| Payment_Method | 字符串 | 支付方式 |
| Device_Type | 字符串 | 设备类型(Mobile/Desktop/Tablet) |
| Session_Duration_Minutes | 整数 | 会话时长(1-120分钟) |
| Pages_Viewed | 整数 | 浏览页面数(1-50) |
| Is_Returning_Customer | 布尔值 | 是否回头客 |
| Delivery_Time_Days | 整数 | 配送天数(1-30天) |
| Customer_Rating | 整数 | 客户评分(1-5星) |
分析目标:
- 客户画像分析:了解不同年龄、性别、地区的客户消费特征
- 销售趋势分析:识别季节性模式和销售高峰期
- 产品类别表现:比较各类别的销售额、评分和退货情况
- 设备行为分析:不同设备类型的购买行为差异
- 客户忠诚度分析:回头客与新客户的行为对比
- 配送与满意度关系:分析配送时间对客户评分的影响
# 1.2 数据获取与加载
# 1.2.1 从Kaggle下载数据集
方式一:直接从Kaggle网站下载
- 访问https://www.kaggle.com/datasets/umuttuygurr/e-commerce-customer-behavior-and-sales-analysis-tr
- 点击"Download"按钮下载CSV文件
方式二:使用Kaggle API(推荐,便于复现)
# 安装Kaggle API
pip install kaggle
# 配置API凭证(需要先在Kaggle账号中创建API token)
# 将下载的kaggle.json放在/Users/kelsen/Code/Jupyter/目录下
# 下载数据集
kaggle datasets download -d umuttuygurr/e-commerce-customer-behavior-and-sales-analysis-tr -p /Users/kelsen/Code/Jupyter/
# 解压
unzip /usr/software/jupyter/e-commerce-customer-behavior-and-sales-analysis-tr.zip -d /Users/kelsen/Code/Jupyter/
2
3
4
5
6
7
8
9
10
# 1.2.2 加载数据集
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
# 设置中文显示(如果需要在图中显示中文)
plt.rcParams['font.sans-serif'] = ['PingFang SC'] # 苹方,macOS默认中文字体
plt.rcParams['axes.unicode_minus'] = False
# 加载数据
df = pd.read_csv('ecommerce_customer_behavior_dataset.csv') # 文件名根据实际下载情况调整
# 查看数据基本信息
print("数据集形状:", df.shape)
print("\n数据前5行:")
df.head()
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 1.2.3 初步探索
# 数据概览
df.info()
# 描述性统计
df.describe(include='all')
# 检查缺失值
print("缺失值统计:")
print(df.isnull().sum()) # 根据数据集说明,应该无缺失值
# 数据类型确认
print("\n数据类型:")
print(df.dtypes)
2
3
4
5
6
7
8
9
10
11
12
13
# 1.3 数据清洗与预处理
根据数据集说明,该数据集已经过清洗,无缺失值。但为了教学完整性,我们仍然进行一些必要的预处理。
# 1.3.1 数据类型转换
# 将Date列转换为datetime类型
df['Date'] = pd.to_datetime(df['Date'])
# 将Is_Returning_Customer转换为整数(0/1)
df['Is_Returning_Customer'] = df['Is_Returning_Customer'].astype(int)
# 确认转换后的类型
print(df.dtypes)
2
3
4
5
6
7
8
# 1.3.2 添加衍生特征
# 提取时间相关特征
df['Year'] = df['Date'].dt.year
df['Month'] = df['Date'].dt.month
df['Quarter'] = df['Date'].dt.quarter
df['DayOfWeek'] = df['Date'].dt.dayofweek # 0=周一, 6=周日
df['IsWeekend'] = (df['DayOfWeek'] >= 5).astype(int)
# 计算平均单价(验证Unit_Price * Quantity - Discount = Total_Amount)
df['Calculated_Total'] = df['Unit_Price'] * df['Quantity'] - df['Discount_Amount']
df['Amount_Check'] = np.abs(df['Calculated_Total'] - df['Total_Amount']) < 0.01
print("金额计算验证通过率:", df['Amount_Check'].mean() * 100, "%")
# 计算折扣率
df['Discount_Rate'] = (df['Discount_Amount'] / (df['Unit_Price'] * df['Quantity'])) * 100
# 无折扣的为0
df['Discount_Rate'] = df['Discount_Rate'].fillna(0)
# 创建年龄分组
bins = [0, 25, 35, 45, 55, 100]
labels = ['18-25', '26-35', '36-45', '46-55', '56+']
df['Age_Group'] = pd.cut(df['Age'], bins=bins, labels=labels, right=False)
# 创建评分分组
df['Rating_Group'] = pd.cut(df['Customer_Rating'],
bins=[0, 2, 3, 4, 5],
labels=['低分(1-2)', '中低分(3)', '中高分(4)', '高分(5)'])
print("衍生特征添加完成")
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
# 1.3.3 异常值检测
# 使用箱线图检测异常值
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
numeric_cols = ['Age', 'Unit_Price', 'Quantity', 'Total_Amount',
'Session_Duration_Minutes', 'Delivery_Time_Days']
for i, col in enumerate(numeric_cols):
row, col_idx = i // 3, i % 3 # 主要是为了拼凑axes[row, col_idx]
axes[row, col_idx].boxplot(df[col]) # col='Age', ...
axes[row, col_idx].set_title(f'{col} 箱线图')
axes[row, col_idx].set_ylabel('值')
plt.tight_layout()
plt.show()
# 使用IQR方法识别异常值
# IQR规则:通常将低于Q1-1.5×IQR或高于Q3+1.5×IQR的值视为异常值。这是统计学中常用的识别离群点的标准
def detect_outliers_iqr(data, column):
Q1 = data[column].quantile(0.25)
Q3 = data[column].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
outliers = data[(data[column] < lower_bound) | (data[column] > upper_bound)]
return outliers, lower_bound, upper_bound
for col in numeric_cols:
outliers, lb, ub = detect_outliers_iqr(df, col)
print(f"{col}: 异常值数量 {len(outliers)} ({len(outliers)/len(df)*100:.2f}%)")
# 对于异常值,我们保留但标记
df['Is_High_Value'] = (df['Total_Amount'] > df['Total_Amount'].quantile(0.95)).astype(int)
df['Is_Long_Delivery'] = (df['Delivery_Time_Days'] > df['Delivery_Time_Days'].quantile(0.95)).astype(int)
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
# 1.4 探索性数据分析(EDA)
# 1.4.1 整体业务概况
# 关键指标汇总
total_sales = df['Total_Amount'].sum()
total_orders = df['Order_ID'].nunique()
total_customers = df['Customer_ID'].nunique()
avg_order_value = total_sales / total_orders
avg_rating = df['Customer_Rating'].mean() # 客户评分
returning_rate = df['Is_Returning_Customer'].mean() * 100 #是否回头客
print("="*50)
print("业务概况")
print("="*50)
print(f"总销售额: {total_sales:,.2f} TRY")
print(f"总订单数: {total_orders}")
print(f"总客户数: {total_customers}")
print(f"平均客单价: {avg_order_value:.2f} TRY")
print(f"平均客户评分: {avg_rating:.2f}/5.0")
print(f"回头客比例: {returning_rate:.1f}%")
print(f"移动端交易占比: {(df['Device_Type']=='Mobile').mean()*100:.1f}%") # 数据集显示约55%
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 1.4.2 销售趋势分析
# 月度销售额趋势
# df['Date'].dt.to_period('M'):将Date列转换为月度周期(例如2023-01),用于按月份分组
# .groupby(...)['Total_Amount'].agg(['sum', 'count', 'mean']):对每个月的Total_Amount列同时计算总和(总销售额)、订单数量(count)和平均值(平均客单价)
monthly_sales = df.groupby(df['Date'].dt.to_period('M'))['Total_Amount'].agg(['sum', 'count', 'mean'])
# 将聚合后的列名改为中文,便于理解
monthly_sales.columns = ['总销售额', '订单数', '平均客单价']
# 索引转换:将月度周期索引(Period类型)转为字符串,便于后续绘图时作为横坐标标签
monthly_sales.index = monthly_sales.index.astype(str)
# 绘制趋势图
fig, axes = plt.subplots(3, 1, figsize=(14, 10))
# 销售额趋势
axes[0].plot(monthly_sales.index, monthly_sales['总销售额'], marker='o', color='blue')
axes[0].set_title('月度销售额趋势 (2023-2024)')
axes[0].set_ylabel('销售额 (TRY)')
axes[0].tick_params(axis='x', rotation=45)
# 订单量趋势
axes[1].plot(monthly_sales.index, monthly_sales['订单数'], marker='s', color='green')
axes[1].set_title('月度订单量趋势')
axes[1].set_ylabel('订单数')
axes[1].tick_params(axis='x', rotation=45)
# 客单价趋势
axes[2].plot(monthly_sales.index, monthly_sales['平均客单价'], marker='^', color='red')
axes[2].set_title('月度平均客单价趋势')
axes[2].set_ylabel('平均客单价 (TRY)')
axes[2].tick_params(axis='x', rotation=45)
plt.tight_layout()
plt.show()
# 识别销售高峰期
# nlargest(3, '总销售额'):从monthly_sales中找出总销售额最高的3个月,并保留这两列(总销售额和订单数)
peak_months = monthly_sales.nlargest(3, '总销售额')[['总销售额', '订单数']]
print("\n销售高峰期TOP3:")
print(peak_months)
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
# 1.4.3 客户画像分析
# 性别分布与消费特征
# 按Gender性别分组
# Customer_ID用'nunique'(去重计数):统计不同性别下的独立客户数量(而非订单数)。
# Total_Amount同时计算总和sum和均值mean,得到该性别的总销售额和平均客单价。
# Order_ID用'count':统计该性别下的总订单数。
# Customer_Rating用'mean':计算该性别客户的平均评分。
gender_analysis = df.groupby('Gender').agg({
'Customer_ID': 'nunique',
'Total_Amount': ['sum', 'mean'],
'Order_ID': 'count',
'Customer_Rating': 'mean'
}).round(2)
# 列重命名:将多级索引简化成直观的中文列名,便于阅读
gender_analysis.columns = ['客户数', '总销售额', '平均客单价', '订单数', '平均评分']
print("性别分析:")
print(gender_analysis)
# 年龄组分析
# 分组键:Age_Group是之前通过分箱创建的年龄段列,如18-25、26-35等。
# observed=True:当分组列为Categorical类型时,此参数确保只显示数据中实际出现的组,而非所有可能的类别(避免出现空组)。如果不设置,可能会显示所有理论分组。
# 聚合指标:与性别分析相同,包括客户数、总销售额、平均客单价、订单数、平均评分。
age_analysis = df.groupby('Age_Group', observed=True).agg({
'Customer_ID': 'nunique',
'Total_Amount': ['sum', 'mean'],
'Order_ID': 'count',
'Customer_Rating': 'mean'
}).round(2)
age_analysis.columns = ['客户数', '总销售额', '平均客单价', '订单数', '平均评分']
print("\n年龄组分析:")
print(age_analysis)
# 城市分析
# 分组:按City城市分组。
# 聚合指标:总销售额、独立客户数、订单数、平均评分。
# 排序:按总销售额降序排列,便于查看销售表现最好的城市。
city_analysis = df.groupby('City').agg({
'Total_Amount': 'sum',
'Customer_ID': 'nunique',
'Order_ID': 'count',
'Customer_Rating': 'mean'
}).round(2)
city_analysis.columns = ['总销售额', '客户数', '订单数', '平均评分']
city_analysis = city_analysis.sort_values('总销售额', ascending=False)
print("\n城市销售排行TOP5:")
print(city_analysis.head())
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
# 1.4.4 产品类别分析
# 各类别销售表现
category_analysis = df.groupby('Product_Category').agg({
'Total_Amount': ['sum', 'mean', 'count'],
'Quantity': 'sum',
'Customer_Rating': 'mean',
'Discount_Amount': 'sum',
'Is_Returning_Customer': 'mean'
}).round(2)
category_analysis.columns = ['总销售额', '平均客单价', '订单数', '总销量', '平均评分', '折扣总额', '回头客比例']
category_analysis = category_analysis.sort_values('总销售额', ascending=False)
print("产品类别分析:")
print(category_analysis)
# 可视化各类别表现
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
# 销售额占比
axes[0,0].pie(category_analysis['总销售额'], labels=category_analysis.index, autopct='%1.1f%%')
axes[0,0].set_title('各类别销售额占比')
# 平均评分
sns.barplot(x=category_analysis.index, y=category_analysis['平均评分'], ax=axes[0,1])
axes[0,1].set_title('各类别平均评分')
axes[0,1].tick_params(axis='x', rotation=45)
# 订单量
sns.barplot(x=category_analysis.index, y=category_analysis['订单数'], ax=axes[1,0])
axes[1,0].set_title('各类别订单量')
axes[1,0].tick_params(axis='x', rotation=45)
# 平均客单价
sns.barplot(x=category_analysis.index, y=category_analysis['平均客单价'], ax=axes[1,1])
axes[1,1].set_title('各类别平均客单价')
axes[1,1].tick_params(axis='x', rotation=45)
plt.tight_layout()
plt.show()
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
# 1.4.5 设备行为分析
# 不同设备的购买行为
device_analysis = df.groupby('Device_Type').agg({
'Order_ID': 'count',
'Total_Amount': ['sum', 'mean'],
'Session_Duration_Minutes': 'mean',
'Pages_Viewed': 'mean',
'Customer_Rating': 'mean',
'Is_Returning_Customer': 'mean'
}).round(2)
device_analysis.columns = ['订单数', '总销售额', '平均客单价', '平均会话时长', '平均浏览页数', '平均评分', '回头客比例']
print("设备类型分析:")
print(device_analysis)
# 设备类型与购买金额关系
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
sns.boxplot(data=df, x='Device_Type', y='Total_Amount', ax=axes[0])
axes[0].set_title('不同设备的客单价分布')
sns.boxplot(data=df, x='Device_Type', y='Session_Duration_Minutes', ax=axes[1])
axes[1].set_title('不同设备的会话时长分布')
sns.boxplot(data=df, x='Device_Type', y='Pages_Viewed', ax=axes[2])
axes[2].set_title('不同设备的浏览页数分布')
plt.tight_layout()
plt.show()
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
# 1.4.6 客户忠诚度分析
# 回头客vs新客户
loyalty_analysis = df.groupby('Is_Returning_Customer').agg({
'Order_ID': 'count',
'Total_Amount': ['sum', 'mean'],
'Customer_Rating': 'mean',
'Session_Duration_Minutes': 'mean',
'Pages_Viewed': 'mean',
'Delivery_Time_Days': 'mean'
}).round(2)
loyalty_analysis.columns = ['订单数', '总销售额', '平均客单价', '平均评分', '平均会话时长', '平均浏览页数', '平均配送时间']
loyalty_analysis.index = ['新客户', '回头客']
print("客户忠诚度分析:")
print(loyalty_analysis)
# 客户购买频次分布
customer_frequency = df.groupby('Customer_ID')['Order_ID'].count().reset_index()
customer_frequency.columns = ['Customer_ID', 'Purchase_Count']
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 购买频次分布
sns.histplot(customer_frequency['Purchase_Count'], bins=20, kde=True, ax=axes[0])
axes[0].set_title('客户购买频次分布')
axes[0].set_xlabel('购买次数')
axes[0].set_ylabel('客户数')
# 帕累托分析(累计销售额贡献)
customer_value = df.groupby('Customer_ID')['Total_Amount'].sum().sort_values(ascending=False).reset_index()
customer_value['Cumulative_Pct'] = customer_value['Total_Amount'].cumsum() / customer_value['Total_Amount'].sum() * 100
axes[1].plot(range(1, len(customer_value)+1), customer_value['Cumulative_Pct'])
axes[1].axhline(y=80, color='r', linestyle='--', label='80% 销售额')
axes[1].axvline(x=len(customer_value)*0.2, color='g', linestyle='--', label='20% 客户')
axes[1].set_title('帕累托分析:客户累计销售额贡献')
axes[1].set_xlabel('客户数(按价值排序)')
axes[1].set_ylabel('累计销售额占比 (%)')
axes[1].legend()
plt.tight_layout()
plt.show()
# 计算前20%客户贡献的销售额比例
top_20_pct = int(len(customer_value) * 0.2)
top_20_contribution = customer_value.iloc[:top_20_pct]['Total_Amount'].sum() / customer_value['Total_Amount'].sum() * 100
print(f"前20%的客户贡献了 {top_20_contribution:.1f}% 的销售额")
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
# 1.4.7 配送时间与客户满意度
# 配送时间分析
delivery_analysis = df.groupby('Delivery_Time_Days').agg({
'Customer_Rating': 'mean',
'Order_ID': 'count'
}).reset_index()
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# 配送时间分布
sns.histplot(df['Delivery_Time_Days'], bins=30, kde=True, ax=axes[0])
axes[0].set_title('配送时间分布')
axes[0].set_xlabel('配送天数')
axes[0].set_ylabel('订单数')
# 配送时间与评分关系
sns.scatterplot(data=delivery_analysis, x='Delivery_Time_Days', y='Customer_Rating',
size='Order_ID', sizes=(20, 200), ax=axes[1])
axes[1].set_title('配送时间 vs 客户评分')
axes[1].set_xlabel('配送天数')
axes[1].set_ylabel('平均客户评分')
plt.tight_layout()
plt.show()
# 计算相关性
correlation = df['Delivery_Time_Days'].corr(df['Customer_Rating'])
print(f"配送时间与客户评分的相关系数: {correlation:.3f}")
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
# 1.5 高级分析与可视化
# 1.5.1 相关性热力图
# 选择数值列进行相关性分析
numeric_df = df[['Age', 'Unit_Price', 'Quantity', 'Total_Amount', 'Discount_Amount',
'Session_Duration_Minutes', 'Pages_Viewed', 'Is_Returning_Customer',
'Delivery_Time_Days', 'Customer_Rating']]
correlation_matrix = numeric_df.corr()
plt.figure(figsize=(12, 10))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0,
square=True, linewidths=1, cbar_kws={"shrink": 0.8})
plt.title('数值特征相关性热力图')
plt.tight_layout()
plt.show()
2
3
4
5
6
7
8
9
10
11
12
13
# 1.5.2 使用Pyecharts创建交互式仪表板
from pyecharts.charts import Bar, Line, Pie, Scatter, Grid, Page
from pyecharts import options as opts
from pyecharts.globals import ThemeType
# 准备数据
monthly_data = monthly_sales.reset_index()
# 动态获取索引列名
index_col_name = monthly_data.columns[0]
months = monthly_data[index_col_name].tolist()
sales_values = monthly_data['总销售额'].tolist()
order_values = monthly_data['订单数'].tolist()
# 1. 月度销售额折线图
line_chart = (
Line()
.add_xaxis(months)
.add_yaxis("销售额", sales_values, is_smooth=True, color="#5470C6")
.set_global_opts(
title_opts=opts.TitleOpts(title="月度销售额趋势"),
tooltip_opts=opts.TooltipOpts(trigger="axis"),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)),
yaxis_opts=opts.AxisOpts(name="销售额 (TRY)"),
legend_opts=opts.LegendOpts(pos_left="center")
)
)
# 2. 类别销售额柱状图
category_data = category_analysis.reset_index()
categories = category_data['Product_Category'].tolist()
category_sales = category_data['总销售额'].tolist()
bar_chart = (
Bar()
.add_xaxis(categories)
.add_yaxis("销售额", category_sales, color="#91CC75")
.set_global_opts(
title_opts=opts.TitleOpts(title="各类别销售额"),
xaxis_opts=opts.AxisOpts(axislabel_opts=opts.LabelOpts(rotate=45)),
yaxis_opts=opts.AxisOpts(name="销售额")
)
.set_series_opts(label_opts=opts.LabelOpts(is_show=True))
)
# 3. 支付方式饼图
payment_counts = df['Payment_Method'].value_counts()
payment_data = [(k, v) for k, v in payment_counts.items()]
pie_chart = (
Pie()
.add("", payment_data, radius=["40%", "70%"])
.set_global_opts(
title_opts=opts.TitleOpts(title="支付方式分布"),
legend_opts=opts.LegendOpts(orient="vertical", pos_top="15%", pos_left="2%")
)
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {d}%"))
)
# 4. 设备类型与客单价散点图
device_sample = df.sample(min(500, len(df)))
device_scatter = (
Scatter()
.add_xaxis(device_sample['Device_Type'].tolist())
.add_yaxis("客单价", device_sample['Total_Amount'].tolist(),
label_opts=opts.LabelOpts(is_show=False))
.set_global_opts(
title_opts=opts.TitleOpts(title="不同设备客单价分布"),
xaxis_opts=opts.AxisOpts(name="设备类型"),
yaxis_opts=opts.AxisOpts(name="客单价")
)
)
# 在Jupyter中显示
line_chart.render_notebook()
bar_chart.render_notebook()
pie_chart.render_notebook()
device_scatter.render_notebook()
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
75
76
# 1.5.3 客户分群(K-Means聚类)
根据客户消费行为进行分群,这是电商分析中常用的技术。
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
# 准备客户级别特征
customer_features = df.groupby('Customer_ID').agg({
'Total_Amount': ['sum', 'mean'],
'Order_ID': 'count',
'Customer_Rating': 'mean',
'Session_Duration_Minutes': 'mean',
'Pages_Viewed': 'mean',
'Delivery_Time_Days': 'mean',
'Discount_Rate': 'mean'
}).round(2)
# 扁平化列名
customer_features.columns = ['总消费额', '平均客单价', '购买次数',
'平均评分', '平均会话时长', '平均浏览页数',
'平均配送时间', '平均折扣率']
# 重置索引使Customer_ID成为列
customer_features = customer_features.reset_index()
# 标准化特征
scaler = StandardScaler()
features_for_clustering = ['总消费额', '购买次数', '平均客单价', '平均评分']
scaled_features = scaler.fit_transform(customer_features[features_for_clustering])
# 使用肘部法则确定最佳聚类数
inertias = []
K_range = range(2, 9)
for k in K_range:
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
kmeans.fit(scaled_features)
inertias.append(kmeans.inertia_)
# 绘制肘部图
plt.figure(figsize=(10, 6))
plt.plot(K_range, inertias, 'bo-')
plt.xlabel('聚类数 K')
plt.ylabel('惯性 (Inertia)')
plt.title('肘部法则确定最佳K值')
plt.grid(True)
plt.show()
# 选择K=4进行聚类
kmeans = KMeans(n_clusters=4, random_state=42, n_init=10)
customer_features['Cluster'] = kmeans.fit_predict(scaled_features)
# 分析各簇特征
cluster_analysis = customer_features.groupby('Cluster')[features_for_clustering].mean()
print("各客户群特征:")
print(cluster_analysis)
# 使用PCA降维可视化
pca = PCA(n_components=2)
pca_result = pca.fit_transform(scaled_features)
plt.figure(figsize=(12, 8))
scatter = plt.scatter(pca_result[:, 0], pca_result[:, 1],
c=customer_features['Cluster'], cmap='viridis', alpha=0.6)
plt.colorbar(scatter, label='聚类')
plt.xlabel('第一主成分')
plt.ylabel('第二主成分')
plt.title('客户聚类可视化 (PCA降维)')
plt.show()
# 为各簇命名
cluster_names = {
0: '高价值忠诚客户',
1: '普通大众客户',
2: '潜力新客户',
3: '低价值客户'
}
customer_features['Cluster_Name'] = customer_features['Cluster'].map(cluster_names)
# 各簇占比
cluster_distribution = customer_features['Cluster_Name'].value_counts()
print("\n各客户群占比:")
print(cluster_distribution)
print(cluster_distribution / len(customer_features) * 100)
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
75
76
77
78
79
80
81
82
# 1.5.4 评分预测建模(基础机器学习)
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
# 准备特征和目标变量
feature_cols = ['Age', 'Unit_Price', 'Quantity', 'Discount_Rate',
'Session_Duration_Minutes', 'Pages_Viewed', 'Is_Returning_Customer',
'Delivery_Time_Days']
target_col = 'Customer_Rating'
# 对分类变量进行独热编码
df_encoded = pd.get_dummies(df, columns=['Gender', 'Product_Category',
'Payment_Method', 'Device_Type'])
# 选择特征列,原来是数字的8列 加上刚刚独热编码的列,组合在一起为X
X = df_encoded[feature_cols + [col for col in df_encoded.columns if col.startswith(('Gender_', 'Product_Category_', 'Payment_Method_', 'Device_Type_'))]]
y = df_encoded[target_col]
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 训练随机森林模型
rf_model = RandomForestRegressor(n_estimators=100, max_depth=10, random_state=42)
rf_model.fit(X_train, y_train)
# 预测
y_pred = rf_model.predict(X_test)
# 评估
mse = mean_squared_error(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
print("模型评估结果:")
print(f"均方误差 (MSE): {mse:.4f}")
print(f"平均绝对误差 (MAE): {mae:.4f}")
print(f"R² 分数: {r2:.4f}")
# 特征重要性
feature_importance = pd.DataFrame({
'feature': X.columns,
'importance': rf_model.feature_importances_
}).sort_values('importance', ascending=False)
print("\n特征重要性TOP10:")
print(feature_importance.head(10))
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
# 1.6 结论与商业建议
# 1.6.1 关键发现总结
# 汇总关键指标
insights = {
"客户概况": {
"回头客比例": f"{returning_rate:.1f}%",
"移动端占比": f"{(df['Device_Type']=='Mobile').mean()*100:.1f}%",
"平均客单价": f"{avg_order_value:.2f} TRY",
"平均评分": f"{avg_rating:.2f}/5.0"
},
"销售表现": {
"总销售额": f"{total_sales:,.2f} TRY",
"总订单数": f"{total_orders}",
"高峰期": f"{peak_months.index[0]} (销售额{peak_months.iloc[0]['总销售额']:,.0f} TRY)"
},
"产品表现": {
"最畅销类别": category_analysis.index[0],
"评分最高类别": category_analysis['平均评分'].idxmax(),
"客单价最高类别": category_analysis['平均客单价'].idxmax()
}
}
print("\n" + "="*60)
print("关键发现总结")
print("="*60)
for category, metrics in insights.items():
print(f"\n{category}:")
for key, value in metrics.items():
print(f" - {key}: {value}")
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
# 1.6.2 商业建议
基于以上分析,提出以下商业建议:
recommendations = [
{
"领域": "客户细分与精准营销",
"发现": f"前20%的客户贡献了{top_20_contribution:.1f}%的销售额,符合帕累托法则",
"建议": "针对高价值客户(聚类中的0簇)建立VIP计划,提供专属优惠和快速配送;针对潜力客户(2簇)推送个性化推荐,提升转化率"
},
{
"领域": "产品策略优化",
"发现": f"{category_analysis.index[0]}类别销售额最高,但评分最高的类别是{category_analysis['平均评分'].idxmax()}",
"建议": "保持{category_analysis.index[0]}类别的库存充足,同时分析{category_analysis['平均评分'].idxmax()}类别的成功因素,应用到其他类别"
},
{
"领域": "移动端体验优化",
"发现": f"移动端交易占比{(df['Device_Type']=='Mobile').mean()*100:.1f}%,但平均客单价低于桌面端",
"建议": "优化移动端购物流程,简化支付步骤,考虑推出移动端专属优惠"
},
{
"领域": "配送服务改进",
"发现": f"配送时间与客户评分相关系数为{correlation:.3f},呈负相关",
"建议": "对配送时间超过7天的订单主动跟踪并提供补偿;考虑在高峰期增加配送人力"
},
{
"领域": "客户忠诚度提升",
"发现": f"回头客比例{returning_rate:.1f}%,且回头客的客单价和评分均高于新客户",
"建议": "实施会员积分制度,对重复购买客户提供累计折扣;定期发送个性化推荐邮件"
}
]
print("\n" + "="*60)
print("商业建议")
print("="*60)
for i, rec in enumerate(recommendations, 1):
print(f"\n{i}. {rec['领域']}")
print(f" 📊 发现: {rec['发现']}")
print(f" 💡 建议: {rec['建议']}")
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
# 1.6.3 未来研究方向
future_work = [
"时间序列预测:使用ARIMA或Prophet模型预测未来销售趋势",
"推荐系统:基于用户购买历史构建协同过滤推荐引擎",
"客户生命周期价值(CLV)预测:预估客户长期价值,优化营销预算分配",
"A/B测试框架:设计实验验证营销策略的有效性",
"自然语言处理:如果获取到评论数据,可进行情感分析"
]
print("\n" + "="*60)
print("未来研究方向")
print("="*60)
for item in future_work:
print(f" • {item}")
2
3
4
5
6
7
8
9
10
11
12
13
# 1.7 代码完整性与可复现性
为确保分析的可复现性,建议将所有代码整合到一个Jupyter Notebook中,并包含以下设置:
# 环境配置和依赖
import sys
print("Python版本:", sys.version)
print("Pandas版本:", pd.__version__)
print("NumPy版本:", np.__version__)
print("Matplotlib版本:", plt.matplotlib.__version__)
print("Seaborn版本:", sns.__version__)
# 如果需要保存处理后的数据
df.to_csv('processed_ecommerce_data.csv', index=False)
customer_features.to_csv('customer_segments.csv', index=False)
# 保存可视化图表
plt.savefig('sales_trend.png', dpi=300, bbox_inches='tight')
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1.8 案例总结
本案例基于Kaggle平台的真实电商数据集,完整演示了数据分析的全流程:
- 数据获取:使用Kaggle API下载真实数据集
- 数据清洗:处理数据类型、添加衍生特征、检测异常值
- 探索性分析:从客户画像、产品表现、设备行为、客户忠诚度等多个维度深入分析
- 高级分析:相关性分析、客户聚类分群、基础预测建模
- 可视化呈现:综合使用Matplotlib、Seaborn和Pyecharts创建静态与交互式图表
- 商业洞察:基于数据得出actionable的商业建议
通过本案例,读者可以掌握处理真实数据集的能力,理解如何将数据分析技术应用于实际业务场景,并能够从数据中提炼有价值的商业洞察。
明天Day6见!See you tomorrow!