【问题标题】:Make Multiple Shifted (Lagged) Columns in Pandas在 Pandas 中创建多个移位(滞后)列
【发布时间】:2022-01-10 23:21:10
【问题描述】:

我有一个时间序列 DataFrame,我想将我的 200 个特征/列中的每一个复制为额外的滞后特征。所以目前我在时间 t 有特征,并想在时间步长 t-1、t-2 等创建特征。

我知道这最好用 df.shift() 来完成,但我很难把它放在一起。我还想将列重命名为“feature (t-1)”、“feature (t-2)”。

我的伪代码尝试是这样的:

lagged_values = [1,2,3,10]
for every lagged_values
    for every column, make a new feature column with df.shift(lagged_values)
    make new column have name 'original col name'+'(t-(lagged_values))'

最后,如果我有 200 列和 4 个滞后时间步长,我将拥有一个具有 1,000 个特征的新 df(在 t、t-1、t-2、t-3 和 t-10 各 200 个)。

我发现了类似的东西,但它没有按照machine learning mastery 保留原始列名(重命名为 var1、var2 等)。不幸的是,我对它的理解不够好,无法根据我的问题对其进行修改。

def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):
    """
    Frame a time series as a supervised learning dataset.
    Arguments:
        data: Sequence of observations as a list or NumPy array.
        n_in: Number of lag observations as input (X).
        n_out: Number of observations as output (y).
        dropnan: Boolean whether or not to drop rows with NaN values.
    Returns:
        Pandas DataFrame of series framed for supervised learning.
    """
    n_vars = 1 if type(data) is list else data.shape[1]
    df = DataFrame(data)
    cols, names = list(), list()
    # input sequence (t-n, ... t-1)
    for i in range(n_in, 0, -1):
        cols.append(df.shift(i))
        names += [('var%d(t-%d)' % (j+1, i)) for j in range(n_vars)]
    # forecast sequence (t, t+1, ... t+n)
    for i in range(0, n_out):
        cols.append(df.shift(-i))
        if i == 0:
            names += [('var%d(t)' % (j+1)) for j in range(n_vars)]
        else:
            names += [('var%d(t+%d)' % (j+1, i)) for j in range(n_vars)]
    # put it all together
    agg = concat(cols, axis=1)
    agg.columns = names
    # drop rows with NaN values
    if dropnan:
        agg.dropna(inplace=True)
    return agg

【问题讨论】:

  • 一些示例数据集和您想要的输出会有所帮助。

标签: python pandas


【解决方案1】:

您可以使用字典理解创建其他列,然后通过 assign 将它们添加到您的数据框中。

df = pd.DataFrame(np.random.randn(5, 2), columns=list('AB'))

lags = range(1, 3)  # Just two lags for demonstration.

>>> df.assign(**{
    f'{col} (t-{lag})': df[col].shift(lag)
    for lag in lags
    for col in df
})
          A         B   A (t-1)   A (t-2)   B (t-1)   B (t-2)
0 -0.773571  1.945746       NaN       NaN       NaN       NaN
1  1.375648  0.058043 -0.773571       NaN  1.945746       NaN
2  0.727642  1.802386  1.375648 -0.773571  0.058043  1.945746
3 -2.427135 -0.780636  0.727642  1.375648  1.802386  0.058043
4  1.542809 -0.620816 -2.427135  0.727642 -0.780636  1.802386

【讨论】:

  • with f-strings /eyebrowbrraise df.assign(**{f'{col} (n-{n})': df[col].shift(n) for n in lags for col in df})
  • 完全使用这个名字的理解传递给assign...大粉丝
  • 我以前没有使用过 f-strings,所以感谢您的指点。 cito.github.io/blog/f-strings
  • 谢谢你,如何只为AB 设置滞后列,如果我们有超过这两列,我使用col = ['A', 'B'],但它不起作用。跨度>
【解决方案2】:

如果您有一个大型数据框并依赖大量滞后值,您可能希望使用pd.concatpd.DataFrame.add_sufix 应用更有效的解决方案:

df = pd.DataFrame(np.random.randn(5, 2), columns=list('AB'))    
lags = range(0, 3)

df = pd.concat([df.shift(t).add_suffix(f" (t-{t})") for t in lags], axis=1)  # add lags

【讨论】:

    【解决方案3】:

    跨滞后映射并一次移动所有列的速度要快得多。父亲比遍历每个滞后/列..

    from functools import partial
    
    def addSimpleLags(df,lag_list,col_list,direction = 'lag'):
    
        if direction == 'lead':
            lag_list = map(lambda x: x*(-1),lag_list)
    
        arr_lags = list(map(partial(_buildLags,df=df,
                            col_list=col_list,
                            direction = direction),
                    lag_list))
    
        df = pd.concat([df]+arr_lags,axis = 1)
    
        return df
    
    def _buildLags(lag,df,col_list,direction):
    
        return df[col_list].shift(lag).add_suffix('_{}_{}'.format(np.abs(lag),direction))
    

    试试这个...比公认的解决方案快约 5 倍(5 滞后 x 261 列 x 3M 行)

    【讨论】:

      猜你喜欢
      • 2017-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-06
      • 1970-01-01
      • 1970-01-01
      • 2015-01-16
      • 2012-11-19
      相关资源
      最近更新 更多