Python 比较pandas groupby中的最后一个值

Python 比较pandas groupby中的最后一个值,python,pandas,pandas-groupby,Python,Pandas,Pandas Groupby,这是我的数据帧: df = pd.DataFrame({'a': list('xxxxxzzz'), 'b':[0,0,1,0,1,0,1,1], 'c': [100, 101, 105, 110, 120, 125, 100, 150], 'd':[0,0,0,1,1,0,0,0]}) 我将他们分组: groups = df.groupby(['a', 'd']) 我想在df中添加另一列,每组显示c的最后一个值与其b为0和b的最后一个值之间的差异(百分比) 例如,在第一组中,我想比较第2行

这是我的数据帧:

df = pd.DataFrame({'a': list('xxxxxzzz'), 'b':[0,0,1,0,1,0,1,1], 'c': [100, 101, 105, 110, 120, 125, 100, 150], 'd':[0,0,0,1,1,0,0,0]})
我将他们分组:

groups = df.groupby(['a', 'd'])
我想在
df
中添加另一列,每组显示
c
的最后一个值与其
b
为0和
b
的最后一个值之间的差异(百分比)

例如,在第一组中,我想比较第2行和第1行的
c

我想要的
如下所示:

('x', 0)
   a  b    c  d   result
0  x  0  100  0     3.96
1  x  0  101  0     3.96
2  x  1  105  0     3.96
('x', 1)
   a  b    c  d   result
3  x  0  110  1     9.09
4  x  1  120  1     9.09
('z', 0)
   a  b    c  d   result
5  z  0  125  0     20.0
6  z  1  100  0     20.0
7  z  1  150  0     20.0

定义自定义函数并使用

输出

    a   b   c   d   result
0   x   0   100 0   3.960396
1   x   0   101 0   3.960396
2   x   1   105 0   3.960396
3   x   0   110 1   9.090909
4   x   1   120 1   9.090909
5   z   0   125 0   20.000000
6   z   1   100 0   20.000000
7   z   1   150 0   20.000000

如果您单独需要每个组,只需使用列表理解
[func(g)for n,g in df.groupby(['a','d'])]

我们可以在这里执行以下操作:

  • 应用
    .pct\u change
    方法计算每行的百分比变化
  • 有条件地将
    result
    列的值填入
    NaN
  • 之后,用
    b填充
    a
    ffill
  • 因此,我们得到:

       a  b    c  d  result
    0  x  0  100  0     NaN
    1  x  0  101  0     NaN
    2  x  1  105  0    3.96
    3  x  0  110  1     NaN
    4  x  1  120  1    9.09
    5  z  0  125  0     NaN
    6  z  1  100  0   20.00
    7  z  1  150  0     NaN
    
    # first we apply .pct_change to all rows
    df['result'] = abs(round(df.groupby(['a', 'd', 'b']).c.pct_change() * 100, 2))
    
    # after that we check if the value if b = 1 and the value of the row before = 0 and we fill in NaN if condition not true
    df['result'] = np.where((df.b == 1) & (df.b.shift(1) == 0), df.result, np.NaN)
    
       a  b    c  d  result
    0  x  0  100  0     NaN
    1  x  0  101  0     NaN
    2  x  1  105  0    3.96
    3  x  0  110  1     NaN
    4  x  1  120  1    9.09
    5  z  0  125  0     NaN
    6  z  1  100  0   20.00
    7  z  1  150  0     NaN
    
    # then backfill and forwardfill NaN
    df.result.fillna(method='bfill', inplace=True)
    df.result.fillna(method='ffill', inplace=True)
    
    print(df)
       a  b    c  d  result
    0  x  0  100  0    3.96
    1  x  0  101  0    3.96
    2  x  1  105  0    3.96
    3  x  0  110  1    9.09
    4  x  1  120  1    9.09
    5  z  0  125  0   20.00
    6  z  1  100  0   20.00
    7  z  1  150  0   20.00