创建动态范围并计算平均值
Create dynamic ranges and calculate mean
我想创建一个额外的列,其中包含基于 A 列的平均值,使用动态范围。
import numpy as np
import pandas as pd
test = {'A' : [100, 120, 70, 300, 190, 70, 300, 190, 70],
'B' : [80, 50, 64, 288, 172, 64, 288, 172, 64],
'C' : ['NO', 'NO', 'YES', 'NO', 'YES', 'YES', 'NO', 'YES', 'YES'],
'D' : [0, 1, 0, 3, 2, 2, 3, 1, 4] }
df = pd.DataFrame(data=test)
A B C D
0 100 80 NO 0
1 120 50 NO 1
2 70 64 YES 0
3 300 288 NO 3
4 190 172 YES 2
5 70 64 YES 2
6 300 288 NO 3
7 190 172 YES 1
8 70 64 YES 4
当第 C
列中的项目为 YES
时,使用第 D
列中的值作为起始行索引和行索引,从第 A
列的动态范围中获取平均值当前行 -1
作为最高行索引。
以下是我希望达到的结果。
A B C D Dyn_Ave
0 100 80 NO 0 NaN
1 120 50 NO 1 NaN
2 70 64 YES 0 110
3 300 288 NO 3 NaN
4 190 172 YES 2 185
5 70 64 YES 2 187
6 300 288 NO 3 NaN
7 190 172 YES 1 175
8 70 64 YES 4 188
虽然我遇到了以下错误 - 类型错误:无法使用非整数键按位置索引索引
,但我尝试创建该列时采用了 np.where 方法
df['Dyn_Ave'] = np.where(df['C'] == 'YES', df['A'].iloc[df['D']:df.loc['C'][-1]].mean(), np.nan)
让我们试试:
s = df['A'].cumsum().shift(fill_value=0)
df['Dyn_Ave'] = np.where(df['C'] == 'YES',
(s - s.reindex(df['D']).values) / (np.arange(len(df)) - df['D']),
np.nan)
输出:
A B C D Dyn_Ave
0 100 80 NO 0 NaN
1 120 50 NO 1 NaN
2 70 64 YES 0 110.000000
3 300 288 NO 3 NaN
4 190 172 YES 2 185.000000
5 70 64 YES 2 186.666667
6 300 288 NO 3 NaN
7 190 172 YES 1 175.000000
8 70 64 YES 4 187.500000
解释:我们先暂时忘掉C=='YES'
,关注动态平均。从第df['D']
行到第j-1
行的平均值可以看作
(cumsum[j-1] - cumsum[df['D']-1])/(j-df['D'])
或:
(cumsum.shift()[j] - cumsum.shift()[df['D']) / (j-df['D'])
这就是为什么我们首先计算 cumsum,然后移动它:
s = df['A'].cumsum().shift(fill_value=0)
要在 df['D']
处获取 cumsum,我们使用 reindex 并传递底层 numpy 数组进行减法:
(s - s.reindex(df['D']).values)
行数可以很容易看出为:
(np.arange(len(df)) - df['D'])
最后一部分只是填写 C=='YES'
的位置,就像您尝试完成的那样。
可以使用df.apply
,但会比np.where
慢。
df['Dyn_Ave'] = df[df.C == 'YES'].apply(lambda x: np.round(df.A.loc[x.D:x.name-1].mean()) ,axis=1)
df
输出:
A B C D Dyn_Ave
0 100 80 NO 0 NaN
1 120 50 NO 1 NaN
2 70 64 YES 0 110.0
3 300 288 NO 3 NaN
4 190 172 YES 2 185.0
5 70 64 YES 2 187.0
6 300 288 NO 3 NaN
7 190 172 YES 1 175.0
8 70 64 YES 4 188.0
我想创建一个额外的列,其中包含基于 A 列的平均值,使用动态范围。
import numpy as np
import pandas as pd
test = {'A' : [100, 120, 70, 300, 190, 70, 300, 190, 70],
'B' : [80, 50, 64, 288, 172, 64, 288, 172, 64],
'C' : ['NO', 'NO', 'YES', 'NO', 'YES', 'YES', 'NO', 'YES', 'YES'],
'D' : [0, 1, 0, 3, 2, 2, 3, 1, 4] }
df = pd.DataFrame(data=test)
A B C D
0 100 80 NO 0
1 120 50 NO 1
2 70 64 YES 0
3 300 288 NO 3
4 190 172 YES 2
5 70 64 YES 2
6 300 288 NO 3
7 190 172 YES 1
8 70 64 YES 4
当第 C
列中的项目为 YES
时,使用第 D
列中的值作为起始行索引和行索引,从第 A
列的动态范围中获取平均值当前行 -1
作为最高行索引。
以下是我希望达到的结果。
A B C D Dyn_Ave
0 100 80 NO 0 NaN
1 120 50 NO 1 NaN
2 70 64 YES 0 110
3 300 288 NO 3 NaN
4 190 172 YES 2 185
5 70 64 YES 2 187
6 300 288 NO 3 NaN
7 190 172 YES 1 175
8 70 64 YES 4 188
虽然我遇到了以下错误 - 类型错误:无法使用非整数键按位置索引索引
,但我尝试创建该列时采用了 np.where 方法df['Dyn_Ave'] = np.where(df['C'] == 'YES', df['A'].iloc[df['D']:df.loc['C'][-1]].mean(), np.nan)
让我们试试:
s = df['A'].cumsum().shift(fill_value=0)
df['Dyn_Ave'] = np.where(df['C'] == 'YES',
(s - s.reindex(df['D']).values) / (np.arange(len(df)) - df['D']),
np.nan)
输出:
A B C D Dyn_Ave
0 100 80 NO 0 NaN
1 120 50 NO 1 NaN
2 70 64 YES 0 110.000000
3 300 288 NO 3 NaN
4 190 172 YES 2 185.000000
5 70 64 YES 2 186.666667
6 300 288 NO 3 NaN
7 190 172 YES 1 175.000000
8 70 64 YES 4 187.500000
解释:我们先暂时忘掉C=='YES'
,关注动态平均。从第df['D']
行到第j-1
行的平均值可以看作
(cumsum[j-1] - cumsum[df['D']-1])/(j-df['D'])
或:
(cumsum.shift()[j] - cumsum.shift()[df['D']) / (j-df['D'])
这就是为什么我们首先计算 cumsum,然后移动它:
s = df['A'].cumsum().shift(fill_value=0)
要在 df['D']
处获取 cumsum,我们使用 reindex 并传递底层 numpy 数组进行减法:
(s - s.reindex(df['D']).values)
行数可以很容易看出为:
(np.arange(len(df)) - df['D'])
最后一部分只是填写 C=='YES'
的位置,就像您尝试完成的那样。
可以使用df.apply
,但会比np.where
慢。
df['Dyn_Ave'] = df[df.C == 'YES'].apply(lambda x: np.round(df.A.loc[x.D:x.name-1].mean()) ,axis=1)
df
输出:
A B C D Dyn_Ave
0 100 80 NO 0 NaN
1 120 50 NO 1 NaN
2 70 64 YES 0 110.0
3 300 288 NO 3 NaN
4 190 172 YES 2 185.0
5 70 64 YES 2 187.0
6 300 288 NO 3 NaN
7 190 172 YES 1 175.0
8 70 64 YES 4 188.0