1
>>> import numpy as np
>>> X = np.arange(27).reshape(3, 3, 3)
>>> x = [0, 1]
>>> X[x, x, :]
array([[ 0,  1,  2],
       [12, 13, 14]])

我需要将它沿0维度求和,但在现实世界中,矩阵是巨大的,我更愿意沿-1维度求和,这由于内存布局而更快。因此,我希望将结果转置:

array([[ 0, 12],
       [ 1, 13],
       [ 2, 14]])

我怎么做?我希望 numpy 的“高级索引”的结果被隐式转置。最后明确地转.T置它甚至更慢,不是一种选择。

Update1:​​在现实世界中,高级索引是不可避免的,并且下标不保证相同。

>>> x = [0, 0, 1]
>>> y = [0, 1, 1]
>>> X[x, y, :]
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [12, 13, 14]])

Update2:为了澄清这不是XY 问题,这里是实际问题:

我有一个大矩阵X,其中包含x来自某些概率分布的元素。元素的概率分布取决于元素的邻域。这个分布是未知的,所以我遵循Gibbs 抽样程序来构建一个矩阵,其中包含来自这个分布的元素。简而言之,这意味着我对矩阵进行了一些初步猜测X,然后我不断迭代矩阵的元素,并使用取决于 的相邻值的公式X更新每个元素。因此,对于矩阵的任何元素,我需要获取其邻居(高级索引)并对它们执行一些操作(在我的示例中求和)。我用过xxline_profiler看到在我的代码中花费大部分时间的行是取数组相对于维度的总和,0而不是-1. 因此,我想知道是否有一种方法可以通过高级索引生成已经转置的矩阵。

4

1 回答 1

4

我想将它沿 0 维求和,但在现实世界中,矩阵很大,我更愿意沿 -1 维求和,由于内存布局,这更快。

我不完全确定你的意思。如果底层数组是行优先的(默认值, ie X.flags.c_contiguous == True),那么沿第0维求和可能会稍微快一些。简单地使用or转置一个数组,它本身不会改变数组在内存中的布局方式。.Tnp.transpose()

例如:

# X is row-major
print(X.flags.c_contiguous)
# True

# Y is just a transposed view of X
Y = X.T

# the indices of the elements in Y are transposed, but their layout in memory
# is the same as in X, therefore Y is column-major rather than row-major
print(Y.flags.c_contiguous)
# False

您可以从行优先转换为列优先,例如使用,但如果不在内存中np.asfortranarray(X)制作完整副本,则无法执行此转换。X除非您要对列执行大量操作,X否则几乎肯定不值得进行转换。

如果您想将求和的结果存储在以列为主的数组中,您可以使用out=kwarg to X.sum(),例如:

result = np.empty((3, 3), order='F') # Fortran-order, i.e. column-major
X.sum(0, out=result)

但是,在您的情况下,行与列求和之间的差异可能非常小 - 因为您已经将索引不相邻的元素,所以X您已经失去了通常会进行求和的参考空间局部性的好处在行上稍快。

例如:

X = np.random.randn(100, 100, 100)

# summing over whole rows is slightly faster than summing over whole columns
%timeit X.sum(0)
# 1000 loops, best of 3: 438 µs per loop
%timeit X.T.sum(0)
# 1000 loops, best of 3: 486 µs per loop

# however, the locality advantage disappears when you are addressing
# non-adjacent elements using fancy indexing
%timeit X[[0, 0, 1], [0, 1, 1], :].sum()
# 100000 loops, best of 3: 4.72 µs per loop
%timeit X.T[[0, 0, 1], [0, 1, 1], :].sum()
# 100000 loops, best of 3: 4.63 µs per loop

更新

@senderle在评论中提到,使用 numpy v1.6.2 他看到了相反的时序顺序,即X.sum(-1)X.sum(0)行优先数组更快。这似乎与他正在使用的 numpy 版本有关 - 使用 v1.6.2 我可以重现他观察到的顺序,但使用两个较新的版本(v1.8.2 和 1.10.0.dev-8bcb756)我观察到相反的(即X.sum(0)X.sum(-1)小幅度快)。无论哪种方式,我认为更改数组的内存顺序可能不会对 OP 的情况有很大帮助。

于 2014-12-28T19:03:57.767 回答