python - Pandas apply() 自定义函数使用多个列作为 "input"

标签 python pandas apply

也许查看这个简单的示例将帮助您理解我尝试做的事情:

import pandas as pd
df = pd.DataFrame({"A": [10,20,30,50,70,40], "B": [20,30,10,15,20,30]})


def _custom_function(X):    
    # whatever... just for the purpose of the example
    # but I need X to be the actual df and not a series

    Y = sum((X['A'] / X['B']) + (0.2 * X['B']))   
    return Y


df['C'] = df.rolling(2).apply(_custom_function, axis=0)

当调用自定义函数时,X是Series类型,并且只有df的第一列。是否可以通过 apply 函数传递 df ?

编辑:可以使用rolling().apply():

import pandas as pd
df = pd.DataFrame({"A": [10,20,30,50,70,40], "B": [20,30,10,15,20,30]})


def _custom_function(X):    
    # whatever... just for the purpose of the example
    Y = sum(0.2 * X)    
    return Y


df['C'] = df['A'].rolling(2).apply(_custom_function)

第二次编辑:滚动列表理解的行为不符合预期

for x in df.rolling(3):
    print(x)

正如您在下面的示例中看到的,两种方法不会给出相同的输出:

import pandas as pd
df = pd.DataFrame({"A": [10,20,30,50,70,40], "B": [20,30,10,15,20,30]})
df['C'] = 0.2


def _custom_function_df(X):    
    # whatever... just for the purpose of the example
    # but I need X to be the actual df and not a series
    Y = sum(X['C'] * X['B'])
    return Y

def _custom_function_series(X):    
    # whatever... just for the purpose of the example
    # but I need X to be the actual df and not a series
    Y = sum(0.2 * X)
    return Y


df['result'] = df['B'].rolling(3).apply(_custom_function_series)

df['result2'] = [x.pipe(_custom_function_df) for x in df.rolling(3, min_periods=3)]

列表推导式滚动输出第一行(没有预期的 NaN),但仅在滚动窗口 len(x) = 3 之后开始正确的滚动。

enter image description here

提前致谢!

最佳答案

将 DataFrame 传递给函数:

df['C'] = _custom_function(df)

或者使用DataFrame.pipe :

df['C'] = df.pipe(_custom_function)

print (df)
    A   B         C
0  10  20  4.500000
1  20  30  6.666667
2  30  10  5.000000
3  50  15  6.333333
4  70  20  7.500000
5  40  30  7.333333

编辑:Rolling.apply每列单独工作,因此不能在此处使用。

可能的解决方案:

df['C'] = [x.pipe(_custom_function) for x in df.rolling(2)]
print (df)
    A   B          C
0  10  20   4.500000
1  20  30  11.166667
2  30  10  11.666667
3  50  15  11.333333
4  70  20  13.833333
5  40  30  14.833333

编辑:如果似乎有错误,默认滚动的工作方式类似于min_periods=1

这是解决方案(黑客):

df['result'] = df['B'].rolling(3).apply(_custom_function_series)

df['result2']=[x.pipe(_custom_function_df) if len(x)==3 else np.nan for x in df.rolling(3)]

print (df)
    A   B    C  result  result2
0  10  20  0.2     NaN      NaN
1  20  30  0.2     NaN      NaN
2  30  10  0.2    12.0     12.0
3  50  15  0.2    11.0     11.0
4  70  20  0.2     9.0      9.0
5  40  30  0.2    13.0     13.0

关于python - Pandas apply() 自定义函数使用多个列作为 "input",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66762002/

相关文章:

python - django无法删除音频文件,因为它被音频播放器使用

python - 如何基于部分匹配选择DataFrame列?

python - MySQL连接器

Python Pandas 将列表中的多个 SAS 文件读取到单独的数据帧中

python - 如何将数据写入 Redshift,这是在 Python 中创建的数据框的结果?

r - 选择一个数据框中与另一数据框中的行部分匹配的行

python - 我可以在没有 for 循环的情况下将函数应用于 Pandas 数据框中的多个列吗?

python - 将两个每日系列合并为一小时系列

python - 如何使用基于列名的向量化运算?

r - 函数对给定字符串长度的可变数量的子字符串进行采样