进入时numpy,某些操作会恢复原状,(R, 1)但有些会返回(R,)。由于reshape需要显式运算,因此这会使矩阵乘法变得更加乏味。例如,给定一个矩阵M,如果我们想在numpy.dot(M[:,0], numpy.ones((1, R)))哪里做R行数(当然,同样的问题也会逐列出现)。我们会得到matrices are not aligned错误,因为M[:,0]是在外形(R,),但numpy.ones((1, R))在形状(1, R)。
numpy
(R, 1)
reshape
numpy.dot(M[:,0]
numpy.ones((1, R)))
matrices are not aligned
M[:,0]
(R,)
numpy.ones((1, R))
所以我的问题是:
numpy.dot(M[:,0].reshape(R, 1)
考虑NumPy数组的最佳方法是它们由两部分组成,一个数据缓冲区只是一个原始元素块,另一个视图描述了如何解释数据缓冲区。
例如,如果我们创建一个由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.strides (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 │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
如果我们调整数组的形状,则不会更改数据缓冲区。相反,它创建一个新视图,该视图描述了另一种解释数据的方式。所以之后:
>>> b = a.reshape((3, 4))
该数组b具有与相同的数据缓冲区a,但是现在它由两个索引分别从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只是创建了一个新视图,因此不必在必要时使用它。当你想以其他方式为数组建立索引时,它是正确的工具。
但是,在较长的计算中,通常可以安排首先构造具有“正确”形状的数组,从而最大程度地减少重塑和转置的次数。但是,没有看到导致需要重塑的实际环境,很难说应该改变什么。
你问题中的示例是:
numpy.dot(M[:,0], numpy.ones((1, R)))
但这是不现实的。首先,此表达式:
M[:,0].sum()
计算结果更简单。第二,第0列真的有什么特别之处吗?也许你实际需要的是:
M.sum(axis=0)