本博客介绍 numpy 模块的使用方法,并对机器学习中应用到的较多的一些方法进行重点讲解。

一、创建numpy的数组(矩阵)

在机器学习中,用到最多的就是矩阵(数组)的运算了,使用 python 的 list 可以完成这些运算,但是效率不高,使用numpy 提供的函数接口可以很高效的完成这些功能。下面介绍了几种创建 numpy 数组(矩阵) 的方法

1 np.array()
import numpy as np
arr=np.array([1,2,3,4],dtype=int)
print(arr)
print(arr.dtype)
arr2=np.array([1,2,3])
print(arr2)
print(arr2.dtype)
arr3=np.array([1,2,3.0])
print(arr3)
print(arr3.dtype)

输出结果:

[1 2 3 4]
int64
[1 2 3]
int64
[1. 2. 3.]
float64

主要参数

arr: python list ,元组,numpy array ,用于初始化数组中的元素

dtype : 数据类型,非必选参数,numpy 会根据初始化的数据自动进行数据类型选择,详见例子 arr2 和 arr3。

2 np.asarray()
import numpy as np
arr=np.asarray([1,2,3,4],dtype=int)
print(arr)
print(arr.dtype)
arr2=np.asarray([1,2,3])
print(arr2)
print(arr2.dtype)
arr3=np.asarray([1,2,3.0])
print(arr3)
print(arr3.dtype)

输出结果:

输出结果:

[1 2 3 4]
int64
[1 2 3]
int64
[1. 2. 3.]
float64

基本用法与 np.array() 一致

3 生成某一个值的特定矩阵

import numpy as np
arr1=np.ones(shape=(4,4),dtype=int)
print(arr1)
print("---------------")
arr2=np.zeros(shape=5,dtype=float)
print(arr2)
print("---------------")
arr3=np.full(shape=(2,5),dtype=int,fill_value=520)
print(arr3)

输出结果:

[[1 1 1 1]
[1 1 1 1]
[1 1 1 1]
[1 1 1 1]]
---------------
[0. 0. 0. 0. 0.]
---------------
[[520 520 520 520 520]
[520 520 520 520 520]]

有三种方法可以生成某一个值的特定矩阵,分别为 np.ones(),np.zeros(),np.full()。三个函数中的参数 dtype 均为可选,判断元素类型的机制和 np.array() 一致。三种函数的用法和返回结果如例所示,理解起来比较简单。

4 创建等步长数组

import numpy as np
arr1=np.arange(0,10)
print(arr1)
arr2=np.arange(0,10,0.5)
print(arr2)
arr3=np.linspace(0,10,11)
print(arr3)

输出结果

[0 1 2 3 4 5 6 7 8 9]
[0. 0.5 1. 1.5 2. 2.5 3. 3.5 4. 4.5 5. 5.5 6. 6.5 7. 7.5 8. 8.5
9. 9.5]
[ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.]

np.arange() 可以用于生成等步长的数组,用法类似于 range() ,参数分别为起始点,终止点,步长。终止值不会出出现在最终的数组中。所不同的是步长可以是浮点数,如例子所示。

除了np.arange() 之外,np.linspace() 函数也可以用于生成等步长的数组,与 arange 函数不同的是,生成的数组中包括终止值,第三个参数不是步长,而是平均分成了多少份,如例子所示。

5 使用随机的方法创建数组

import numpy as np
arr1=np.random.randint(low=0,high=10,size=(2,5))
print(arr1)
arr2=np.random.random(size=(3,3))
print(arr2)
arr3=np.random.normal(loc=0,scale=1,size=20)
print(arr3)

输出结果:

[[2 8 1 2 7]
[6 9 0 3 5]]
[[0.74831657 0.32991162 0.53259451]
[0.7005176 0.17805907 0.58690404]
[0.19568012 0.59133077 0.31332564]]
[-0.16324593 0.12253359 1.2257147 2.35137786 -0.79876596 -0.1480339
1.03034397 0.63034462 0.91966266 -1.24178813 -0.02773027 0.68352114
0.01390874 -0.04098013 0.52609043 -0.83886096 0.07309302 0.49478078
1.7656865 1.1617786 ]

函数 np.random.randint(low,high,size) 用于生成在 low 和 high 之前的一个随机的整数,注意,high 取不到。size 可以是一个整数或者元组,使用整数表示创建一个一位数组,元组表示创建一个shape 为 size 的矩阵。

函数 np.random.random(size) 用于均匀的生成在 0-1 范围内的浮点数。size 的含义和 randint 一致。

函数 np.random.normal(loc,scale,size) 用于生成正太分布的随机数,size 的含义没有变化,loc 表示均值,scale 可以理解为方差,例子中arr3 就是一个均值为0,方差为 1 的正态分布的具有20个元素的数组。

多说一句,计算机中的随机数字不是真正的随机数字,而是使用随机算法生成的伪随机数字,如果想要得到相同的随机数字用于实验的时候复现算法,可以人为的设置随机种子:

np.random.seed(seed) #seed 是一个整数

二、numpy array 的基本属性和操作

import numpy as np
arr1=np.random.randint(low=0,high=10,size=(2,5))
print(arr1.shape)
print(arr1.size)
print(arr1.ndim)
print(arr1.dtype)
输出
(2, 5)
10
2
int64

1 基本属性

ndim:数组(矩阵)的维度

shape:数组(矩阵)的形状

dtype:数组(矩阵)的数据类型

size:数组中(矩阵)的元素的个数

2 数据访问方法

