Python数据分析04:Numpy——数组运算、排序、输入输出、矩阵运算、随机数生成

CHAPTER 4

NumPy Basics: Arrays and Vectorized Computation


文章目录

  • CHAPTER 4
  • NumPy Basics: Arrays and Vectorized Computation
    • 4.3 数组导向编程(Array-Oriented Programming with Arrays)
      • 4.3.1 将条件逻辑表述为数组运算(Expressing Conditional Logic as Array Operations)
      • 4.3.2 数学和统计方法(Mathematical and Statistical Methods)
      • 4.3.3 用于布尔型数组的方法(Methods for Boolean Arrays)
      • 4.3.4 排序(Sorting)
      • 4.3.5 单一性和其他集合逻辑(Unique and Other Set Logic)
    • 4.4 用于数组的文件输入输出(File Input and Output with Arrays)
    • 4.5 线性代数(Linear Algebra)
    • 4.6 生成伪随机数(Pseudorandom Number Generation)
    • 4.7 栗子:随机漫步(Example: Random Walks)
      • 4.7.1 ⼀次模拟多个随机漫步(Simulating Many Random Walks at Once)

4.3 数组导向编程(Array-Oriented Programming with Arrays)

向量化的数组运算比纯python同等程度的运算要快很多。

一个简单的例子,假设我们想要评价函数sqrt(x^2 + y^2)np.meshgrid函数取两个1维的数组,产生一个2维的矩阵,对应于所有两个数组中(x, y)的组合:

import numpy as np

先看个栗子,说明meshgrid的效果。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] = meshgrid(x,y) 将向量(x,y)定义的区域转换成矩阵X和Y,其中矩阵X的行向量是向量x的简单复制,而矩阵Y的列向量是向量y的简单复制(注:下面代码中X和Y均是数组,在文中统一称为矩阵了)。

假设x是长度为m的向量,y是长度为n的向量,则最终生成的矩阵X和Y的维度都是 nm (注意不是mn)。

>>>m, n = (5, 3)
>>>x = np.linspace(0, 1, m)
>>>y = np.linspace(0, 1, n)
>>>X, Y = np.meshgrid(x, y)
>>>x
array([0.  , 0.25, 0.5 , 0.75, 1.  ])
>>>y
array([0. , 0.5, 1. ])
>>>X
array([[0.  , 0.25, 0.5 , 0.75, 1.  ],
       [0.  , 0.25, 0.5 , 0.75, 1.  ],
       [0.  , 0.25, 0.5 , 0.75, 1.  ]])
>>>Y
array([[0. , 0. , 0. , 0. , 0. ],
       [0.5, 0.5, 0.5, 0.5, 0.5],
       [1. , 1. , 1. , 1. , 1. ]])

可以看到X和Y的shape都是3x5,用图的话更好理解:

Python数据分析04:Numpy——数组运算、排序、输入输出、矩阵运算、随机数生成_第1张图片

把X和Y画出来后,就可以看到网格了:

>>>import matplotlib.pyplot as plt
>>>%matplotlib inline
>>>plt.style.use('ggplot')

>>>plt.plot(X, Y, marker='.', color='blue', linestyle='none')
[<matplotlib.lines.Line2D at 0x1d2a83192c8>,
 <matplotlib.lines.Line2D at 0x1d2a8328648>,
 <matplotlib.lines.Line2D at 0x1d2a8328048>,
 <matplotlib.lines.Line2D at 0x1d2a8328808>,
 <matplotlib.lines.Line2D at 0x1d2a8328a08>]

Python数据分析04:Numpy——数组运算、排序、输入输出、矩阵运算、随机数生成_第2张图片

可以用zip得到网格平面上坐标点的数据:

>>>z = [i for i in zip(X.flat, Y.flat)]
>>>z
[(0.0, 0.0),
 (0.25, 0.0),
 (0.5, 0.0),
 (0.75, 0.0),
 (1.0, 0.0),
 (0.0, 0.5),
 (0.25, 0.5),
 (0.5, 0.5),
 (0.75, 0.5),
 (1.0, 0.5),
 (0.0, 1.0),
 (0.25, 1.0),
 (0.5, 1.0),
 (0.75, 1.0),
 (1.0, 1.0)]

