机器学习:Jupyter Notebook中numpy的使用
一、Jupyter Notebook的魔法命令
# 模块/方法 + ?或者help(模块/方法):查看模块/方法的解释文档;
1)%run
# 机械学习中主要应用两个魔法命令:%run、%timeit
# 魔法命令格式:% + 命令
# %run:将模块引用并在Jupyter Notebook中执行(这是与import的区别),模块被引用后,其内部的函数可以在Jupyter Notebook中直接被引用;
# 格式:%run + 文件的地址 + 文件名
2)%timeit
- 测试代码的性能,后面只能接一条语句/代码块,得出运行此条语句或代码块所用的时间;
- %timeit + 一条语句:测试该条语句运行所用时间;
- %%timeit:表示测试在该单元格内的全部代码运行时所用时间;
- %timeit、%%timeit,一般是将代码运行多遍,然后去取执行最快的几次的平均值;
- 如果%timeit和%%timeit后面的代码,每次运行的效率不同,则测量的结果又偏差;
- %time,返回只将代码运行一遍所用时间;但这样的测试结果不稳定,每次测得结果差异很大,但对于一次测试用时较长的代码/算法,测试差异可以忽略;
3)其它
- 命令 + ?:查看命令的文档;
- 可以通过%lsmagic查看素有的魔法命令;
- 机器学习算法中,scikit-learn中的函数封装的都是接收一个Numpy的矩阵,通常使用Pandas对数据进行预处理,将Pandas数据转换为Numpy的矩阵,再送给机械学习的算法;
二、numpy.array基础
1)numpy.array的基础
- python的list数据非常灵活,运行效率较低,因为系统需要检测其中所有数据的类型;
- Python中的array模块,可以限定只存储一种数据类型:
import array arr = array.array('i', [i for i in range(10)]) # 其中'i'表示数据类型为整数 print(type(arr[5])) # 5 arr[5] = 'a' # 报错,arr内的数据只能赋值为整数
- Python的array模块缺陷:1)中没有将数据看成向量或矩阵,因此也没有向量和矩阵相关的运算;2)只有一种数据类型,不够灵活使用;
- numpy模块的array方法,可以进行向量和矩阵的运算;
- numpy模块的array方法创建的数据,只能是整数,若将小数赋值给array方法创建的数据时,会自动转换为整数;
- 机械学习中所操作的大多数数值为浮点数;
2)np.array的创建
A、创建全0数组
- np.zeros(10):默认为float64类型的一维全0数组;
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
- np.zeros(10, dtype = int):数据类型为int的一维全0数组;
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
- np.zeros((3, 5)):默认fioat64类型的3行5列的矩阵;
array([[0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.], [0., 0., 0., 0., 0.]])
- np.zeros(shape = (3, 5), dtype = int)或者np.zeros( dtype = int, shape = (3, 5)):类型为int的3行5列的矩阵;
array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]])
B、创建全1的数组
- np.ones(),操作方法同理全0矩阵的创建;
C、创建所有值都相同的数组
- np.full((3, 5), 666)或者np.full(shape = (3, 5), fill_value = 666)或者np.full(fill_value = 666, shape = (3, 5)):默认为int;
array([[666, 666, 666, 666, 666], [666, 666, 666, 666, 666], [666, 666, 666, 666, 666]])
- np.full(10, 666)或者np.full(shape = 10, fill_value = 666)或者np.full(fill_value = 666, shape = 10):
array([666, 666, 666, 666, 666, 666, 666, 666, 666, 666])
D、numpy中arange的用法:参数的用法与python中range的参数用法一样
- np.arange(0, 10):默认步长为1;
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
- np.arange(10):默认起始值为0,默认步长为1;
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
- np.arange(0, 10, 2):取值间隔为2;
array([0, 2, 4, 6, 8])
- np.arange(0, 1, 0.2):步长可以为小数,0.2,而python中的range的参数,步长不能为小数;
rray([0. , 0.2, 0.4, 0.6, 0.8])
- range()生成列表,np.arange()生成数组;
E、numpy中linspace的用法,与arange类似
- np.linspace(0, 20, 10):将0~20间的数等分10个点,首尾分别是0和20,此处10不是步长,而是将区间等分的点数(包含首尾数值);
array([ 0. , 2.22222222, 4.44444444, 6.66666667, 8.88888889, 11.11111111, 13.33333333, 15.55555556, 17.77777778, 20. ])
F、numpy中random的用法:生产随机int数random.randint()
- 区间为前闭后开:[m,n);
- 随机生成的数据给算法时,运行的结果不一致,导致调试困难;
- 计算机中,所有的随机数都是伪随机数,都是随机算法实现的;推动算法生产随机数的是随机种子:同一个随机种子生产的随机数是一定的,再次调用该种子时可以得到上一次该种子生产的随机数;
- np.random.randint(0, 10):从0~10间随机生产一个z
5
- np.random.randint(0, 10, 5):从0~10间随机生成5个int类型的数;
array([8, 6, 3, 3, 6])
- np.random.randint(4, 8, size = 10):一般标出size = 10,提高代码可读性;
array([6, 5, 6, 7, 4, 7, 7, 6, 5, 5])
- np.random.randint(4, 8, size = (3, 5)):从[4, 8)中,随机生成3行5列的矩阵;
array([[7, 7, 5, 5, 5], [5, 7, 5, 7, 4], [6, 6, 4, 6, 5]])
- 随机种子的使用
# Jupyter Notebook中实现的代码 np.random.seed(666) np.random.randint(4, 8, size = (3, 5)) # 设定随机种子,并生成随机数据 np.random.seed(666) np.random.randint(4, 8, size = (3, 5)) # 再次调用该种子,并再次生成原来格式的随机数据,所得到的数据与第一次随机生成的数据相同;
G、numpy中random的使用:生成随机float数random.random()
- 生成的float数为0~1的随机数;
- random.random()的操作格式与random.randint()一样;
H、numpy中random的使用:随机生产满足正态分布的folat数;
# 正态分布:均值为0,方差为1的分布规律;
- np.random.normal():默认为-1~1,默认均值为0方差为1,随机取一个数;
-0.770927518770882
- np.random.normal(10, 100):默认均值为10方差为100,随机取一个数;
-213.49687669162455
- np.random.normal(0, 1, (3, 5))或者np.random.normal(0, 1, size = (3, 5)):
array([[ 1.42965241, -0.41407013, -1.32672274, -0.14880188, 0.34771289], [ 0.61030791, -1.17532603, 0.82985368, -0.30236752, -0.04327047], [ 0.06706965, -1.59102817, 0.01705112, -1.87296591, -0.96457904]])
I、创建空矩阵
- np.empty(shape = (m, n), dtype = float):创建一个m行n列,数据类型为float的空矩阵;
3)np.array的元素访问
- np.aange(15).reshape(3, 5):将一维数组转换为多维数组;此处必须是3 X 5 = 15,数据总数不变;
array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]])
A、array的基本属性
# np.arange(15).reshape(3, 5) == np.arange(15).reshape(3, -1)
- array.ndim:返回array的维度;
- array.shape:返回array的行数和列数;
# Jupyter Notebook中的代码 import numpy as np x = np.arange(15).reshape(3, 5) x.shape # (3, 5)
- array.size:返回数组元素个数;
B、numpy.array的数据访问
- 访问一维数组的一个:用 [ ] 进行引索,方式与python中访问列表元素一样;
- 访问一维数组的一段连续的数据:采用切片,方式与python中访问列表元素一样;
import numpy as np arr = np.arange(10) print(arr[5:]) # 输出:array([5, 6, 7, 8, 9]) print(arr[::2]) # 输出:array([0, 2, 4, 6, 8]) print(arr[::-1]) # 输出:array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
- 访问多维数组中的一个元素:arr[m, n],访问数组arr中第m + 1行与第n + 1列所对应的元素;
- 访问多维数组中的一段连续的元素:
import numpy as np arr = np.arange(15).reshape(3, 5) print(arr[:2, :3]) # 输出:array([[0, 1, 2], [5, 6, 7]]) print(arr[:2]) # 输出:array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) print(arr[:2, ::2]) # 输出:array([[0, 2, 4], [5, 7, 9]]) print(arr[::-1, ::-1]) # 输出:array([[14, 13, 12, 11, 10], [ 9, 8, 7, 6, 5], [ 4, 3, 2, 1, 0]])
- 由sub生成的子矩阵,是直接引用的原矩阵,并没有生成一个真实的矩阵,这样可提高数据的生成效率;
- 由sub生成的子矩阵更改是,子矩阵所引用(通过引用生成的子矩阵,而不是新建立)的矩阵也跟着更改;相同,更改矩阵后,引用它所生成的子矩阵也相应更改;
arr = np.arange(15).reshape(3, 5) subarr = arr[:2, :3] print(subarr) # 输出:array([[0, 1, 2], [5, 6, 7]]) subarr[0, 0] = 100 print(arr) # 输出:array([[100, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [ 10, 11, 12, 13, 14]]) arr[0, 0] = 20 print(subarr) # 输出:array([[20, 1, 2], [ 5, 6, 7]])
- 子矩阵.copy():将子矩阵数据在磁盘中真实生成;再更改子矩阵时,对应的原矩阵不再跟着更改;
4)numpy.array的合并
#一维数组和向量都是一行,但向量是二位,可以通过reshape将一维数组转换为二位向量:arr.reshape(1, n);
A、np.concatenate
- 连接两个一维数组:np.concatenate([arr1, arr2]),仍然为一维数组;
import numpy as np a = np.array([1, 2, 3]) b = np.array([4, 5, 6]) c = np.concatenate([a, b]) print(c) # 输出:array([1, 2, 3, 4, 5, 6])
- 连接两个二维数组:默认axis = 0,增加行数;axis = 1,增加列数; 当列数不相等的两个数组,只能连接增加列数;
import numpy as np a = np.array([[1, 2, 3], [4, 5, 6]]) b1 = np.concatenate([a, a]) print(b1) #array([[1, 2, 3], [4, 5, 6], [1, 2, 3], [4, 5, 6]]) b2 = np.concatenate([a, a], axis = 1) print(b2) # array([[1, 2, 3, 1, 2, 3], [4, 5, 6, 4, 5, 6]])
- np.vstack([arr1, arr2]),两数组垂直相加,增加行数;
a = np.arange(15).reshape(5, 3) b = np.arange(3) # 将b矩阵堆叠成和a矩阵行数相等; c = np.vstack([b] * a.shape[0]) # array([[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]])
- np.hstack([arr1, arr2]),两数组水平相加,增加列数;
import numpy as np # 创建全 1 向量:np.ones((m, n), dtype),(m, n) m 行 n 列,必须用tuple类型,不能用list类型,不然会报类型错误:data type not understood x = np.random.random(size=100).reshape(-1, 1) y = np.ones((len(x), 1), dtype = float) z = np.hstack([x, y])
5)numpy.array的分割
A、一维数组分割:分割点是数组中的数据的位号,而且必须为数组格式;
- 分成两断:
a = np.arange(10) a1, a2 = np.aplit(a, [5]) print(a1, a2) #array([0, 1, 2, 3, 4]) array([5, 6, 7, 8, 9])
- 分成多段:
a = np.arange(10) a1, a2, a3 = np.aplit(a, [3, 6]) print(a1, a2) #array([0, 1, 2]) array([4, 5, 6]) array([7, 8, 9])
B、分割二位数组:
- 默认垂直分割,即axis = 0:把行数等分,若行数为奇数,第一个数组多一行;
a = np.arange(15).reshape(3, 5) a1, a2 = np.split(a, [2]) print(a1, a2) # array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) # array([[10, 11, 12, 13, 14]])
- 水平分割,axis = 1:与一维数组分割方式一样,分割点为第一行数据中的位号(序号);
a = np.arange(15).reshape(3, 5) a1, a2 = np.split(a, [3], axis = 1) print(a1, a2) # array([[ 0, 1, 2], [ 5, 6, 7], [10, 11, 12]]) # array([[ 3, 4], [ 8, 9], [13, 14]])
- 直接垂直分割:np.vsplit();
- 水平分割:np.hsplit(),不用指定axis的值;
- #数据分割的意义:可以将数据集中的特征样本和标志分离开;
6)numpy.array的具体运算
A、numpy.array的加、减、乘、除法运算,array可以做为除数,也可以作为被除数
#与数组中的每个元素相乘;
#Python中的list直接与数字相乘,是把list中的数据复制对应次数,而不是与list数据中的每个数相乘;
# np.array的运算比Python中的list的运算效率高很多;
B、numpy.array的其它函数运算
- np.abs(array):向量中的所有元素取绝对值
- np.var(array):向量中所有元素的方差
- np.std(array):向量的均方差
- np.linalg.inv(array):矩阵的逆矩阵
- np.sin/cos/tan/cot(array):向量中的所有元素进行三角函数运算;
- np.mean(array):向量的平均值;
- np.exp(array):向量中的所有元素作为e的幂;
- np.power(3, array) == 3 ** array:向量中的所有元素作为3的幂;
- np.log5(array):对向量中的所有元素取5的对数;
- np.log(array):对向量中的所有元素取e的对数;
- len(array):返回矩阵的行数,或者向量的元素个数
C、向量与矩阵之间的运算
- array.T:将矩阵转置;
- 向量 + 矩阵:
a = np.arange(15).reshape(5, 3) b = np.arange(3) print(a + b) # array([[ 0, 2, 4], [ 3, 5, 7], [ 6, 8, 10], [ 9, 11, 13], [12, 14, 16]])
- 向量 * 矩阵:
a = np.arange(15).reshape(5, 3) b = np.arange(3) print(a + b) # array([[ 0, 1, 4], [ 0, 4, 10], [ 0, 7, 16], [ 0, 10, 22], [ 0, 13, 28]])
- 矩阵与矩阵间的运算:必须满足矩阵运算的条件,与线性代数规则一样;格式:arr1.dot(arr2)、arr2.dot(arr1);
- 在numpy模块中,一维数组,即可以看成一行,也可以看做是一列;
- 求逆矩阵:np.linalg.inv(array);(逆矩阵必须满足一定的条件)
- 逆矩阵 * 原矩阵、原矩阵 * 逆矩阵 == 单位矩阵;
- 伪逆矩阵:一些没有逆矩阵的矩阵,可以求其伪逆矩阵:np.linalg.pinv(array),伪逆矩阵 * 原矩阵 == 伪单位矩阵(对角线的数为1,其余数不为0);
7)numpy中的聚合运算
# 聚合:将一组数合并成一个数;
# Python中的sum()函数运算效率,远低于numpy.sum()方法;
A、向量的聚合
- np.sum(array):将数组中的所有书相加;
- np.min/max(array):求数组中的最小值/最大值;
- 也可以:big_array.sum/min/max(),求值,只是方式不一样,但一般使用np.min(),增加代码的可读性;
B、矩阵的聚合
- np.sum/min/max(array),对整个矩阵进行聚合;
- np.sum/min/max(array, axis = 1):对矩阵各行进行聚合;
x = np.arange(16).reshape(4, 4) y = np.sum(x, axis = 1) print(y) # array([ 6, 22, 38, 54])
- np.sum/min/max(array, axis = 0):对矩阵各列进行聚合;
x = np.arange(16).reshape(4, 4) y = np.sum(x, axis = 1) print(y) # array([24, 28, 32, 36])
- np.prod(array):将矩阵中所有元素相乘;
- np.prod(array + 1):先将矩阵中的所有元素都加1,再讲所有元素相乘;
- np.mean(array):求矩阵所有元素的平均值;
- np.median(array):求矩阵所有元素的中位数;
- np.percentile(big_array, q = 30):求百分位点的值,矩阵中30%的值都小于此数;
- np.percentile(big_array, q = 50) == np.median(array)、np.percentile(big_array, q = 100) == np.max(array);
- 一般看一组数的5个百分位点的值,就可大致看出此组数的分布情况:
x = np.random.randint(0, 100, 200) for percent in [0, 25, 50, 75, 100]: print(np.percentile(x, q = percent))
- 求方差:np.var(big_array);
- 求标准差:np.std(big_array);
8)numpy中的arg运算
A、求数据的索引位置
- np.argmin/argmax(array):求矩阵中最小/大值在矩阵中的位置;
B、排序和使用索引
- 出向量进行乱序处理:np.random.shuffle(array),将向量中的数据顺序打乱;
- 对向量中的数据进行排序处理:np.sort(array),此方法是返回了一个新的排好序的array,原来的array并没有改变;
- array.sort():对向量本身进行排序;
- np.sort(array):对矩阵进行排序,默认(axis = 1)每一行为一组数据单独排序;
- np.sort(array, axis = 0):对矩阵的每一列进行排序;
- np.argsort(array):对向量进行排序,返回一个新的数组,新的数组中为原数组元素排序号的元素序号;
x1 = np.arange(15) np.random.shuffle(x1) x2 = np.argsort(x1) print(x1, x2) # array([ 3, 13, 4, 2, 8, 12, 6, 14, 11, 5, 1, 7, 10, 0, 9]) # array([13, 10, 3, 0, 2, 9, 6, 11, 4, 14, 12, 8, 5, 1, 7], dtype=int64)
- np.partition(array, n):对数组中的数进行排序,小于n的数在左侧,大于n的数在右侧,左右两侧的数即不按大小顺序排列也不在按原来位置排列;一般多用于求数组中比某一值大/小的数;
x1 = np.arange(15) np.random.shuffle(x1) x2 = np.argsort(x1) print(x1, x2) # array([ 4, 9, 10, 8, 11, 7, 13, 2, 5, 3, 6, 1, 0, 12, 14]) # array([ 3, 2, 0, 1, 4, 5, 6, 7, 8, 10, 9, 11, 13, 12, 14])
- np.argpartition(array, n):返回x2数组中各元素在x1数组中的位置,与np.partition(array, n)的功能一样;
x1 = np.arange(15) np.random.shuffle(x1) x2 = np.argsort(x1) print(x1, x2) # array([ 4, 9, 10, 8, 11, 7, 13, 2, 5, 3, 6, 1, 0, 12, 14]) # array([ 3, 2, 0, 1, 4, 5, 6, 7, 8, 10, 9, 11, 13, 12, 14]) # array([ 9, 7, 12, 11, 0, 8, 10, 5, 3, 2, 1, 4, 6, 13, 14], dtype=int64)
- np.argsort(array, axis = 1):对矩阵进行排序,返回各数据在原矩阵中的位置,axis默认为1,表示按进行排序;
- np.argsort(array, axis = 0):按列进行排序;规则同上;
9)Numpy中的比较和Fancy Indexing
A、索引一维数组中的任意数
- 索引是一维数组:ind = [1, 2, 5, 7, 8]
x = np.arange(16) # 目标数在数组中对应的位置序号 ind = [1, 2, 5, 7, 8] print(x[ind]) # array([1, 2, 5, 7, 8])
- 索引是二维数组,则生成一个二维数组:ind = np.arange(4).reshape(2, 2);
x = np.arange(16) # 目标数在数组中对应的位置序号 ind = np.arange(4, 8).reshape(2, 2) print(x[ind]) # array([[4, 5], [6, 7]])
B、索引二位数组中的任意数
- 只索引其中的某几行:
import numpy as np X = np.arange(16).reshape(4, -1) # 1)索引一行:X[2] == X[2, :] y1 = X[2] print(y1) # array([ 8, 9, 10, 11]) # 2)索引某几行 row = np.array([0, 1, 2]) y2 = X[row] print(y2) # array([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]])
- 只索引其中的某几列:
import numpy as np X = np.arange(16).reshape(4, -1) # 1)索引一列:X[:, 2] y1 = X[:, 2] print(y1) # array([ 2, 6, 10, 14]) # 2)索引某几列:X[:, array] row = np.array([0, 1, 2]) y2 = X[:, row] print(y2) # array([[ 0, 1, 2], [ 4, 5, 6], [ 8, 9, 10], [12, 13, 14]])
- 将目标数据在矩阵中的行号和列号,分别写在两个数组中:
X = np.arange(16).reshape(4, -1) row = np.array([0, 1, 2]) col = np.array([1, 2, 3]) # 获取矩阵中的任意数据 print(X[row, col]) # array([1, 6, 11]) # 获取矩阵中的某一行内的几个数据 print(X[0, col]) # array([1, 2, 3]) # 获取矩阵中前两行数据中的某些数 print(X[:2, col]) # array([1, 2, 3], [5, 6, 7])
- 使用布尔数组进行引索:
X = np.arange(16).reshape(4, -1) col = array([True, False, True, True]) # 只对数组中为True的列/行进行引索 print(X[1:3, col]) # array([[4, 6, 7], [8, 10, 11]])
C、比较
- array与一个数比较:将array中的所有数据与该数比较,返回布尔数组;
x = np.arange(16) print(x < 5) # array([ True, True, True, True, True, False, False, False, False, False, False, False, False, False, False, False])
- array与array比较:两数组中的元素个数相等,对应元素进行比较,返回布尔数组;
x1 = np.array([5, 4, 3, 2, 1]) x2 = np.array([1, 2, 3, 4, 5]) print(x1 > x2) # array([ True, True, False, False, False])
- array经过运算后,与一个数或者另一个array比较:规则同理运算前的比较;
- np.sum(array < 5):获取array中小于5的数的个数;
- np.count_nonzero(array < 5):返回()内的布尔数组中非0元素的个数;
- np.any(array == 0):只要()内的布尔数组中有True,返回True,否则返回False;多用于查看array中是否有0元素;# np.any()的用法;
- np.all(array > 0):只有()内的布尔数组全为True,返回True,只要有一个False,则返回False;# np.all()的用法;
- np.sum(array % 2 == 0):获取矩阵中偶数的个数;
- np.sum(array % 2 == 0, axis = 1):获取矩阵每一行中偶数的个数;
- np.sum(array % 2 == 0, axis = 0):获取矩阵每一列中偶数的个数;
- np.sum((array >3) & (array < 10)):获取array中大于3且小于10的元素的个数;此处用“&”符号,相当于“and”;
- np.sum((array % 2 == 0) | (array > 10)):获取array中偶数与大于10的数的个数;此处用“|”符号,相当于“or”;
- np.sum(-(array == 0)):获取array中非0的数的个数;此处用“-”符号,相当于“not”;
- axis = 0:对矩阵中的每一列进行操作;axis = 1:对矩阵中的每一行进行操作;适用于所有方法;
- 二维矩阵的比较运算规则,与一维数组相同;