Python中NumPy或Pandas等价于R函数sweep()

5

什么是 numpy 或者 pandas 中等同于 R 函数 sweep() 的函数?

详细说明: 在 R 中,假设我们有一个系数向量,例如 beta (数值类型),和一个数组,例如 data (20x5 数值类型)。我想将向量叠加到数组的每一行,并乘以相应的元素。然后返回结果为 (20x5) 的数组,我可以使用 sweep() 来实现这一点。

等效的样例 R 代码:

beta <-  c(10, 20, 30, 40)
data <- array(1:20,c(5,4))
sweep(data,MARGIN=2,beta,`*`)
#---------------
 > data
      [,1] [,2] [,3] [,4]
 [1,]    1    6   11   16
 [2,]    2    7   12   17
 [3,]    3    8   13   18
 [4,]    4    9   14   19
 [5,]    5   10   15   20

 > beta
 [1] 10 20 30 40

 > sweep(data,MARGIN=2,beta,`*`)
      [,1] [,2] [,3] [,4]
 [1,]   10  120  330  640
 [2,]   20  140  360  680
 [3,]   30  160  390  720
 [4,]   40  180  420  760
 [5,]   50  200  450  800

我听说Python中的numpypandas非常出色,它们似乎有很多类似于R的命令。使用这些库实现相同功能的最快方法是什么?实际数据有数百万行和约50列。beta向量当然与数据兼容。


3
由于一些有经验的Pandas用户可能没有安装R,因此展示sweep函数的输入和输出结果可以极大地改善这个问题。 - Paul H
这个MARGIN是什么?文档没有明确说明仅仅扫描(即beta * data)和使用MARGIN之间的区别。 - Andy Hayden
MARGIN 表示是在列上还是行上进行操作,MARGIN=2 表示列,MARGIN=1 表示行。 - infominer
可能是重复问题?https://dev59.com/7nA65IYBdhLWcg3wxRk8 - infominer
需要稍微调整一下,但是 vstack 和例如 for i in range(1,6): out = i*array([10, 20, 30, 40]) 应该可以解决问题。 - Aleksander Lidtke
显示剩余3条评论
3个回答

6
Pandas也有一个apply()方法,这种方法就是R的sweep()在幕后使用的。 (请注意,MARGIN参数在许多pandas函数中与axis参数“等效”,除了它取值0和1而不是1和2。)
np.random.seed = 1    
beta = pd.Series(np.random.randn(5))    
data = pd.DataFrame(np.random.randn(20, 5))

您可以使用apply函数对每一行进行调用的方法:

data.apply(lambda row: row * beta, axis=1)

注意:当axis=0时,将应用于每列,这是默认设置,因为数据按列存储,因此列操作更有效率。
然而,在这种情况下,通过逐行相乘可以使向量化变得显著更快(并且更易读)。
In [21]: data.apply(lambda row: row * beta, axis=1).head()
Out[21]:
          0         1         2         3         4
0 -0.024827 -1.465294 -0.416155 -0.369182 -0.649587
1  0.026433  0.355915 -0.672302  0.225446 -0.520374
2  0.042254 -1.223200 -0.545957  0.103864 -0.372855
3  0.086367  0.218539 -1.033671  0.218388 -0.598549
4  0.203071 -3.402876  0.192504 -0.147548 -0.726001

In [22]: data.mul(beta, axis=1).head()  # just show first few rows with head
Out[22]:
          0         1         2         3         4
0 -0.024827 -1.465294 -0.416155 -0.369182 -0.649587
1  0.026433  0.355915 -0.672302  0.225446 -0.520374
2  0.042254 -1.223200 -0.545957  0.103864 -0.372855
3  0.086367  0.218539 -1.033671  0.218388 -0.598549
4  0.203071 -3.402876  0.192504 -0.147548 -0.726001

注意:这比使用*更加健壮/允许更多控制。

在numpy中你也可以做同样的事情(即在这里使用data.values),直接相乘会更快,因为它不需要担心数据对齐,或者使用vectorize而不是apply。


非常好的答案。我现在正在尝试这种方法,并且有一个问题。您能否请评论一下在apply中使用lambda的用途?与使用def声明的函数相比,有什么优势吗?非常感谢。 - sriramn
这只是一个匿名函数,除了令人愉悦/简洁的语法之外,没有理由偏爱它! - Andy Hayden

4
在numpy中,这个概念被称为“广播”。例如:
import numpy as np
x = np.random.random((4, 3))
x * np.array(range(4))[:, np.newaxis] # sweep along the rows
x + np.array(range(3))[np.newaxis, :] # sweep along the columns

-1

是的,已经编辑并包含了在numpy中等效调用的参考。我建议我的代码作为速度问题的解决方法,因为扫描对于矩阵乘法来说很慢。O.P可以查看我链接的答案以查看运行时间。 - infominer

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