对于python 的list 数组,我们可以使用 方括号+ 下标的方式进行数据访问。例如一个二维的 python list 数组 arr,可以使用 arr[0][0] 来访问二维数组的第一行,第一列的元素。但是这种方法在 numpy 数组中虽然也可以,但是不建议使用,在numpy 数组中建议使用如下方式访问:

import numpy as np
arr1=np.random.randint(low=0,high=10,size=(2,5))
print(arr1)
print(arr1[1,2])

输出结果:

[[4 5 1 4 0]
[7 4 9 4 7]]
9

arr1[1,2] 表示arr1矩阵的 第第二行,第三列的元素,就是 9 。

除此之外,numpy 还支持切片访问(如果不清楚可以查看Python的基础语法)

import numpy as np
arr=np.array([1,2,3,4,5])
print(arr[:3]) # 访问第四个元素之前的元素(前三个元素)
print(arr[2:]) # 访问第三个元素以及之后的元素
print(arr[0:2]) # 访问第1个元素到第三个元素之间的元素,不包括第三个元素

前面提到过numpy array 不建议使用 arr[索引1][索引2] 来访问二位数组中的元素,为什么呢?其实是容易混淆,下面的例子就演示了这种情况:

import numpy as np
arr=np.random.randint(0,10,size=(5,5))
print(arr)
print("-------------------")
print(arr[:3,:3]) # 取 arr 数组中的 前三行,前三列
print("-------------------")
print(arr[:3][:3]) # 返回的结果是啥?

输出结果:

[[9 2 9 5 8]
[8 3 9 5 5]
[4 7 5 7 2]
[4 2 7 3 3]
[8 8 6 7 7]]
-------------------
[[9 2 9]
[8 3 9]
[4 7 5]]
-------------------
[[9 2 9 5 8]
[8 3 9 5 5]
[4 7 5 7 2]]

是不是觉得很懵? arr[:3][:3] 怎么会返回一个 3行5列的数组呢?其实是 arr[:3] 首先取到了arr 数组的前三行元素,得到了一个中间的数组 arr1,然后 arr1[:3] 又得到了arr1的前三行,最终的结果就是上面展示的那样,看吧,其实 arr[:3][:3] 是对 arr 数组两次取前三行的结果,特别容易混淆,所以,听我一句劝,numpy 数组别用这种双重方括号加索引的方式访问。

特别提醒一下:使用切片的方式得到的子数组其实是对于原数组的引用,修改子数组,原数组也会收到影响,这与python 的list 不同,python list 是默认会复制一个副本到子数组。示例如下:

import numpy as np
arr=np.random.randint(0,10,size=(5,5))
print(arr)
print("-------------------")
subarr=arr[:3,:3]
print(subarr) # 取 arr 数组中的 前三行,前三列
print("--------------------")
subarr[0,0]=250
print(subarr)
print("--------------------")
print(arr)

输出结果:

[[3 6 6 7 8]
[8 7 1 9 2]
[8 6 8 3 3]
[9 5 8 4 2]
[6 0 1 6 0]]
-------------------
[[3 6 6]
[8 7 1]
[8 6 8]]
--------------------
[[250 6 6]
[ 8 7 1]
[ 8 6 8]]
--------------------
[[250 6 6 7 8]
[ 8 7 1 9 2]
[ 8 6 8 3 3]
[ 9 5 8 4 2]
[ 6 0 1 6 0]]

想要建立副本要调用 copy 方法

subarr=arr[:3,:3].copy()

3 数组形状改变

import numpy as np
arr=np.random.randint(0,10,size=25)
print(arr)
print("-------------------")
arr1=arr.reshape(5,5)
print(arr1)
print("--------------------")
print(arr) # 取 arr 数组中的 前三行,前三列
print("--------------------")
arr2=arr.reshape(5,-1)
print(arr2)
print("--------------------")
print(arr.reshape(10,-1))

输出结果:

[2 1 2 2 6 3 4 1 6 7 8 8 4 2 7 2 4 6 8 3 2 3 9 5 8]
-------------------
[[2 1 2 2 6]
[3 4 1 6 7]
[8 8 4 2 7]
[2 4 6 8 3]
[2 3 9 5 8]]
--------------------
[2 1 2 2 6 3 4 1 6 7 8 8 4 2 7 2 4 6 8 3 2 3 9 5 8]
--------------------
[[2 1 2 2 6]
[3 4 1 6 7]
[8 8 4 2 7]
[2 4 6 8 3]
[2 3 9 5 8]]
--------------------
Traceback (most recent call last):
File "/home/qianqianjun/CODE/Python/ML_ Mooc/draw.py", line 3, in 
print(arr.reshape(10,-1))
ValueError: cannot reshape array of size 25 into shape (10,newaxis)

reshape(shape) 可以获得形状改变之后的数组,shape 可以是元组,但是可以不写括号

如例子所示,arr1是一个 5 × 5 的矩阵,由原来的数组变换而来。需要注意的是 reshape不会改变原数组,如例子所示。

另外,为了方便起见,numpy 还提供了一种自动计算维度的机制,只要待计算的维度可以唯一确定,numpy 会自动计算,我们只需要填写 -1 即可,如例子所示。

此外,不是随便写啥维度都可以的,必须要可以整除,如例子所示,25 没有办法整除 10,所以 reshape 会报错。

三、numpy数组合并和分割

1 合并操作

import numpy as np
arr1=np.array([1,2,3])
arr2=np.array([4,5,6])
arr3=np.array([7,8,9])
arr12=np.concatenate([arr1,arr2])
print(arr12)
print("--------------")
arr123=np.concatenate([arr1,arr2