Pandas函数内条件判断问题求助:average_shares函数修正
我是Pandas新手,正在学习函数创建与if-else语句的实现。写了average_shares()函数但没达到预期效果,问题出在函数应该按行处理但我没搞对。非Pandas场景我会用for i in range(len(column))循环,但Pandas教程里常用apply(),而且函数参数是row不是DataFramedf,试了还是不行。
需求说明
现有包含id、week、order、share列的DataFrame,week会重复。需要为每个id计算share_1和share_2:
- share_1:各周首次出现(index=1)的share平均值
- share_2:各周第二次出现(index=2)的share平均值
规则
- 若某id的某周重复次数>2,先剔除share>0.95或<0.05的行再计算平均
- 若某周无重复(len<2),share_1等于该行share,share_2为0
当前代码
df = pd.DataFrame({'id': [1, 1, 1], 'week': [1, 1, 2], 'order': [2, 4, 3]}) df['index'] = df.groupby(['id', 'week']).cumcount()+1 #can be many id-s (not only id=1) df['share'] = df['order']/df.groupby(['id', 'week'])['order'].transform('sum') df['len'] = (df.groupby(['id', 'week']))['order'].transform('count') def average_shares(df): if df['repeats']>2: df = df[(df['share'])>0.05 & (df['share']<0.95)] df['share_1'] = df[df['index']==1].groupby('id')['share'].transform('mean') df['share_2'] = df[df['index']==2].groupby('id')['share'].transform('mean') elif df['repeats']==2: df['share_1'] = df[df['index']==1].groupby('id')['share'].transform('mean') df['share_2'] = df[df['index']==2].groupby('id')['share'].transform('mean') elif df['repeats']<2: df['share_1'] = df['share'] df['share_2'] = 0 return df['share_1'], df['share_2'] df['share_1'], df['share_2'] = zip(*df.apply(average_shares, axis=1))
数据示例
| input | calculated | 需要计算的结果 |
|---|---|---|
| id | week | order |
| ---- | ------ | ------- |
| 1 | 1 | 2 |
| 1 | 1 | 4 |
| 1 | 2 | 3 |
字段说明
len:同一week的重复次数index:重复项的出现顺序share:order除以该week的order总和share_1:同一id下index=1的share平均值share_2:同一id下index=2的share平均值
问题分析与修正方案
你的核心问题是误用了apply(axis=1)——当用axis=1时,函数接收的是单行数据(Series),而不是整个DataFrame,所以函数里不能直接对整个DataFrame做筛选、分组操作。另外代码里用了df['repeats'],但原DataFrame里只有len列,这也是一个错误。
正确思路是先按id和week处理数据,再按id聚合计算平均值,而非逐行处理。以下是修正后的代码:
import pandas as pd df = pd.DataFrame({'id': [1, 1, 1], 'week': [1, 1, 2], 'order': [2, 4, 3]}) df['index'] = df.groupby(['id', 'week']).cumcount() + 1 df['share'] = df['order'] / df.groupby(['id', 'week'])['order'].transform('sum') df['len'] = df.groupby(['id', 'week'])['order'].transform('count') # 按(id, week)组过滤异常数据 def filter_group(group): if group['len'].iloc[0] > 2: return group[(group['share'] > 0.05) & (group['share'] < 0.95)] return group filtered_df = df.groupby(['id', 'week']).apply(filter_group).reset_index(drop=True) # 计算每个id下index=1和index=2的share平均值 id_index_mean = filtered_df[filtered_df['index'].isin([1,2])].groupby(['id', 'index'])['share'].mean().unstack() id_index_mean.columns = ['share_1', 'share_2'] id_index_mean = id_index_mean.fillna({'share_2': 0}) # 合并结果到原DataFrame result_df = df.merge(id_index_mean, on='id', how='left') # 处理len<2的情况 mask = df['len'] < 2 result_df.loc[mask, 'share_1'] = result_df.loc[mask, 'share'] result_df.loc[mask, 'share_2'] = 0 print(result_df)
代码解释
- 组内过滤:按
(id, week)分组,对重复次数>2的组过滤掉异常share值,保留有效数据。 - 聚合平均值:按
id和index分组,计算每个id下index=1和index=2的share平均值,用unstack()将index转为列。 - 合并与规则处理:把平均值合并回原DataFrame,对
len<2的行单独覆盖share_1和share_2的值。
运行后结果会符合你给出的数据示例要求。
内容的提问来源于stack exchange,提问作者friendly_girl
相关产品推荐
相关产品推荐

