numpy.array形状(R,1)和(R,)之间的区别
在numpy
,一些操作返回形状(R, 1)
但有一些返回(R,)
。 这将使matrix乘法更加乏味,因为需要显式reshape
。 例如,给定一个matrixM
,如果我们想要做numpy.dot(M[:,0], numpy.ones((1, R)))
其中R
是行数(当然,同样的问题也是按列发生)。 由于M[:,0]
在形状(R,)
但numpy.ones((1, R))
在形状(1, R)
我们将得到matrices are not aligned
错误。
所以我的问题是:
-
形状
(R, 1)
和(R,)
什么区别。 我从字面上知道这是列表中的数字和列表,其中所有列表只包含一个数字。 只是想知道为什么不devisenumpy
所以它有利于形状(R, 1)
而不是(R,)
,以便于matrix乘法。 -
上面的例子有更好的方法吗? 没有像这样明确重塑:
numpy.dot(M[:,0].reshape(R, 1), numpy.ones((1, R)))
1. NumPy中形状的含义
你写道:“我从字面上知道它是列表中的数字和列表,其中列表中只包含一个数字”,但这是一个无用的方式来思考它。
考虑NumPy数组的最好方法是它们由两部分组成:一个数据缓冲区 ,它只是一个原始元素块,另一个是描述如何解释数据缓冲区的视图 。
例如,如果我们创build一个12个整数的数组:
>>> a = numpy.arange(12) >>> a array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
然后a
数据缓冲区,如下所示:
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
以及描述如何解释数据的视图:
>>> a.flags C_CONTIGUOUS : True F_CONTIGUOUS : True OWNDATA : True WRITEABLE : True ALIGNED : True UPDATEIFCOPY : False >>> a.dtype dtype('int64') >>> a.itemsize 8 >>> a.shape (12,)
这里的形状 (12,)
意味着数组被索引从一个单一的指数运行从0到11.从概念上讲,如果我们标签这个单一的索引i
,数组a
看起来像这样:
i= 0 1 2 3 4 5 6 7 8 9 10 11 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
如果我们重塑一个数组,这不会改变数据缓冲区。 相反,它会创build一个新的视图来描述解释数据的不同方式。 所以之后:
>>> b = a.reshape((3, 4))
数组b
具有与b
相同的数据缓冲区,但现在它由两个分别从0到2和0到3运行的索引进行索引。 如果我们标记两个下标i
和j
,则数组b
看起来像这样:
i= 0 0 0 0 1 1 1 1 2 2 2 2 j= 0 1 2 3 0 1 2 3 0 1 2 3 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
意思就是:
>>> b[2,1] 9
您可以看到第二个索引变化很快,第一个索引缓慢变化。 如果您更喜欢这种方式,您可以指定order
参数:
>>> c = a.reshape((3, 4), order='F')
这会导致像这样索引数组:
i= 0 1 2 0 1 2 0 1 2 0 1 2 j= 0 0 0 1 1 1 2 2 2 3 3 3 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
意思就是:
>>> c[2,1] 5
现在应该清楚数组的大小为1的一个或多个维度的形状意味着什么。之后:
>>> d = a.reshape((12, 1))
数组d
由两个索引索引,第一个索引从0到11,第二个索引总是0:
i= 0 1 2 3 4 5 6 7 8 9 10 11 j= 0 0 0 0 0 0 0 0 0 0 0 0 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
所以:
>>> d[10,0] 10
长度为1的维度是“自由的”(从某种意义上说),所以没有任何东西阻止你去镇上:
>>> e = a.reshape((1, 2, 1, 6, 1))
给这样一个数组索引:
i= 0 0 0 0 0 0 0 0 0 0 0 0 j= 0 0 0 0 0 0 1 1 1 1 1 1 k= 0 0 0 0 0 0 0 0 0 0 0 0 l= 0 1 2 3 4 5 0 1 2 3 4 5 m= 0 0 0 0 0 0 0 0 0 0 0 0 ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
所以:
>>> e[0,1,0,0,0] 6
有关数组如何实现的更多细节,请参阅NumPy内部文档 。
2.怎么办?
由于numpy.reshape
只是创build一个新的视图,你不应该害怕在必要时使用它。 当你想以不同的方式索引一个数组的时候,这是正确的工具。
但是,在长时间计算中,通常可以首先安排构build“正确”形状的arrays,从而尽量减less重塑和转置次数。 但没有看到导致需要重塑的实际情况,很难说什么应该改变。
你的问题的例子是:
numpy.dot(M[:,0], numpy.ones((1, R)))
但这是不现实的。 首先,这个expression:
M[:,0].sum()
计算结果更简单。 其次,第0列真的有特别之处吗? 也许你真正需要的是:
M.sum(axis=0)
(R,)
和(1,R)
之间的区别实际上就是您需要使用的索引数目。 ones((1,R))
是一个二维数组,恰好只有一行。 ones(R)
是一个向量。 一般来说,如果variables没有多个行/列的意义,你应该使用一个向量,而不是单一维的matrix。
对于您的具体情况,有几个选项:
1)只要第二个参数是一个向量。 以下工作正常:
np.dot(M[:,0], np.ones(R))
2)如果你想像matrix运算的matlab,使用类matrix
而不是ndarray
。 所有的matricies被迫成为二维数组,而operator *
不是matrix乘法,而是单元化(所以你不需要点)。 根据我的经验,这是值得的更麻烦,但是如果你习惯了matlab,那可能会很好。
对于它的基类数组,2d数组并不比1d或3d更特殊。 有一些维护维度的操作,有些维护维度,有的维护维护维度,有的维护维护维护维度,有的维护维护维度,有的维护维护维护维度,有的维护维护维护维度,
M=np.arange(9).reshape(3,3) M[:,0].shape # (3,) selects one column, returns a 1d array M[0,:].shape # same, one row, 1d array M[:,[0]].shape # (3,1), index with a list (or array), returns 2d M[:,[0,1]].shape # (3,2) In [20]: np.dot(M[:,0].reshape(3,1),np.ones((1,3))) Out[20]: array([[ 0., 0., 0.], [ 3., 3., 3.], [ 6., 6., 6.]]) In [21]: np.dot(M[:,[0]],np.ones((1,3))) Out[21]: array([[ 0., 0., 0.], [ 3., 3., 3.], [ 6., 6., 6.]])
其他expression式给出相同的数组
np.dot(M[:,0][:,np.newaxis],np.ones((1,3))) np.dot(np.atleast_2d(M[:,0]).T,np.ones((1,3))) np.einsum('i,j',M[:,0],np.ones((3))) M1=M[:,0]; R=np.ones((3)); np.dot(M1[:,None], R[None,:])
MATLAB刚开始只有2D数组。 较新的版本允许更多的维度,但保留2的下限。但是你仍然需要注意行matrix和第一列之间的差异,一个是形状(1,3)
v (3,1)
。 你多久写一次[1,2,3].'
? 我正在写row vector
和column vector
,但是有了这个2d约束,在MATLAB中没有任何向量 – 至less在向量的math意义上不是1d。
你看过np.atleast_2d
(还有_1d和_3d版本)吗?
1)不喜欢(R, 1)
的形状而不是(R,)
是它不必要地使事情复杂化。 此外,为什么最好在长度为R的向量上,而不是(1, R)
的情况下(R, 1)
最好有形状(R, 1)
(1, R)
? 当你需要额外的维度时,最好保持简单明了。
2)对于你的例子,你正在计算一个外部产品,所以你可以做到这一点,而无需使用np.outer
reshape
调用:
np.outer(M[:,0], numpy.ones((1, R)))