1.1NumPy ndarray:多维数组对象
1.1.1NumPy的数据类型
可以使用astype方法显式的转换数组的数据类型
in:
arr = np.array([1,2,3,4,5])
arr.dtype
out:
dtype('int32')
in:
float_arr = arr.astype(np.float64)
float_arr.dtype
out:
dtype('float64')
1.1.2布尔索引
in:
names = np.array(['a','v','a','qw','a','dfsa','qw'])
data = np.random.randint(0,12,(7,3))
names
out:
array(['a', 'v', 'a', 'qw', 'a', 'dfsa', 'qw'], dtype='<U4')
in:
data
out:
array([[ 3, 4, 9],
[ 2, 11, 4],
[ 5, 5, 1],
[ 4, 0, 9],
[11, 3, 7],
[ 2, 11, 8],
[10, 10, 2]])
in:
data[names == 'a']
out:
array([[ 3, 4, 9],
[ 5, 5, 1],
[11, 3, 7]])
布尔值数组的长度必须和数组轴索引长度一致。还可以用切片或整数值对布尔值数组进行混合和匹配。
若想排除某些数据,可以使用!=或在条件表达式前使用~对条件取反
in:
data[names!='a']
out:
array([[ 2, 11, 4],
[ 4, 0, 9],
[ 2, 11, 8],
[10, 10, 2]])
in:
data[~(names == 'a')]
out:
array([[ 2, 11, 4],
[ 4, 0, 9],
[ 2, 11, 8],
[10, 10, 2]])
(~符号可以在想要对一个通用条件取反时使用)
还可以对多个布尔值条件进行联合,需要使用数学操作符如&(and)和|(or):
(在这里,and和or没用,要使用符号&和|)
cond = (names == 'a')|(names == 'v')
data[cond]
1.1.3神奇索引
神奇索引是Numpy中的术语,用于描述用整数数组进行数据索引
in:
arr = np.empty((8,4),dtype = float)
print(arr)
for i in range(8):
arr[i] = i
arr
out:
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:
arr[[4,1,3,5]]
out:
array([[4., 4., 4., 4.],
[1., 1., 1., 1.],
[3., 3., 3., 3.],
[5., 5., 5., 5.]])
也可以使用负的索引,从尾部进行选择
in:
arr[[-1,-5,-3]]
out:
array([[7., 7., 7., 7.],
[3., 3., 3., 3.],
[5., 5., 5., 5.]])
传递多个索引数组时情况会有不同
in:
arr = np.arange(32).reshape((8,4))
arr
out:
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:
arr[[0,2,4,3],[2,3,1,2]]
out:
array([ 2, 11, 17, 14])
索引有多个数组时,根据原来数据的形式,将索引组成对进行提取数据。
这个例子中,提取的数据位置分别是:(0,2),(2,3),(4,1),(3,2)
如果不考虑数组的维数,神奇索引的结果总是一维的
例:
in:
arr = np.random.randint(10,40,(3,4,2))
arr
out:
array([[[38, 30],
[38, 38],
[10, 35],
[25, 39]],
[[31, 16],
[13, 12],
[15, 17],
[29, 21]],
[[39, 21],
[19, 35],
[22, 20],
[33, 34]]])
in:
arr[[0,1,2],[1,2,0],[0,1,1]]
out:
array([38, 17, 21])
所提取元素位置为:(0,1,0),(1,2,1),(2,0,1)
1.1.4数组转置和转换
转置是一种特殊的数据重组形式,可以返回底层数据的视图而不需要复制任何内容。数组拥有transpose方法,也有特殊的T属性:
in:
arr = np.arange(15).reshape((3,5))
arr
out:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
in:
arr.T
out:
array([[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]])
当计算矩阵内积时会用到np.dot
in:
np.dot(arr.T,arr)
out:
array([[125, 140, 155, 170, 185],
[140, 158, 176, 194, 212],
[155, 176, 197, 218, 239],
[170, 194, 218, 242, 266],
[185, 212, 239, 266, 293]])
对于更高维度的数组,transpose方法可以接收包含轴编号的元组,用于置换轴
in:
arr = np.random.randint(10,20,(3,4,4))
arr
out:
array([[[12, 13, 19, 11],
[19, 11, 14, 10],
[17, 13, 10, 13],
[11, 19, 11, 13]],
[[14, 14, 12, 18],
[16, 14, 15, 18],
[19, 16, 11, 12],
[18, 15, 12, 11]],
[[16, 14, 12, 16],
[16, 13, 18, 15],
[14, 15, 10, 19],
[18, 15, 10, 10]]])
in:
arr.transpose((1,0,2))
out:
array([[[12, 13, 19, 11],
[14, 14, 12, 18],
[16, 14, 12, 16]],
[[19, 11, 14, 10],
[16, 14, 15, 18],
[16, 13, 18, 15]],
[[17, 13, 10, 13],
[19, 16, 11, 12],
[14, 15, 10, 19]],
[[11, 19, 11, 13],
[18, 15, 12, 11],
[18, 15, 10, 10]]])
使用 numpy.transpose ()进行变换,其实就是交换了坐标轴,如:arr.transpose(1,0,2),其实就是将arr第二维度挪到第一维上,第一维移到第二维上,第三维不动
具体来看,比如原数组中的(0,1,0)元素19,经过transpose(1,0,2)变换以后,位置为(1,0,0)
又比如
in:
arr.transpose((2,0,1))
out:
array([[[12, 19, 17, 11],
[14, 16, 19, 18],
[16, 16, 14, 18]],
[[13, 11, 13, 19],
[14, 14, 16, 15],
[14, 13, 15, 15]],
[[19, 14, 10, 11],
[12, 15, 11, 12],
[12, 18, 10, 10]],
[[11, 10, 13, 13],
[18, 18, 12, 11],
[16, 15, 19, 10]]])
原来(1,0,0)的元素14,经过transpose(2,0,1)后,位置为(0,1,0)
原来(1,2,3)的元素12,经过transpose(2,0,1)后,位置为(3,1,2)
ndarray有一个swapaxes方法,该方法接收一对轴编号作为参数,并对轴进行调整用于重组数据
该方法返回的是数据的视图,而没有对数据进行复制。其实内含思想也是同transpose,对数据的位置轴进行变动
2.1通用函数:快速的逐元素数组函数
通用函数,也可以成为ufunc,是一种在ndarray数据中进行逐元素操作的函数。
有一些是一元通用函数,比如:sqrt和exp
in:
arr = np.arange(10)
arr
out:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
in:
np.sqrt(arr)
np.exp(arr)
out:
array([0. , 1. , 1.41421356, 1.73205081, 2. ,
2.23606798, 2.44948974, 2.64575131, 2.82842712, 3. ])
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函数和maximum函数,可以接收两个数组并返回一个数组作为结果,因此称为二元通用函数
in:
x = np.random.randn(8)
x
out:
array([-0.39034926, -0.34423708, -0.25188629, 0.10196532, 1.34835458,
-1.64449736, 0.95792044, 1.19094318])
in:
y = np.random.randn(8)
y
out:
array([ 0.19414313, -0.42147069, 2.32430213, -0.00970313, -0.64480793,
-0.80754999, -0.31132155, 0.43763349])
in:
np.maximum(x,y)
out:
np.maximum(x,y)
1
np.maximum(x,y)
array([ 0.19414313, -0.34423708, 2.32430213, 0.10196532, 1.34835458,
-0.80754999, 0.95792044, 1.19094318])
也有一些通用函数返回多个数组,比如modf,是Python内建函数divmod的向量化版本,返回一个浮点值数组的小数部分和整数部分。
in:
arr = np.random.randn(6)*5
arr
out:
array([ 3.64870412, -1.35675755, 3.25894282, -2.26235885, 6.93745003,
2.72651166])
in:
remainder,whole_part = np.modf(arr)
remainder
out:
remainder
1
remainder
array([ 0.64870412, -0.35675755, 0.25894282, -0.26235885, 0.93745003,
0.72651166])
in:
whole_part
out:
array([ 3., -1., 3., -2., 6., 2.])
2.3
2.3.1将条件逻辑作为数组操作
numpy.where函数是三元表达式x if condition else y的向量化版本。
in:
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])
result = [(x if c else y) for x,y,c in zip(xarr,yarr,cond)]
result
out:
[1.1, 2.2, 1.3, 1.4, 2.5]
这样做的缺点:如果数组很大,运行速度很慢。其次,数组是多维时,就无法使用该方法
我们可以使用np.where
in:
result = np.where(cond,xarr,yarr)
result
out:
array([1.1, 2.2, 1.3, 1.4, 2.5])
np.where中第二个和第三个参数并不需要是数组,它们可以是标量。where在数据分析中的一个典型用法是根据一个数组来生成一个新的数组。比如有一个随机生成的矩阵,想将其中的正数都换成2,负数都换成-2,可以使用np.where
arr = np.random.randn(4,4)
arr
Out[43]:
array([[ 1.30315488, -0.22223176, 0.54369484, -0.88955594], [ 0.34442376, 0.41744182, -1.1753601 , -0.74890968], [ 0.51194144, 1.14262409, 0.32093189, -0.68170886], [-0.3892433 , -0.78697111, 0.18882084, 0.80510885]])
In [44]:
arr = np.where(arr>0,2,-2)
arr
Out[44]:
array([[ 2, -2, 2, -2], [ 2, 2, -2, -2], [ 2, 2, 2, -2], [-2, -2, 2, 2]])
In [45]:
arr>0 Out [45]:
array([[ True, False, True, False], [ True, True, False, False], [ True, True, True, False], [False, False, True, True]])
传递给np.where的数组既可以是同等大小的数组,也可以是标量
2.3.2数学和统计方法
基础数组统计方法
布尔值数组:1(True),0(False)。对于布尔值数组,有两个非常有用的方法any和all。any检查数组中是否至少有一个True,all检查是否每个值都是True。这些方法也适用于非布尔值数组,所有的非0元素都会按True处理
排序:
Numpy数组可以使用sort方法按位置排序
arr = np.random.randint(0,10,6)
arr
Out[51]:
array([6, 7, 4, 1, 2, 9])
In [53]:
arr.sort() arr
Out[53]:
array([1, 2, 4, 6, 7, 9])
可以在多维数组中根据传递的axis值,沿着轴向对每个一维数据段进行排序
关于python的sort函数详解,参考:
数组的集合操作:
2.4Numpy中的线性代数函数
常用的numpy.linalg函数
2.5伪随机数生成
numpy.random中的部分函数
2.6示例:随机漫步
首先用python内建random模块进行一个简单的随机漫步
从0开始,步进为1或-1,且两种步进发生的概率相等。注意,random.randint是包含边界的
in:
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)
将上述随机漫步的前100步用matplotlib进行可视化
注意,在导入matplotlib时,不要漏掉.pyplot
in:
import matplotlib.pyplot as plt
plt.plot(walk[:100])
也可以一次性模拟多次随机漫步,比如5000步
in:
nw = 5000
ns = 1000
draws = np.random.randint(0,2,size = (nw,ns))
#draws
steps = np.where(draws>0,1,-1)
walks = steps.cumsum(1)
walks
out:
array([[ 1, 0, 1, ..., -16, -17, -18],
[ -1, -2, -1, ..., -38, -39, -38],
[ 1, 2, 3, ..., 40, 41, 42],
...,
[ -1, 0, -1, ..., -64, -65, -64],
[ 1, 0, 1, ..., 2, 1, 2],
[ 1, 2, 1, ..., 36, 37, 38]], dtype=int32)
一下子就生成了5000个随机漫步。walks中的每一行都是一个总步数为1000的一个随机漫步,一共有5000行
in:
#随机步的最大值
walks.max()
out:
127
in:
#随机步的最小值
walks.min()
out:
-124