NumPy¶
numpy为python提供了数组的支持
import numpy as np
类型¶
一个np数组只能存储相同的一种数据类型,int/float(字符串也是可以的,但是基本不用) 在int数组里修改元素为float会被截断
arr_float = arr.astype(float) 利用.astype()方法转换数组的类型
类似于c/cpp的类型提升,当整数型数组进行除法等涉及到浮点数的运算时,会转换成浮点型数组
打印时,数字之间是空格(列表是逗号)
维度¶
数组的维度信息,就是形状.shape,是一个元组
使用.reshape()方法,传入形状元组,可以在不同维度的数组之间转换
arr1 = np.array([1,2,3,4,5,6])
arr2 = arr1.reshape(2, -1) #两行三列
print(arr2.reshape(-1)) #转回一维数组,或者写(6)
-1,让程序自行计算
创建¶
arr = np.array([1,2,3]) #创建的过程是把列表转换为np数组
arr = np.array( [[1,5,9], [8,8,8]] ) #二维数组,但是依旧传入一个列表
arr = np.arange(start, end, step) #创建递增数组,和range一样左闭右开
np.zeros() np.ones() 创建全0和全1的数组
第一个参数是形状的元组,第二个参数dtype=可以指定float/int
随机数组
np.random.random(shape) 0-1
np.random.randint(start, end, shape) 随机int
np.random.normal(mean, standard_deviation, shape) 正态分布
注意numpy数组进行赋值只是绑定,类似于指针层面的浅拷贝
arr2 = arr1,修改arr2,arr1也会同样被修改
需要拷贝,使用.copy()方法
访问¶
下标[]访问
二维数组一般使用[i,j]的形式访问,[i][j]也可以
切片¶
注意numpy切片得到的不是拷贝,是一个视图,这和py列表不一致
需要创建拷贝就使用arr[:, 0:2].copy()
向量的切片方法和列表一致 对于矩阵的切片,需要用两个参数分别对行列切片
arr = np.arange(20).reshape(4,-1)
# [[ 0 1 2 3 4]
# [ 5 6 7 8 9]
# [10 11 12 13 14]
# [15 16 17 18 19]]
print(arr[1:3, 1:4]) #分别对行[1:3] 列[1:4]切片
# [[ 6 7 8]
# [11 12 13]]
提取行列
切片的时候某个参数不写冒号,就可以提取矩阵的某一行列
比如arr[1, :]就是提取第1行,保留所有列(可以简写为arr[1])
提取列的时候不会输出n*1的二维数组,而是一维向量
花哨索引¶
允许使用数组作为下标来访问元素,需要使用双层中括号(传入一或多个列表) 返回副本拷贝
arr = np.array([10, 20, 30, 40, 50])
print(arr[[3, 1, 4]]) #按 [3, 1, 4] 的顺序取值 输出: [40, 20, 50]
X = np.arange(12).reshape(3, 4)
# [[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]]
rows = [0, 1, 2]
cols = [2, 0, 3]
print(X[rows, cols]) #取 (0,2), (1,0), (2,3) 三个点 输出: [2, 4, 11]
常用于数据清洗,特别是结合布尔数组的情况下
data = np.array([1, -2, 3, -4, 5])
mask = (data > 0) & (data < 4) #data > 0得到的是一个相同形状的布尔数组
print(data[mask]) #[1, 3]
data[data < 0] = 0
print(data) #[1, 0, 3, 0, 5]
变形¶
.T转置矩阵方法
如果是向量(一维数组),先.reshape(1,-1)转换为1*n的矩阵(二维数组)
两个翻转函数
arr2 = np.flipud(arr) flip up-down上下翻转
np.fliplr left-right 左右
对于向量,只能使用上下翻转(数学上写成列向量)
前面提到的.reshape()方法,传入形状元组
拼接函数
np.concatenate( [arr, arr2], axis=0 )
第二个参数axis是拼接的方向,默认为0在行的方向(行标增加的方向)上拼接
分割
arr1, arr2, arr3 = np.split(arr, [1,3])
第二个参数传入切断位置的列表,代表切断成 0-1 1-3 3-end三部分,同样是左闭右开区间
如果是分割矩阵,第三个参数axis是分割的方向,默认为0,在行的方向进行分割
分割向量得到的是向量,分割矩阵得到的是矩阵,以元组的形式返回
运算¶
使用*进行乘法,是逐元素:
- 数组和系数之间进行运算,运算会作用到每一个元素上
- 数组和数组之间进行运算,也是逐元素运算
比如矩阵乘法是
一般来说数组之间的运算需要形状相匹配,除了
- 向量和矩阵进行运算,向量自动升级为行矩阵
- 行/列矩阵和矩阵进行运算,行/列矩阵自动扩充到匹配的形状,这称之为广播(准确的说,是参与运算时,从最后一个维度开始对齐,缺失维度补 1,各维度取 max)
使用@乘法,才是矩阵乘法,相当于np.dot(arr1,arr2)函数
向量和向量做点积,返回标量;向量与矩阵相乘,返回向量,而不是列/行矩阵的形式;矩阵和矩阵相乘,就算数学上结果是标量,依旧会返回矩阵
常用函数¶
下面都是利用np.func()调用
abs
cos sin tan
exp log 注意log默认是e为底,自然对数
max min argmax argmin sum prod mean std 均值和标准差 对于矩阵,默认是求所有元素的最值/和/积;当给定参数axis=0/1的时候,会按行/列求出最值/和/积的向量 第二部分的函数如果遇到缺失值会报错,这是需要使用nanmin等安全版本
where
返回一个元组,打包符合条件的下标位置数组布尔数组¶
在进行比较运算的时候,返回的就是逐元素比较结果构成的布尔数组
在python中逻辑运算符是and/or/not,而numpy使用的是& | ~
注意添加括号保证运算顺序
对布尔数组,np.sum()被重载为统计True的个数
np.any()和np.all()和python内置类型的用法一样
在前面花哨索引的部分提到过,布尔数组可以作为掩码 注意这样的操作返回的是数组: