NumPy 学习

本文是在学习numpy 的时候做的笔记,记录了numpy 的常用操作,方便用的时候查找。

1. 什么是NumPy,它有什么用

NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。

简单来说 NumPy 就是提供一个数组、矩阵存储和运算的库。与Python 自带的list 相似,不过速度更快,功能更多。

2. NumPy 的数据类型

2.1 ndarray–NumPy 的主要数据对象

我们所说的多维数组或者矩阵,在 NumPy 中的存放对象是 ndarray ,ndarray 也就是 n 维数组的意思。

ndarray 对象内部由以下内容组成:

  • 一个指向数据 (内存中的一块区域)的指针。
  • 元素的数据类型,用来确定一个元素占多大空间。
  • 一个表示数组形状(shape)的元祖,表示各维度的大小。
  • 一个跨度元组(stride),其中的整数指的是为了前进到当前维度下一个元素需要”跨过”的字节数。(方便内存区域中直接取数据)

创建一个 ndarray 只需调用 NumPy 的 array 函数即可:

numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)

参数说明:

名称 描述
object 数组或嵌套的数列
dtype 数组元素的数据类型,可选
copy 对象是否需要复制,可选
order 创建数组的样式,C为行方向,F为列方向,A为任意方向(默认)
subok 默认返回一个与基类类型一致的数组
ndmin 指定生成数组的最小维度

实例:

1
2
3
4
5
6
7
import numpy as np 
a = np.array([[1, 2], [3, 4]])
print (a)

结果:
[[1, 2]
[3, 4]]

2.2 ndarray 中元素的数据类型

numpy 支持的数据类型比 Python 内置的类型要多很多,基本上可以和 C 语言的数据类型对应上,其中部分类型对应为 Python 内置的类型。下表列举了常用 NumPy 基本类型。

名称 描述
bool_ 布尔型数据类型(True 或者 False)
int_ 默认的整数类型(类似于 C 语言中的 long,int32 或 int64)
intc 与 C 的 int 类型一样,一般是 int32 或 int 64
intp 用于索引的整数类型(类似于 C 的 ssize_t,一般情况下仍然是 int32 或 int64)
int8 字节(-128 to 127)
int16 整数(-32768 to 32767)
int32 整数(-2147483648 to 2147483647)
int64 整数(-9223372036854775808 to 9223372036854775807)
uint8 无符号整数(0 to 255)
uint16 无符号整数(0 to 65535)
uint32 无符号整数(0 to 4294967295)
uint64 无符号整数(0 to 18446744073709551615)
float_ float64 类型的简写
float16 半精度浮点数,包括:1 个符号位,5 个指数位,10 个尾数位
float32 单精度浮点数,包括:1 个符号位,8 个指数位,23 个尾数位
float64 双精度浮点数,包括:1 个符号位,11 个指数位,52 个尾数位
complex_ complex128 类型的简写,即 128 位复数
complex64 复数,表示双 32 位浮点数(实数部分和虚数部分)
complex128 复数,表示双 64 位浮点数(实数部分和虚数部分)

numpy 的数值类型实际上是 dtype 对象的实例,并对应唯一的字符,包括 np.bool_,np.int32,np.float32,等等。

这些类型记住几个常用就行,一般就是int和float。

引用方法如:np.int32

1
2
3
4
import numpy as np
a = np.array([1,2,3], dtype=np.int32)
或者:
a = np.array([1,2,3], dtype='int32')

其中,直接写 ‘int’,就等于 ‘int32’ ;’float’ = ‘float64’

重点:修改数据类型

1.直接硬改数据类型导致数组值变化

如:

1
2
3
4
5
6
7
8
9
import numpy as np
a = np.array([1,2,3], dtype='int64')
print(a)
>>[1 2 3]

# 硬改a的数据类型
a.dtype = 'int32'
print(a)
>>[1 0 2 0 3 0]

上面修改完a 的数据类型,a 数组的值和元素个数都变了。仔细想想可以发现,ndarray是根据数组中dtype 的信息来解析内存中的数据,所以64位int改成32位int后元素个数会翻2倍。如果改成 ‘int16’ 型,将会变成12个元素。

当然float 强转成int 型数值也会变化。从文本中读入数据的类型默认是float64。

2. 想要改变数据类型而不改变数组元素的值,要用数组的 aseype() 函数。

1
2
3
4
5
6
7
8
9
10
11
import numpy as np
a = np.array([1,2,3], dtype='int64')
print(a)
>>[1 2 3]

# 硬改a的数据类型
b = a.astype('int32') # 这里不会改变a 原有的数据类型
print(b)
>>[1 2 3]
print(a.dtype)
>>int64

