本文目录导读:

我来详细讲解如何使用Pandas进行数据分组替换,包含多个实用案例:
基本概念准备
import pandas as pd import numpy as np
创建示例数据
# 创建示例数据集
df = pd.DataFrame({
'department': ['销售部', '技术部', '销售部', '技术部', '市场部', '市场部'],
'employee': ['张三', '李四', '王五', '赵六', '孙七', '周八'],
'salary': [8000, 12000, 9500, 15000, 7000, 8500],
'years': [3, 5, 2, 6, 1, 4]
})
print("原始数据:")
print(df)
分组替换的多种方法
方法1:使用groupby + transform
# 案例1:替换为组内平均值
print("=== 替换为各部门平均薪资 ===")
df['salary_avg_dept'] = df.groupby('department')['salary'].transform('mean')
print(df)
# 案例2:替换为组内排名
print("\n=== 替换为各部门薪资排名(从低到高)===")
df['salary_rank'] = df.groupby('department')['salary'].rank()
print(df)
# 案例3:标准化组内数据
print("\n=== 各部门薪资标准化(Z-score)===")
def z_score(x):
return (x - x.mean()) / x.std()
df['salary_zscore'] = df.groupby('department')['salary'].transform(z_score)
print(df)
方法2:使用自定义替换规则
# 案例4:条件分组替换
print("=== 根据部门和工作年限调整薪资 ===")
def adjust_salary(group):
if group.name == '销售部':
group['salary'] = group['salary'] * 1.1 # 销售部涨薪10%
elif group.name == '技术部':
group['salary'] = group['salary'] * 1.2 # 技术部涨薪20%
elif group.name == '市场部':
# 市场部按年限调整
group['salary'] = np.where(group['years'] >= 3,
group['salary'] * 1.15, # 老员工涨15%
group['salary'] * 1.05) # 新员工涨5%
return group
df_adjusted = df.groupby('department', group_keys=False).apply(adjust_salary)
print(df_adjusted[['department', 'employee', 'salary']])
方法3:使用map/dict映射
# 案例5:基于分组的映射替换
print("=== 基于部门的分级替换 ===")
# 创建替换映射
dept_level = {
'销售部': 'A级',
'技术部': 'A级',
'市场部': 'B级'
}
df['dept_level'] = df['department'].map(dept_level)
print(df)
# 案例6:多条件分组替换
print("\n=== 复合条件替换 ===")
def classify_employee(row):
if row['department'] == '技术部' and row['salary'] > 12000:
return '高级技术'
elif row['department'] == '销售部' and row['salary'] > 8000:
return '高级销售'
elif row['years'] >= 5:
return '资深员工'
else:
return '普通员工'
df['employee_level'] = df.apply(classify_employee, axis=1)
print(df)
方法4:使用cut/qcut进行分组
# 案例7:按薪资分箱(等距)
print("=== 各部门薪资分层 ===")
for dept in df['department'].unique():
dept_data = df[df['department'] == dept].copy()
dept_data['salary_lvl'] = pd.cut(dept_data['salary'],
bins=3,
labels=['低', '中', '高'])
print(f"\n{dept}部门:")
print(dept_data[['employee', 'salary', 'salary_lvl']])
# 案例8:按百分位分组
print("\n=== 按百分位分组 ===")
def assign_percentile(group):
group['salary_percentile'] = pd.qcut(group['salary'],
q=4,
labels=['Q1', 'Q2', 'Q3', 'Q4'])
return group
df_percentile = df.groupby('department', group_keys=False).apply(assign_percentile)
print(df_percentile)
实战案例:销售数据分析
# 创建更实际的销售数据
np.random.seed(42)
sales_df = pd.DataFrame({
'date': pd.date_range('2024-01-01', periods=100, freq='D'),
'product': np.random.choice(['手机', '电脑', '平板'], 100),
'region': np.random.choice(['华东', '华南', '华北'], 100),
'sales': np.random.randint(10000, 50000, 100),
'quantity': np.random.randint(10, 100, 100)
})
print("销售数据预览:")
print(sales_df.head())
# 案例9:按产品和地区分组替换异常值
print("\n=== 按组替换异常值 ===")
def remove_outliers(group):
Q1 = group['sales'].quantile(0.25)
Q3 = group['sales'].quantile(0.75)
IQR = Q3 - Q1
# 将异常值替换为中位数
median = group['sales'].median()
group['sales_cleaned'] = group['sales'].clip(Q1 - 1.5*IQR, Q3 + 1.5*IQR)
group['sales_cleaned'] = np.where(
(group['sales'] < Q1 - 1.5*IQR) | (group['sales'] > Q3 + 1.5*IQR),
median, group['sales']
)
return group
sales_cleaned = sales_df.groupby(['product', 'region'], group_keys=False).apply(remove_outliers)
print("清洗前后对比:")
print(sales_cleaned[sales_cleaned['sales'] != sales_cleaned['sales_cleaned']])
高级技巧:滚动替换
# 案例10:按时间分组滚动计算
print("=== 按产品分组滚动平均 ===")
sales_df['rolling_avg_7d'] = (
sales_df.groupby('product')['sales']
.rolling(window=7, min_periods=1)
.mean()
.reset_index(level=0, drop=True)
)
# 案例11:分组累计替换
print("\n=== 各产品累计销售额 ===")
sales_df['cumulative_sales'] = (
sales_df.groupby('product')['sales']
.cumsum()
)
print(sales_df[sales_df['product'] == '手机'].head(10))
性能优化技巧
# 方法5:使用agg聚合后合并(大数据量时更高效)
print("=== 高效分组替换方式 ===")
# 计算统计值
dept_stats = df.groupby('department')['salary'].agg(['mean', 'median', 'std']).reset_index()
print("部门统计:")
print(dept_stats)
# 合并回原数据
df_efficient = df.merge(dept_stats, on='department', how='left')
print("\n合并后数据:")
print(df_efficient)
# 案例12:并行分组处理(大数据场景)
from multiprocessing import Pool
def process_group(group):
# 处理每个组
group['processed_salary'] = group['salary'] * 1.1
return group
# 注意:实际使用时需要根据数据量选择是否并行
完整实战:数据清洗案例
# 案例13:完整的数据清洗流程
print("=== 数据清洗完整流程 ===")
# 创建带有缺失值和异常值的数据
dirty_data = pd.DataFrame({
'category': ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C'],
'value': [100, 200, 1000, 150, 175, 50, 300, 350, 25] # 1000和25可能异常
})
print("原始脏数据:")
print(dirty_data)
# 完整清洗流程
def clean_data(df, group_col, value_col, threshold=1.5):
def clean_group(group):
Q1 = group[value_col].quantile(0.25)
Q3 = group[value_col].quantile(0.75)
IQR = Q3 - Q1
lower_bound = Q1 - threshold * IQR
upper_bound = Q3 + threshold * IQR
# 标记异常值
group['is_outlier'] = ((group[value_col] < lower_bound) |
(group[value_col] > upper_bound))
# 替换异常值为组内中位数
median_val = group[value_col].median()
group[value_col + '_cleaned'] = np.where(
group['is_outlier'],
median_val,
group[value_col]
)
return group
return df.groupby(group_col, group_keys=False).apply(clean_group)
# 执行清洗
cleaned_data = clean_data(dirty_data, 'category', 'value')
print("\n清洗后数据:")
print(cleaned_data)
主要方法:
- groupby + transform:最常用,保持原数据结构
- groupby + apply:灵活的自定义处理
- map/dict:简单的映射替换
- merge + agg:大数据集的高效方案
- cut/qcut:数值分段分组
选择建议:
- 小数据量:使用transform或apply
- 大数据量:使用merge+agg
- 简单映射:使用map或replace
- 数值分段:使用cut或qcut
这些方法可以帮助你高效地处理各种分组替换需求。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播