下面是书中内容

>>>points = np.arange(-5, 5, 0.01) # 1000 equally spaced points
>>>xs, ys = np.meshgrid(points, points)  #xs, ys是一样的
>>>ys
array([[-5.  , -5.  , -5.  , ..., -5.  , -5.  , -5.  ],
       [-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99],
       [-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98],
       ...,
       [ 4.97,  4.97,  4.97, ...,  4.97,  4.97,  4.97],
       [ 4.98,  4.98,  4.98, ...,  4.98,  4.98,  4.98],
       [ 4.99,  4.99,  4.99, ...,  4.99,  4.99,  4.99]])
>>>z = np.sqrt(xs ** 2 + ys ** 2)
>>>z
array([[7.07106781, 7.06400028, 7.05693985, ..., 7.04988652, 7.05693985,
        7.06400028],
       [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,
        7.05692568],
       [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,
        7.04985815],
       ...,
       [7.04988652, 7.04279774, 7.03571603, ..., 7.0286414 , 7.03571603,
        7.04279774],
       [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,
        7.04985815],
       [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,
        7.05692568]])

这里我们用matplotlib把图画出来:

>>>import matplotlib.pyplot as plt
>>>plt.imshow(z, cmap=plt.cm.gray); plt.colorbar()
>>>plt.title("Image plot of $\sqrt{x^2 + y^2}$ for a grid of values")
Text(0.5, 1.0, 'Image plot of $\\sqrt{x^2 + y^2}$ for a grid of values')

Python数据分析04:Numpy——数组运算、排序、输入输出、矩阵运算、随机数生成_第3张图片

>>>plt.draw()
>>>plt.close('all')

4.3.1 将条件逻辑表述为数组运算(Expressing Conditional Logic as Array Operations)

numpy.where函数是一个向量版的三元表达式,x if condition else y。假设我们有一个布尔数组和两个数组:

>>>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])

假设如果cond中为true,取xarr中对应的值,否则就取yarr中的值。列表表达式的话会这么写:

>>>result = [(x if c else y)
             for x, y, c in zip(xarr, yarr, cond)]
>>>result
[1.1, 2.2, 1.3, 1.4, 2.5]

这么做的话会有很多问题。首先,对于很大的数组,会比较慢。第二,对于多维数组不起作用。但np.where能让我们写得更简洁:

>>>result = np.where(cond, xarr, yarr)
>>>result
array([1.1, 2.2, 1.3, 1.4, 2.5])

np.where中第二个和第三个参数不用必须是数组。where在数据分析中一个典型的用法是基于一个数组,产生一个新的数组值。假设我们有一个随机数字生成的矩阵,我们想要把所有的正数变为2,所有的负数变为-2。用where的话会非常简单:

>>>arr = np.random.randn(4, 4)
>>>arr
array([[-0.86617612,  0.20749266,  0.79432893,  1.37933292],
       [ 0.16468301,  1.33738792,  0.48931202, -1.93456647],
       [-1.04318554,  0.35130318,  1.93013893, -0.49548614],
       [ 0.06879538,  0.14403184, -0.6829035 , -0.15724614]])
>>>arr > 0
array([[False,  True,  True,  True],
       [ True,  True,  True, False],
       [False,  True,  True, False],
       [ True,  True, False, False]])
>>>np.where(arr > 0, 2, -2)
array([[-2,  2,  2,  2],
       [ 2,  2,  2, -2],
       [-2,  2,  2, -2],
       [ 2,  2, -2, -2]])

我们可以结合标量和数组。比如只把整数变为2,其他仍未原来的数字:

>>>np.where(arr > 0, 2, arr) # set only positive values to 2
array([[-0.86617612,  2.        ,  2.        ,  2.        ],
       [ 2.        ,  2.        ,  2.        , -1.93456647],
       [-1.04318554,  2.        ,  2.        , -0.49548614],
       [ 2.        ,  2.        , -0.6829035 , -0.15724614]])

