numpy.array形状(R,1)和(R,)之间的区别

clw*_*wen 280 python numpy matrix multidimensional-array

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).

所以我的问题是:

  1. 形状(R, 1)和形状有什么区别(R,).我知道字面上它是数字列表和列表列表,其中所有列表只包含一个数字.只是想知道为什么不设计numpy使它有利于形状(R, 1)而不是(R,)更容易的矩阵乘法.

  2. 上面的例子有更好的方法吗?没有明确重塑像这样:numpy.dot(M[:,0].reshape(R, 1), numpy.ones((1, R)))

Gar*_*ees 479

1. NumPy中形状的含义

你写道,"我确实知道它的数字列表和列表列表,其中所有列表只包含一个数字",但这是一个无用的思考方式.

考虑NumPy数组的最佳方法是它们由两部分组成,一个数据缓冲区,它只是一个原始元素块,另一个视图描述了如何解释数据缓冲区.

例如,如果我们创建一个12个整数的数组:

>>> a = numpy.arange(12)
>>> a
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
Run Code Online (Sandbox Code Playgroud)

然后a由一个数据缓冲区组成,排列如下:

?????????????????????????????????????????????????????????????
?  0 ?  1 ?  2 ?  3 ?  4 ?  5 ?  6 ?  7 ?  8 ?  9 ? 10 ? 11 ?
?????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

以及描述如何解释数据的视图:

>>> 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,)
Run Code Online (Sandbox Code Playgroud)

这里的形状 (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 ?
?????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

如果我们重塑数组,这不会改变数据缓冲区.相反,它会创建一个新视图,描述解释数据的不同方式.之后:

>>> b = a.reshape((3, 4))
Run Code Online (Sandbox Code Playgroud)

该数组b具有a与之相同的数据缓冲区,但现在它由两个索引索引,这两个索引分别从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 ?
?????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

意思就是:

>>> b[2,1]
9
Run Code Online (Sandbox Code Playgroud)

您可以看到第二个索引快速变化,第一个索引变化缓慢.如果您更喜欢这种方式,则可以指定order参数:

>>> c = a.reshape((3, 4), order='F')
Run Code Online (Sandbox Code Playgroud)

这会导致数组索引如下:

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 ?
?????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

意思就是:

>>> c[2,1]
5
Run Code Online (Sandbox Code Playgroud)

现在应该清楚,数组具有一个或多个尺寸为1的形状意味着什么.

>>> d = a.reshape((12, 1))
Run Code Online (Sandbox Code Playgroud)

数组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 ?
?????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

所以:

>>> d[10,0]
10
Run Code Online (Sandbox Code Playgroud)

长度1的尺寸是"自由的"(在某种意义上),所以没有什么能阻止你去城镇:

>>> e = a.reshape((1, 2, 1, 6, 1))
Run Code Online (Sandbox Code Playgroud)

给出一个像这样索引的数组:

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 ?
?????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

所以:

>>> e[0,1,0,0,0]
6
Run Code Online (Sandbox Code Playgroud)

有关如何实现数组的更多详细信息,请参阅NumPy内部文档.

2.怎么办?

由于numpy.reshape只是创建了一个新视图,因此您不应该害怕在必要时使用它.当您想以不同的方式索引数组时,它是正确的工具.

然而,在长时间的计算中,通常可以首先安排构造具有"正确"形状的阵列,从而最小化重塑和转置的数量.但是,如果没有看到导致需要重塑的实际背景,很难说应该改变什么.

您问题中的示例是:

numpy.dot(M[:,0], numpy.ones((1, R)))
Run Code Online (Sandbox Code Playgroud)

但这不现实.首先,这个表达式:

M[:,0].sum()
Run Code Online (Sandbox Code Playgroud)

更简单地计算结果.第二,第0列真的有什么特别之处吗?也许你真正需要的是:

M.sum(axis=0)
Run Code Online (Sandbox Code Playgroud)

  • 这在考虑如何存储数组时非常有用.谢谢!访问(2-d)矩阵的列(或行)以进行进一步的矩阵计算是不方便的,因为我总是必须适当地重新整形列.每次我必须将形状从(n,)更改为(n,1). (29认同)
  • 一种简单的思考方式是 numpy 在这里完全按预期工作,但 Python 的元组打印可能会产生误导。在 `(R, )` 的情况下,`ndarray` 的形状是一个具有单个元素的元组,因此由 Python 打印并带有尾随逗号。如果没有额外的逗号,它会[括号中的表达式不明确](https://wiki.python.org/moin/TupleSyntax)。一个单一维度的 `ndarray` 可以看作是一个长度为 `R` 的列向量。在 `(R, 1)` 的情况下,元组有两个元素,因此可以将其视为行向量(或具有 1 行长度为 `R` 的矩阵。 (4认同)
  • @SammyLee:如果你需要另一个轴,请使用[`newaxis`](http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#numpy.newaxis),例如`a [:,j ,np.newaxis]`是`a`的`j`th列,`a [np.newaxis,i]`是`i`行. (3认同)

Eva*_*van 15

(R,)和之间的差异(1,R)实际上是您需要使用的索引数. ones((1,R))是一个二维数组恰好只有一行. ones(R)是一个向量.通常,如果变量具有多个行/列没有意义,则应使用向量,而不是具有单个维度的矩阵.

对于您的具体情况,有几个选择:

1)只需将第二个参数作为向量.以下工作正常:

    np.dot(M[:,0], np.ones(R))
Run Code Online (Sandbox Code Playgroud)

2)如果你想要matlab像矩阵运算,请使用类matrix而不是ndarray.所有matricies都被强制为2-D数组,运算符*执行矩阵乘法而不是元素(因此您不需要点).根据我的经验,这是值得的麻烦,但如果你习惯了matlab,这可能会很好.

  • `matrix`的问题在于它只是2D,而且因为它重载了运算符'*',所以为'ndarray`编写的函数如果在`矩阵'上使用可能会失败. (2认同)

Kat*_*ens 7

形状是一个元组。如果只有一维,则形状将是一个数字,并且在逗号后为空白。对于2维以上的尺寸,所有逗号后面都会有一个数字。

# 1 dimension with 2 elements, shape = (2,). 
# Note there's nothing after the comma.
z=np.array([  # start dimension
    10,       # not a dimension
    20        # not a dimension
])            # end dimension
print(z.shape)
Run Code Online (Sandbox Code Playgroud)

(2,)

# 2 dimensions, each with 1 element, shape = (2,1)
w=np.array([  # start outer dimension 
    [10],     # element is in an inner dimension
    [20]      # element is in an inner dimension
])            # end outer dimension
print(w.shape)
Run Code Online (Sandbox Code Playgroud)

(2,1)


hpa*_*ulj 5

对于其基本数组类,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.]])
Run Code Online (Sandbox Code Playgroud)

其他给出相同数组的表达式

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,:])
Run Code Online (Sandbox Code Playgroud)

MATLAB最初只是2D阵列。较新的版本允许更大的尺寸,但保留2的下限。但是,您仍然必须注意行矩阵和列1之间的差异,一个是形状(1,3)v (3,1)。你多久写一次[1,2,3].'?我打算编写row vectorcolumn vector,但是由于2d的限制,MATLAB中没有任何矢量-至少从矢量的数学意义上讲不是1d的。

您是否看过np.atleast_2d(还有_1d和_3d版本)?