numpy矩阵子集视图

时间:2014-02-07 12:27:02

标签: python numpy

我想通过指定行号和列号来查看numpy矩阵。例如,行0和2以及3×3矩阵的第0列和第2列。

M = np.array(range(9)).reshape((3,3))
M[:,[0,2]][[0,2],:]

但我知道这不是一个视图,由于迭代索引而创建了一个新矩阵。有可能做这样的观点吗? 我觉得我能做到这很奇怪

M[:2,:2]

查看矩阵。但不要使用

M[[0,1],[0,1]]

实现相同的观点。

编辑:提供另一个例子。如果我有一个矩阵

M = np.array(range(16)).reshape((4,4))

如何通过一个索引步骤获取行[1,2,3]和列[0,2,3]?这将分两步完成:

M[[1,2,3],:][:,[0,2,3]]

4 个答案:

答案 0 :(得分:2)

如何通过一个索引步骤获取行[1,2,3]和列[0,2,3]?

您可以使用np.ix_代替,但这既不是打字也不是更快。实际上它的速度较慢:

%timeit M[np.ix_([1,2,3],[0,2,3])]
100000 loops, best of 3: 17.8 µs per loop

%timeit M[[1,2,3],:][:, [0,2,3]]
100000 loops, best of 3: 10.9 µs per loop

如何强制视图(如果可能)?

您可以使用numpy.lib.stride_tricks.as_strided来请求定制的数组视图。 以下是scipy-lectures中使用的示例。

这将允许您在第一个示例中获取视图而不是副本:

from numpy.lib.stride_tricks import as_strided

M = np.array(range(9)).reshape((3,3))
sub_1 = M[:,[0,2]][[0,2],:]
sub_2 = as_strided(M, shape=(2, 2), strides=(48,16))

print sub_1
print ''
print sub_2

[[0 2]
 [6 8]]

[[0 2]
 [6 8]]

# change the initial array
M[0,0] = -1

print sub_1
print ''
print sub_2

[[0 2]
 [6 8]]

[[-1  2]
 [ 6  8]]

正如您所看到的,sub_2确实是一个视图,因为它反映了对初始数组M所做的更改。

传递给strides的{​​{1}}参数指定每个维度中“走”的字节 - 尺寸:

初始数组as_strided的数据类型是M(在我的机器上),因此numpy.int64在内存中是8个字节。由于Numpy默认在introw-major order)中排列数组,因此C-style中的一行在内存中是连续的,需要24个字节。由于您希望每隔一行在第一个维度中指定48个字节作为步幅。对于第二个维度,您还需要每个其他元素 - 现在它们在内存中彼此相邻 - 因此您指定16个字节作为步幅。

对于后一个示例,Numpy无法返回视图,因为请求的索引是不规则的,需要通过M进行描述。

答案 1 :(得分:1)

对于你的第二个例子:

import numpy as np
M = np.array(range(16)).reshape((4,4))
print(M[np.meshgrid([1,2,3],[0,2,3])].transpose())

由于.transpose()的索引顺序,meshgrid是必需的。根据{{​​3}},有一个新的indexing选项,因此M[np.meshgrid([1,2,3],[0,2,3],indexing='ij')]应该有效,但我没有Numpy的最新版本,也无法测试它。

答案 2 :(得分:0)

M[[0,1],[0,1]]返回矩阵中(0,0)和(1,1)处的元素。

切片numpy数组会显示数组视图,但代码M[:2, :2]会获得一个子行,行{0}和{0} {0},您需要M

::2

答案 3 :(得分:0)

要理解numpy的这种行为,你需要阅读numpy数组striding。 numpy的巨大力量在于为整个numpy / scipy生态系统提供一个统一的界面来生长。该接口是ndarray,它提供了一种简单而通用的方法来存储数值数据。

'简单'和'一般'当然是价值判断,但是通过建立跨步阵列来形成这个界面已经达到了平衡。每个numpy数组都有一组步长,告诉你如何在数组中找到任何给定元素,作为步幅和索引之间的简单内积。

当然,可以想象一个替代的numpy,它具有用于各种其他数据表示的不同代码路径;就像人们可以想象的吉萨金字塔一样,除了十倍大。容易想象;但建立它是一项更多的工作。

然而无法想象的是,将数组索引为arr [[2,0,1]],并将该数组表示为同一块内存的跨步视图。另一方面,arr [[1,0]]可以表示为视图,但是根据您正在索引的索引的内容返回视图或副本将意味着应该是简单操作的性能损失;它也会带来相当有趣的语义。