4.3.2 数学和统计方法(Mathematical and Statistical Methods)

一些能计算统计值的数学函数能基于整个数组,或者沿着一个axis(轴)。可以使用aggregations(often called reductions,汇总,或被叫做降维),比如sum, mean, std(标准差).

下面是一些aggregate statistics(汇总统计):

>>>arr = np.random.randn(5, 4)
>>>arr
array([[-0.65977766,  0.10657405, -0.30306886,  1.6113779 ],
       [ 1.38028712,  0.19333709,  0.27204392,  0.57891583],
       [-1.68330481, -1.13381567,  2.40248441,  0.15887473],
       [ 1.14870515,  0.21836443,  0.48274068, -0.49030261],
       [ 0.03152238,  1.95722114,  1.15613118, -1.28873975]])
>>>arr.mean()
0.30697853186336255
>>>np.mean(arr)
0.30697853186336255
>>>arr.sum()
6.139570637267251

mean, sum这样的函数能接受axis作为参数来计算统计数字,返回的结果维度更少:

>>>arr.mean(axis=1)
array([ 0.18877635,  0.60614599, -0.06394034,  0.33987691,  0.46403374])
>>>arr.sum(axis=0)
array([0.21743217, 1.34168105, 4.01033133, 0.57012609])

这里arr.mean(1)表示,compute mean acros the rows(计算各行之间的平均值)。arr.sum(0)表示,compute sum down the columns(计算各行总和)。

其他一些方法,像cumsumcumprod不做汇总,而是产生一个中间结果的数组:

>>>arr = np.array([0, 1, 2, 3, 4, 5, 6, 7])
>>>arr.cumsum()  #累加
array([ 0,  1,  3,  6, 10, 15, 21, 28], dtype=int32)

上面的计算是一个累加的结果,0+1=1,1+2=3,3+3=6以此类推。

>>>arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
>>>arr
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
>>>arr.cumsum(axis=0)
array([[ 0,  1,  2],
       [ 3,  5,  7],
       [ 9, 12, 15]], dtype=int32)
>>>arr.cumprod(axis=1)
array([[  0,   0,   0],
       [  3,  12,  60],
       [  6,  42, 336]], dtype=int32)

数组的基本统计方法

方法 说明
sum 对数组中全部或某轴上的元素求和。零长度的数组sum为0
mean 算术平均数。零长度的数组mean为NaN
stdvar 分别为标准差和方差,自由度可调(默认为n)
minmax 最大值和最小值
argminargmax 分别为最大和最小元素的索引
cumsum 所有元素累计和
cumprod 所有元素累计积

4.3.3 用于布尔型数组的方法(Methods for Boolean Arrays)

sum对象是布尔型数组时,它是用来计算布尔数组中有多少个true的:

>>>arr = np.random.randn(100)
>>>(arr > 0).sum() # Number of positive values
46

有两个其他方法,any和all,对于布尔数组特别有用。any检测数组中只要有一个ture返回就是true,而all检测数组中都是true才会返回true。

>>>bools = np.array([False, False, True, False])
>>>bools.any()
True
>>>bools.all()
False

4.3.4 排序(Sorting)

numpy中也有sort方法:

>>>np.random.randn?  #返回符合正态分布的数值
>>>arr = np.random.randn(6)
>>>arr
array([-1.47806717, -0.13365593,  0.58858679, -2.3985419 , -0.96422824,
        0.04325962])
>>>arr.sort()
>>>arr
array([-2.3985419 , -1.47806717, -0.96422824, -0.13365593,  0.04325962,
        0.58858679])

如果是多维数组,还可以按axis来排序:

>>>arr = np.random.randn(5, 3)
>>>arr
array([[ 0.78097059, -0.72495837,  0.73126231],
       [ 0.03407071,  1.15173636,  0.03578452],
       [-0.89827663,  2.26539341, -0.68835086],
       [ 0.15338572,  0.47898484,  0.47362358],
       [ 0.4391983 ,  0.30683821,  0.97400495]])
