【问题标题】:Efficient python pandas equivalent/implementation of R sweep with multiple arguments具有多个参数的 R 扫描的高效 python pandas 等效/实现
【发布时间】:2019-02-10 21:24:10
【问题描述】:

试图提供与R 的sweep 函数等效的python 的其他问题(如here)并没有真正解决最有用的多个参数的情况。

假设我希望对 Dataframe 的每一行应用一个 2 参数函数,并使用来自另一个 DataFrame 的列的匹配元素:

df = data.frame("A" = 1:3,"B" = 11:13)
df2= data.frame("X" = 10:12,"Y" = 10000:10002)
sweep(df,1, FUN="*",df2$X)

在python 中,我使用apply 得到了等价物,基本上是通过行计数的循环。

df = pd.DataFrame( { "A" : range(1,4),"B" : range(11,14) } )
df2 = pd.DataFrame( { "X" : range(10,13),"Y" : range(10000,10003) } )
pd.Series(range(df.shape[0])).apply(lambda row_count: np.multiply(df.iloc[row_count,:],df2.iloc[row_count,df2.columns.get_loc('X')]))

我非常怀疑这在pandas 中是否有效,有什么更好的方法呢?

在应用* 时,这两个代码位都应生成 6 个数字的数据帧/矩阵:

   A   B
1 10 110
2 22 132
3 36 156

我应该明确说明,目的是将自己的功能插入到这种sweep 类似行为中说:

df = data.frame("A" = 1:3,"B" = 11:13)
df2= data.frame("X" = 10:12,"Y" = 10000:10002)
myFunc = function(a,b) { floor((a + b)^min(a/2,b/3))  }
sweep(df,1, FUN=myFunc,df2$X)

导致:

 A B
[1,] 3 4
[2,] 3 4
[3,] 3 5

在 python pandas 中这样做的好方法是什么?

【问题讨论】:

  • 我不明白你为什么需要sweep,因为你只是在做df*df2$X。你能举一个你实际需要sweep的例子吗?
  • 我修改了问题。感谢您的评论,乘法不是问题的重点。
  • 你的问题是什么?当然,您可以使用apply、but I wouldn't recommend it's use unless you're sure there's no better option。现在,什么是“更好”实际上取决于您正在实现的功能。没有更多上下文,您的问题无法作为答案得到令人满意的解决,抱歉。
  • 如果您确定迭代解决方案是唯一的,there are better alternatives using loops and comprehensions,更不用说用于 JIT 编译和更好性能的 numba 和 cython。那么,你的问题究竟是什么?
  • 最好更新您的问题以添加有关您的实际问题的更多信息。

标签: python pandas dataframe


【解决方案1】:

如果我理解正确,您正在寻找将二进制函数 f(x,y) 逐行应用于数据帧(对于 x),其中参数来自 y 的系列。一种方法是从 pandas 内部借用实现。如果你想扩展这个函数(例如沿列应用,只要 f 是二进制的,它可以以类似的方式完成。如果你需要更多参数,你可以简单地在 f 上做一个partial 使其成为二进制

import pandas as pd
from pandas.core.dtypes.generic import ABCSeries

def sweep(df, series, FUN):
    assert isinstance(series, ABCSeries)

    # row-wise application
    assert len(df) == len(series)
    return df._combine_match_index(series, FUN)


# define your binary operator
def f(x, y):
    return x*y    

# the input data frames
df = pd.DataFrame( { "A" : range(1,4),"B" : range(11,14) } )
df2 = pd.DataFrame( { "X" : range(10,13),"Y" : range(10000,10003) } )

# apply
test1 = sweep(df, df2.X, f)

# performance
# %timeit sweep(df, df2.X, f)
# 155 µs ± 1.27 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)#

# another method
import numpy as np
test2 = pd.Series(range(df.shape[0])).apply(lambda row_count: np.multiply(df.iloc[row_count,:],df2.iloc[row_count,df2.columns.get_loc('X')]))

# %timeit performance
# 1.54 ms ± 56.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

assert all(test1 == test2)

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    在pandas

    df.mul(df2.X,axis=0)
        A    B
    0  10  110
    1  22  132
    2  36  156
    

    【讨论】:

    • 非常好 +1,但如果它不是乘法(即不是 pandas.Dataframe 的内置函数?)
    • @HansRoggeman 例如? BTW pandas 对索引敏感,这意味着您可以在两个数据帧之间分配值,匹配索引将具有值,如果不匹配将返回 NaN
    • 好的,假设我想将这两个数字与一个不同的统一随机数相乘,然后得到最接近两个乘积之和的素数?但实际上没有内置的任何东西都是好的......只是在这个sweep-like能力中寻找通过自己的多参数函数插入的能力。
    • @HansRoggeman 例如n=range(df.shape[0]) ;np.multiply(df.iloc[n,:],df2.iloc[n,:]['X'])
    • 这与我所拥有的非常接近。在熊猫中可能无法做到这一点,如果在设置赏金后没有任何问题,我会接受答案。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-26
    • 2011-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多