Numpy,一篇足以
numpy
用于数值计算
- ndarray, 一个有效的多维数组,能提供以数组为导向的快速数值计算和灵活的广播功能(broadcasting)
- 便利的数学函数
- 用于读取/写入(reading/writing)数据到磁盘的便利工具
- 线性代数,随机数生成,傅里叶变换能力
- 可以用C API来写C,C++,或FORTRAN
ndarray
N-dimensional array object(n维数组对象)
# 生成一个随机数组
import numpy as np
data = np.random.randn(2, 3)
print(data.shape) # shape表示维度
print(data.dtype) # data type, output:dtype('float64')
创建
# list类型转化
data1 = [6, 7.5, 8, 0, 1]
arr1 = np.array(data1) # 自动分配data type
# 嵌套的list也可
data2 = [[1, 2, 3, 4], [5, 6, 7, 8]]
arr2 = np.array(data2)
print(arr2.ndim) # 输出维度
# 其他创建方式
np.zeros(10)
np.zeros((3, 6))
np.empty((2, 3, 4)) # 其中内容相当于未初始化的数组,而非0
np.arange(15) # output:array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
数据类型
arr1 = np.array([1, 2, 3], dtype=np.float64) # 指定为浮点型
# astype:类型转化,总是会返回一个新的数组
arr = np.array([1, 2, 3, 4, 5])
float_arr = arr.astype(np.float64) # 用astype转化类型
numeric_strings = np.array(['1.25', '-9.6', '42'], dtype=np.string_)
numeric_strings.astype(float) # string也能转
# 使用其他数组的dtype定制类型
int_array = np.arange(10)
calibers = np.array([.22, .270, .357, .380, .44, .50], dtype=np.float64)
print(int_array.astype(calibers.dtype))
计算
不需要for,任何两个大小相等的数组,运算都是点对点
element-wise 点对点,就是指两个数组的运算,在同一位置的元素间才会进行运算。
这种算数操作如果涉及标量(scalar)的话,会涉及到数组的每一个元素:
arr = np.array([[1., 2., 3.], [4., 5., 6.]])
arr * arr # array([[ 1., 4., 9.], [ 16., 25., 36.]])
arr - arr # array([[ 0., 0., 0.], [ 0., 0., 0.]])
1 / arr # array([[ 1. , 0.5 , 0.33333333], [ 0.25 , 0.2 , 0.16666667]])
arr2 = np.array([[0., 4., 1.], [7., 2., 12.]])
arr2 > arr # array([[False, True, False], [ True, False, True]], dtype=bool)
基本索引和切片
array的切片后的结果只是一个views(视图),用来代表原有array对应的元素,而不是创建了一个新的array。但list里的切片是产生了一个新的list
# 和列表的区别:broadcasted(广式转变)
arr = np.arange(10)
arr1[5:8] = 12 # 如果是列表,会报错:TypeError: can only assign an iterable
# 数组切片的结果类似于指针
arr_slice = arr[5:8]
arr_slice[:] = 64 # 赋值给arr[5:8]的所有元素 array([ 0, 1, 2, 3, 4, 64, 64, 64, 8, 9])
# 二维数组单一索引指一维数组
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr2d[2] # array([7, 8, 9])
# 访问单一元素
arr2d[0][2]
arr2d[0, 2]
# 多维数组: 返回一个低维度的多维数组
arr3d = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
arr3d[0] # np.array([[1, 2, 3], [4, 5, 6]])
# 用标量赋值
old_values = arr3d[0].copy()
arr3d[0] = 42 # array([[[42, 42, 42],[42, 42, 42]], [[ 7, 8, 9],[10, 11, 12]]])
# 用数组赋值
arr3d[0] = old_values # array([[[ 1, 2, 3],[ 4, 5, 6]], [[ 7, 8, 9],[10, 11, 12]]])
切片后返回的数组都是views
用切片索引
# 选中前两行
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
arr2d[:2] # array([[1, 2, 3],[4, 5, 6]])
# 区别
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
list2d = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# 由于数组更兼容的访问方式
arr2d[1,1] # 5,但list2d[1,1]会报错
# 因此数组可以通过下列方式切片,但列表不能
arr2d[:, 1:] # array([[2,3], [5,6], [8,9]])
bool索引
通过布尔值作为数组的索引
score = np.array([45, 68, 95, 35, 77, 44, 60])
reward = np.random.randn(7, 3)
reward[score > 60] # 输出reward的2,3,5,7行
reward[score > 60, 1] # 输出reward的2,3,5,7行2列的一维数组
布尔运算 | 符号 | 说明 |
---|---|---|
取反 | != 或~ |
|
且 | & |
and 无效 |
或 | ` | ` |
用布尔索引总是会返回一份新创建的数据,原本的数据不会被改变。
# 改变所有行或列
reward[score > 70] = 100 # 改变3,5行的所有值
reward[:, 条件] = 100
花式索引
会套两层
[[]]
,得到的是一个新的array
arr = np.empty((8, 4))
for i in range(8):
arr[i] = i
# 按一定顺序选出几行
arr[[4, 3, 0, 6]] # array([[ 4., 4., 4., 4.], [ 3., 3., 3., 3.], [ 0., 0., 0., 0.], [ 6., 6., 6., 6.]])
arr[[-3, -5, -7]] # array([[ 5., 5., 5., 5.],[ 3., 3., 3., 3.],[ 1., 1., 1., 1.]])
arr = np.arange(32).reshape((8, 4))
arr[[1, 5, 7, 2], [0, 3, 1, 2]] # array([ 4, 23, 29, 10])
可以看到[ 4, 23, 29, 10]
分别对应(1, 0), (5, 3), (7, 1), (2, 2)
。不论数组有多少维,fancy indexing的结果总是一维。
arr[[1, 5, 7, 2]][:, [0, 3, 1, 2]] # array([[ 4, 7, 5, 6], [20, 23, 21, 22], [28, 31, 29, 30], [ 8, 11, 9, 10]])
上面的意思是,先从arr中选出[1, 5, 7, 2]这四行:
array([[ 4, 5, 6, 7],
[20, 21, 22, 23],
[28, 29, 30, 31],
[ 8, 9, 10, 11]])
然后[:, [0, 3, 1, 2]]表示选中所有行,但是列的顺序要按0,3,1,2来排。于是得到:
array([[ 4, 7, 5, 6],
[20, 23, 21, 22],
[28, 31, 29, 30],
[ 8, 11, 9, 10]])
数组转置和轴交换
常用于矩阵乘法
转置也是返回一个view,而不是新建一个数组。有两种方式,一个是transpose方法,一个是T属性
# T属性
arr = np.arange(15).reshape((3, 5))
'''
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])'''
arr.T
'''output
array([[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]])'''
# transpose会接受由轴数字组成的tuple,来交换轴:
arr = np.arange(16).reshape((2, 2, 4))
'''
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])'''
arr.transpose((1, 0, 2))
'''output
array([[[ 0, 1, 2, 3],
[ 8, 9, 10, 11]],
[[ 4, 5, 6, 7],
[12, 13, 14, 15]]])'''
# swapaxes方法:取两个axis值,并交换这两个轴:
arr.swapaxes(1, 2) # 直交换second axis和last axis
'''
array([[[ 0, 4],
[ 1, 5],
[ 2, 6],
[ 3, 7]],
[[ 8, 12],
[ 9, 13],
[10, 14],
[11, 15]]])'''
通用函数
快速点对点函数
一元通用函数
需要一个数组
arr = np.arange(10)
np.sqrt(arr) # 开方
np.exp(arr) # e^x
函数名 | 描述 |
---|---|
np.abs(x) |
返回数组的绝对值 |
np.fabs(x) |
返回数组的绝对值(忽略复数) |
np.sqrt(x) |
返回数组的平方根 |
np.square(x) |
返回数组的平方 |
np.exp(x) |
返回数组的指数值 \(e^x\) |
np.log(x) |
返回数组的自然对数 |
np.log10(x) |
返回数组的以10为底的对数 |
np.log2(x) |
返回数组的以2为底的对数 |
np.sign(x) |
返回数组的符号值,1表示正数,-1表示负数,0表示零 |
np.ceil(x) |
返回数组的上限值,即大于等于每个元素的最小整数 |
np.floor(x) |
返回数组的下限值,即小于等于每个元素的最大整数 |
np.rint(x) |
返回数组的四舍五入值,保留到最近的整数 |
np.modf(x) |
将数组拆分为小数部分和整数部分 |
np.isnan(x) |
返回一个布尔数组,指示每个元素是否为 NaN |
np.isinf(x) |
返回一个布尔数组,指示每个元素是否为无穷大 |
np.cos(x) |
返回数组中每个元素的余弦值 |
np.sin(x) |
返回数组中每个元素的正弦值 |
np.tan(x) |
返回数组中每个元素的正切值 |
np.arccos(x) |
返回数组中每个元素的反余弦值 |
np.arcsin(x) |
返回数组中每个元素的反正弦值 |
np.arctan(x) |
返回数组中每个元素的反正切值 |
np.degrees(x) |
将数组中每个元素从弧度转换为角度 |
np.radians(x) |
将数组中每个元素从角度转换为弧度 |
np.exp2(x) |
返回数组的指数值 \(2^x\) |
np.expm1(x) |
返回数组的指数值 \(e^x-1\) |
np.log1p(x) |
返回数组的对数值 \(log_e(x+1)\) |
np.deg2rad(x) |
将数组中每个元素从角度转换为弧度 |
np.rad2deg(x) |
将数组中每个元素从弧度转换为角度 |
二元通用函数
需要两个数组
x = np.random.randn(8)
y = np.random.randn(8)
np.maximum(x, y) # 最大值
arr = np.array([3.14, 2.718, 1.414, 0.618])
# 使用 np.modf 将数组拆分为整数部分和小数部分
fractional, integral = np.modf(arr)
# 打印结果
print("原始数组:", arr)
print("小数部分:", fractional)
print("整数部分:", integral)
# ufunc能接受一个可选参数作为输出,这样可以直接更改原有的数组:
np.sqrt(arr) # 没有改变原有的arr
np.sqrt(arr, arr) # 改变了原有的arr
函数名 | 描述 |
---|---|
np.add(x1, x2) |
返回两个数组的逐元素和 |
np.subtract(x1, x2) |
返回两个数组的逐元素差 |
np.multiply(x1, x2) |
返回两个数组的逐元素乘积 |
np.divide(x1, x2) |
返回两个数组的逐元素除法 |
np.power(x1, x2) |
返回两个数组的逐元素幂运算结果 |
np.mod(x1, x2) |
返回两个数组的逐元素取模结果 |
np.remainder(x1, x2) |
返回两个数组的逐元素求余结果 |
np.fmax(x1, x2) |
返回两个数组的逐元素最大值 |
np.fmin(x1, x2) |
返回两个数组的逐元素最小值 |
np.maximum(x1, x2) |
返回两个数组的逐元素最大值,其中 NaN 被视为无限大 |
np.minimum(x1, x2) |
返回两个数组的逐元素最小值,其中 NaN 被视为无限小 |
np.copysign(x1, x2) |
返回 x1 的符号与 x2 相同的数组 |
np.greater(x1, x2) |
返回一个布尔数组,指示 x1 中的每个元素是否大于 x2 中的对应元素 |
np.greater_equal(x1, x2) |
返回一个布尔数组,指示 x1 中的每个元素是否大于等于 x2 中的对应元素 |
np.less(x1, x2) |
返回一个布尔数组,指示 x1 中的每个元素是否小于 x2 中的对应元素 |
np.less_equal(x1, x2) |
返回一个布尔数组,指示 x1 中的每个元素是否小于等于 x2 中的对应元素 |
np.equal(x1, x2) |
返回一个布尔数组,指示 x1 中的每个元素是否等于 x2 中的对应元素 |
np.not_equal(x1, x2) |
返回一个布尔数组,指示 x1 中的每个元素是否不等于 x2 中的对应元素 |
np.logical_and(x1, x2) |
返回一个布尔数组,指示 x1 和 x2 中的对应元素是否都为 True |
np.logical_or(x1, x2) |
返回一个布尔数组,指示 x1 和 x2 中的对应元素是否至少有一个为 True |
np.logical_xor(x1, x2) |
返回一个布尔数组,指示 x1 和 x2 中的对应元素是否恰好有一个为 True |
np.arctan2(x1, x2) |
返回两个数组中每个元素的反正切值 |
数组导向编程
网格
meshgrid函数用两个坐标轴上的点在平面上画网格。用法:
-
[X,Y]=meshgrid(x,y)
-
[X,Y]=meshgrid(x)
与[X,Y]=meshgrid(x,x)
是等同的 -
[X,Y,Z]=meshgrid(x,y,z)
生成三维数组,可用来计算三变量的函数和绘制三维立体图
[X,Y] = meshgrid(x,y)
将向量x和y定义的区域转换成矩阵X和Y,其中矩阵X的行向量是向量x的简单复制,而矩阵Y的列向量是向量y的简单复制(注:下面代码中X和Y均是数组,在文中统一称为矩阵了)。
假设x是长度为m的向量,y是长度为n的向量,则最终生成的矩阵X和Y的维度都是 nm
X, Y = np.meshgrid(x, y) # X = [x, x, .., x] Y = [y变为列向量拼接而成]
m, n = (5, 3)
x = np.linspace(0, 1, m) # 生成5个[0,1]之间的等间隔数字序列
y = np.linspace(0, 1, n)
X, Y = np.meshgrid(x, y)
X.shape, y.shape # (3, 5) (3, 5)
# 绘制网格
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot')
plt.plot(X, Y, marker='.', color='blue', linestyle='none')
# 用zip得到网格平面的坐标数据
z = [i for i in zip(X.flat, Y.flat)] # .flat:将多维数组展成一维,zip:将可迭代对象打包为元组
python中可迭代的对象:
- 列表(List)
- 元组(Tuple)
- 字符串(String)
- 集合(Set)
- 字典(Dictionary)
- 文件对象(File)
- range 对象(Range)
- 迭代器对象(Iterator)
- 生成器对象(Generator)
数组-逻辑条件
numpy.where
函数是一个向量版的三相表达式,
x if condition else y
# where 第二个参数和第三个参数不必是数组
xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])
result = np.where(cond, xarr, yarr) # array([ 1.1, 2.2, 1.3, 1.4, 2.5])
数学和统计方法
函数 | 描述 |
---|---|
numpy.sum |
计算数组或某个轴向上的元素总和 |
numpy.cumsum |
计算数组或某个轴向上的元素累积和 |
numpy.mean |
计算数组或某个轴向上的元素平均值 |
numpy.std |
计算数组或某个轴向上的元素标准差 |
numpy.var |
计算数组或某个轴向上的元素方差 |
numpy.min |
找出数组或某个轴向上的最小值 |
numpy.max |
找出数组或某个轴向上的最大值 |
numpy.argmin |
找出数组或某个轴向上的最小值的索引值 |
numpy.argmax |
找出数组或某个轴向上的最大值的索引值 |
numpy.median |
计算数组或某个轴向上的元素中位数 |
numpy.percentile |
计算数组或某个轴向上的元素在指定百分位数处的值 |
numpy.any |
判断数组或某个轴向上是否有任意一个元素为 True |
numpy.all |
判断数组或某个轴向上是否所有元素都为 True |
numpy.ptp |
计算数组或某个轴向上的元素峰值-峰值距离 |
轴向参数:axis=0 | 1
布尔数组
有两个其他方法,any和all,对于布尔数组特别有用。any检测数组中只要有一个ture返回就是true,而all检测数组中都是true才会返回true。
arr = np.random.randn(100)
(arr > 0).sum() # Number of positive values
排序
# sort 二维
arr.sort(0) # 排列向量,默认是0
arr.sort(1) # 排行向量
# np.sort 不改变原有数组
np.sort(a, axis=-1, kind=None, order=None)
单一性
# unqiue 排序&不重复
names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
np.unique(names) # array(['Bob', 'Joe', 'Will'], dtype='<U4')
# 一个数组中是否存在另一个数组的值
values = np.array([6, 0, 0, 3, 2, 5, 6])
np.in1d(values, [2, 3, 6]) # array([ True, False, False, True, True, False, True], dtype=bool)
运算
运算 | 用例 | \(a*b\) | np.multiple(a,b) |
np.matmul(a,b) |
np.dot(a,b) |
a@b |
---|---|---|---|---|---|---|
向量 | \(\begin{bmatrix} 0&1\end{bmatrix} \begin{bmatrix}1&2\end{bmatrix}\) | \(\begin{bmatrix}0&2\end{bmatrix}\) | \(\begin{bmatrix}0&2\end{bmatrix}\) | 2 | 2 | 2 |
不同维度的多维数组(np.array) | \(\begin{bmatrix}1&2\\3&4\\5&6\end{bmatrix} \begin{bmatrix}1\\2\end{bmatrix}\) | ValueError |
ValueError |
\(\begin{bmatrix}5\\11\\17\end{bmatrix}\) | \(\begin{bmatrix}5\\11\\17\end{bmatrix}\) | \(\begin{bmatrix}5\\11\\17\end{bmatrix}\) |
同维的多维数组(np.array) | $\begin{bmatrix}0&1\2&3\end{bmatrix} \begin{bmatrix}2&3\4&5\end{bmatrix} $ | \(\begin{bmatrix}0&3\\8&15\end{bmatrix}\) | \(\begin{bmatrix}0&3\\8&15\end{bmatrix}\) | \(\begin{bmatrix}4&5\\16&21\end{bmatrix}\) | \(\begin{bmatrix}4&5\\16&21\end{bmatrix}\) | \(\begin{bmatrix}4&5\\16&21\end{bmatrix}\) |
矩阵(np.array) | $\begin{bmatrix}0&1\2&3\end{bmatrix} \begin{bmatrix}2&3\4&5\end{bmatrix} $ | \(\begin{bmatrix}4&5\\16&21\end{bmatrix}\) | \(\begin{bmatrix}0&3\\8&15\end{bmatrix}\) | \(\begin{bmatrix}4&5\\16&21\end{bmatrix}\) | \(\begin{bmatrix}4&5\\16&21\end{bmatrix}\) | \(\begin{bmatrix}4&5\\16&21\end{bmatrix}\) |
推荐
- 对应项相乘用
np.multiple(a,b)
- 矩阵乘法用
np.dot(a,b)
或np.matmul(a,b)