Numpy 笔记

我使用的环境是 ipython,所以很多时候会不使用print(),而是直接使用变量输出。

导入 numpy 库

1
import numpy as np

数值范围的数组

创建等差数列 arange

arange接受单个参数,创建从0开始到参数等差为1的数列

arange接受三个参数:start,stop,step(开始,结束,差)

1
2
3
4
5
np.arange(10)
Out:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) #这句话是输出不是程序内容,后续Out均代表输出
np.arange(1,13,3)
Out:
array([ 1., 4., 7., 10.])

创建等长数列 linspace

linspace支持三种参数:start,stop,number (开始,结束,数值个数)

1
2
3
np.linspace(0,3,10)
Out:
array([ 0. , 0.33333333, 0.66666667, 1. , 1.33333333, 1.66666667, 2. , 2.33333333, 2.66666667, 3. ])

创建对数数列

linspace支持三种参数:start,stop,number (开始,结束,个数)底数默认为10

1
2
3
4
5
np.logspace(1,2,10)
Out:
array([ 10. , 12.91549665, 16.68100537, 21.5443469 ,
27.82559402, 35.93813664, 46.41588834, 59.94842503,
77.42636827, 100. ])

将底数改为2

1
2
3
4
np.logspace(1,2,10,base=2)
Out[32]:
array([ 2. , 2.16011948, 2.33305808, 2.5198421 , 2.72158 ,
2.93946898, 3.1748021 , 3.42897593, 3.70349885, 4. ])

数组调整

多维数组/调整数组大小 ndarry.shape

ndarry.shape显示了数组的大小

1
2
3
4
a = np.array([[1,2,3],[4,5,6]])
print (a.shape)
Out:
(2,3)

这会调整数组大小

1
2
3
4
5
6
7
a = np.array([[1,2,3],[4,5,6]])
a.shape = (3,2)
print (a)
Out:
[[1 2]
[3 4]
[5 6]]

用这个更方便调整数组大小

1
2
3
4
5
6
7
a = np.array([[1,2,3],[4,5,6]])
b = a.reshape(3,2)
print (b)
Out:
[[1 2]
[3 4]
[5 6]]

数组创建

empty 创建数组

创建一个没有初始化的数组

numpy.empty(shape, dtype = float, order = ‘C’)

1
2
3
4
5
np.empty([3,2], dtype = int) #创建数组,数值类型为int
Out:
[[0 0]
[0 0]
[0 0]]

numpy.zeros

用0填充数组,默认数值类型为float

1
2
3
4
5
np.zeros((3,2))
Out:
array([[ 0., 0.],
[ 0., 0.],
[ 0., 0.]])

numpy.ones

1
2
3
4
5
np.ones((3,2),dtype=int)
Out:
array([[1, 1],
[1, 1],
[1, 1]])

asarray 转换数值为array

类似与 numpy.array 但是主要功能是将list、tuple转换为ndarray数组

list转换

1
2
3
4
x = [1,2,3]
np.asarray(x)
Out:
[1 2 3]

list转换为float类型

1
2
3
4
x = [1,2,3]
np.asarray(x, dtype =float)
Out:
[ 1. 2. 3.]

tuple 元组转换

1
2
3
4
x = (1,2,3)
np.asarray(x)
Out:
[1 2 3]

元组列表转换

1
2
3
4
x = [(1,2,3),(4,5)]
np.asarray(x)
Out:
[(1, 2, 3) (4, 5)]

切片、索引

整数索引

1
2
3
4
5
a = np.arange(10)^M
s = slice(2,7,2)
a[s]
Out:
array([2, 4, 6])

组合切片

1
2
3
4
5
6
7
8
x = np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])
rows = np.array([[0,0],[3,3]])
cols = np.array([[0,2],[0,2]])
y = x[rows,cols]
print(y)
Out:
[[ 0, 2],
[ 9, 11]]

高级切片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
x = np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])
z = x[1:4,1:3]
print(z)
Out:
[[ 4 5]
[ 7 8]
[10 11]]
y = x[1:4,[1,2]]
print(y)
Out:
[[ 4 5]
[ 7 8]
[10 11]]

布尔索引

条件判断,ture输出

1
2
3
4
x = np.array([[ 0, 1, 2],[ 3, 4, 5],[ 6, 7, 8],[ 9, 10, 11]])
print(x[x>5])
Out:
[ 6 7 8 9 10 11]

用~(取补运算符)过滤NaN

1
2
a = np.array([np.nan, 1,2,np.nan,3,4,5])
print(a[~np.isnan(a)])

取出复数

python中复数ij表示。

1
2
a = np.array([1, 2+6j, 5, 3.5+5j])
print (a[np.iscomplex(a)])