2.3 ndarray 对象的属性

ndarray 对象的属性,常用的有:数组形状shape、元素个数size、元素数据类型dtype。

属性 说明
ndarray.ndim 秩,即轴的数量或维度的数量
ndarray.shape 数组的维度,对于矩阵,n 行 m 列
ndarray.size 数组元素的总个数,相当于 .shape 中 n*m 的值
ndarray.dtype ndarray 对象的元素类型
ndarray.itemsize ndarray 对象中每个元素的大小,以字节为单位
ndarray.flags ndarray 对象的内存信息
ndarray.real ndarray元素的实部
ndarray.imag ndarray 元素的虚部
ndarray.data 包含实际数组元素的缓冲区,由于一般通过数组的索引获取元素,所以通常不需要使用这个属性。

3. 创建ndarray数组

3.1 利用函数创建空、全0、全1数组

1
2
3
x = np.empty([3,2], dtype = int)  # 默认float64型
y = np.zeros((5,), dtype = np.int) # 默认float64型
x = np.ones([2,2], dtype = 'int') # 默认float64型

3.2 利用列表、元组创建数组

函数:np.array() 、 np.asarray

两个函数用法差别不大。

未指定数据类型时,如果传入的数组中全是整数,则ndarray 默认int32 ;如果有小数,则默认float64;

1
2
3
4
5
6
7
import numpy as np 

x = [1,2,3]
a = np.asarray(x) # a.dtype 为int32

y = [1,2,3.5]
b = np.array(y) # b.dtype 为float64

3.3 利用可迭代对象创建数组

函数:numpy.fromiter(iterable, dtype, count=-1)

1
2
3
4
5
6
7
8
9
import numpy as np 

# 使用 range 函数创建列表对象
list=range(5)
it=iter(list)

# 使用迭代器创建 ndarray
x=np.fromiter(it, dtype=float)
print(x)

3.4 从数值范围创建数组,创建等比、等差数组

(1)从一定范围创建数组

函数:numpy.arange(start, stop, step, dtype)

参数:起始值,终止值,步长,数据类型。起始值默认为0,数组不包含终止值。

1
2
3
4
5
6
7
8
x = np.arange(5)
>>[0 1 2 3 4]

x = np.arange(5, dtype = float)
>>[0. 1. 2. 3. 4.]

x = np.arange(10,20,2)
>>[10 12 14 16 18]

(2)创建等差数列

numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)

参数:

参数 描述
start 序列的起始值
stop 序列的终止值,如果endpointtrue,该值包含于数列中
num 要生成的等步长的样本数量,默认为50
endpoint 该值为 true 时,数列中中包含stop值,反之不包含,默认是True。
retstep 如果为 True 时,生成的数组中会显示间距,反之不显示。
dtype ndarray 的数据类型

linspace函数与arange函数不同,前者是用起始、终止和元素个数,后者是用起始终止和步长。

1
2
3
4
5
6
7
8
9
a = np.linspace(1,10,10) # 创建1-10,十个数
>>[ 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]

a = np.linspace(1,1,10)
>>[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]

a = np.linspace(1,100) # 1-100,50个数

# 将 endpoint 设为 false,则不包含终止值

(3)创建等比数列

函数:np.logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None)

参数 描述
start 序列的起始值为:base ** start
stop 序列的终止值为:base ** stop。如果endpointtrue,该值包含于数列中
num 要生成的等步长的样本数量,默认为50
endpoint 该值为 true 时,数列中中包含stop值,反之不包含,默认是True。
base 对数 log 的底数。
dtype ndarray 的数据类型

与创建等差数列的参数不同,start=1、stop=5 范围是10-100000。

1
2
3
# 从1-2的9次方,十个数
a = np.logspace(0,9,10,base=2)
>>[ 1. 2. 4. 8. 16. 32. 64. 128. 256. 512.]

4. 索引、切片

用来选取某些行、列,这是numpy最常用的操作。

实际中比较常用的有普通索引和布尔索引,花式索引偶尔也用得到。

索引方式有:

  • 普通索引。a[2:3:7]
  • 整数数组索引。要取得元素序号存放于另一个数组中。
  • 布尔索引。[true, false, true, false] 选取第1、3个元素。或者 x[x > 5],这样用
  • 花式索引。传入行号数组。

4.1 普通索引

冒号作用是 start : stop : step 。在某一维度内选。只有1个冒号时,表示step默认为1;省略start,即默认start为0;省略stop,即默认后面所有。

逗号的作用是 行, 列 。逗号分隔不同维度。

1
2
3
4
5
6
# 一维,用不到逗号
a = np.arange(10)
b = a[2:7:2] # 从索引 2 开始到索引 7 停止,间隔为 2

