使用map或apply引用前一行的值
假设你有一个叫做 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-moments 和 http://pandas.pydata.org/pandas-docs/stable/generated/pandas.rolling_apply.html#pandas.rolling_apply