广播

在numpy中的广播,实质上指的的是算数运算期间处理不同形状的数组的能力。

相同的array相加

如果两个array的形状完全相同,那么操作执行起来就非常简单。

1
2
3
4
5
6
a = np.array([1,2,3,4])
b = np.array([10,20,30,40])
c = a + b
print(c)
Out:
[11 22 33 54]

这里展示的是加法,但是其他的运算也是同理。

不同array相加

一个 1x3 数组与 3x3 数组相加

可以看到的是这个操作是将 1x3 数组与 3x3 数组的每一行相加。

1
2
3
4
5
6
7
8
e = np.array([ 1.0, 2.0 ,3.0])
f = np.array([[0.0,0.0,0.0],[10.0,10.0,10.0],[20.0,20.0,20.0],[30.0,30.0,30.0]])
e+f
Out:
array([[ 1., 2., 3.],
[ 11., 12., 13.],
[ 21., 22., 23.],
[ 31., 32., 33.]])

那么如果将一个 1x4 数组与一个 4x1 数组相加呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
a = np.arange(3)
b = np.arange(3)[:,np.newaxis] #[:,np.newaxis] 作用是转置
print(a)
Out:
[0 1 2]
print(b)
Out:
[[0]
[1]
[2]]
print(a+b)
Out:
[[0 1 2]
[1 2 3]
[2 3 4]]

我们得到了一个 4x4 的矩阵。

但是这个加法必须满足一定条件才可以实现

  • 一个多维数组与一个一维数组相加,一维数组对应的行/列数与多维数组的行/列数一致(上面的上面)
  • 一个行向量数组与一个列向量数组相加 (上面的情况)

再演示一下第一种条件:

2x3 + 1x3

1
2
3
4
5
6
a = np.ones((2,3))
b =range(3)
a + b
Out:
array([[ 1., 2., 3.],
[ 1., 2., 3.]])

错误演示

3x2 + 1x3 会怎么样呢

1
2
3
4
5
a = np.ones((3,2))
b =range(3)
a + b
#报错
ValueError: operands could not be broadcast together with shapes (3,2) (3,)

如果是 2x 3 + 3x2 呢? 就不能满足这个状态了,只能将两个array合并。

1
2
3
4
5
a = ([[1.0,2.0,3.0],[4.0,5.0,6.0]])
b = ([[10.0,20.0],[30.0,40.0],[50.0,60.0]])
print(a+b)
Out:
[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [10.0, 20.0], [30.0, 40.0], [50.0, 60.0]]

数组迭代

数组迭代需要使用 numpy.nditer() ,可以迭代出数据(默认导出为零维数组)

代码说明

1
2
3
4
5
6
7
8
9
10
a = np.arange(0,60,5).reshape(3,4)
print(a)
Out:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]
for i in np.nditer(a):
print (i)
Out:
0 5 10 15 20 25 30 35 40 45 50 55

迭代顺序

array使用的存储风格不同(有F ,C,默认为F)根据排序不同,实际在迭代输出的也不同

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
a = np.arange(0,60,5).reshape(3,4)
b = a.T
print(b)
Out:
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
c = b.copy(order='C')
print (c)
Out:
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
for i in np.nditer(c):
print (i)
Out:
0 20 40 5 25 45 10 30 50 15 35 55
d = b.copy(order='F')
print (d)
Out:
[[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]]
for x in np.nditer(d):
print (x)
Out:
0 5 10 15 20 25 30 35 40 45 50 55

当然你也可以在输出的时候再去指定风格

1
2
3
4
5
6
7
8
9
a = np.arange(0,60,5).reshape(3,4)
for i in np.nditer(a, order = 'C'):
print (i)
Out:
0 20 40 5 25 45 10 30 50 15 35 55
for i in np.nditer(a, order = 'F'):
print (i)
Out:
0 5 10 15 20 25 30 35 40 45 50 55

修改数组的值

迭代的时候nditer也是可以修改值的(默认为read 只读),我们只需要将参数 op_flags的状态改为’readwrite’即可。

1
2
3
4
5
6
7
8
a = np.arange(0,60,5).reshape(3,4)
for i in np.nditer(a, op_flags=['readwrite']):
i[...] = 3*i
print (a)
Out:
[[ 0 15 30 45]
[ 60 75 90 105]
[120 135 150 165]]

导出一维数组

将flags 参数设为[‘external_loop’] 即可

1
2
3
4
5
6
7
8
a = np.arange(0,60,5).reshape(3,4)
for i in np.nditer(a, flags = ['external_loop'], order = 'F'):
print (i)
Out:
[ 0 20 40]
[ 5 25 45]
[10 30 50]
[15 35 55]

