美文网首页Python数据分析
用Python进行数据分析 第四章 Numpy

用Python进行数据分析 第四章 Numpy

作者: Jason数据分析生信教室 | 来源:发表于2021-08-14 08:04 被阅读0次

    结束了枯燥复杂的前戏铺垫,终于可以进入主题了。
    Numpy,是Numerical Python的简称,他是目前Python数值计算中最为重要的基础包。大多数计算包都提供了基于NumPy的科学函数功能。
    NumPy具备以下内容

    • ndarray,一种高效的多维数组,提供了基于数组的便捷算数操作以及灵活的广播功能。
    • 对所有的数据进行快速的矩阵计算,无需编写循环程序。
    • 线性代数,随机数生成以及傅立叶变换功能。
    • 用于连接NumPy到C,C++和FORTRAN语言类库的C语言API。

    对于大多数的数据分析应用,以下的内容会备受关注。

    • 在数据处理,清洗,构造子集,过滤,变换以及其他计算中进行快速的向量化计算。
    • 常见的数组算法,比如sort、unique以及set操作等。
    • 高效的描述性统计和聚合/概述数据。
    • 数据排列和相关数据操作,例如对异构数据进行merge和join。
    • 使用数组表达式来表明条件逻辑,代替if-elif-else条件分支的循环。
    • 分组数据的操作(聚合,变换以及函数式操作)

    NumPy的特点

    • Numpy在内部将数据储存在连续的内存块上,这与其他的Python内建数据结构是不同的。NumPy的算法库是用C语言写的,所以在操作数据内存时,不需要任何类型检查或者其他操。NumPy数组使用的内存量也小于其他内建序列。
    • NumPy可以针对全量数组进行复杂计算而不需要写Python循环。

    举个例子

    import numpy as np
    my_arr = np.arange(1000000)
    my_list = list(range(1000000))
    
    %time for _ in range(10): my_arr2 = my_arr * 2
     In [24]: %time for _ in range(10): my_arr2 = my_arr * 2
    CPU times: user 18.3 ms, sys: 15.4 ms, total: 33.7 ms
    Wall time: 32.8 ms
    
    %time for _ in range(10): my_list2 = [x*2 for x in my_list]
    In [25]: %time for _ in range(10): my_list2 = [x*2 for x in my_list]
    CPU times: user 468 ms, sys: 165 ms, total: 633 ms
    Wall time: 633 ms
    

    可以看出来在这个简单的例子里numPy比内建list快了20倍。实际上一般情况下要快10-100倍。单位是秒的话还能忍,变成分甚至小时的时候就没法忍了。

    0708

    4.1 Numpy ndarray : 多维数组对象

    NumPy的核心特征之一就是N-维数组对象-ndarray。ndarray是Python中一个快速,灵活的大型数据集容器。数组允许你使用类似于标量的操作语法在整块数据上进行数学计算。

    4.1.1 生成ndarray

    生成数组最简单的方式就是使用array函数,这个函数接受任意的序列型对象(当然也包括数组)。例如,列表的转换就是一个好例子。

    In [3]: import numpy as np
    
    In [4]: data1=[6,7.5,8,0,1]
    
    In [5]: arr1=np.array(data1)
    
    In [6]: arr1
    Out[6]: array([6. , 7.5, 8. , 0. , 1. ])
    

    套嵌序列,例如同等长度的列表,将会自动转换成多维数组。

    In [7]: data2=[[1,2,3,4],[5,6,7,8]]
    
    In [8]: arr2=np.array(data2)
    
    In [9]: arr2
    Out[9]: 
    array([[1, 2, 3, 4],
           [5, 6, 7, 8]])
    

    因为data2是一个包含列表的列表,所以Numpy数组arr2形成了二维数组。我们可以通过ndimshape的属性来确认纬度。

    arr2.ndim
    Out[10]: 2
    
    arr2.shape
    Out[11]: (2, 4)
    

    除了np.array,还有很多其他函数可以创建新数组。例如,给定长度和形状后,zeros 可以一次性创造全0数组,ones可以创造全1数组。empty可以创造一个诶呦初始化数值的数组。

    np.zeros(10)
    Out[12]: array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
    
    In [13]: np.zeros((3,6))
    Out[13]: 
    array([[0., 0., 0., 0., 0., 0.],
           [0., 0., 0., 0., 0., 0.],
           [0., 0., 0., 0., 0., 0.]])
    

    arange是Python内奸函数的range的数组版:

    In [16]: np.arange(15)
    Out[16]: array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14])
    

    4.1.2 ndarray的数据类型

    数据类型,就是dytpe是一个特殊的对象,它包含了ndarray需要为某一种类型数据所定义的内存信息。是32位还是64位。不过这些内容貌似只有在内存或者硬盘上读取大数据的时候才会用到。所以在此跳过。

    4.1.3 NumPy数组

    数组之间之所以重要是因为它允许你进行批量操作而无需任何for循环。NumPy用户称这种特性为向量化。任何在两个等尺寸数组之间的算数操作都应用了逐元素操作的方式:

    In [17]: arr=np.array([[1.,2.,3.],[4.,5.,6.]])
    
    In [18]: arr
    Out[18]: 
    array([[1., 2., 3.],
           [4., 5., 6.]])
    
    In [19]: arr*arr
    Out[19]: 
    array([[ 1.,  4.,  9.],
           [16., 25., 36.]])
    
    In [20]: arr-arr
    Out[20]: 
    array([[0., 0., 0.],
           [0., 0., 0.]])
    In [21]: 1/arr
    Out[21]: 
    array([[1.        , 0.5       , 0.33333333],
           [0.25      , 0.2       , 0.16666667]])
    

    同尺寸数组之间的比较,会产生一个布尔数组值:

    In [24]: arr2 = np.array([[0.,4.,1.],[7.,2.,12.]])
    
    In [25]: arr2 > arr
    Out[25]: 
    array([[False,  True, False],
           [ True, False,  True]])
    

    4.1.4 基础索引与切片

    Numpy数组索引比较有意思。看起来比较简单,例如

    In [6]: arr=np.arange(10)
    In [7]: arr
    Out[7]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    
    In [8]: arr[5]
    Out[8]: 5
    
    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])
    

    看起来没什么特别的,但是,神奇的地方来了。

    In [12]: arr_slice=arr[5:8]
    
    In [13]: arr_slice
    Out[13]: array([12, 12, 12])
    
    In [14]: arr_slice[1]=123456
    
    In [15]: arr
    Out[15]: 
    array([     0,      1,      2,      3,      4,     12, 123456,     12,
                8,      9])
    

    当你传入了一个数值给数组的切片,数值被传递给了整个数组。也就是说当你修改数值的时候,整个数组也被修改了。

    二维数组也是大同小异。

    In [17]: arr2d=np.array([[1,2,3],[4,5,6],[7,8,9]])
    
    In [18]: arr3d[2]
    
    In [19]: arr2d[2]
    Out[19]: array([7, 8, 9])
    
    In [20]: arr2d[0][2]
    Out[20]: 3
    
    In [23]: arr3d=np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
    
    In [24]: arr3d
    Out[24]: 
    array([[[ 1,  2,  3],
            [ 4,  5,  6]],
    
           [[ 7,  8,  9],
            [10, 11, 12]]])
    

    可以用copy 来把一段数组复制出来。

    In [25]: old_values=arr3d[0].copy()
    
    In [26]: arr3d[0]=42
    
    In [27]: arr3d
    Out[27]: 
    array([[[42, 42, 42],
            [42, 42, 42]],
    
           [[ 7,  8,  9],
            [10, 11, 12]]])
    In [28]: arr3d[0]=old_values
    
    In [29]: arr3d
    Out[29]: 
    array([[[ 1,  2,  3],
            [ 4,  5,  6]],
    
           [[ 7,  8,  9],
            [10, 11, 12]]])
    

    4.1.5 布尔索引

    假设数据都在数组中,并且数组中的数据是一些存在重复的人名。我会使用numpy.random中的randn函数来生成一些随机正太分布的数据。

    In [30]: names=np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
    
    In [31]: data=np.random.randn(7,4)
    
    In [32]: names
    Out[32]: array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype='<U4')
    In [33]: data
    Out[33]: 
    array([[-0.88924733,  0.02403723, -0.2819186 , -0.8339795 ],
           [-0.96695021, -0.25844618, -0.87496546, -1.34230515],
           [-0.60602287, -1.04525004, -1.08273008,  0.52821153],
           [-1.07298679, -0.14768328,  1.4163847 , -0.03429055],
           [-1.97392465,  0.20266476, -0.27259933,  0.56379019],
           [ 1.2778814 ,  0.39804652, -0.64640604,  1.27419257],
           [ 0.76621013,  0.33428609, -1.02705212,  1.71906965]])
    

    假设每个人名都和data数组中的一行相对应,并且我们想要选中所有'Bob'对应的行。可以用数组的比较操作(==)。所以比较names和字符串Bob会产生一个布尔值数组。

    In [34]: names=='Bob'
    Out[34]: array([ True, False, False,  True, False, False, False])
    

    在索引数组时也可以传入布尔值数组。

    In [35]: data[names=='Bob']
    Out[35]: 
    array([[-0.88924733,  0.02403723, -0.2819186 , -0.8339795 ],
           [-1.07298679, -0.14768328,  1.4163847 , -0.03429055]])
    

    注意,布尔值数组长度必须和数组索引长度一致。
    210723
    我们还可以进行更深入的索引,比方说索引行的同时并且指定列的范围或者条件。
    在这些例子中,我选择了names=="Bob"的行,并索引了各个列。

    import numpy as np
    data=np.random.randn(7,4)
    names=np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
    

    随机构建的data是这样的。

    In [12]: data
    Out[12]: 
    array([[ 0.26340275, -0.03634885, -1.37852202, -0.16936625],
           [-0.01249   ,  1.37169676, -0.88089887,  1.11568434],
           [ 0.01107993,  1.23480053,  1.39456221, -1.61094371],
           [-0.78822633, -1.17399347, -1.39451976, -1.30386953],
           [-0.91854665,  1.29636153,  0.19805605,  0.92456866],
           [-0.65095089,  0.49196212,  0.81500823, -0.46259821],
           [ 1.09026396,  1.36101244, -0.35450887, -0.92431959]])
    
    In [18]: data[names=="Bob",2:]
    Out[18]: 
    array([[ 0.50520346,  0.56492566],
           [-0.82929928,  0.20443228]])
    

    这个操作相当于选取了第1,第4行的第3,4列数据。
    然后除了使用==以外,还可以使用!=或者表达式前使用~对条件取反。

    In [19]: names != "Bob"
    Out[19]: array([False,  True,  True, False,  True,  True,  True])
    In [20]: data[~(names=="Bob")]
    Out[20]: 
    array([[-1.62349406, -0.315799  , -0.04982011, -1.15152024],
           [ 0.44194909, -0.1669004 ,  1.47321445,  3.23723779],
           [-0.12262588,  0.17314998,  0.02109545, -0.80360207],
           [-0.95687212,  1.48905832,  0.91855663, -0.04753174],
           [ 3.44643971,  0.38780427,  0.05220767, -1.78855402]])
    

    ~符号可以在你想要对一个通用条件进行取反时使用。

    In [21]: cond=names=="Bob"
    
    In [22]: data[~cond]
    Out[22]: 
    array([[-1.62349406, -0.315799  , -0.04982011, -1.15152024],
           [ 0.44194909, -0.1669004 ,  1.47321445,  3.23723779],
           [-0.12262588,  0.17314998,  0.02109545, -0.80360207],
           [-0.95687212,  1.48905832,  0.91855663, -0.04753174],
           [ 3.44643971,  0.38780427,  0.05220767, -1.78855402]])
    

    当要选择三个名字中的两个时,可以对多个布尔值条件进行联合,需要使用数学进行操作符号如&(and), |(or)

    In [23]: mask =(names=="Bob") | (names=="Will")
    
    In [24]: mask
    Out[24]: array([ True, False,  True,  True,  True, False, False])
    In [25]: data[mask]
    Out[25]: 
    array([[-1.0006796 ,  0.46976477,  0.50520346,  0.56492566],
           [ 0.44194909, -0.1669004 ,  1.47321445,  3.23723779],
           [ 0.54567394,  0.66362766, -0.82929928,  0.20443228],
           [-0.12262588,  0.17314998,  0.02109545, -0.80360207]])
    

    基于常识来设置布尔值数组的值也是可以的。将data中所有的负值设置为0,只需要如下的步骤

    In [26]: data[data<0]=0
    
    In [27]: data
    Out[27]: 
    array([[0.        , 0.46976477, 0.50520346, 0.56492566],
           [0.        , 0.        , 0.        , 0.        ],
           [0.44194909, 0.        , 1.47321445, 3.23723779],
           [0.54567394, 0.66362766, 0.        , 0.20443228],
           [0.        , 0.17314998, 0.02109545, 0.        ],
           [0.        , 1.48905832, 0.91855663, 0.        ],
           [3.44643971, 0.38780427, 0.05220767, 0.        ]])
    

    后续章节还会学习到如何用pandas更为方便快速的在二维数据上进行上述的操作。

    0802

    4.1.6 神奇索引

    神奇索引时Numpy中的术语,用于描述使用整数数组进行数据索引。
    假设我们有一个8x4的数组。

    In [7]: import numpy as np
    In [8]: arr = np.empty((8,4))
    In [9]: for i in range(8):
       ...:     arr[i] = i
    
    In [10]: arr
    Out[10]: 
    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 [11]: arr[[4,3,0,6]]
    Out[11]: 
    array([[4., 4., 4., 4.],
           [3., 3., 3., 3.],
           [0., 0., 0., 0.],
           [6., 6., 6., 6.]])
    

    如果使用负的索引,将从尾部进行选择:

    In [12]: arr[[-3,-5,-7]]
    Out[12]: 
    array([[5., 5., 5., 5.],
           [3., 3., 3., 3.],
           [1., 1., 1., 1.]])
    

    传递多个索引数组时情况有些许不同,这样会根据索引元素选出一个一维数组。

    In [18]: arr=np.arange(32).reshape((8,4))
    In [19]: arr
    Out[19]: 
    array([[ 0,  1,  2,  3],
           [ 4,  5,  6,  7],
           [ 8,  9, 10, 11],
           [12, 13, 14, 15],
           [16, 17, 18, 19],
           [20, 21, 22, 23],
           [24, 25, 26, 27],
           [28, 29, 30, 31]])
    In [20]: arr[[1,5,7,2],[0,3,1,2]]
    Out[20]: array([ 4, 23, 29, 10])
    

    在上述的例子中,元素(1,0), (5,3), (7,1), (2,2)被选中。如果不考虑数组的维数,神奇所以的结果总是一维的。
    但是我们设想的结果是通过选择矩阵中行列的子集所形成的矩阵

    In [21]: arr[[1,5,7,2]][:,[0,3,1,2]]
    Out[21]: 
    array([[ 4,  7,  5,  6],
           [20, 23, 21, 22],
           [28, 31, 29, 30],
           [ 8, 11,  9, 10]])
    

    4.1.7 数组转置和换轴

    转置是一种特殊的特殊重组形式,可以返回底层数据的视图而不需要复制任何内容。数组拥有transpose方法,也有特殊的T属性。

    In [24]: arr=np.arange(15).reshape((3,5))
    In [25]: arr
    Out[25]: 
    array([[ 0,  1,  2,  3,  4],
           [ 5,  6,  7,  8,  9],
           [10, 11, 12, 13, 14]])
    In [26]: arr.T
    Out[26]: 
    array([[ 0,  5, 10],
           [ 1,  6, 11],
           [ 2,  7, 12],
           [ 3,  8, 13],
           [ 4,  9, 14]])
    

    当进行矩阵计算时,你可能会经常进行一些特定操作,比如,当计算矩阵内积会使用np.dot

    In [27]: arr=np.random.randn(6,3)
    In [28]: arr
    Out[28]: 
    array([[ 1.04149511, -0.20596742,  1.49805046],
           [-0.58367316,  0.59855097,  0.4582216 ],
           [ 1.24107983, -2.17385221, -0.19432956],
           [ 0.21063377, -0.80522536,  0.86875731],
           [-1.03346892,  0.78591013, -0.74811735],
           [-1.67747023, -0.42874406,  1.53915289]])
    
    In [30]: np.dot(arr.T,arr)
    Out[30]: 
    array([[ 6.89199653, -3.52441228, -0.57415541],
           [-3.52441228,  6.57618335, -1.55923793],
           [-0.57415541, -1.55923793,  6.17529662]]
    

    0803

    4.2 通用函数,快速的逐元素数组函数

    通用函数,也被称为ufunc,是一种在ndarray数据中进行逐元素操作的函数。这些函数会产生标量结果。比如sqrt或者exp

    In [2]: import numpy as np
    
    In [3]: arr=np.arange(10)
    
    In [4]: arr
    Out[4]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    
    In [5]: np.sqrt(arr)
    Out[5]: 
    array([0.        , 1.        , 1.41421356, 1.73205081, 2.        ,
           2.23606798, 2.44948974, 2.64575131, 2.82842712, 3.        ])
    
    In [6]: np.exp(arr)
    Out[6]: 
    array([1.00000000e+00, 2.71828183e+00, 7.38905610e+00, 2.00855369e+01,
           5.45981500e+01, 1.48413159e+02, 4.03428793e+02, 1.09663316e+03,
           2.98095799e+03, 8.10308393e+03])
    

    这些是所谓的一元通用函数。还有一些,比如add或者maxium则会接受两个数组并返回一个数组作为结果。所以被叫做二元通用函数。

    In [10]: x=np.random.randn(8)
    In [11]: y=np.random.randn(8)
    In [12]: x
    Out[12]: 
    array([ 0.26369905, -0.49904012,  0.02438028,  0.40406891,  0.41731139,
           -0.25703924, -0.7447314 , -0.64328482])
    In [14]: np.maximum(x,y)
    Out[14]: 
    array([ 2.52806516, -0.17691024,  0.37252638,  0.40406891,  0.41731139,
            0.52093052,  0.05425714, -0.64328482])
    

    这里,numpy.maximum逐个元素将x和y中元素的最大值计算出来。
    也有一些通用函数返回多个数组。还可以通过函数接收一个可选参数out,允许对数组按位置操作

    In [24]: arr=np.random.randn(7)*5
    
    In [25]: arr
    Out[25]: 
    array([-10.54437197,  -1.88517283,  -1.38245398,   0.62219403,
             5.46339811,   6.02828586,  -4.84169485])
    
    In [26]: np.sqrt(arr)
    __main__:1: RuntimeWarning: invalid value encountered in sqrt
    Out[26]: 
    array([       nan,        nan,        nan, 0.78879276, 2.3373913 ,
           2.45525678,        nan])
    
    In [27]: arr
    Out[27]: 
    array([-10.54437197,  -1.88517283,  -1.38245398,   0.62219403,
             5.46339811,   6.02828586,  -4.84169485])
    
    In [28]: np.sqrt(arr,arr)
    __main__:1: RuntimeWarning: invalid value encountered in sqrt
    Out[28]: 
    array([       nan,        nan,        nan, 0.78879276, 2.3373913 ,
           2.45525678,        nan])
    
    In [29]: arr
    Out[29]: 
    array([       nan,        nan,        nan, 0.78879276, 2.3373913 ,
           2.45525678,        nan])
    

    4.3 使用数组进行数组指向编程

    使用NumPy数组可以让你利用简单的数组表达式完成多种数据操作任务。而无需写大量的循环。这种利用数组表达式来代替显示循环的方法,成为向量化。
    这里出现了np.meshgrid,书里的解释是这个函数可以接收两个一维数组,并根据 (x,y) 对生成一个二维矩阵:

    points=np.arange(-5,5,0.01)
    xs,ys=np.meshgrid(points,points)
    z=np.sqrt(xs**2+ys**2)
    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")
    

    4.3.1 将条件逻辑作为数组操作

    np.where函数是三元表达式x if condition else y的向量化版本。

    In [46]: xarr=np.array([1.1,1.2,1.3,1.4,1.5])
    
    In [47]: yarr=np.array([2.1,2.2,2.3,2.4,2.5])
    
    In [48]: cond=np.array([True,False,True,True,False])
    
    In [49]: result=np.where(cond,xarr,yarr)
    
    In [50]: result
    Out[50]: array([1.1, 2.2, 1.3, 1.4, 2.5])
    

    np.where的第二个和第三个参数并不需要是数组,可以是标量。
    假设有一个随机生成的数据,想把大于0的数值都替换成2,小于0的替换成-2

    arr
    Out[52]: 
    array([[ 1.05993392, -2.13979616, -0.24930099,  0.74476249],
           [ 0.62190215,  0.21205643, -0.92070166, -0.05722416],
           [ 1.3147729 , -0.64100254,  0.6969657 , -0.69911315],
           [-0.83147394,  0.5328311 , -1.27371665,  0.83683149]])
    
    arr>0
    Out[53]: 
    array([[ True, False, False,  True],
           [ True,  True, False, False],
           [ True, False,  True, False],
           [False,  True, False,  True]])
    
    np.where(arr>0,2,-2)
    Out[54]: 
    array([[ 2, -2, -2,  2],
           [ 2,  2, -2, -2],
           [ 2, -2,  2, -2],
           [-2,  2, -2,  2]])
    

    也可以用np.where将标量和数组结合,只把正值替换成2。

    np.where(arr>0,2,arr)
    Out[55]: 
    array([[ 2.        , -2.13979616, -0.24930099,  2.        ],
           [ 2.        ,  2.        , -0.92070166, -0.05722416],
           [ 2.        , -0.64100254,  2.        , -0.69911315],
           [-0.83147394,  2.        , -1.27371665,  2.        ]])
    

    4.3.2 数学和统计方法

    很多函数可以直接用于计算整个数组统计值或关于轴向数据的数学函数。可以使用聚合函数(通常也叫缩减函数)??【什么意思,没有看懂,是人话吗?】。例如sum,mean,std,既可以直接调用数组,也可以使用顶层的NumPy函数。
    此处生成了一些正规分布的随机数,并进行了部分聚合统计数据。

    In [3]: import numpy as np
    
    In [4]: arr=np.random.randn(5,4)
    
    In [5]: arr
    Out[5]: 
    array([[-1.20907349, -0.79244291, -0.83736474,  0.56926916],
           [ 1.84050471,  0.44005309, -0.89901265, -0.86572061],
           [ 1.06164979,  0.08397982,  0.88183564, -0.93072073],
           [ 0.08464084,  0.48199149,  0.36814596,  0.18346437],
           [ 0.78778644, -1.72560519, -1.13181619, -0.82849128]])
    
    In [6]: arr.mean()
    Out[6]: -0.12184632401737742
    
    In [7]: np.mean(arr)
    Out[7]: -0.12184632401737742
    
    In [8]: arr.sum()
    Out[8]: -2.4369264803475486
    

    mean,sum函数可以设置一个可选参数,来计算给定轴向上的统计值,形成一个下降一纬度的数组。

    In [11]: arr.mean(axis=1)
    Out[11]: array([-0.567403  ,  0.12895614,  0.27418613,  0.27956066, -0.72453155])
    
    In [12]: arr.sum(axis=0)
    Out[12]: array([ 2.56550829, -1.5120237 , -1.61821199, -1.87219909])
    

    在这里会出现两个函数,cumsum,cumprod。前者是求累积和,后者是求累积乘积。

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

    4.3.3 布尔值数组的方法

    布尔值会被强制为1(True)和0(False)

    In [7]: arr=np.random.randn(100)
    
    In [8]: (arr>0).sum()
    Out[8]: 50
    

    对于布尔值数组,有两个非常有效的方法all和any。any检查数组中是否至少有一个True,而all检查是否每个值都是True

    In [9]: bools=np.array([False,False,True,False])
    
    In [10]: bools.any()
    Out[10]: True
    
    In [11]: bools.all()
    Out[11]: False
    

    4.3.4 排序

    和Python的内建列表类型相似,Numpy数组可以使用sort方法按位置排序

    In [12]: arr=np.random.randn(6)
    
    In [13]: arr
    Out[13]: 
    array([ 0.35459006, -1.42757946, -0.55868553,  1.37073275,  0.09445346,
           -1.24252249])
    
    In [14]: arr.sort()
    
    In [15]: arr
    Out[15]: 
    array([-1.42757946, -1.24252249, -0.55868553,  0.09445346,  0.35459006,
            1.37073275])
    

    也可以在多维数组中根据传递的axis值,沿着轴向对每一维数据段进行排序。0是行,1是列。

    In [16]: arr=np.random.randn(5,3)
    
    In [17]: arr
    Out[17]: 
    array([[-1.52524433, -2.06004427, -1.13242247],
           [-2.38627045, -0.38389541,  0.36746816],
           [-0.20633995,  0.38960894,  0.42550959],
           [ 0.57888334, -0.35361831, -0.55893923],
           [ 0.6830678 ,  0.30014391, -0.52747145]])
    
    In [18]: arr.sort(1)
    
    In [19]: arr
    Out[19]: 
    array([[-2.06004427, -1.52524433, -1.13242247],
           [-2.38627045, -0.38389541,  0.36746816],
           [-0.20633995,  0.38960894,  0.42550959],
           [-0.55893923, -0.35361831,  0.57888334],
           [-0.52747145,  0.30014391,  0.6830678 ]])
    

    4.3.5 唯一值与其他集合逻辑

    Numpy包含一些针对一维ndarray的基础集合操作。常用的一个方法是np.unique。返回的是数组中唯一值排序后形成的数组。

    In [20]: names=np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
    
    In [21]: np.unique(names)
    Out[21]: array(['Bob', 'Joe', 'Will'], dtype='<U4')
    

    书里还介绍了几个函数,感觉现在学了也会忘掉,以后用到的时候再来看吧。

    因为没什么价值,所以跳过原书的文件输入和输出,以及线性代数部分。文件输入和输出会在后面的Pandas里给出详细解说。

    4.6 伪随机数生成

    nump.random模块填补了Python内建的random的不足,可以高效地生成多种概率分布下的完整样本值数组。例如,可以生成耦合4x4的正太分布样本数组:

    In [2]: import numpy as np
    
    In [3]: samples=np.random.normal(size=(4,4))
    
    In [4]: samples
    Out[4]: 
    array([[-1.05119616, -1.50358421,  1.47131296,  0.48181491],
           [-0.26104341, -0.00633089, -0.33003799, -0.73249104],
           [ 1.26644795, -0.15377429,  1.55892977,  1.39527939],
           [ 0.73842726, -0.1810329 , -2.07712623,  0.2069095 ]])
    

    也可以定义随机种子

    In [5]: np.random.seed(1234)
    

    numpy.random中补分布函数列表

    函数 描述
    seed 随机种子
    permutation 返回一个序列的随机排列
    shuffle 随机排列一个序列
    rand 从均匀分布中抽取样本
    randint 根据给定的由低到高的范围抽取随机整数
    randn 从均值0方差1的正太分布中抽取样本
    binomial 拟合二项式分布随机样本
    noraml 拟合高斯分布随机样本
    beta 你和beta分布的随机样本
    chisquare 拟合卡方分布的随机样本
    gama 拟合伽马分布的随机样本
    uniform 从均匀[0,1)分布中抽取样本

    4.7 随机漫步 Random walk

    文章里举了一个最简单的随机漫步的例子。已0为起点,进步为1和-1,发生的概率相等。以下是使用内建random模块实现的1000布的随机漫步。

    import random
    import matplotlib.pyplot as plt 
    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.plot(walk[:100])
    

    通过观察可能会观察到walk只是对随机步进行了累积。并且可以通过一个数组表达式实现。因此,使用np.random模块一次性抽取1000次投掷硬币的结果,每次透支的结果为1或-1,然后计算累积值。
    作为对比,现在开始用np.random来实现一下。

    In [37]: draws=np.random.randint(0,2,size=nsteps)
    
    In [38]: steps=np.where(draws>0,1,-1)
    
    In [39]: walk=steps.cumsum()
    
    In [40]: walk.min()
    Out[40]: 0
    
    In [41]: walk.max()
    Out[41]: 55
    

    相关文章

      网友评论

        本文标题:用Python进行数据分析 第四章 Numpy

        本文链接:https://www.haomeiwen.com/subject/dizdbltx.html