如何根据 pandas 的组获取变量的滞后值?

How to get the lagged values of a variable based on groups with pandas?

我想找到按连续值对数据进行分组的最有效方法,并创建一个新变量,在每组中给出前一组的值(第一组除外,其中的值应该相同).

我现在可能不是很清楚,所以这是一个玩具示例:

import pandas as pd

var = [1,1,1,2,2,3,1,1,2,4,4,4]
toy_df = pd.DataFrame(var, columns = ['var'])

我想要的输出如下:

desired_output = pd.DataFrame(
                {'var': var,
                 'lagged_var':[1,1,1,1,1,2,3,3,1,2,2,2]}
                )

    var  lagged_var
0     1           1
1     1           1
2     1           1
3     2           1
4     2           1
5     3           2
6     1           3
7     1           3
8     2           1
9     4           2
10    4           2
11    4           2

到目前为止,我想出了以下函数来解决问题:

def make_lag(var):
    groups = ( var.shift() != var ).cumsum()
    var_shifted = pd.Series([0]*len(var))
    for n_gp in groups.unique():
        if n_gp == 1: 
            var_shifted[groups == n_gp] = var[groups == n_gp]
        else:
            var_shifted[groups == n_gp] = var[groups == n_gp - 1].iloc[0]
    
    return ( var_shifted )

toy_df['lagged_values'] = toy_df.apply(lambda x: make_lag(x))

给出了想要的输出。但是,我怀疑它效率很低,因为它涉及遍历所有行。有人知道产生相同输出的矢量化方法吗?(我必须对数百个很长的时间序列重复这个任务,这真的很节省时间!)

非常感谢!

对下一个值使用Series.shift,如果匹配原始值则替换,然后通过向前和向后填充缺失值来重复值:

s = toy_df['var'].shift()
toy_df['new'] = s.mask(toy_df['var'].eq(s)).ffill().bfill()
print (toy_df)
    var  new
0     1  1.0
1     1  1.0
2     1  1.0
3     2  1.0
4     2  1.0
5     3  2.0
6     1  3.0
7     1  3.0
8     2  1.0
9     4  2.0
10    4  2.0
11    4  2.0

如果要将值转换为整数:

s = toy_df['var'].shift()
toy_df['new'] = s.mask(toy_df['var'].eq(s)).ffill().bfill().astype(int)
print (toy_df)
 var  new
0     1    1
1     1    1
2     1    1
3     2    1
4     2    1
5     3    2
6     1    3
7     1    3
8     2    1
9     4    2
10    4    2
11    4    2