广播迭代

如果是两个数组是可广播的那么nditer可以同时迭代他们

1
2
3
4
5
6
a = np.arange(0,60,5).reshape(3,4)
b = np.array([1, 2, 3, 4])
for x,y in np.nditer([a,b]):
print ("{}:{}".format(x,y))
Out:
0:1 5:2 10:3 15:4 20:1 25:2 30:3 35:4 40:1 45:2 50:3 55:4

数组操作

修改形状的四种方式

序号 形状及描述
1. reshape 不改变数据的条件下修改形状
2. flat 数组上的一维迭代器
3. flatten 返回折叠为一维的数组副本
4. ravel 返回连续的展开数组

numpy.reshape

1
2
3
4
5
6
7
8
9
a = np.arange(0,60,5)
print(a)
Out:
[ 0 5 10 15 20 25 30 35 40 45 50 55]
print(a.reshape(3,4))
Out:
[[ 0 5 10 15]
[20 25 30 35]
[40 45 50 55]]

numpy.ndarray.flat

1
2
3
4
5
6
7
8
a = np.arange(8).reshape(2,4)
print(a)
Out:
[[0 1 2 3]
[4 5 6 7]]
print (a.flat[5])
Out:
5

numpy.ndarray.flatten

该函数返回折叠为一维的数组副本,函数接受下列参数:

ndarray.flatten(order)

  • order'C' – 按行,'F' – 按列,'A' – 原顺序,'k' – 元素在内存中的出现顺序。
1
2
3
4
5
6
7
a = np.arange(8).reshape(2,4)
print (a.flatten())
Out:
[0 1 2 3 4 5 6 7]
print (a.flatten(order = 'F'))
Out:
[0 4 1 5 2 6 3 7]

numpy.ravel

这个函数返回展开的一维数组,并且按需生成副本。返回的数组和输入数组拥有相同数据类型。这个函数接受两个参数。

numpy.ravel(array, order)

  • array:要转置的array
  • order'C' – 按行,'F' – 按列,'A' – 原顺序,'k' – 元素在内存中的出现顺序
1
2
3
4
5
6
7
a = np.arange(8).reshape(2,4)
print (a.ravel())
Out:
[0 1 2 3 4 5 6 7]
print (a.ravel(order = 'F'))
Out:
[0 4 1 5 2 6 3 7]

数组翻转(转置)

转置是一个经常操作的操作,存在一下集中方式

序号 操作及描述
1. transpose 翻转数组的维度
2. ndarray.Tself.transpose()相同
3. rollaxis 向后滚动指定的轴
4. swapaxes 互换数组的两个轴

#[:,np.newaxis] 作用是转置

numpy.transpose

numpy.transpose(arr, axes=None)

  • array:要转置的array
  • axes:整数的列表,对应维度,通常所有维度都会翻转。(该参数略过)
1
2
3
4
5
x = np.arange(4).reshape((2,2))
np.transpose(x)
Out:
array([[0, 2],
[1, 3]])

ndarray.T 与上面完全相同(所以经常用的是它)

1
2
3
4
5
x = np.arange(4).reshape((2,2))
x.T
Out:
array([[0, 2],
[1, 3]]) #一毛一样

numpy.rollaxis(这个难懂)

该函数向后滚动特定的轴,直到一个特定位置。这个函数接受三个参数:

numpy.rollaxis(arr, axis, start)

  • arr:输入数组
  • axis:要向后滚动的轴,其它轴的相对位置不会改变
  • start:默认为零,表示完整的滚动。会滚动到特定位置。

第二个参数为要滚动的轴,第三个为滚动的目标位置。

这里容易搞不懂 axis/axes ,所以请看Numpy小记——有关axis/axes的理解

直接上代码,多想想吧,想通了就好理解了。

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
x = np.arange(0,120,10).reshape(2,2,3)
x
Out[152]:
array([[[ 0, 10, 20],
[ 30, 40, 50]],
[[ 60, 70, 80],
[ 90, 100, 110]]])
np.rollaxis(x,1)
Out:
array([[[ 0, 10, 20],
[ 60, 70, 80]],
[[ 30, 40, 50],
[ 90, 100, 110]]])
np.rollaxis(x,2)
Out:
array([[[ 0, 30],
[ 60, 90]],
[[ 10, 40],
[ 70, 100]],
[[ 20, 50],
[ 80, 110]]])
np.rollaxis(x,2,1)
Out:
array([[[ 0, 30],
[ 10, 40],
[ 20, 50]],
[[ 60, 90],
[ 70, 100],
[ 80, 110]]])