结束了枯燥复杂的前戏铺垫,终于可以进入主题了。
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
形成了二维数组。我们可以通过ndim
和shape
的属性来确认纬度。
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
网友评论