文章目录
数组与向量化计算。优点:数组类型;快速的向量化计算(由于由C语言实现)
导入:
import numpy as np # 标准的NumPy导入方式
比较NumPy的数组与list的效率,因为NumPy用C语言实现。并且矩阵运算不需要循环。
# 100万个数循环10次*2,计时
arr = np.arange(1000000)
ls = list(range(1000000))
%time for _ in range(10):arr2 = arr*2 # Wall time: 22.9 ms
%time for _ in range(10):ls2 = [x*2 for x in ls] # Wall time: 750 ms
数据结构-ndarray:多维数组对象
数组内数据同类型,默认float型
属性:
.shape: 各维度大小
.dtype: 数据类型
.ndim: 几维
data = np.random.randn(2,3) # 生成2*3的二维随机数组
data
# array([[-0.00513612, -0.13435869, 0.41686502],
# [-0.09536552, -0.65670825, 1.03684946]])
?np.random.randn(d0, d1, ..., dn) # 返回服从标准正态分布的样本
# 参数是各维度大小,参数为空时返回一个符合的实数
- 生成一维数组:从任意序列使用np.array(seq) 转换为一维数组
l = [1,2,3]
arr = np.array(l) # 列表转换为数组
arr.ndim # 1
arr.dtype # int32
或使用arange():range()的数组版,将range结果变成数组
np.arange(5) # array([0, 1, 2, 3, 4])
np.arange(2,8,2) # 从2到7,步长是2,array([2, 4, 6])
- 生成多维数组,从嵌套序列转换,几重嵌套就是几维
l = [[1,2,3],[4,5,6]]
arr = np.array(l)
arr.shape # (2, 3)
np.array(seq): 默认复制所有的数据
np.asarray(seq): 也是将序列转换为数组,但如果输入已经是ndarray,则不再复制
3. 生成特殊数组
np.zeros(5) # 生成全0数组,1*5,默认float型,array([0., 0., 0., 0., 0.])
np.ones((2,3)) # 生成全1数组,2*3,参数用元组给出
np.empty((2,3,2)) # 生成未初始化值的数组,不一定是0,可能是内存原来的垃圾值
np.identity(3) # 生成3*3的对角矩阵,对角线全是1,等价于
np.eye(3)
其余生成函数 | 描述(_like:就是与给定数组形状一样) |
---|---|
ones_like | 根据所给数组生成形状一样的全1数组 |
zeros_like | 同上,全0 |
empty_like | 同上,全未初始化 |
full | 根据给定形状和数据类型生成指定数值的数组 |
full_like | 根据给定数组生成形状一样但是内容是指定数值的数组 |
数据类型dtype
全名:np.类型名+元素位数:np.int8/16/32/64,np.float16/32/64/128,np.complex64/128/256,np.bool,np.string_,np.unicode
简名:int,float,complex,bool(非0都是True),str
用场:
- 转换为数组时或生成数组时同时指定类型,通过参数dtype=
np.array(seq,dtype=)
np.empty(n,dtype=) - 显式改变类型:reresult = .astype(类型名) 总是返回一个新数组
前提:类型之间要能转换,浮点数转为整数则丢失小数部分
arr2 = arr.astype(float) 等价于 arr2 = arr.astype(np.float64)
数组算术-向量化
等尺寸数组之间的算术操作是逐元素操作。
*:逐元素相乘
/:逐元素相除
**n:逐元素计算n次幂
<等大小比较:逐元素比较大小,返回同等大小的True/False数组
不同尺寸的数组间操作,将用到广播特性。
索引与切片
1.一维数组直接索引与切片,同列表一样。
注意,对切片赋值时,是赋给切片内所有的数据。
arr = np.arange(5)
arr[2:5] = 10
arr # [ 0, 1, 10, 10, 10]
注意2:数组的切片类似于原数组的引用(指针),任何对切片的操作都将反映到原数组上。原因是NumPy设计为处理非常大的数组,不能动不动就复制数组。如果一定要复制数组切片,则必须显式的复制,如arr[5:8].copy()
arr = np.arange(5)
slice = arr[2:5]
print(slice) # [2 3 4]
slice[:] = 10 # 引用数组的所有值
print(slice) # [10 10 10]
print(arr) # [ 0, 1, 10, 10, 10]
2.高维数组的一个索引是低一维的数组
索引单个元素:可以每个中括号一个索引也可以通过索引值的列表
比如二维数组 arr[0][2] 等价于 arr[0,2],轴0是行,轴1是列。
数组子集选择中,返回的数组都是引用。
3. 数组切片
一维直接切
高维中,只有一组切片时是沿轴0切片,比如二维数组arr[:2]:选择前两行
多组切片也是逗号列表,比如arr[:2,1:]表示前两行第2列到最后一列。
多组切片维度不变,但索引与切片混合时,得到维度减少的结果。
arr = np.eye(3)
arr[1:2,:2] # array([[0., 1.]]),.ndim=2 ,两组切片
arr[1,:2] # array([0., 1.]),.ndim=1 ,索引与切片混合
对切片表达式赋值时,整个切片所有数据都被赋值
arr = np.eye(3)
arr[:,1:] = (6,3) # 所有行, # arr[:,1:] = 6,则后两列全为6
print(arr)
- 布尔索引:使用逻辑表达式作为索引
比如data[(data<0) & (data>-3)] = 0
与或非必须使用逻辑运算符&,|,!(~条件),不能使用and,or - 神奇索引:使用整数数组进行索引,见《数据分析》P103
数组转置与换轴
.T属性返回转置后的数组
.reshape(各维度大小的元组,order=‘C’):改变数组形状,默认按行排列,‘F’按列排列
arr = np.arange(6).reshape((2,3)) # 变成2*3
print(arr)
print(arr.T) # .T属性转置
计算矩阵内积,即矩阵乘法
arr = np.random.randn(3,2)
print(arr)
np.dot(arr.T,arr) # 3*2 2*3 = 2*2
转置是换轴的一个特例,轴0(行)与轴1(列)互换,因为二维数组换轴就是转置。换轴只针对高维数组而言,
法一:a.swapaxes(axis1, axis2) : Return a view of the array with axis1
and axis2
interchanged.返回的是数据的视图,没有复制数据
法二:a.transpose(新的所有轴编号的元组)
# 换轴,对于3维数组,轴0是最外层,轴1是行,轴2是列
arr = np.arange(6).reshape((1,3,2),order='C')
print(arr)
print(arr.swapaxes(1,2)) # 轴1与轴2互换,等价于下面
print(arr.transpose((0,2,1)))
通用函数ufunc
逐元素数组函数
arr = np.arange(5)
print(np.sqrt(arr)) # 根号
print(np.exp(arr)) # 指数
x = np.random.randn(3)
y = np.random.randn(3)
print('x:',x,'\ny:',y)
print('max:',np.maximum(x,y)) # 计算每个位置的元素最大值
decimals,integer = np.modf(x) # 返回每个元素的小数部分和整数部分,各为一个数组
print('小数:',decimals,'整数:',integer)
示例:根据网格数据计算
x
2
+
y
2
\sqrt{x^2+y^2}
x2+y2
points = np.arange(-5,5,0.01) # 1000个相同步长的点
xs, ys = np.meshgrid(points,points) # 接受两个一维数组,根据两个数组的所有(x,y)对生成一个二维矩阵
print('xs:',xs)
z = np.sqrt(xs ** 2 + ys ** 2)
print('z:',z)
# 二维数组可视化
import matplotlib.pyplot as plt
plt.imshow(z,cmap='summer');plt.colorbar() # 在图旁边把colorbar显示出来
plt.title("Image plot of $\sqrt{x^2 + y^2}$ for a grid of values") # 添加标题,公式用LaTeX表示
注:matplotlib.pyplot.imshow(X, cmap=None)
X: 要绘制的图像或数组。
cmap: 颜色图谱(colormap), 默认绘制为RGB(A)颜色空间。例如;matplotlib.pyplot.imshow(img, cmap=‘jet’)
颜色图谱的取值:
数组中的条件判断np.where
典型用场:根据一个数组,根据条件改变里面的值,变成另一个数组
np.where(condition, x, y): Return elements chosen from x
or y
depending on condition
.
返回值 : An array with elements from x
where condition
is True, and elements from y
elsewhere.
# 将矩阵中的正值替换为2,负值不替换
arr = np.random.randn(4,4)
np.where(arr > 0,2,arr) # 应该是逐元素判断条件并应用
统计函数
axis问题:二维数据拥有两个轴:轴0看做行,轴1看做列。
但轴向不等于轴,0轴向:沿着行的方向即垂直往下,1轴向:沿着列的方向即水平延伸。
统计函数里的参数axis表示沿轴向计算(along)
arr = np.random.randn(2,3)
print(arr)
print(arr.mean(axis=1)) # 跨列计算,即行均值
print(arr.sum(axis=0)) # 跨行计算,即列和
常用数组统计方法:
True/False数组
计数:.sum():计算True的个数
arr = np.random.randn(100)
(arr > 0).sum() # 56
.any(): 是否至少有一个True
.all(): 是否全为True
非布尔值数组也适用,非0均为True。
排序
.sort([axis]): 直接改变原数组,默认升序,可选参数axis表示按轴向
例如二维数组中 arr.sort(axis=1) :按列的方向,即对每一行排序。
np.sort(arr): 返回排好序的数组拷贝
集合操作:针对一维数组1d
np.unique(arr): 求arr中的唯一值(不重复的值),并排序,等价于sorted(set(arr))
arr = np.array(['a','b','b'])
print(np.unique(arr)) # ['a' 'b']
sorted(set(arr)) # ['a', 'b']
np.in1d(arr1,arr2): arr1中的值是否包含在arr2中,类似于R的%in%,返回同等大小的True/False数组。
其他集合操作 | 描述 |
---|---|
intersect1d(x,y) | 求交集,并排序 |
union1d(x,y) | 求并集,并排序 |
setdiff1d(x,y) | 求差集,在x中但不在y中的x元素 |
setxor1d(x,y) | 求异或集,在x或y中,但不属于交集的元素 |
数据在硬盘上的存取
np.save(路径,arr): 将数组保存到硬盘,默认未压缩,后缀.npy
np.load(路径) :将数组载入
详情见P116
线性代数
NumPy中矩阵*矩阵是逐元素相乘,因此dot()方法用于矩阵乘法。
x.dot(y)
⇔
\Leftrightarrow
⇔ np.dot(x,y)
⇔
\Leftrightarrow
⇔ x @ y:
如果是两个向量,则返回其内积(一个数);如果是两个矩阵,则返回矩阵的乘积。
x = np.array([[1,2,3],[4,5,6]])
y = np.array([[6,23],[-1,7],[8,9]])
x @ y
numpy.linalg拥有一个矩阵分解的标准函数集及矩阵常用函数
使用:np.linalg.inv(arr)
from numpy.linalg import inv,qr
伪随机数生成numpy.random模块
比Python内建的random模块快了一个数量级
伪随机数:根据算法由随机数生成器中的随机数种子生成的。
更改NumPy中的随机数种子:np.random.seed(1234):使得随机数据可预测。
注:上下限的区间均是不包含右端点
示例:随机漫步
随机漫步,从0开始,步进只能为1或-1,二者发生概率相等,计算累积值。
nsteps = 1000 # 1000步
drows = np.random.randint(0,2,size=nsteps) # 一次性生成1000个0,1
steps = np.where(drows == 0,-1,1) # 把0全改为-1
walk = steps.cumsum() # 计算步进的累积值
print(walk.min(),walk.max()) # -25 15
plt.plot(walk[:100]) # 画出前100步
何时第一次朝某个方向连续走了10步?
(np.abs(walk)>=10).argmax()-10 # 47
# 先得到走了超过10步的布尔数组,再计算第一个True的位置,
# 得到第一次走了10步的位置,-10得到何时开始走这10步
# argmax():返回最大值的第一个位置,在这里True就是最大值,效率不高,因为它首先要完整扫描整个数组