NumPy vectorize pyfunc将数组扩展为参数

92dk7w1h  于 2023-08-05  发布在  其他
关注(0)|答案(2)|浏览(80)

我有一个形状为Ax2的直角坐标数组,其中A是一个任意数。这里有一个我正在谈论的例子:

>>> np.arange(20).reshape(10, 2)
array([[ 0,  1],
       [ 2,  3],
       [ 4,  5],
       [ 6,  7],
       [ 8,  9],
       [10, 11],
       [12, 13],
       [14, 15],
       [16, 17],
       [18, 19]])

字符串
我想将每个沿着轴0的两个值的数组转换为极坐标数组(也是两个值)。所以末端数组的形状也应该是Ax2。下面是我想要的输出示例:

>>> a = np.arange(20).reshape(10, 2)
>>> toPolar(a)
[[ 1.          1.57079633]
 [ 3.60555128  0.98279372]
 [ 6.40312424  0.89605538]
 [ 9.21954446  0.86217005]
 [12.04159458  0.84415399]
 [14.86606875  0.83298127]
 [17.69180601  0.82537685]
 [20.51828453  0.81986726]
 [23.34523506  0.81569192]
 [26.17250466  0.81241861]]


我通过按列拆分数组来获得x值和y值的数组,然后将这两个数组传递给通用直角坐标到极坐标函数的向量化形式,从而使以下代码工作。然而,最后一步给出了一个形状为2xA的数组,所以我需要将它转置回Ax2

def toPolar(arr):
    def rect2polar(x, y):
        r = math.sqrt(x**2 + y**2)
        ang = math.atan2(y, x)
        return (r, ang)

    vect = np.vectorize(rect2polar)
    p = vect(r[:, 0], r[:, 1])  # splits coords up and returns in 2x10 array
    p = np.transpose(p)  # converts from 2x10 back to 10x2
    return p


我认为拆分数组然后再转置是很慢的。
有没有办法跳过转置步骤,让np.vectorize创建一个以数组为输入的函数,这样我就可以沿着轴0运行向量化的函数?

7ajki6be

7ajki6be1#

你需要做的就是使用numpy函数,而不是vectorize

In [109]: def rect2polar(x, y):
     ...:         r = np.sqrt(x**2 + y**2)
                  # r=np.hypot(x,y) # faster
     ...:         ang = np.arctan2(y, x)
     ...:         return (r, ang)
     ...: 
In [110]: rect2polar(arr[:,0],arr[:,1])
Out[110]: 
(array([ 1.        ,  3.60555128,  6.40312424,  9.21954446, 12.04159458,
        14.86606875, 17.69180601, 20.51828453, 23.34523506, 26.17250466]),
 array([1.57079633, 0.98279372, 0.89605538, 0.86217005, 0.84415399,
        0.83298127, 0.82537685, 0.81986726, 0.81569192, 0.81241861]))

字符串
结果是2个数组,但它们很容易与np.transpose组合:

In [111]: np.transpose(rect2polar(arr[:,0],arr[:,1]))
Out[111]: 
array([[ 1.        ,  1.57079633],
       [ 3.60555128,  0.98279372],
       [ 6.40312424,  0.89605538],
       [ 9.21954446,  0.86217005],
       [12.04159458,  0.84415399],
       [14.86606875,  0.83298127],
       [17.69180601,  0.82537685],
       [20.51828453,  0.81986726],
       [23.34523506,  0.81569192],
       [26.17250466,  0.81241861]])


顺便说一下,np.argwhere使用相同的技巧将np.nonzero数组变成一个。
得到x,y的另一种方法是x,y = arr.T。看看x.base,我们看到x只是原始arangeview。所以这是有效率的。
组合结果数组的另一种方法是:np.array(rect2polar(arr[:,0],arr[:,1])).T .这个稍微快一点。但与您的mathvectorize版本相比,这些组合方法中的任何一种都很快。
使用math函数,使用vectorize比直接的列表解析要慢:

np.array([rect2polar(i,j) for i,j in zip(x,y)])


作为一般规则,math函数对于单个数字比等效的np更快。但对于阵列,np更快。尽管交叉点可以变化。

wgmfuz8q

wgmfuz8q2#

为了回答你的部分问题,不幸的是,我认为不可能直接将函数应用于数组“沿着轴0”而不引起某种(可能是隐藏的)Python级别的循环。问题是,大多数有用的numpy内置函数都单独使用它们的参数,而不是沿着数组中的维度。
从这个意义上说,将数据处理为一对x, y变量(每个变量的形状为A)而不是A x 2形状的数组可能更自然:

>>> x = np.arange(0, 20, 2)
>>> y = np.arange(1, 20, 2)
>>> x
array([ 0,  2,  4,  6,  8, 10, 12, 14, 16, 18])
>>> y
array([ 1,  3,  5,  7,  9, 11, 13, 15, 17, 19])

字符串
用于转换为polar的相关numpy函数是np.hypotnp.arctan2。简单地说:

>>> r = np.hypot(y, x)
>>> theta = np.arctan2(y, x)
>>> r
array([ 1.        ,  3.60555128,  6.40312424,  9.21954446, 12.04159458,
       14.86606875, 17.69180601, 20.51828453, 23.34523506, 26.17250466])
>>> theta
array([1.57079633, 0.98279372, 0.89605538, 0.86217005, 0.84415399,
       0.83298127, 0.82537685, 0.81986726, 0.81569192, 0.81241861])


话虽如此,有一些方法可以摆弄形状,使它们以你想要的方式对齐。例如,你可以通过hsplita中提取xy作为形状A x 1,然后通过hstack将它们返回到A x 2数组:

>>> a = np.arange(20).reshape(10, 2)

>>> def toPolar(arr):
...     x, y = np.hsplit(arr, 2)
...     return np.hstack([np.hypot(y, x), np.arctan2(y, x)])

>>> toPolar(a)
array([[ 1.        ,  1.57079633],
       [ 3.60555128,  0.98279372],
       [ 6.40312424,  0.89605538],
       [ 9.21954446,  0.86217005],
       [12.04159458,  0.84415399],
       [14.86606875,  0.83298127],
       [17.69180601,  0.82537685],
       [20.51828453,  0.81986726],
       [23.34523506,  0.81569192],
       [26.17250466,  0.81241861]])

相关问题