查找列中值的平均值并创建一个分布平均值的新数据框
Finding the average of values in a column and create a new dataframe that distributes the average
我想用 python 的同一列的平均值替换列中的现有值,最好。我想将付款平均分配给从付款的第一个月到最后一个月的所有月份。平均每月付款应分配给 cust_id 和 sub_id。
付款可能会跳过几个月并且不一样。
希望你能帮助我,因为我才刚刚开始学习 python。
数据如下所示:
cust_id
sub_id
date
payment
1
A
12/1/20
200
1
A
2/2/21
200
1
A
2/3/21
100
1
A
5/1/21
200
1
B
1/2/21
50
1
B
1/9/21
20
1
B
3/1/21
80
1
B
4/23/21
90
2
C
1/4/21
200
2
C
1/9/21
300
我想要的结果是这样的:
cust_id
sub_id
date
payment
1
A
12/1/20
116.67
1
A
1/1/21
116.67
1
A
2/1/21
116.67
1
A
3/1/21
116.67
1
A
4/1/21
116.67
1
A
5/1/21
116.67
1
B
1/1/21
60
1
B
2/1/21
60
1
B
3/1/21
60
1
B
4/1/21
60
2
C
1/1/21
500
非常感谢!
如评论中所述,您对 cust_id=2 和 sub_id='C' 的回答似乎与您的要求不一致,所以我选择后者。
首先,我们将日期汇总为最小值、最大值,并将付款汇总为总和:
df2 = df.groupby(['cust_id','sub_id']).agg({'date':[min,max], 'payment':sum})
df2.columns = df2.columns.get_level_values(1)
df2
我们得到
min max sum
cust_id sub_id
1 A 2020-12-01 2021-05-01 700
B 2021-01-02 2021-04-23 240
2 C 2021-01-04 2021-01-09 500
然后我们为从最小值到最大值的每一行创建每月计划。在这里你可能需要 fiddle 稍微调整一下日期才能让它们很好地排列,我只是做了一些基础来展示这个想法:
from datetime import timedelta
df2['schedule'] = df2.apply(lambda row: pd.date_range(row['min'],row['max'] + timedelta(days = 31), freq = '1M'),axis=1)
现在 df2
看起来像这样:
min max sum schedule
-------- ------------------- ------------------- ----- ---------------------------------------------------------------------------------------------------------
(1, 'A') 2020-12-01 00:00:00 2021-05-01 00:00:00 700 DatetimeIndex(['2020-12-31', '2021-01-31', '2021-02-28', '2021-03-31',
'2021-04-30', '2021-05-31'],
dtype='datetime64[ns]', freq='M')
(1, 'B') 2021-01-02 00:00:00 2021-04-23 00:00:00 240 DatetimeIndex(['2021-01-31', '2021-02-28', '2021-03-31', '2021-04-30'], dtype='datetime64[ns]', freq='M')
(2, 'C') 2021-01-04 00:00:00 2021-01-09 00:00:00 500 DatetimeIndex(['2021-01-31'], dtype='datetime64[ns]', freq='M')
现在我们 explode
我们 'schedule' 并平均分配付款,并对列名称等进行一些清理:
df3 = df2.groupby(['cust_id','sub_id'], as_index = False).apply(lambda g: g.explode('schedule'))
(df3.groupby(['cust_id','sub_id'], as_index = False)
.apply(lambda g: g.assign(sum = g['sum']/len(g)))
.reset_index(drop = False)
.drop(columns = ['min','max','level_0'])
.rename(columns = {'sum':'payment'})
)
得到
cust_id sub_id payment schedule
-- --------- -------- --------- -------------------
0 1 A 116.667 2020-12-31 00:00:00
1 1 A 116.667 2021-01-31 00:00:00
2 1 A 116.667 2021-02-28 00:00:00
3 1 A 116.667 2021-03-31 00:00:00
4 1 A 116.667 2021-04-30 00:00:00
5 1 A 116.667 2021-05-31 00:00:00
6 1 B 60 2021-01-31 00:00:00
7 1 B 60 2021-02-28 00:00:00
8 1 B 60 2021-03-31 00:00:00
9 1 B 60 2021-04-30 00:00:00
10 2 C 500 2021-01-31 00:00:00
这可以使用 resample()
和 transform()
函数通过几个步骤完成:
首先,我们将缺失的月份添加到原始 table 中,将所有日期值更改为该月的第一天,将同月的行与添加的原始付款值合并,并将 0 放入新行中的付款列:
resampled_df = (df
.set_index('date')
.groupby(['cust_id', 'sub_id'])
.resample('MS')
.agg({'payment': sum})
.reset_index()
)
然后,我们计算每个组所有月份的平均值,并将该平均值分配给组中的每一行,将结果分配给新列:
resampled_df['avg_monthly_payment'] = (resampled_df
.groupby(['cust_id', 'sub_id'])['payment']
.transform('mean')
)
我想用 python 的同一列的平均值替换列中的现有值,最好。我想将付款平均分配给从付款的第一个月到最后一个月的所有月份。平均每月付款应分配给 cust_id 和 sub_id。
付款可能会跳过几个月并且不一样。
希望你能帮助我,因为我才刚刚开始学习 python。
数据如下所示:
cust_id | sub_id | date | payment |
---|---|---|---|
1 | A | 12/1/20 | 200 |
1 | A | 2/2/21 | 200 |
1 | A | 2/3/21 | 100 |
1 | A | 5/1/21 | 200 |
1 | B | 1/2/21 | 50 |
1 | B | 1/9/21 | 20 |
1 | B | 3/1/21 | 80 |
1 | B | 4/23/21 | 90 |
2 | C | 1/4/21 | 200 |
2 | C | 1/9/21 | 300 |
我想要的结果是这样的:
cust_id | sub_id | date | payment |
---|---|---|---|
1 | A | 12/1/20 | 116.67 |
1 | A | 1/1/21 | 116.67 |
1 | A | 2/1/21 | 116.67 |
1 | A | 3/1/21 | 116.67 |
1 | A | 4/1/21 | 116.67 |
1 | A | 5/1/21 | 116.67 |
1 | B | 1/1/21 | 60 |
1 | B | 2/1/21 | 60 |
1 | B | 3/1/21 | 60 |
1 | B | 4/1/21 | 60 |
2 | C | 1/1/21 | 500 |
非常感谢!
如评论中所述,您对 cust_id=2 和 sub_id='C' 的回答似乎与您的要求不一致,所以我选择后者。
首先,我们将日期汇总为最小值、最大值,并将付款汇总为总和:
df2 = df.groupby(['cust_id','sub_id']).agg({'date':[min,max], 'payment':sum})
df2.columns = df2.columns.get_level_values(1)
df2
我们得到
min max sum
cust_id sub_id
1 A 2020-12-01 2021-05-01 700
B 2021-01-02 2021-04-23 240
2 C 2021-01-04 2021-01-09 500
然后我们为从最小值到最大值的每一行创建每月计划。在这里你可能需要 fiddle 稍微调整一下日期才能让它们很好地排列,我只是做了一些基础来展示这个想法:
from datetime import timedelta
df2['schedule'] = df2.apply(lambda row: pd.date_range(row['min'],row['max'] + timedelta(days = 31), freq = '1M'),axis=1)
现在 df2
看起来像这样:
min max sum schedule
-------- ------------------- ------------------- ----- ---------------------------------------------------------------------------------------------------------
(1, 'A') 2020-12-01 00:00:00 2021-05-01 00:00:00 700 DatetimeIndex(['2020-12-31', '2021-01-31', '2021-02-28', '2021-03-31',
'2021-04-30', '2021-05-31'],
dtype='datetime64[ns]', freq='M')
(1, 'B') 2021-01-02 00:00:00 2021-04-23 00:00:00 240 DatetimeIndex(['2021-01-31', '2021-02-28', '2021-03-31', '2021-04-30'], dtype='datetime64[ns]', freq='M')
(2, 'C') 2021-01-04 00:00:00 2021-01-09 00:00:00 500 DatetimeIndex(['2021-01-31'], dtype='datetime64[ns]', freq='M')
现在我们 explode
我们 'schedule' 并平均分配付款,并对列名称等进行一些清理:
df3 = df2.groupby(['cust_id','sub_id'], as_index = False).apply(lambda g: g.explode('schedule'))
(df3.groupby(['cust_id','sub_id'], as_index = False)
.apply(lambda g: g.assign(sum = g['sum']/len(g)))
.reset_index(drop = False)
.drop(columns = ['min','max','level_0'])
.rename(columns = {'sum':'payment'})
)
得到
cust_id sub_id payment schedule
-- --------- -------- --------- -------------------
0 1 A 116.667 2020-12-31 00:00:00
1 1 A 116.667 2021-01-31 00:00:00
2 1 A 116.667 2021-02-28 00:00:00
3 1 A 116.667 2021-03-31 00:00:00
4 1 A 116.667 2021-04-30 00:00:00
5 1 A 116.667 2021-05-31 00:00:00
6 1 B 60 2021-01-31 00:00:00
7 1 B 60 2021-02-28 00:00:00
8 1 B 60 2021-03-31 00:00:00
9 1 B 60 2021-04-30 00:00:00
10 2 C 500 2021-01-31 00:00:00
这可以使用 resample()
和 transform()
函数通过几个步骤完成:
首先,我们将缺失的月份添加到原始 table 中,将所有日期值更改为该月的第一天,将同月的行与添加的原始付款值合并,并将 0 放入新行中的付款列:
resampled_df = (df
.set_index('date')
.groupby(['cust_id', 'sub_id'])
.resample('MS')
.agg({'payment': sum})
.reset_index()
)
然后,我们计算每个组所有月份的平均值,并将该平均值分配给组中的每一行,将结果分配给新列:
resampled_df['avg_monthly_payment'] = (resampled_df
.groupby(['cust_id', 'sub_id'])['payment']
.transform('mean')
)