NumPy基础
前言
初学,文中有错误之处请多多指教
一、NumPy ndarray多维数组对象
简介:NumPy核心特征之一就是N-维数组对象——ndarray。ndarray是python中一个快速、灵活的大数据集容器。
In [3]: import numpy as np
In [4]: data = np.random.randn(2,3) # 2行3列
In [5]: data
Out[5]:
array([[ 1.34079197, 0.46045205, -0.03534556],
[ 0.02915913, 1.25976312, -0.00408892]])
# 每个数据都有shape和dtype属性
In [6]: data.shape # 描述数组形状
Out[6]: (2, 3)
In [7]: data.dtype # 描述数组数据类型
Out[7]: dtype('float64')
In [21]: arr1.ndim # 返回几维
Out[21]: 2
1. 生成ndarray
-
np.array(任意的序列型对象)
arr1=np.array([[[1,2],[3,4]],[5,6],[7,8]]) -
np.zeros((2,3)) 给定长度及形状,生成全0数组,类型为float64
-
np.ones(10) 给定长度及形状,生成全1数组,类型为float64
-
np.empty((2,2,2)) 创建没有初始化值的数组,形状为(2,2,2),如下:
Out[28]:
array([[[0.00000000e+000, 0.00000000e+000],
[0.00000000e+000, 0.00000000e+000]],
[[0.00000000e+000, 9.56511090e-321], [1.16825884e-307, 8.90060779e-307]]])
下表展示标准数组的生成函数。默认数据类型为float64:
函数名 | 描述 |
---|---|
array | 将输入数据(元组、列表等序列类型对象)转换为ndarray对象,如不显示指明数据类型,将自动推断;默认复制所有的输入数据 |
asarray | 将输入转换为ndarray,如果输入已是ndarray则不在复制 |
arange | pyrhon内建函数range的数组版,返回一个ndarray数组对象 |
ones | 根据给定形状和数据类型生成全1数组 |
ones_like | 根据所给的数组生成一个形状一样的全1数组 |
zeros | 根据给定形状和数据类型生成全0数组 |
zeros_like | 根据所给的数组生成一个形状一样的全0数组 |
empty | 根据给定形状生成一个无初始化数值的空数组 |
empty_like | 根据所给的数组生成一个形状无初始化数值的空数组 |
full | 根据给定形状和数据类型生成指定数值的数组 |
full_like | 根据所给的数组生成一个形状一样但内容是指定数值的数组 |
eye,identity | 生成一个N x N 特征矩阵(对角线位置都是1,其余都是0) |
2. ndarray数据类型
- 生成ndarray数组时指定数据类型
arr1 = np.array([1,2,3], dtype=np.float64) # dtype也可使用类型代码 f8或d表示
- Numpy数据类型
类型 | 类型代码 | 描述 |
---|---|---|
int8,unit8 | i1,u1 | 有符号和无符号的8数位整数 |
int16,unit16 | i2,u2 | 有符号和无符号的16数位整数 |
int32,unit32 | i4,u4 | 有符号和无符号的32数位整数 |
int64,unit64 | i8,u8 | 有符号和无符号的64数位整数 |
float16 | f2 | 半精度浮点数 |
float32 | f4或f | 标准单精度浮点数 |
float64 | f8或d | 标准双精度浮点数 |
float128 | f16或g | 拓展精度浮点数 |
complex64,complex128,complex256 | c8,c16,c32 | 分别基于32,64,128位浮点数的复数 |
bool | ? | 布尔值,存储True或False |
object | o | Python object类型 |
string_ | S | 修正的ASCII字符串类型;例如生成一个长度为10的字符串类型,使用‘S10’ |
unicode_ | U | 修正的Unicode字符串类型;例如生成一个长度为10的Unicode类型,使用‘U10’ |
- 显示转换数组的数据类型 astype
arr2 = np.array([1.1,2.2,3.3], dtype=np.float64)
arr2.astype(np.int32)
In [43]: arr2.astype(np.int32) # 浮点数转换为整数,小数点后部分将会消除;这里的np.int32也可以使用其他数组的dtype属性
Out[43]: array([1, 2, 3])
注:使用astype时总是生成一个新的数组,即使传入的dtype与之前的相同
3. NumPy数组算术
-
标量,向量,矩阵与张量的定义
-
任何在两个等尺寸数组之间的算数操作都应用了逐元素操作的方式; 带有标量计算的算数操作,会把计算参数传递给数组的每一个元素; 同尺寸数组之间的比较,会产生一个布尔值数组; 不同尺寸数组间的操作,将会用到广播特性
4. 基础索引与切片
- 数组的切片是原数组的视图。意味着数组并不是被copy了,对于视图(切片)的修改都会反应在原数组上
In [7]: arr = np.arange(10)
In [8]: arr
Out[8]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [9]: arr[5:8]
Out[9]: array([5, 6, 7])
In [10]: arr[5:8]=12
In [11]: arr
Out[11]: array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
- 如果还是想要一份数组切片的拷贝而不是视图的话,必须显示复制这个数组,arr[5:8].copy()
- 对于高维度数组,省略后续索引值将返回降低一个维度的数组,高维数组获取切片2种方式 arr2[1][0],arr[1, 0] 这2种一样;数组子集选择种,返回的数组都是视图。
In [14]: arr2 = np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
In [15]: arr2
Out[15]:
array([[[ 1, 2, 3],
[ 4, 5, 6]],
[[ 7, 8, 9],
[10, 11, 12]]])
In [16]: arr2[1]
Out[16]:
array([[ 7, 8, 9],
[10, 11, 12]])
In [17]: arr2[1]=0
In [18]: arr2
Out[18]:
array([[[1, 2, 3],
[4, 5, 6]],
[[0, 0, 0],
[0, 0, 0]]])
-
数组的切片索引
一维数组切片于python的list类似 多维数组切片如下:
In [19]: arr2 = np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]]) In [20]: arr2 Out[20]: array([[[ 1, 2, 3], [ 4, 5, 6]], [[ 7, 8, 9], [10, 11, 12]]]) In [21]: arr2[:1, :1, 1:2] Out[21]: array([[[2]]])
注:多维数组切片,每一个表示一个维度,如上arr2[:1, :1, 1:2] 表示 arr2[行, 列, 高],多维数组的切片同样是原数组之上的视图。
5. 布尔索引(使用布尔数组进行数据索引)
- 数组的比较操作(比如==)也是可以向量化的,因此会产生一个布尔值数组,如下:
In [29]: names = np.array(['A','B','A','C','F','D','E','F'])
In [30]: names == 'A'
Out[30]: array([ True, False, True, False, False, False, False, False])
- 索引数组时可以传入布尔数组
In [31]: data = np.random.randn(8,4)
In [32]: data
Out[32]:
array([[ 0.33608636, 0.17550124, 1.19479257, -0.4358839 ],
[ 0.36730991, 0.67254338, -1.19878999, 1.45670343],
[ 0.71388598, -0.54661267, 0.64380686, 1.74134696],
[-0.88032197, -0.27226242, -0.19297905, 0.46968656],
[-0.20510321, -1.64660913, 0.64278628, 1.91326965],
[ 0.89976643, 0.79458378, -0.12327598, 0.1473952 ],
[ 0.13563593, -0.99592832, 1.07706521, 0.53599575],
[ 0.03876084, -0.46944013, -0.36635615, -0.13396386]])
In [34]: data[names == 'F'] # 选择names == 'F'数组True位置于data数组相对应的行
Out[34]:
array([[-0.20510321, -1.64660913, 0.64278628, 1.91326965],
[ 0.03876084, -0.46944013, -0.36635615, -0.13396386]])
In [36]: data[names == 'F', 2:] # 这里可以理解为对data的切片操作 names == 'F' 表示行,2: 表示列
Out[36]:
array([[ 0.64278628, 1.91326965],
[-0.36635615, -0.13396386]])
注:布尔值数组的长度必须和数组轴索引长度一致,当长度不正确时,不会报错。
-
布尔数组的其余运算符操作
可以使用 != 或在条件表达式之前使用 ~ 对条件进行取反,如:names != 'F' 或 cond = names=='F', data[~cond],等同于上面; 当要选择其中多个字母时可以对多个布尔条件进行联合,需使用数学操作如&和|(and和or无效),如: cond= (names='A')|(name='B'), data[cond]
6. 神奇索引(使用整数数组进行数据索引)
语言不好描述,直接上例子
In [45]: arr3 = np.empty((8,4)) # 根据给定形状生成无初始化的数组
In [46]: for i in range(8):
...: arr3[i]=i
...:
In [47]: arr3
Out[47]:
array([[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.],
[3., 3., 3., 3.],
[4., 4., 4., 4.],
[5., 5., 5., 5.],
[6., 6., 6., 6.],
[7., 7., 7., 7.]])
In [48]: arr3[[4,3,0,6]] # arr3[行]
Out[48]:
array([[4., 4., 4., 4.],
[3., 3., 3., 3.],
[0., 0., 0., 0.],
[6., 6., 6., 6.]])
In [50]: arr3[[4,3,0,6],[0,1,2,3]] # arr3[行,列]
Out[50]: array([4., 3., 0., 6.])
注:使用负索引同python一样,从后往前,如:arr3[[-1,-2,-3]]。
7. 数组转置和换轴
转置:是一种特殊的数据重组形式,可以返回底层数据的视图而不需要复制任何内容。数组拥有transpose方法和特殊的T属性
- 转置 arr.T(换轴的特殊案例)
In [80]: arr = np.arange(15).reshape((3,5)) # 生成(3,5)的二位数组
In [81]: arr
Out[81]:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
In [82]: arr.T # 对生成的数组arr进行转置(换轴的特殊案例)
Out[82]:
array([[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]])
# arr.T:二维数组arr有x轴(表示为0)和y轴(表示为1)现为(0,1),arr.T将y轴与x轴进行换轴后为(1,0)。高维度数组默认(0,1,2,3,4,...)进行转置后为(...,4,3,2,1,0)
- 计算矩阵内积 np.dot(arr.T, arr)
In [98]: arr = np.arange(1,7).reshape((2,3))
In [99]: arr
Out[99]:
array([[1, 2, 3],
[4, 5, 6]])
In [100]: arr.T
Out[100]:
array([[1, 4],
[2, 5],
[3, 6]])
In [101]: np.dot(arr.T, arr)
Out[101]:
array([[17, 22, 27],
[22, 29, 36],
[27, 36, 45]])
# 这里用到了矩阵乘法(点乘积),dot里的arr决定了结果数组的y轴长度,arr.T决定了结果数组的x轴长度。过程如下:
[[1*1+4*4,1*2+4*5,1*3+4*6],
[2*1+5*4,2*2+5*5,2*3+5*6].
[3*1+6*4,3*2+6*5,3*3+6*6]]
- 换轴 arr.transpose((0,1,2))
In [107]: arr = np.arange(16).reshape((2,2,4))
In [108]: arr
Out[108]:
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
In [112]: arr.transpose((1,0,2))
Out[112]:
array([[[ 0, 1, 2, 3],
[ 8, 9, 10, 11]],
[[ 4, 5, 6, 7],
[12, 13, 14, 15]]])
# 原本数组arr轴x,y,z对应(0,1,2),进行换轴为(1,0,2)x和y轴进行的调换,z轴不变。这里降维操作更好理解。如果transpose不传参数,相当于转置arr.T。
# arr.swapaxes((1,2))方法接收一对轴编号作为参数(只能是2,否则报错),并对轴进行调整用于重组数据。并不会对原arr进行改变。arr.swapaxes((1,2))相当于arr.transpose((0,2,1)),对1和2进行了交换
二、通用函数:快速的逐元素数组函数
通用函数:对简单函数的向量化封装。
1. 一元通用函数
函数名 | 描述 |
---|---|
abs、fabs | 逐元素的计算整数、浮点数、或复数的绝对值 |
sqrt | 计算每个元素的平方根 |
square | 计算每个元素的平方 |
exp | 计算每个元素的自然指数值e^x |
log、log10、log2、log1p | 分别对应自然对数(e为底)、对数10为底、对数2为底、log(1+x) |
sign | 计算每个元素的符号值1(正数)、0(0)、-1(负数) |
ceil | 计算每个元素的最高整数值(即大于等于给定元素的最小整数) |
floor | 计算每个元素的最小整数值(即小于等于给定元素的最大整数) |
rint | 将元素保留到整数位,并保持dtype(四舍五入) |
modf | 分别将数组的小数部分和整数部分按数组形式返回 |
isnan | 返回数组中的元素是否是一个NaN,形式为布尔值数组 |
isfinite、isinf | 返回数组中的元素是否有限(非inf、非NaN)、是否无限的,形式为布尔值数组 |
cos、cosh、sin | 常规的双曲三角函数 |
sinh、tan、tanh、arccos、arccosh、arcsin、arcsinh、arctan、arctanh、logical_not | 对数组的元素按位取反(与~arr效果一致) |
2. 二元通用函数
函数名 | 描述 |
---|---|
add | 将数组的对应元素相加 |
subtract | 在第二个数组中,将第一个数组中包含的元素去除? |
multiply | 将数组的对应元素相乘 |
divide、floor_divide | 除或整除(放弃余数) |
power | 将第二个数组的元素作为第一个数组对应元素的幂次方 |
maximum、fmax | 逐元素计算最大值,fmax忽略NaN |
minimum、fmin | 逐元素计算最小值,fmin忽略NaN |
mod | 元素的求模计算(即求除法的余数) |
copysign | 将第一个数组的符号值改为第二个数组的符号值 |
greater、greater_equal、less、less_equal、equal、not_equal | 进行逐个元素的比较,返回布尔值数组(与数学操作符>、>=、<、<=、==、!=效果一致) |
logical_and、logical_or、logical_xor | 进行逐个元素的逻辑操作(与逻辑运算符&、 |
三、使用数组进行面向数组编程
利用数组表达式来替代显示循环的方法,称为向量化
# 对一些网格数据计算函数sqrt(x^2+y^2)的值
points = np.arange(-5,5,0.01) # 生成1000个值的一维数组
xs,ys = np.meshgrid(points,points) # 根据2个数组的所有(x,y)对生成一个二位矩阵,xs.T等于ys
z = np.sqrt(xs**2 + ys**2 ) # 用和两个坐标值一样的表达式使用函数
# 生成可视化
import matplotlib.pyplot as plt
plt.imshow(z,cmap=plt.cm.gray)
plt.colorbar()
plt.title("$\sqrt{x^2+y^2}$")
plt.show() # 如下图
1. 将条件逻辑作为数组操作
numpy.where函数是三元表达式 x if condtion else y 的向量化版本,速度快,适用于多维
In [44]: xarr = np.arange(0,10,2)
In [45]: xarr
Out[45]: array([0, 2, 4, 6, 8])
In [46]: yarr = np.arange(1,10,2)
In [47]: yarr
Out[47]: array([1, 3, 5, 7, 9])
In [62]: cond
Out[62]: array([False, True, True, True, False])
# 如果cond为true取xarr对应元素值,否则取yarr中对应元素值
In [63]: result = np.where(cond,xarr,yarr)
In [64]: result
Out[64]: array([1, 2, 4, 6, 9])
注意:np.where的第一个参数为布尔数组,第二个和第三个参数并不一定是数组,也可以是标量,典型用法是利用一个数组,生成一个新的数组,如下:
# 随机生成一个4x4的二维数组
arr = np.random.randn(4,4)
# arr数组中正值替换为1,反之替换为-1
np.where(arr>0, 1, -1)
# 也可以使用标量和数组结合,这里仅将正值设置为1
np.where(arr>0, 1, arr)
2. 数学和统计方法
基础数组统计方法
方法 | 描述 |
---|---|
sum | 沿着轴向计算所有元素的累和,0长度的数组,累和为0 |
mean | 数学平均,0长度的数组平均值为NaN |
std,var | 标准差和方差可以选择自由度调整(默认分母是n) |
min、max | 最小值和最大值 |
argmin、argmax | 最小值和最大值的位置 |
cumsum | 从0开始元素累积和(不会聚合会产生一个中间结果,返回相同长度的数组) |
cumprod | 从1开始元素累积积(不会聚合会产生一个中间结果,返回相同长度的数组) |
# mean、sum等函数可以接受一个可选参数axis,这个参数可以用于计算给定轴向上的统计值,杏城下降一维度的数组
arr.mean(axis=1) # 计算每一列的平均值
3. 布尔值数组的方法
sum通常可以用于计算布尔值数组中True的个数
any检查数组中是否至少有一个True
all检查是否每个值都是True
4. 排序
和python的内建列表类型相似,Numpy数据可以使用sort方法按位置排序
可在多维数组中传递一个axis值,沿着轴向每个一维数据段进行排序
顶层的np.sort方法返回的是已经排号序的数组拷贝,而不是对原数组按位置排序。
5. 唯一值与其他集合逻辑
Numpy包含针对一维数组ndarray的基础集合操作,常用方法:
np.unique,返回的是数组中唯一值排序后形成的数组(python实现为集合+排序)
np.in1d,检查一个数组中的值是否在另外一个数组中,并返回一个布尔数组
In [97]: values = np.arange(6)
In [98]: values
Out[98]: array([0, 1, 2, 3, 4, 5])
# 检查values数组中的值在[1,3,5,7]中是否存在
In [99]: np.in1d(values,[1,3,5,7])
Out[99]: array([False, True, False, True, False, True])
数组的集合操作
方法 | 描述 |
---|---|
unique(x) | 计算x的唯一值,并排序 |
intersect1d(x,y) | 计算x和y的交集,并排序 |
union1d(x,y) | 计算x和y的并集,并排序 |
in1d(x,y) | 计算x的元素是否包含在y中,返回一个布尔值数组 |
setdiff1d(x,y) | 差集,在x中,不在y中的x元素 |
setxor1d(x,y) | 异或集,在x或y中,但不属于x、y交集的元素 |
四、使用数组进行文件输入和输出
Numpy可在硬盘中将数据以文本或二进制文件的形式进行存入硬盘或由硬盘载入。(大部分人更倾向于pandas或其他工具进行载入)
# 保存单个数组
arr = np.arange(10)
In [102]: arr
Out[102]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 生成some_array.npy文件,存储arr
In [103]: np.save(r"C:\Users\jkn\Desktop\some_array",arr)
# 从some_array.npy文件中读取arr
In [106]: np.load(r"C:\Users\jkn\Desktop\some_array.npy")
Out[106]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# 用于在未压缩文件中保存多个数组
In [107]: arr1 = np.arange(0,10,2)
In [108]: arr2 = np.arange(1,10,2)
In [109]: arr1
Out[109]: array([0, 2, 4, 6, 8])
In [110]: arr2
Out[110]: array([1, 3, 5, 7, 9])
# 生成并保存在two_array.npz的文件中
In [115]: np.savez(r"C:\Users\jkn\Desktop\two_array",arr1=arr1, arr2=arr2)
# 读取two_array.npz文件中数组(字典格式)
In [116]: arch = np.load(r"C:\Users\jkn\Desktop\two_array.npz")
In [117]: arch['arr1']
Out[117]: array([0, 2, 4, 6, 8])
In [118]: arch['arr2']
Out[118]: array([1, 3, 5, 7, 9])
# 用于在已压缩文件中保存多个数组,读取方式同savez一样
np.savez_compressed(r"C:\Users\jkn\Desktop\array.npz",arr3=arr3)
五、线性代数
线性代数,比如矩阵乘法、分解、行列式等方阵数学是所有数组类库的重要组成部分。Numpy中*是矩阵的逐元素乘积,而不是矩阵的点乘积
# 矩阵乘法(点乘积)
In [148]: x
Out[148]:
array([[1, 2, 3],
[4, 5, 6]])
In [149]: y=x.T
In [150]: y
Out[150]:
array([[1, 4],
[2, 5],
[3, 6]])
In [151]: x.dot(y) # 等价于np.dot(x,y)或x@y
Out[151]:
array([[14, 32],
[32, 77]])
# 二维数组和一个长度合适的一维数组之间的矩阵乘积,结果是一个一维数组
numpy.linalg拥有一个矩阵分解的标准函数集,以及其他常用函数。如求逆和行列式求解。
# 不太懂
In [153]: from numpy.linalg import inv,qr
In [154]: x = np.random.randn(5,5)
In [156]: mat=x.T.dot(x)
In [158]: mat.dot(inv(mat))
In [159]: q,r = qr(mat)
In [160]: r
Out[160]:
array([[-2.83921542, 0.90127278, 4.02571766, -0.65581964, -3.22722098],
[ 0. , -3.09398091, -4.73038664, 3.31873677, 2.08137644],
[ 0. , 0. , -0.96081295, -2.01481613, 2.83169485],
[ 0. , 0. , 0. , -2.13954722, 0.88843327],
[ 0. , 0. , 0. , 0. , 0.05822623]])
常用numpy.linalg函数
函数 | 描述 |
---|---|
diag | 将一个方阵的对角(或非对角)元素作为一维数组返回,或者将一维数组转换成一个方阵,并且在非对角线上有零点 |
dot | 矩阵点乘 |
trace | 计算对角元素和 |
det | 计算矩阵的行列式 |
eig | 计算方阵的特征值和特征向量 |
inv | 计算方阵的逆矩阵 |
pinv | 计算矩阵的Moore-Penrose伪逆 |
qr | 计算QR分解 |
svd | 计算奇异值分解(SVD) |
slove | 求解x的线性系统Ax = b ,其中A是方阵 |
lstsq | 计算Ax = b 的最小二乘解 |
六、伪随机数生成
python内建random模块一次只能生成一个值,
numpy.random模块可以高效的生成多种概率分布下的完整样本值数组。
# 我们可以称这些为伪随机数(具有确定性行为的算法根据随机数生成器中的随机数种子生成的)
In [165]: np.random.normal(size=(10000000,100))
# 通过np.random.seed(1234)更改随机数种子
In [166]: np.random.seed(1234)
# numpy.random中的数据生成函数公用了一个全局的随机数种子。为避免全局状态,可以使用numpy.random.RandomState生成一个随机数生成器,使数据独立于其他的随机数状态
In [167]: rng = np.random.RandomState(1234)
In [168]: rng.randn(10)
Out[168]:
array([ 0.47143516, -1.19097569, 1.43270697, -0.3126519 , -0.72058873,
0.88716294, 0.85958841, -0.6365235 , 0.01569637, -2.24268495])
numpy.random中的部分函数列表
函数 | 描述 |
---|---|
seed | 向随机数生成器传递随机状态种子 |
permutation | 返回一个序列的随机排列,或者返回一个乱序的整数范围序列 |
shuffle | 随机排列一个序列 |
rand | 从均匀分布中抽取样本 |
randint | 根据给定的由低到高的范围抽取随机整数 |
randn | 从均值0方差1的正态分布中抽取样本(MATLAB型接口) |
binomial | 从二项分布中抽取样本 |
normal | 从正态(高斯)分布中抽取样本 |
beta | 从beta分布中抽取样本 |
chisquare | 从卡方分布中抽取样本 |
gamma | 从伽马分布中抽取样本 |
uniform | 从均匀[0,1)分布中抽取样本 |
七、示例:随机漫步
python实现随机漫步
In [172]: import random
In [173]: position = 0
In [174]: walk = [position]
In [175]: steps = 1000
In [176]: for i in range(steps):
...: step = 1 if random.randint(0,1) else -1
...: position += step
...: walk.append(position)
# 生成可视化 如下图
In [180]: import matplotlib.pyplot as plt
In [181]: plt.plot(walk)
Out[181]: [<matplotlib.lines.Line2D at 0x17f3e22df08>]
In [182]: plt.show()
NumPy实现
In [183]: nsteps = 1000
In [184]: draws = np.random.randint(0,2,size=nsteps)
In [185]: steps = np.where(draws>0, 1,-1)
In [186]: walk = steps.cumsum()
In [189]: walk.min()
Out[189]: -9
In [190]: walk.max()
Out[190]: 60
# 如果想要知道漫步中是何时连续朝某个方向连续走了10步。np.abs(walk)>=10给我们一个布尔数组,用于表示漫步是否连续在同一方向走了10步。
# 我们想要第一次走了10步或-10步的位置,可以使用argmax()来计算,用于返回布尔值数组中最大值的第一个位置(True就是最大值,argmax()方法效率不高总是完整的扫描整个数组
In [192]: (np.abs(walk)>=10).argmax()
Out[192]: 297
1. 一次性模拟多次随机漫步
# 用二维数组来模拟多次随机漫步
In [1]: import numpy as np
In [2]: nwalks = 5000
In [3]: nsteps = 1000
In [6]: draws = np.random.randint(0,2,size=(nwalks,nsteps))
In [7]: steps = np.where(draws>0,1,-1)
In [8]: walks = steps.cumsum(1)
In [9]: walks
Out[9]:
array([[ 1, 2, 1, ..., -58, -57, -58],
[ 1, 2, 3, ..., -26, -25, -24],
[ -1, -2, -3, ..., -38, -39, -38],
...,
[ 1, 2, 1, ..., 0, -1, -2],
[ 1, 2, 1, ..., -26, -25, -24],
[ -1, -2, -3, ..., -40, -41, -42]], dtype=int32)
In [10]: walks.shape
Out[10]: (5000, 1000)
# 在随机步中计算出30或-30的最小穿越时间(并不一定是5000个都到了30),可以用any方法查看
# 所有的列中有值大于等于30为True,否则为false,返回x长度的一维布尔数组
In [11]: hits30 = (np.abs(walks)>=30).any(1)
In [12]: hits30.shape
Out[12]: (5000,)
In [13]: hits30
Out[13]: array([ True, True, True, ..., False, True, True])
# 布尔数组和即为达到30的总列数量
In [14]: hits30.sum()
Out[14]: 3452
# 计算超过30每一列的位置
In [15]: crossing_times = (np.abs(walks[hits30])>=30).argmax(1)
In [16]: crossing_times
Out[16]: array([165, 323, 783, ..., 375, 273, 483], dtype=int64)
In [17]: crossing_times.shape
Out[17]: (3452,)
# 对位置求平均
In [19]: crossing_times.mean()
Out[19]: 500.6917728852839