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错误。

所以我的问题是:

  1. 形状(R, 1)(R,)什么区别。 我从字面上知道这是列表中的数字和列表,其中所有列表只包含一个数字。 只是想知道为什么不devisenumpy所以它有利于形状(R, 1)而不是(R,) ,以便于matrix乘法。

  2. 上面的例子有更好的方法吗? 没有像这样明确重塑: 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运行的索引进行索引。 如果我们标记两个下标ij ,则数组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 vectorcolumn 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)))