当前位置: 首页 > 面试题库 >

如何将通用函数应用于numpy行?

庞乐池
2023-03-14
问题内容

在将其标记为重复之前,让我向您解释,我已经阅读了此页面以及许多其他内容,但仍然没有找到解决问题的方法。

这就是我遇到的问题:给定两个2D数组,我想在两个数组上应用函数F。F将两个一维数组作为输入。

import numpy as np
a = np.arange(15).reshape([3,5])
b = np.arange(30, step=2).reshape([3,5])

# what is the 'numpy' equivalent of the following?
np.array([np.dot(x,y) for x,y in zip(a,b)])

请注意,这np.dot仅用于演示。这里真正的问题是在两组一维数组上工作的泛型函数F。

  • 向量化要么完全失败,要么出错,或者应用逐个元素的功能,而不是逐个数组(或逐行)
  • np.apply_along_axis迭代地应用功能;例如,使用上面所定义的变量,它F(a[0], b[0])和与此结合F(a[0], b[1])F(a[0], b[2])。这不是我想要的。理想情况下,我希望它停止在F(a[0], b[0])
  • 索引切片/高级切片也不符合我的要求。例如,如果我这样做,则会np.dot(a[np.arange(3)], b[np.arange(3)])引发ValueError,表示形状(3,5)和(3,5)没有对齐。我不知道该如何解决。

我试图以任何可能的方式解决此问题,但我想到的唯一解决方案是使用列表理解。但是我担心使用列表理解会降低性能。如果可能,我想使用numpy操作达到相同的效果。我该怎么做呢?


问题答案:

此类问题已被SO淘汰,但我将尝试说明您的框架存在的问题:

In [1]: a = np.arange(15).reshape([3,5])
   ...: b = np.arange(30, step=2).reshape([3,5])
   ...: 
In [2]: def f(x,y):
   ...:     return np.dot(x,y)

压缩理解

该列表解析方法适用f于3行ab。也就是说,像遍历列表一样在两个数组上进行迭代。每次调用时,您的函数将获得2个1d数组。
dot可以接受其他形状,但目前我们假装它仅适用于一对1ds

In [3]: np.array([f(x,y) for x,y in zip(a,b)])
Out[3]: array([  60,  510, 1460])
In [4]: np.dot(a[0],b[0])
Out[4]: 60

向量化/ frompyfunc

np.vectorize迭代输入(使用广播-
可能很方便),并给出函数标量值。我将用frompyfuncreturn来说明一个对象dtype数组(并由所使用vectorize):

In [5]: vf = np.frompyfunc(f, 2,1)
In [6]: vf(a,b)
Out[6]: 
array([[0, 2, 8, 18, 32],
       [50, 72, 98, 128, 162],
       [200, 242, 288, 338, 392]], dtype=object)

因此结果是(3,5)数组;偶然地跨列求和得到期望的结果

In [9]: vf(a,b).sum(axis=1)
Out[9]: array([60, 510, 1460], dtype=object)

np.vectorize 没有做出任何速度承诺。

apply_along_axis

我不知道你怎么用apply_along_axis。它只需要一个数组。经过大量设置后,它最终完成了(对于像这样的2d数组a):

for i in range(3):
    idx = (i, slice(None))
    outarr[idx] = asanyarray(func1d(arr[idx], *args, **kwargs))

对于3d和更大的尺寸,它使在“其他”轴上的迭代更加简单;对于2d来说,这是过分的杀伤力。无论如何,它不会加快计算速度。它仍然是迭代。

apply_along_axis采用arr*args。迭代arr,但使用*args整体。)。

索引编制

np.dot(a[np.arange(3)], b[np.arange(3)])

是相同的

np.dot(a, b)

dot是矩阵乘积,(3,5)与(5,3)一起产生(3,3)。它将1d作为特殊情况处理(请参阅文档),(3)与(3,)产生(3,)。

迭代

对于真正的泛型来说f(x,y),压缩列表理解的唯一替代方法是如下所示的索引循环:

In [18]: c = np.zeros((a.shape[0]))
In [19]: for i in range(a.shape[0]):
    ...:    c[i] = f(a[i,:], b[i,:])
In [20]: c
Out[20]: array([   60.,   510.,  1460.])

速度会差不多。(可以通过将操作移至已编译的代码cython,但我认为您不准备深入了解该代码。)

如评论中所述,如果数组为(N,M),并且N与相比较小M,则此迭代的成本并不高。也就是说,完成一个大任务的几个循环是可以的。如果它们简化了大型阵列内存管理,它们甚至可能更快。

最好

理想的解决方案是使用numpy编译函数重写通用函数,使其可用于2d数组。

在矩阵乘法的情况下,einsum已在编译代码中实现了“乘积和”的广义形式:

In [22]: np.einsum('ij,ij->i',a,b)
Out[22]: array([  60,  510, 1460])

matmul 也可以推广该产品,但最适合3D阵列:

In [25]: a[:,None,:]@b[:,:,None]    # needs reshape
Out[25]: 
array([[[  60]],

       [[ 510]],

       [[1460]]])


 类似资料:
  • 问题内容: 我对熊猫还很陌生,所以我希望这将是一个简单的答案(我也感谢所有指向数据框设置的指针) 假设我有以下DataFrame: 现在,我想按“ gp”分组并获取“ vector”的均值 我试过了 乃至 但我收到一个错误,没有要聚合的“数字类型”。那么np.arrays在熊猫中不起作用吗? 问题答案: 对我来说,它有效: 我取两次平均值,因为您想要向量均值的均值组值(不是吗?)。 如果要使用均值

  • 我有以下函数(一个以列作为输入的热编码函数)。我基本上想把它应用到我的数据框中的一列,但似乎不明白出了什么问题。 猜我怎么称呼它有问题?

  • 我必须从二维坐标计算希尔伯特曲线上的距离。使用hilbertcurve包,我构建了自己的“hilbert”函数。坐标存储在数据帧(列1和列2)中。如您所见,我的函数在应用于两个值(test)时有效。 然而,它只是不工作时,应用行明智通过应用函数!这是为什么呢?我到底做错了什么?我需要一个额外的列“希尔伯特”,希尔伯特距离在列“col_1”和“col_2”中给出。 最后一个命令以错误结束: 谢谢你的

  • 怎么办? **添加详细示例如下***

  • 问题内容: 我是Python的新手,正在学习 TensorFlow 。在使用 notMNIST数据集 的教程中,他们提供了示例代码以将标签矩阵转换为n之一的编码数组。 目标是获取一个由标签整数0 … 9组成的数组,并返回一个矩阵,其中每个整数都已转换为n之一的编码数组,如下所示: 他们为此提供的代码是: 但是,我根本不了解这段代码是如何做到的。看起来它只是生成一个介于0到9之间的整数数组,然后将其

  • 假设我有这个命令代码: 我该如何以函数式的方式写这篇文章(就像fold在Scala中做的那样)?