python里的体格是啥r_numpy.数组形状(R,1)和(R,)之间的差异

本文深入解析了NumPy数组的形状概念,包括数据缓冲区和视图的组成部分。通过实例展示了reshape函数如何改变数组的索引方式,而不改变数据本身。强调了在长时间计算中合理安排数组形状的重要性,以及如何避免不必要的重塑操作。同时,讨论了特定重塑案例的优化建议,如使用sum代替dot运算,并考虑轴上的总和操作。
摘要由CSDN通过智能技术生成

一。形状在NumPy中的意义

你写,“我知道字面上它是一个数字列表和所有列表中只包含一个数字的列表”,但这是一个有点无益的思考方式。

考虑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,)

这里的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 │

└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

如果我们reshape一个数组,这不会改变数据缓冲区。相反,它创建了一个新视图,该视图描述了解释数据的不同方式。所以之后:>>> 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

2。怎么办?

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

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

你问题的例子是:numpy.dot(M[:,0], numpy.ones((1, R)))

但这并不现实。首先,这个表达式:M[:,0].sum()

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>