b = a[2:] # 从索引2 到数组结束
b = a[:7] # 从0 到7
1
2
3
4
5
# 多维(二维)
a = np.array([[1,2,3],[3,4,5],[4,5,6]])
b = a[2:] # 选第三行
b = a[..., :2] # 选第1、2列
# ... 三个点表示选这个维度上所有的。

4.2 整数数组索引

需要选取元素的位置是放在一个数组中。

1
2
3
4
x = np.array([[1,  2],  [3,  4],  [5,  6]]) 
y = x[[0,1,2], [0,1,0]]
print (y)
>>[1 4 5]

4.3 布尔索引

True为选取,False为不选取。

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

布尔索引也常用来过滤空值、复数等。

1
2
3
4
5
6
7
8
9
# 过滤空值,~表示取反
a = np.array([np.nan, 1,2,np.nan,3,4,5])
print (a[~np.isnan(a)])
>>[ 1. 2. 3. 4. 5.]

# 选择复数
a = np.array([1, 2+6j, 5, 3.5+5j])
print (a[np.iscomplex(a)])
>>[2.0+6.j 3.5+5.j]

4.4 花式索引

花式索引也是传入整数数组,选取某些行、某些列,传入负数时时倒着的顺序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
x=np.arange(32).reshape((8,4))
print (x[[4,2,1,7]])
>>
[[16 17 18 19]
[ 8 9 10 11]
[ 4 5 6 7]
[28 29 30 31]]

print (x[[-4,-2,-1,-7]])
>>
[[16 17 18 19]
[24 25 26 27]
[28 29 30 31]
[ 4 5 6 7]]

# 传入多个索引数组(要使用np.ix_)
print (x[np.ix_([1,5,7,2],[0,3,1,2])])
>>
[[ 4 7 5 6]
[20 23 21 22]
[28 31 29 30]
[ 8 11 9 10]]

5. NumPy 广播机制

也就是当两个形状不同的数组进行数值计算时,会触发广播机制,小的数组会自动想大的对齐。

1
2
3
4
5
6
7
8
9
10
11
a = np.array([[ 0, 0, 0],
[10,10,10],
[20,20,20],
[30,30,30]])
b = np.array([1,2,3])
print(a + b)
>>
[[ 1 2 3]
[11 12 13]
[21 22 23]
[31 32 33]]

6. 迭代数组

1
2
3
4
5
a = np.arange(6).reshape(2,3)
for x in np.nditer(a):
print (x)

>> 0, 1, 2, 3, 4, 5,

迭代与内存中是行优先存放还是列优先存放有关,也可以选择行列迭代顺序。

7. 数组操作

这里只列出了最常用的方法。

7.1 修改形状 reshape

1
2
a = np.arange(8)
b = a.reshape(4,2) # 转换成4行2列的数组

7.2 翻转数组,转置

可以直接a.T ,也可以np.transpose(a) ,都是转置操作。

1
2
3
a = np.arange(12).reshape(3,4)
print (np.transpose(a))
print (a.T)

7.3 连接数组

(1)numpy.concatenate((a1, a2, …), axis)

连接数组,axis参数是指定沿哪个轴连接,默认为0,行连接。

1
2
3
4
5
6
7
8
9
10
11
12
13
a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])
print (np.concatenate((a,b)))
>>
[[1 2]
[3 4]
[5 6]
[7 8]]

print (np.concatenate((a,b),axis = 1))
>>
[[1 2 5 6]
[3 4 7 8]]

(2)numpy.stack(arrays, axis)

输入的数组需要有相同的形状,功能与concatenate 函数相同。

(3)numpy.hstack、numpy.vstack

stack 函数的变体,水平堆叠和垂直堆叠。

7.4 分割数组

函数 数组及操作
split 将一个数组分割为多个子数组
hsplit 将一个数组水平分割为多个子数组(按列)
vsplit 将一个数组垂直分割为多个子数组(按行)

(1)numpy.split(ary, indices_or_sections, axis)

沿特定的轴将数组分割为子数组。

参数:

ary:被分割的数组
indices_or_sections:果是一个整数(3),就用该数平均切分(平均切成3份),如果是一个数组,[2, 4],就在第二个和第四个元素位置切开(左开右闭)。
axis:沿着哪个维度进行切向,默认为0,横向切分。为1时,纵向切分。

1
2
3
4
5
6
7
8
a = np.arange(9)  #[0 1 2 3 4 5 6 7 8]
b = np.split(a,3) # 将 a 平均切成3份
print (b)
>> [array([0, 1, 2]), array([3, 4, 5]), array([6, 7, 8])]

