使用其他行的值将函数应用于pandas数据帧行

12

我有一个情况,需要对数据框中的一行进行计算,并且需要使用下面(或者可能是上面)的行中的值来进行这些计算(基于真实数据集的完美预测)。我从之前的df.apply调用中获取每一行,因此我可以将整个df传递给下游对象,但是考虑到我的分析对象的复杂性,这似乎不是最理想的选择。

我找到了一个相关的问题和答案[1],但实际上问题在本质上是不同的,因为我不需要整个 df 来进行计算,只需要下面 x 行的值(对于大型 df 可能会有影响)。

因此,例如:

df = pd.DataFrame([100, 200, 300, 400, 500, 600, 700, 800, 900, 1000], 
                  columns=['PRICE'])
horizon = 3

在我的逐行应用(df.apply)调用中,我需要访问以下3行(horizon)的值。如何在我的逐行应用计算中动态地获取接下来3个数据点的天真预测?例如,对于第一行,其中PRICE100,我需要使用[200, 300, 400]作为我的计算预测。

[1] 将函数应用于基于其他行的返回值的Pandas Dataframe

2个回答

10
通过在df.apply()调用中使用row.name获取行的索引,您可以生成与当前行相关的“预测”数据。这实际上是一个预处理步骤,将“预测”放到相关行上,或者如果df可在下游使用,则可以作为初始df.apply()调用的一部分完成。
df = pd.DataFrame(
    [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000],
    columns=["PRICE"]
)
horizon = 3
    
df["FORECAST"] = df.apply(
    lambda x: [df["PRICE"][x.name + 1 : x.name + horizon + 1]],
    axis=1
)

结果是这个:
   PRICE          FORECAST
0    100   [200, 300, 400]
1    200   [300, 400, 500]
2    300   [400, 500, 600]
3    400   [500, 600, 700]
4    500   [600, 700, 800]
5    600   [700, 800, 900]
6    700  [800, 900, 1000]
7    800       [900, 1000]
8    900            [1000]
9   1000                []

可以用于行级的 df.apply() 计算。
编辑: 如果您想从结果中剥离索引,请执行以下操作:“Forecast”:
df["FORECAST"] = df.apply(
    lambda x: [df["PRICE"][x.name + 1 : x.name + horizon + 1].reset_index(drop=True)],
    axis=1
)

2
您可能也会发现这非常有用。
keys = range(horizon + 1)
pd.concat([df.shift(-i) for i in keys], axis=1, keys=keys)

      0       1       2       3
  PRICE   PRICE   PRICE   PRICE
0   100   200.0   300.0   400.0
1   200   300.0   400.0   500.0
2   300   400.0   500.0   600.0
3   400   500.0   600.0   700.0
4   500   600.0   700.0   800.0
5   600   700.0   800.0   900.0
6   700   800.0   900.0  1000.0
7   800   900.0  1000.0     NaN
8   900  1000.0     NaN     NaN
9  1000     NaN     NaN     NaN

如果您将concat分配给df_c
keys = range(horizon + 1)
df_c = pd.concat([df.shift(-i) for i in keys], axis=1, keys=keys)

df_c.apply(lambda x: pd.Series([x[0].values, x[1:].values]), axis=1)

          0                       1
0   [100.0]   [200.0, 300.0, 400.0]
1   [200.0]   [300.0, 400.0, 500.0]
2   [300.0]   [400.0, 500.0, 600.0]
3   [400.0]   [500.0, 600.0, 700.0]
4   [500.0]   [600.0, 700.0, 800.0]
5   [600.0]   [700.0, 800.0, 900.0]
6   [700.0]  [800.0, 900.0, 1000.0]
7   [800.0]    [900.0, 1000.0, nan]
8   [900.0]      [1000.0, nan, nan]
9  [1000.0]         [nan, nan, nan]

你认为有没有性能上的优势,无论哪种方式,在什么情况下? - lukewitmer
1
@lukewitmer 不是的,我只是运行了 %%timeit,你的方法比我的快了5倍以上。我喜欢我的方式,因为我觉得它更优雅。但我会选择你的方式,因为它非常直观且更快。 - piRSquared

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接