【问题标题】:Using numpy to vectorize subtraction of array with scalar (via another array) without using double for-loop使用 numpy 向量化带有标量的数组减法(通过另一个数组)而不使用双 for 循环
【发布时间】:2019-03-29 16:14:36
【问题描述】:

假设有人想使用numpy 来向量化数组减法。例如,考虑以下设置(下面的代码):我正在计算具有给定质心的一些 (x,y) 点之间的euclidean distance。这个问题的原因是下面的示例代码正好适用于二维(xy),但我想将此操作推广到 N 维以适应我的k-means algorithm .下面的代码只是计算给定质心的误差。

import numpy as np

np.random.seed(10) ## for reproducibility
x = np.random.normal(40, 10, 10)
y = np.random.normal(50, 10, 10)
data = np.array([x, y])

centroids = np.array([[25, 75], [45, 55], [20, 80], [40, 60]])
k = len(centroids)
print("\nDATA:\n{}\n\n{} CENTROIDS:\n{}\n".format(data, k, centroids))
partials = np.array([[(data[i] - centroid[i])**2 for i in range(len(data))] for centroid in centroids])
res = np.sqrt(np.sum(partials))
print("\nPARTIAL DISTANCES:\n{}\n\nTOTAL DISTANCE:\n{}\n".format(partials, res))

运行上面的代码会产生以下输出:

DATA:
[[53.31586504 47.15278974 24.54599708 39.9161615  46.21335974 32.79914439
  42.65511586 41.08548526 40.04291431 38.25399789]
 [54.3302619  62.03037374 40.34934329 60.28274078 52.2863013  54.45137613
  38.63397788 51.35136878 64.84537002 39.20195114]]

4 CENTROIDS:
[[25 75]
 [45 55]
 [20 80]
 [40 60]]


PARTIAL DISTANCES:
[[[8.01788213e+02 4.90746093e+02 2.06118652e-01 2.22491874e+02
   4.50006631e+02 6.08266533e+01 3.11703116e+02 2.58742836e+02
   2.26289271e+02 1.75668460e+02]
  [4.27238073e+02 1.68211205e+02 1.20066801e+03 2.16597719e+02
   5.15912109e+02 4.22245943e+02 1.32248756e+03 5.59257758e+02
   1.03116510e+02 1.28150030e+03]]

 [[6.91536114e+01 4.63450368e+00 4.18366235e+02 2.58454139e+01
   1.47224186e+00 1.48860878e+02 5.49848164e+00 1.53234257e+01
   2.45726985e+01 4.55085444e+01]
  [4.48549123e-01 4.94261549e+01 2.14641742e+02 2.79073501e+01
   7.36416063e+00 3.00988153e-01 2.67846680e+02 1.33125097e+01
   9.69313108e+01 2.49578348e+02]]

 [[1.10994686e+03 7.37273991e+02 2.06660894e+01 3.96653489e+02
   6.87140229e+02 1.63818097e+02 5.13254274e+02 4.44597689e+02
   4.01718414e+02 3.33208439e+02]
  [6.58935454e+02 3.22907468e+02 1.57217458e+03 3.88770311e+02
   7.68049096e+02 6.52732182e+02 1.71114779e+03 8.20744071e+02
   2.29662810e+02 1.66448079e+03]]

 [[1.77312262e+02 5.11624011e+01 2.38826206e+02 7.02889396e-03
   3.86058392e+01 5.18523215e+01 7.04964021e+00 1.17827824e+00
   1.84163795e-03 3.04852335e+00]
  [3.21459301e+01 4.12241752e+00 3.86148309e+02 7.99423486e-02
   5.95011476e+01 3.07872269e+01 4.56506901e+02 7.47988219e+01
   2.34776106e+01 4.32558836e+02]]]

TOTAL DISTANCE:
163.00230640508593

我在这段代码中使用了嵌套的双 for 循环。我注意到numpy.subtract 没有axis kwarg。我在想我可以numpy.tile 质心来执行减法,但这对于大 N 来说似乎效率低下,特别是如果需要多次迭代才能收敛。有没有不同的方法来矢量化这个操作?

【问题讨论】:

  • 所以data 是 (2,10) 形状,centroids (4,2) 和 partials (4,2,10)。如果 centroids 扩展为 (4,2,1),则广播会处理其余部分。
  • data - centroids[:,:,None]

标签: python-3.x numpy for-loop vector vectorization


【解决方案1】:

您可以使用expand_dims 来创建缺失轴:

partials = (data.T - np.expand_dims(centroids, axis=1))**2

这样data.T 的形状为(10,2),然后您从中减去一个形状为(4,1,2) 的数组,因此减法将在该数组的第二个轴上广播。

您也可以通过在centroids 末尾添加一个额外的轴而不是转置`data:

partials = (data - centroids[:,:,np.newaxis])**2

【讨论】:

    猜你喜欢
    • 2018-08-26
    • 2020-10-20
    • 1970-01-01
    • 1970-01-01
    • 2016-02-20
    • 1970-01-01
    • 1970-01-01
    • 2017-07-26
    • 2021-04-29
    相关资源
    最近更新 更多