numpy中,一些操作返回形状(R, 1),但一些返回形状(R,).这将使矩阵乘法变得更加繁琐,因为需要显式乘法.例如,给定一个矩阵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. 对于上面的例子,有更好的方法吗?没有明确的reshape :numpy.dot(M[:,0].reshape(R, 1), numpy.ones((1, R)))

推荐答案

1.形状在NumPy中的意义

你写道,"我知道这是一个数字列表,所有列表只包含一个数字的列表",但这是一种没有帮助的思考方式.

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

例如,如果我们创建一个由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,)

在这里,shape (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相同的数据缓冲区,但现在它由two个索引索引,这些索引分别运行在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 internals documentation.

2.怎么办?

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

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

你问题中的例子是:

numpy.dot(M[:,0], numpy.ones((1, R)))

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

M[:,0].sum()

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

M.sum(axis=0)

Python相关问答推荐

如何比较numPy数组中的两个图像以获取它们不同的像素

连接两个具有不同标题的收件箱

使用groupby Pandas的一些操作

如何请求使用Python将文件下载到带有登录名的门户网站?

avxspan与pandas period_range

对象的`__call__`方法的setattr在Python中不起作用'

如何禁用FastAPI应用程序的Swagger UI autodoc中的application/json?

如何在Python中使用Pandas将R s Tukey s HSD表转换为相关矩阵''

如何在两列上groupBy,并使用pyspark计算每个分组列的平均总价值

为什么Python内存中的列表大小与文档不匹配?

为什么t sns.barplot图例不显示所有值?'

在极点中读取、扫描和接收有什么不同?

如何设置nan值为numpy数组多条件

为罕见情况下的回退None值键入

多索引数据帧到标准索引DF

对于数组中的所有元素,Pandas SELECT行都具有值

我如何为测试函数的参数化提供fixture 生成的数据?如果我可以的话,还有其他 Select 吗?

如何通过特定导入在类中执行Python代码

使用_in链接操作管道传输的中间结果是否可用于链中的后续函数?

如何判断变量可调用函数的参数是否都属于某个子类?