使用map或apply引用前一行的值

2 投票
2 回答
4559 浏览
提问于 2025-04-18 04:33

假设你有一个叫做 df 的数据表,我想为每一行生成一个新的变量或者列,这个新列的值是根据前一行的值来决定的。这个 df 是有序的,所以行的顺序是有意义的。

通常,我们可以使用 map 或者 apply 来处理数据,但看起来这两种方法都不能直接访问前一行的值。

举个例子,假设现在有几行数据是 a b c,我想生成一个新的列 d,这个列的值是通过对前一行的 c 值进行某种计算得到的。

那我该如何在 pandas 中实现这个呢?

2 个回答

1

你可以使用数据框的 'apply' 函数,并利用未使用的 'kwargs' 参数来存储前一行的数据。

import pandas as pd

df = pd.DataFrame({'a':[0,1,2], 'b':[0,10,20]})

new_col = 'c'

def apply_func_decorator(func):
    prev_row = {}
    def wrapper(curr_row, **kwargs):
        val = func(curr_row, prev_row)
        prev_row.update(curr_row)
        prev_row[new_col] = val
        return val
    return wrapper

@apply_func_decorator
def running_total(curr_row, prev_row):
    return curr_row['a'] + curr_row['b'] + prev_row.get('c', 0)

df[new_col] = df.apply(running_total, axis=1)

print(df)
# Output will be:
#    a   b   c
# 0  0   0   0
# 1  1  10  11
# 2  2  20  33

这个例子使用了一个装饰器来把前一行的数据存储在一个字典里,然后在 Pandas 处理下一行时把这个字典传给函数。

注意事项 1:'prev_row' 变量在处理第一行时是空的,所以在 'apply' 函数中使用它时,我必须提供一个默认值,以避免出现 'KeyError' 错误。

注意事项 2:我比较确定这个方法会比直接使用 'apply' 操作慢,但我没有进行测试来具体了解慢多少。

4

如果你只是想根据前一行的数据进行计算,可以先计算出结果,然后再移动一下数据:

In [2]: df = pd.DataFrame({'a':[0,1,2], 'b':[0,10,20]})

In [3]: df
Out[3]:
   a   b
0  0   0
1  1  10
2  2  20

# a calculation based on other column
In [4]: df['c'] = df['b'] + 1

# shift the column
In [5]: df['c'] = df['c'].shift()

In [6]: df
Out[6]:
   a   b   c
0  0   0 NaN
1  1  10   1
2  2  20  11

如果你想根据多行的数据进行计算,可以看看 rolling_apply 这个函数。你可以在这里找到相关信息:http://pandas.pydata.org/pandas-docs/stable/computation.html#moving-rolling-statistics-momentshttp://pandas.pydata.org/pandas-docs/stable/generated/pandas.rolling_apply.html#pandas.rolling_apply

撰写回答