>>>arr.sort(1)
>>>arr
array([[-0.72495837,  0.73126231,  0.78097059],
       [ 0.03407071,  0.03578452,  1.15173636],
       [-0.89827663, -0.68835086,  2.26539341],
       [ 0.15338572,  0.47362358,  0.47898484],
       [ 0.30683821,  0.4391983 ,  0.97400495]])

上面是直接调用数组的sort方法,会改变原有数组的顺序。但如果使用np.sort()函数的话,会生成一个新的排序后的结果。

一个计算分位数的快捷方法是先给数组排序,然后选择某个排名的值:

>>>large_arr = np.random.randn(1000)
>>>large_arr.sort()
>>>large_arr[int(0.05 * len(large_arr))] # 5% quantile
-1.5547315605495498

4.3.5 单一性和其他集合逻辑(Unique and Other Set Logic)

Numpy也有一些基本的集合操作用于一维数组。np.unique,能返回排好序且不重复的值:

>>>names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])
>>>np.unique(names)
array(['Bob', 'Joe', 'Will'], dtype=')
>>>ints = np.array([3, 3, 3, 2, 2, 1, 1, 4, 4])
>>>np.unique(ints)
array([1, 2, 3, 4])

如果用纯python代码来实现的话,要这么写:

>>>sorted(set(names))
['Bob', 'Joe', 'Will']

np.in1d, 测试一个数组的值是否在另一个数组里,返回一个布尔数组:

>>>values = np.array([6, 0, 0, 3, 2, 5, 6])
>>>np.in1d(values, [2, 3, 6])
array([ True, False, False,  True,  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种
setxor1d(x, y) 集合的对称差,即存在于一个数组中但不同时存在于两个数组中的元素

4.4 用于数组的文件输入输出(File Input and Output with Arrays)

Numpy能从磁盘直接存储和加载数据,不论是文本格式还是二进制模式。这里我们只考虑Numpy的二进制模式,因为大多数用户更喜欢用pandas或其他工具来加载text或tabular数据。

np.savenp.load。数组会以未压缩的原始二进制模式被保存,后缀为.npy:

>>>import numpy as np

>>>arr = np.arange(10)
>>>np.save('some_array', arr)

即使保存的时候没有加后缀,也会被自动加上。可以用np.load来加载数组。

>>>np.load('some_array.npy')
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

np.savez能保存多个数组,还可以指定数组对应的关键字,不过是未压缩的npz格式:

>>>np.savez('array_archive.npz', a=arr, b=arr)

加载.npz文件的时候,得到一个dict object:

>>>arch = np.load('array_archive.npz')
>>>arch['b']
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

可以用np.savez_compressed来压缩文件:

>>>np.savez_compressed('arrays_compressed.npz', a=arr, b=arr)

4.5 线性代数(Linear Algebra)

在MATLAB里,* 代表矩阵乘法。但是在numpy里,*表示element-wise prodct。要想做到矩阵乘法,要用多函数dot

>>>import numpy as np
>>>x = np.array([[1., 2., 3.], [4., 5., 6.]])
>>>y = np.array([[6., 23.], [-1, 7], [8, 9]])
>>>x
array([[1., 2., 3.],
       [4., 5., 6.]])
>>>y
array([[ 6., 23.],
       [-1.,  7.],
       [ 8.,  9.]])
>>>x.dot(y)
array([[ 28.,  64.],
       [ 67., 181.]])

x.dot(y)等同于np.dot(x, y):

>>>np.dot(x, y)
array([[ 28.,  64.],
       [ 67., 181.]])

一个二维数组和一个一维数组的矩阵乘法,得到一个一维数组:

>>>np.dot(x, np.ones(3))
array([ 6., 15.])

@作为一个中缀计算符,也能实现矩阵乘法:

>>>x @ np.ones(3)
array([ 6., 15.])

np.linalg能用来做矩阵分解,以及比如转置和求秩之类的事情:

>>>from numpy.linalg import inv, qr
>>>X = np.random.randn(5, 5)
#X = np.round(np.random.randn(5, 5), 3)  #这里我们用np.round控制小数点后的位数,看起来更舒服一些
>>>X
array([[-1.21810897, -0.29265147, -0.17907474, -0.24168411, -2.25091962],
       [-0.58843199, -0.61295374,  0.59243325,  0.6684168 ,  0.32061682],
       [-0.18505361,  0.93213111, -1.77880663,  1.23613944,  0.42735645],
       [ 0.94444125, -0.76661742, -2.40385328,  0.08920931, -0.33557356],
       [-1.47261914,  0.05994258, -1.54126795, -0.08375278, -1.52619611]])
>>>mat = X.T.dot(X)  #X转置乘以X
>>>np.round(mat, 2)
array([[ 4.92, -0.27,  0.2 , -0.12,  4.4 ],
       [-0.27,  1.92, -0.22,  0.74,  1.03],
       [ 0.2 , -0.22, 11.7 , -1.84,  2.99],
       [-0.12,  0.74, -1.84,  2.05,  1.38],
       [ 4.4 ,  1.03,  2.99,  1.38,  7.79]])
>>>np.round(inv(mat), 2)
array([[ 1.19,  0.39,  0.42,  1.03, -1.07],
       [ 0.39,  0.75,  0.13,  0.13, -0.39],
       [ 0.42,  0.13,  0.29,  0.55, -0.46],
       [ 1.03,  0.13,  0.55,  1.75, -1.12],
       [-1.07, -0.39, -0.46, -1.12,  1.16]])
>>>np.round(mat.dot(inv(mat)), 2)
array([[ 1.,  0.,  0.,  0.,  0.],
       [ 0.,  1.,  0., -0.,  0.],
       [-0., -0.,  1., -0.,  0.],
       [-0., -0., -0.,  1.,  0.],
       [-0., -0.,  0.,  0.,  1.]])
>>>q, r = qr(mat)
>>>np.round(r, 2)
array([[ -6.62,  -0.39,  -2.53,  -0.71,  -8.49],
       [  0.  ,  -2.29,   1.  ,  -1.97,  -2.56],
       [  0.  ,   0.  , -11.91,   1.78,  -3.15],
       [  0.  ,   0.  ,   0.  ,  -1.59,  -1.81],
       [  0.  ,   0.  ,   0.  ,   0.  ,   0.49]])

X.T.dot(X)计算的是X和X的转置的矩阵乘法。

一些常用的numpy.linalg函数

函数 描述
diag 以一维数组的形式返回方阵的对角线(或非对角线)元素,
或将一维数组转换为方阵(非对角线元素为零)
dot 矩阵乘法
trace 计算对角线元素和(即矩阵的迹)
det 计算方阵行列式
eig 计算方阵特征值和特征向量
inv 计算矩阵的逆
pinv 计算矩阵的Moore-Penrose伪逆
qr 计算QR分解
svd 计算奇异值分解(SVD)
solve 解线性方程组Ax=b,其中A为一个方阵
lstsq 计算Ax=b的最小二乘解

4.6 生成伪随机数(Pseudorandom Number Generation)

numpy.random模块提供了很多生成随机数的函数,可以选择生成符合某种概率分布的随机数。比如我们可以用normal得到一个4 x 4的,符合标准正态分布的数组:

>>>import numpy as np
>>>samples = np.random.normal(size=(4, 4))
>>>samples
array([[ 0.40335566,  0.49012624,  0.51915573,  4.03131376],
       [ 1.14935054, -0.33330548, -0.31231616,  0.40892981],
       [-1.5456503 ,  0.52125239, -0.37211993,  1.18562307],
       [-1.67826879, -0.91838905,  0.65828423,  0.65344736]])

相对的,python内建的random模块一次生成一个样本。在生成大量样本方法,numpy.random是非常快的:

>>>from random import normalvariate
>>>N = 1000000
>>>%timeit samples = [normalvariate(0, 1) for _ in range(N)]
1.19 s ± 112 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>>%timeit np.random.normal(size=N)
38.1 ms ± 3.75 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

之所以称之为伪随机数,是因为随机数生成算法是根据seed来生成的。也就是说,只要seed设置一样,每次生成的随机数是相同的:

>>>np.random.seed(1234)

当然,这个seed是全局的,如果想要避免全局状态,可以用numpy.random.RandomState来创建一个独立的生成器:

>>>rng = np.random.RandomState(1234)
>>>rng.randn(10)
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 产生标准正态分布样本值
binomial 产生二项分布样本值
normal 产生正态(高斯)分布样本值
beta 产生Beta分布样本值
chisquare 产生卡方分布样本值
gamma 产生Gamma分布样本值
uniform 产生[0,1]均匀分布样本值

4.7 栗子:随机漫步(Example: Random Walks)

这个例子让我了解一个在实际任务中如何利用数组操作。首先一个最简单的随机漫步:从0开始,步幅为1和-1,以相同的概率出现。

下面是纯python的实现方法,1000步:

>>>import random
>>>position = 0
>>>walk = [position]
>>>steps = 1000
>>>for i in range(steps):
>>>    step = 1 if random.randint(0, 1) else -1
>>>    position += step
>>>    walk.append(position)

>>>plt.figure()
<Figure size 432x288 with 0 Axes>
<Figure size 432x288 with 0 Axes>

>>>plt.plot(walk[:100])
[<matplotlib.lines.Line2D at 0x1a0f9d34a08>]

其中随机游动的前100个值的示例图:

Python数据分析04:Numpy——数组运算、排序、输入输出、矩阵运算、随机数生成_第4张图片

随机漫步其实就是一个简单的累加。而用np.random能更快:

>>>import numpy as np
>>>np.random.seed(12345)

>>>nsteps = 1000
>>>draws = np.random.randint(0, 2, size=nsteps)
>>>steps = np.where(draws > 0, 1, -1)
>>>walk = steps.cumsum()

我们能直接从中得到一些统计数据,比如最大值和最小值:

>>>walk.min()
-5
>>>walk.max()
24

一个更复杂的统计值是在哪一步random walk到达了一个指定值。我们想知道从0走出10步用了多久,不论是正方向还是负方向。np.abs(walk) >= 10给我们一个布尔数组,walk已经到达或超过10的位置,但是我们需要第一个10或-10的索引。因此,可以使用argmax来计算,它返回布尔数组中最大值的第一个索引(True是最大值):

>>>(np.abs(walk) >= 10).argmax()
119

注意,使用argmax并不总是高效的,因为它总会搜索整个数组。在这里例子里,一旦True被找到了,我们就返回为最大值。

4.7.1 ⼀次模拟多个随机漫步(Simulating Many Random Walks at Once)

>>>nwalks = 5000
>>>nsteps = 1000
>>>draws = np.random.randint(0, 2, size=(nwalks, nsteps)) # 0 or 1
>>>steps = np.where(draws > 0, 1, -1)
>>>walks = steps.cumsum(1)
>>>walks
array([[  1,   2,   3, ...,  50,  51,  50],
       [ -1,   0,  -1, ..., -12, -11, -10],
       [ -1,   0,   1, ...,  10,   9,   8],
       ...,
       [ -1,   0,   1, ...,  48,  47,  48],
       [ -1,   0,   1, ..., -28, -29, -28],
       [ -1,   0,   1, ...,  72,  71,  72]], dtype=int32)

找到所有漫步中的最大值和最小值:

>>>walks.max()
108
>>>walks.min()
-119

在这些漫步模拟中,我们想找到30步以上的。用any方法:

>>>hits30 = (np.abs(walks) >= 30).any(1)
>>>hits30
array([ True, False, False, ...,  True,  True,  True])
>>>hits30.sum() # Number that hit 30 or -30
3353

然后我们利用这个布尔型数组选出那些穿越了30(绝对值)的随机漫步(⾏),并调⽤argmax在轴1上获取穿越时间:

>>>crossing_times = (np.abs(walks[hits30]) >= 30).argmax(1)
>>>crossing_times.mean()
504.5872353116612

参考资料:

  • 利用Python进行数据分析学习笔记(有惊喜^_^

  • 书籍:《Python for Data Analysis》

你可能感兴趣的:(利用Python进行数据分析)