c = np.split(a,[4,7]) # 在第四个和第七个元素位置切两刀
print (c)
>> [array([0, 1, 2, 3]), array([4, 5, 6]), array([7, 8])]

(2)numpy.hsplit(array, n)

将数组竖着切成相等的 n 份。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import numpy as np

harr = np.floor(10 * np.random.random((2, 6)))
print ('原array:')
print(harr)
>>原array:
[[4. 7. 6. 3. 2. 6.]
[6. 3. 6. 7. 9. 7.]]

print ('拆分后:')
print(np.hsplit(harr, 3))
>>拆分后:
[array([[4., 7.],
[6., 3.]]),
array([[6., 3.],
[6., 7.]]),
array([[2., 6.],
[9., 7.]])]

(3)numpy.vsplit(array, n)

将数组横着切成相等的 n 份。

8. 数组元素的添加与删除

函数 元素及描述
append 将值添加到数组末尾
insert 沿指定轴将值插入到指定下标之前
delete 删掉某个轴的子数组,并返回删除后的新数组
unique 查找数组内的唯一元素

8.1 追加 append

函数:numpy.append(arr, values, axis=None)

在数组的末尾添加值。 追加操作会分配整个数组,并把原来的数组复制到新数组中。 此外,输入数组的维度必须匹配否则将生成ValueError。

参数:

  • arr:输入数组

  • values:要向arr添加的值,需要和arr形状相同(除了要添加的轴)

  • axis:默认为 None。当axis无定义时,是横向加成,返回总是为一维数组!当axis有定义的时候,分别为0和1的时候。当axis有定义的时候,分别为0和1的时候(列数要相同)。当axis为1时,数组是加在右边(行数要相同)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
a = np.array([[1,2,3],[4,5,6]])
print (a)
>>[[1 2 3]
[4 5 6]]

print (np.append(a, [7,8,9]))
>>[1 2 3 4 5 6 7 8 9]

# 向 0 轴添加元素
print (np.append(a, [[7,8,9]],axis = 0))
>>
[[1 2 3]
[4 5 6]
[7 8 9]]

# 向 1 轴添加元素
print (np.append(a, [[5,5,5],[7,8,9]],axis = 1))
>>
[[1 2 3 5 5 5]
[4 5 6 7 8 9]]

8.2 指定位置插入 insert

函数:numpy.insert(arr, obj, values, axis)

在数组指定位置插入元素。

参数:

  • arr:输入数组
  • obj:在其之前插入值的索引,即插入在第几个数后
  • values:要插入的值,如果是单值,则会被广播
  • axis:沿着它插入的轴,如果未提供,则输入数组会被展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
a = np.array([[1,2],[3,4],[5,6]])
print (np.insert(a,3,[11,12])) # 为传入axis,则原数组被展开
>>[ 1 2 3 11 12 4 5 6]

print (np.insert(a,1,[11, 12],axis = 0))
>>
[[ 1 2]
[11 12]
[ 3 4]
[ 5 6]]

print (np.insert(a,1,[11],axis = 0)) # 插入单值11,则11会沿0轴广播
# print (np.insert(a,1,11,axis = 0)) # 与上面效果相同
>>
[[ 1 2]
[11 11]
[ 3 4]
[ 5 6]]

8.3 删除 delete

函数:Numpy.delete(arr, obj, axis)

删除某些行、列。

参数:

  • arr:输入数组
  • obj:可以被切片,整数或者整数数组,表明要从输入数组删除的子数组。如[0,1]表示第1、2列;1表示删除第二列。
  • axis:沿着它删除给定子数组的轴,如果未提供,则输入数组会被展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
a = np.arange(12).reshape(3,4)
>>
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]

print (np.delete(a,5)) # a 会被展开
>> [ 0 1 2 3 4 6 7 8 9 10 11]

print (np.delete(a,1,axis = 1)) # 删除第二列
>>
[[ 0 2 3]
[ 4 6 7]
[ 8 10 11]]

a = np.array([1,2,3,4,5,6,7,8,9,10])
print (np.delete(a, np.s_[::2])) # 隔两个删除一个数
>>[ 2 4 6 8 10]

8.4 去重 unique

函数:numpy.unique(arr, return_index, return_inverse, return_counts)

数组去重,可以返回多种形式,比如去重后的数组、重复值的索引、重复的个数等。

参数:

  • arr:输入数组,如果不是一维数组则会展开
  • return_index:如果为true,返回新列表元素在旧列表中的位置(下标),并以列表形式储
  • return_inverse:如果为true,返回旧列表元素在新列表中的位置(下标),并以列表形式储
  • return_counts:如果为true,返回去重数组中的元素在原数组中的出现次数