本文目录导读:

我来详细讲解如何使用Pandas进行数据分组上线的完整案例。
基础数据分组与条件过滤
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
# 创建示例数据
np.random.seed(42)
data = {
'user_id': [f'user_{i}' for i in range(100)],
'group': np.random.choice(['A', 'B', 'C'], 100),
'value': np.random.randint(1, 100, 100),
'score': np.random.uniform(0, 100, 100),
'date': pd.date_range('2024-01-01', periods=100, freq='D')
}
df = pd.DataFrame(data)
print("原始数据预览:")
print(df.head())
print("\n数据基本信息:")
print(df.info())
数据分组统计
# 按group分组计算统计量
group_stats = df.groupby('group').agg({
'value': ['mean', 'std', 'min', 'max', 'count'],
'score': ['mean', 'median', 'std'],
'user_id': 'nunique'
})
print("分组统计信息:")
print(group_stats)
# 简化分组统计
simple_stats = df.groupby('group')['value'].agg(['mean', 'std', 'count'])
print("\n简单分组统计:")
print(simple_stats)
分组阈值上线逻辑
def calculate_threshold(group_data, method='percentile', threshold=0.9):
"""
计算分组阈值
"""
if method == 'percentile':
return group_data.quantile(threshold)
elif method == 'mean_std':
return group_data.mean() + 1.5 * group_data.std()
elif method == 'mad':
median = group_data.median()
mad = np.median(np.abs(group_data - median))
return median + 3 * mad
else:
return group_data.max() * 0.8
# 应用分组阈值
df['value_threshold'] = df.groupby('group')['value'].transform(
lambda x: calculate_threshold(x, method='percentile', threshold=0.9)
)
df['score_threshold'] = df.groupby('group')['score'].transform(
lambda x: calculate_threshold(x, method='mean_std')
)
print("添加阈值后的数据:")
print(df[['user_id', 'group', 'value', 'value_threshold', 'score', 'score_threshold']].head())
条件筛选上市/下市决策
def online_decision(row, thresholds):
"""
基于多条件的上市/下市决策
"""
conditions = []
# 条件1: 值是否超过阈值
if row['value'] > row['value_threshold']:
conditions.append('value_high')
# 条件2: 分数是否超过阈值
if row['score'] > row['score_threshold']:
conditions.append('score_high')
# 条件3: 综合判断
if len(conditions) >= 2:
return '上线'
elif len(conditions) == 1:
return '观察'
else:
return '下线'
# 应用决策逻辑
df['decision'] = df.apply(online_decision, axis=1, args=(None,))
# 分组统计上线情况
online_stats = df.groupby(['group', 'decision']).size().unstack(fill_value=0)
print("\n各分组上线情况:")
print(online_stats)
# 每组上线的比例
group_total = df.groupby('group').size()
online_ratio = df[df['decision'] == '上线'].groupby('group').size() / group_total
print("\n每组上线比例:")
print(online_ratio.round(3))
时间序列分组上线
# 创建时间序列示例
time_data = pd.DataFrame({
'date': pd.date_range('2024-01-01', periods=365, freq='D'),
'group': np.random.choice(['A', 'B'], 365),
'metric': np.random.normal(50, 15, 365) + np.sin(np.arange(365) * 2 * np.pi / 30) * 10
})
# 按周分组统计
time_data['week'] = time_data['date'].dt.isocalendar().week
time_data['month'] = time_data['date'].dt.month
# 计算滚动阈值
def calculate_rolling_threshold(data, window=7):
"""
计算滚动阈值
"""
return data.rolling(window=window, min_periods=1).quantile(0.8)
# 按组和日期计算阈值
time_data['rolling_threshold'] = time_data.groupby('group')['metric'].transform(
lambda x: calculate_rolling_threshold(x)
)
# 上线决策
time_data['online_flag'] = time_data['metric'] > time_data['rolling_threshold']
print("时间序列上线分析:")
print(time_data[time_data['online_flag']].head())
高级分组上线策略
class GroupOnlineStrategy:
"""
分组上线策略管理器
"""
def __init__(self, df, group_col, value_cols, methods='auto'):
self.df = df.copy()
self.group_col = group_col
self.value_cols = value_cols
self.methods = methods
self.online_results = {}
def percentile_based_online(self, threshold=0.85):
"""基于百分位数的上线策略"""
for col in self.value_cols:
self.df[f'{col}_threshold'] = self.df.groupby(self.group_col)[col].transform(
lambda x: x.quantile(threshold)
)
self.df[f'{col}_online'] = self.df[col] > self.df[f'{col}_threshold']
return self.df
def zscore_based_online(self, z_threshold=2):
"""基于Z分数的上线策略"""
for col in self.value_cols:
group_stats = self.df.groupby(self.group_col)[col].agg(['mean', 'std'])
group_stats.columns = ['mean', 'std']
# 合并回原数据
self.df = self.df.merge(group_stats, on=self.group_col, suffixes=('', '_stat'))
# 计算Z分数
self.df[f'{col}_zscore'] = (self.df[col] - self.df['mean']) / self.df['std']
self.df[f'{col}_online'] = self.df[f'{col}_zscore'] > z_threshold
# 删除临时列
self.df.drop(['mean', 'std'], axis=1, inplace=True)
return self.df
def ensemble_online(self, methods=['percentile', 'zscore']):
"""集成多个策略"""
voters = []
if 'percentile' in methods:
result_p = self.percentile_based_online()
voters.append(result_p[[f'{col}_online' for col in self.value_cols]].any(axis=1))
if 'zscore' in methods:
result_z = self.zscore_based_online()
voters.append(result_z[[f'{col}_online' for col in self.value_cols]].any(axis=1))
# 多数投票
if len(voters) == 2:
self.df['ensemble_online'] = voters[0] & voters[1] # 两个条件都满足
else:
self.df['ensemble_online'] = voters[0] if len(voters) == 1 else False
return self.df
# 使用策略管理器
strategy = GroupOnlineStrategy(df, 'group', ['value', 'score'])
result = strategy.percentile_based_online(threshold=0.85)
print("\n百分位策略结果:")
print(result.groupby('group')[['value_online', 'score_online']].mean())
# 集成策略
ensemble_result = strategy.ensemble_online(['percentile', 'zscore'])
print("\n集成策略结果:")
print(ensemble_result.groupby('group')['ensemble_online'].mean())
结果可视化和报告
import matplotlib.pyplot as plt
import seaborn as sns
def visualize_online_results(df, group_col, metric_col):
"""
可视化分组上线结果
"""
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# 1. 各组上线比例
online_ratio = df.groupby(group_col)[f'{metric_col}_online'].mean()
axes[0, 0].bar(online_ratio.index, online_ratio.values)
axes[0, 0].set_title(f'{metric_col} 各分组上线比例')
axes[0, 0].set_ylabel('上线比例')
# 2. 阈值分布
for group in df[group_col].unique():
group_data = df[df[group_col] == group]
axes[0, 1].hist(group_data[metric_col], alpha=0.5, label=group, bins=20)
axes[0, 1].axvline(df[f'{metric_col}_threshold'].mean(), color='r', linestyle='--', label='平均阈值')
axes[0, 1].set_title(f'{metric_col} 分布与阈值')
axes[0, 1].legend()
# 3. 上线 vs 下线对比
online_data = df[df[f'{metric_col}_online'] == True][metric_col]
offline_data = df[df[f'{metric_col}_online'] == False][metric_col]
axes[1, 0].boxplot([online_data, offline_data], labels=['上线', '下线'])
axes[1, 0].set_title(f'{metric_col} 上线/下线对比')
# 4. 分组箱线图
df.boxplot(column=metric_col, by=group_col, ax=axes[1, 1])
axes[1, 1].set_title(f'{metric_col} 分组箱线图')
plt.tight_layout()
plt.show()
# 可视化结果
visualize_online_results(result, 'group', 'value')
完整上线流程示例
def complete_online_workflow(data_path=None):
"""
完整的分组上线流程
"""
# 1. 数据准备
if data_path is None:
# 创建模拟数据
np.random.seed(42)
df = pd.DataFrame({
'item_id': [f'item_{i}' for i in range(1000)],
'category': np.random.choice(['电子', '服装', '食品', '家居'], 1000),
'price': np.random.uniform(10, 1000, 1000),
'sales': np.random.randint(0, 1000, 1000),
'rating': np.random.uniform(1, 5, 1000),
'date': pd.date_range('2024-01-01', periods=1000, freq='H')
})
else:
df = pd.read_csv(data_path)
print("=== 第1步: 数据概览 ===")
print(df.describe())
# 2. 数据预处理
print("\n=== 第2步: 数据预处理 ===")
df['log_sales'] = np.log1p(df['sales']) # 对销售额取对数
df['price_per_sales'] = df['price'] / (df['sales'] + 1) # 价格/销售比
# 3. 分组统计
print("\n=== 第3步: 分组统计 ===")
category_stats = df.groupby('category').agg({
'price': ['mean', 'std', 'quantile', 'max'],
'sales': ['mean', 'median', 'std'],
'rating': ['mean', 'std']
})
print(category_stats)
# 4. 计算上线阈值
print("\n=== 第4步: 计算阈值 ===")
for metric in ['sales', 'price', 'rating']:
df[f'{metric}_threshold'] = df.groupby('category')[metric].transform(
lambda x: x.quantile(0.8)
)
# 5. 综合评分
print("\n=== 第5步: 综合评估 ===")
df['综合评分'] = (
(df['sales'] / df['sales_threshold']) * 0.4 +
(df['price'] / df['price_threshold']) * 0.3 +
(df['rating'] / df['rating_threshold']) * 0.3
)
# 6. 上线决策
print("\n=== 第6步: 上线决策 ===")
def decision_logic(row):
scores = 0
if row['sales'] > row['sales_threshold']:
scores += 1
if row['price'] > row['price_threshold']:
scores += 1
if row['rating'] > row['rating_threshold']:
scores += 1
if row['综合评分'] > 1:
scores += 1
if scores >= 3:
return '立即上线'
elif scores == 2:
return '观察后上线'
else:
return '暂缓上线'
df['online_status'] = df.apply(decision_logic, axis=1)
# 7. 结果汇总
print("\n=== 第7步: 结果汇总 ===")
result_summary = df.groupby(['category', 'online_status']).size().unstack(fill_value=0)
print(result_summary)
# 8. 生成上线报告
print("\n=== 第8步: 上线报告 ===")
for category in df['category'].unique():
cat_data = df[df['category'] == category]
online_count = len(cat_data[cat_data['online_status'] == '立即上线'])
total_count = len(cat_data)
print(f"{category}: 建议上線 {online_count}/{total_count} ({online_count/total_count*100:.1f}%)")
return df
# 执行完整流程
result_df = complete_online_workflow()
print("\n最终上线结果:")
print(result_df[['item_id', 'category', 'online_status', '综合评分']].head(10))
这个案例涵盖了分组上线的完整流程:
- 基础数据分组统计
- 多种阈值计算方法
- 条件筛选和决策逻辑
- 时间序列数据分析
- 高级策略管理
- 可视化和报告生成
- 完整的上线工作流
你可以根据实际业务需求调整阈值、权重和决策规则。