Files
ailearning/docs/da/031.md
2023-11-30 17:29:30 +08:00

1186 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Numpy 数组及其索引
先导入numpy
In [1]:
```py
from numpy import *
```
## 产生数组
从列表产生数组:
In [2]:
```py
lst = [0, 1, 2, 3]
a = array(lst)
a
```
Out[2]:
```py
array([0, 1, 2, 3])
```
或者直接将列表传入:
In [3]:
```py
a = array([1, 2, 3, 4])
a
```
Out[3]:
```py
array([1, 2, 3, 4])
```
## 数组属性
查看类型:
In [4]:
```py
type(a)
```
Out[4]:
```py
numpy.ndarray
```
查看数组中的数据类型:
In [5]:
```py
# 32比特的整数
a.dtype
```
Out[5]:
```py
dtype('int32')
```
查看每个元素所占的字节:
In [6]:
```py
a.itemsize
```
Out[6]:
```py
4
```
查看形状,会返回一个元组,每个元素代表这一维的元素数目:
In [7]:
```py
# 1维数组返回一个元组
a.shape
```
Out[7]:
```py
(4L,)
```
或者使用:
In [8]:
```py
shape(a)
```
Out[8]:
```py
(4L,)
```
`shape` 的使用历史要比 `a.shape` 久,而且还可以作用于别的类型:
In [9]:
```py
lst = [1,2,3,4]
shape(lst)
```
Out[9]:
```py
(4L,)
```
查看元素数目:
In [10]:
```py
a.size
```
Out[10]:
```py
4
```
In [11]:
```py
size(a)
```
Out[11]:
```py
4
```
查看所有元素所占的空间:
In [12]:
```py
a.nbytes
```
Out[12]:
```py
16
```
但事实上数组所占的存储空间要比这个数字大因为要用一个header来保存shapedtype这样的信息。
查看数组维数:
In [13]:
```py
a.ndim
```
Out[13]:
```py
1
```
## 使用fill方法设定初始值
可以使用 `fill` 方法将数组设为指定值:
In [14]:
```py
a.fill(-4.8)
a
```
Out[14]:
```py
array([-4, -4, -4, -4])
```
但是与列表不同,数组中要求所有元素的 `dtype` 是一样的,如果传入参数的类型与数组类型不一样,需要按照已有的类型进行转换。
## 索引与切片
和列表相似,数组也支持索引和切片操作。
索引第一个元素:
In [15]:
```py
a = array([0, 1, 2, 3])
a[0]
```
Out[15]:
```py
0
```
修改第一个元素的值:
In [16]:
```py
a[0] = 10
a
```
Out[16]:
```py
array([10, 1, 2, 3])
```
切片,支持负索引:
In [17]:
```py
a = array([11,12,13,14,15])
a[1:3]
```
Out[17]:
```py
array([12, 13])
```
In [18]:
```py
a[1:-2]
```
Out[18]:
```py
array([12, 13])
```
In [19]:
```py
a[-4:3]
```
Out[19]:
```py
array([12, 13])
```
省略参数:
In [20]:
```py
a[::2]
```
Out[20]:
```py
array([11, 13, 15])
```
In [21]:
```py
a[-2:]
```
Out[21]:
```py
array([14, 15])
```
假设我们记录一辆汽车表盘上每天显示的里程数:
In [22]:
```py
od = array([21000, 21180, 21240, 22100, 22400])
```
可以这样计算每天的旅程:
In [23]:
```py
dist = od[1:] - od[:-1]
dist
```
Out[23]:
```py
array([180, 60, 860, 300])
```
在本质上,**Python**会将array的各种计算转换为类似这样的**C**代码:
```py
int compute_sum(int *arr, int N) {
int sum = 0;
int i;
for (i = 0; i < N; i++) {
sum += arr[i];
}
return sum;
}
```
## 多维数组及其属性
`array` 还可以用来生成多维数组:
In [24]:
```py
a = array([[ 0, 1, 2, 3],
[10,11,12,13]])
a
```
Out[24]:
```py
array([[ 0, 1, 2, 3],
[10, 11, 12, 13]])
```
事实上我们传入的是一个以列表为元素的列表,最终得到一个二维数组。
甚至可以扩展到3D或者4D的情景。
查看形状:
In [25]:
```py
a.shape
```
Out[25]:
```py
(2L, 4L)
```
这里2代表行数4代表列数。
查看总的元素个数:
In [26]:
```py
# 2 * 4 = 8
a.size
```
Out[26]:
```py
8
```
查看维数:
In [27]:
```py
a.ndim
```
Out[27]:
```py
2
```
## 多维数组索引
对于二维数组,可以传入两个数字来索引:
In [28]:
```py
a[1, 3]
```
Out[28]:
```py
13
```
其中1是行索引3是列索引中间用逗号隔开事实上**Python**会将它们看成一个元组(1,3),然后按照顺序进行对应。
可以利用索引给它赋值:
In [29]:
```py
a[1, 3] = -1
a
```
Out[29]:
```py
array([[ 0, 1, 2, 3],
[10, 11, 12, -1]])
```
事实上,我们还可以使用单个索引来索引一整行内容:
In [30]:
```py
# 返回第二行元组组成的array
a[1]
```
Out[30]:
```py
array([10, 11, 12, -1])
```
**Python**会将这单个元组当成对第一维的索引,然后返回对应的内容。
## 多维数组切片
多维数组,也支持切片操作:
In [31]:
```py
a = array([[ 0, 1, 2, 3, 4, 5],
[10,11,12,13,14,15],
[20,21,22,23,24,25],
[30,31,32,33,34,35],
[40,41,42,43,44,45],
[50,51,52,53,54,55]])
a
```
Out[31]:
```py
array([[ 0, 1, 2, 3, 4, 5],
[10, 11, 12, 13, 14, 15],
[20, 21, 22, 23, 24, 25],
[30, 31, 32, 33, 34, 35],
[40, 41, 42, 43, 44, 45],
[50, 51, 52, 53, 54, 55]])
```
想得到第一行的第 4 和第 5 两个元素:
In [32]:
```py
a[0, 3:5]
```
Out[32]:
```py
array([3, 4])
```
得到最后两行的最后两列:
In [33]:
```py
a[4:, 4:]
```
Out[33]:
```py
array([[44, 45],
[54, 55]])
```
得到第三列:
In [34]:
```py
a[:, 2]
```
Out[34]:
```py
array([ 2, 12, 22, 32, 42, 52])
```
每一维都支持切片的规则,包括负索引,省略:
```py
[lower:upper:step]
```
例如取出35行的奇数列
In [35]:
```py
a[2::2, ::2]
```
Out[35]:
```py
array([[20, 22, 24],
[40, 42, 44]])
```
## 切片是引用
切片在内存中使用的是引用机制。
In [36]:
```py
a = array([0,1,2,3,4])
b = a[2:4]
print b
```
```py
[2 3]
```
引用机制意味着,**Python**并没有为 `b` 分配新的空间来存储它的值,而是让 `b` 指向了 `a` 所分配的内存空间,因此,改变 `b` 会改变 `a` 的值:
In [37]:
```py
b[0] = 10
a
```
Out[37]:
```py
array([ 0, 1, 10, 3, 4])
```
而这种现象在列表中并不会出现:
In [38]:
```py
a = [1,2,3,4,5]
b = a[2:3]
b[0] = 13234
print a
```
```py
[1, 2, 3, 4, 5]
```
这样做的好处在于,对于很大的数组,不用大量复制多余的值,节约了空间。
缺点在于,可能出现改变一个值改变另一个值的情况。
一个解决方法是使用copy()方法产生一个复制,这个复制会申请新的内存:
In [39]:
```py
a = array([0,1,2,3,4])
b = a[2:4].copy()
b[0] = 10
a
```
Out[39]:
```py
array([0, 1, 2, 3, 4])
```
## 花式索引
切片只能支持连续或者等间隔的切片操作,要想实现任意位置的操作,需要使用花式索引 `fancy slicing`
### 一维花式索引
与 range 函数类似,我们可以使用 arange 函数来产生等差数组。
In [40]:
```py
a = arange(0, 80, 10)
a
```
Out[40]:
```py
array([ 0, 10, 20, 30, 40, 50, 60, 70])
```
花式索引需要指定索引位置:
In [41]:
```py
indices = [1, 2, -3]
y = a[indices]
print y
```
```py
[10 20 50]
```
还可以使用布尔数组来花式索引:
In [42]:
```py
mask = array([0,1,1,0,0,1,0,0],
dtype=bool)
```
In [43]:
```py
a[mask]
```
Out[43]:
```py
array([10, 20, 50])
```
或者用布尔表达式生成 `mask`选出了所有大于0.5的值:
In [44]:
```py
from numpy.random import rand
a = rand(10)
a
```
Out[44]:
```py
array([ 0.37214708, 0.48594733, 0.73365131, 0.15769295, 0.30786017,
0.62068734, 0.36940654, 0.09424167, 0.53085308, 0.12248951])
```
In [45]:
```py
mask = a > 0.5
a[mask]
```
Out[45]:
```py
array([ 0.73365131, 0.62068734, 0.53085308])
```
mask 必须是布尔数组。
### 二维花式索引
In [46]:
```py
a = array([[ 0, 1, 2, 3, 4, 5],
[10,11,12,13,14,15],
[20,21,22,23,24,25],
[30,31,32,33,34,35],
[40,41,42,43,44,45],
[50,51,52,53,54,55]])
a
```
Out[46]:
```py
array([[ 0, 1, 2, 3, 4, 5],
[10, 11, 12, 13, 14, 15],
[20, 21, 22, 23, 24, 25],
[30, 31, 32, 33, 34, 35],
[40, 41, 42, 43, 44, 45],
[50, 51, 52, 53, 54, 55]])
```
对于二维花式索引,我们需要给定 `row``col` 的值:
In [47]:
```py
a[(0,1,2,3,4), (1,2,3,4,5)]
```
Out[47]:
```py
array([ 1, 12, 23, 34, 45])
```
返回的是一条次对角线上的5个值。
In [48]:
```py
a[3:, [0,2,5]]
```
Out[48]:
```py
array([[30, 32, 35],
[40, 42, 45],
[50, 52, 55]])
```
返回的是最后三行的第135列。
也可以使用mask进行索引
In [49]:
```py
mask = array([1,0,1,0,0,1],
dtype=bool)
a[mask, 2]
```
Out[49]:
```py
array([ 2, 22, 52])
```
与切片不同,花式索引返回的是原对象的一个复制而不是引用。
### “不完全”索引
只给定行索引的时候,返回整行:
In [50]:
```py
y = a[:3]
y
```
Out[50]:
```py
array([[ 0, 1, 2, 3, 4, 5],
[10, 11, 12, 13, 14, 15],
[20, 21, 22, 23, 24, 25]])
```
这时候也可以使用花式索引取出第235行
In [51]:
```py
condition = array([0,1,1,0,1,0],
dtype=bool)
a[condition]
```
Out[51]:
```py
array([[10, 11, 12, 13, 14, 15],
[20, 21, 22, 23, 24, 25],
[40, 41, 42, 43, 44, 45]])
```
### 三维花式索引
In [52]:
```py
a = arange(64)
a.shape = 4,4,4
a
```
Out[52]:
```py
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]],
[[16, 17, 18, 19],
[20, 21, 22, 23],
[24, 25, 26, 27],
[28, 29, 30, 31]],
[[32, 33, 34, 35],
[36, 37, 38, 39],
[40, 41, 42, 43],
[44, 45, 46, 47]],
[[48, 49, 50, 51],
[52, 53, 54, 55],
[56, 57, 58, 59],
[60, 61, 62, 63]]])
```
In [53]:
```py
y = a[:,:,[2, -1]]
y
```
Out[53]:
```py
array([[[ 2, 3],
[ 6, 7],
[10, 11],
[14, 15]],
[[18, 19],
[22, 23],
[26, 27],
[30, 31]],
[[34, 35],
[38, 39],
[42, 43],
[46, 47]],
[[50, 51],
[54, 55],
[58, 59],
[62, 63]]])
```
## where语句
```py
where(array)
```
`where` 函数会返回所有非零元素的索引。
### 一维数组
先看一维的例子:
In [54]:
```py
a = array([0, 12, 5, 20])
```
判断数组中的元素是不是大于10
In [55]:
```py
a > 10
```
Out[55]:
```py
array([False, True, False, True], dtype=bool)
```
数组中所有大于10的元素的索引位置
In [56]:
```py
where(a > 10)
```
Out[56]:
```py
(array([1, 3], dtype=int64),)
```
注意到 `where` 的返回值是一个元组。
使用元组是由于 where 可以对多维数组使用,此时返回值就是多维的。
在使用的时候,我们可以这样:
In [57]:
```py
indices = where(a > 10)
indices = indices[0]
indices
```
Out[57]:
```py
array([1, 3], dtype=int64)
```
或者:
In [58]:
```py
indices = where(a>10)[0]
indices
```
Out[58]:
```py
array([1, 3], dtype=int64)
```
可以直接用 `where` 的返回值进行索引:
In [59]:
```py
loc = where(a > 10)
a[loc]
```
Out[59]:
```py
array([12, 20])
```
### 多维数组
考虑二维数组:
In [60]:
```py
a = array([[0, 12, 5, 20],
[1, 2, 11, 15]])
loc = where(a > 10)
```
返回结果是一个二维的元组,每一维代表这一维的索引值:
In [61]:
```py
loc
```
Out[61]:
```py
(array([0, 0, 1, 1], dtype=int64), array([1, 3, 2, 3], dtype=int64))
```
也可以直接用来索引a
In [62]:
```py
a[loc]
```
Out[62]:
```py
array([12, 20, 11, 15])
```
或者可以这样:
In [63]:
```py
rows, cols = where(a>10)
```
In [64]:
```py
rows
```
Out[64]:
```py
array([0, 0, 1, 1], dtype=int64)
```
In [65]:
```py
cols
```
Out[65]:
```py
array([1, 3, 2, 3], dtype=int64)
```
In [66]:
```py
a[rows, cols]
```
Out[66]:
```py
array([12, 20, 11, 15])
```
再看另一个例子:
In [67]:
```py
a = arange(25)
a.shape = 5,5
a
```
Out[67]:
```py
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
```
In [68]:
```py
a > 12
```
Out[68]:
```py
array([[False, False, False, False, False],
[False, False, False, False, False],
[False, False, False, True, True],
[ True, True, True, True, True],
[ True, True, True, True, True]], dtype=bool)
```
In [69]:
```py
where(a > 12)
```
Out[69]:
```py
(array([2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4], dtype=int64),
array([3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4], dtype=int64))
```