Numpy,是Numerical Python 的简称,它是目前Python数值计算中最为重要的基础包。
虽然 numpy 提供了数值数据操作的计算基础,但大多数读者还是想把 pandas 作为统计分析的基石,尤其是针对表格数据。
pandas提供了更多的针对特定场景的函数功能,例如时间序列操作等numpy等并不包含的功能。
numpy之所以如此重要,其中一个原因就是它的设计对于含有大量数组的数据非常有效。
Numpy的核心特征之一就是N-维数组对象——ndarray.
有两种方法可以生成 ndarray :
a = [6,7.5,4,8,9]
s = np.array(a)
s = array([6. , 7.5, 4. , 8. , 9. ])
a = np.array([6,7.5,4,8,9])
a = array([6. , 7.5, 4. , 8. , 9. ])
可以通过 zeros 一次性创造一个全0数组,ones 可以一次性创造一个全1数组,empty 可以创建一个没有初始化数值的数组
np.empty((2,3,2))
# array([[[1.38888748e-311, 3.16202013e-322],
[0.00000000e+000, 0.00000000e+000],
[8.45593933e-307, 1.40438095e+165]],
[[9.23500886e-071, 6.27832385e+174],
[3.31411587e-033, 7.49695553e-067],
[6.95634324e-042, 1.04890625e-042]]])
使用np.empty 来生成一个全0数组,并不安全,有时候它会返回未初始化的垃圾数值
a = np.arange(1,10)
# a = array([1, 2, 3, 4, 5, 6, 7, 8, 9])
如果没有特别指定,numpy生成的都是float类型
如果需要转换,则需用到 dtype 类型
可以用dtype 对数组内容进行转换
a = np.array([1.2,3,4,6.5],dtype = int)
# a = array([1, 3, 4, 6])
也可以用astype对数据类型进行转换
a = np.array([1.2,3,4,6.5])
b = a.astype(int)
# b = array([1, 3, 4, 6])
对于astype来说,每次总是生成一个新的数组
a
# a = array([1.2, 3. , 4. , 6.5]) a的值是不变的,所以需要用一个值来接收
数组之所以如此重要是因为它允许你进行批量操作而无需任何for循环,numpy用户称这种特征为向量化
例如:
a = array([1.2, 3. , 4. , 6.5])
a*a
# array([ 1.44, 9. , 16. , 42.25])
a+a
# array([ 2.4, 6. , 8. , 13. ])
对于不同尺寸的数组间操作会用到广播特性,对于本书来说,并不需要深入理解广播特性
a = np.arange(10)
# a = array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
a[3]
# 3
a[5:8]
# array([5, 6, 7])
a[5:8]=12
a
# array([ 0, 1, 2, 3, 4, 12, 12, 12, 8, 9])
如你所见,如果传入了一个数值给数组的切片,例如 a[5:8] = 12 ,数值被传递给了整个切片,区别于Python的内建列表,数组的切片是原数组的视图,这意味着数组不是被复制了,任何对于视图的修改都会反映到原数组上
如果你还是想要一份数组的切片拷贝而不是一份视图的话,你就必须显式地复制这个数组,例如:
a[5:8].copy()
# array([12, 12, 12])
b =a[5:8].copy()
b[1] =10
# b = array([12, 10, 12])
这一章是书中没有的(书中讲的是神奇索引),但是感觉花式索引用得更多些,神奇索引使用的是整数数组进行数据索引
普通索引就不会有括号(也就是index)的出现
a = np.array([[1,2,3,4],[5,6,7,8]])
a[1,3] # 8
a[0,3:5]
a[4:,4:]
....
花式索引则不然:
a = np.array([[0,1,2,3,4,5],[10,11,12,13,14,15],[20,21,22,23,24,25],
b = a[3:,(0,2,4)]
# b = array([[30, 32, 34],
# [40, 42, 44],
# [50, 52, 54]])
最直白的展示就是多了个(index)
转置是一种特殊的数据重组形式,可以返回底层数据的视图而不需要复制任何内容。数组拥有 transpose 方法,也有特殊的T属性。
a = np.arange(15).reshape((3,5))
'''
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
'''
a.T
'''
array([[ 0, 5, 10],
[ 1, 6, 11],
[ 2, 7, 12],
[ 3, 8, 13],
[ 4, 9, 14]])
'''
当进行矩阵计算时,当计算矩阵内积时会使用 np.dot:
b = np.random.randn(6,3)
np.dot(b.T,b)
'''
array([[ 4.25461861, -1.21334502, -0.17279715],
[-1.21334502, 9.36874022, 1.81220759],
[-0.17279715, 1.81220759, 8.23414671]])
'''
a.T 方法针对的是二元数组
对于更高维的数组,transpose 方法可以接收包含轴编号的元组,用于置换轴:
a = np.arange(16).reshape((2,2,4))
'''
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]])
'''
a.transpose((1,0,2))
'''
array([[[ 0, 1, 2, 3],
[ 8, 9, 10, 11]],
[[ 4, 5, 6, 7],
[12, 13, 14, 15]]])
'''
具体解读如下:
transpose 的默认参数为 transpose((0,1,2))
数组a中10的坐标为a(1,0,3),经过transpose(1,0,2)转置后的数组b中的10的坐标为b(0,1,3)。原始的transpose参数(默认的参数)为(0,1,2),这个转置相当于将第一个坐标与第二坐标进行了互换。
第1列和最后一列不变是因为
数组a中12的坐标为a(1,1,0),经过transpose(1,0,2)转置后,前两个坐标依然不变所以列数也没有发生改变
通用函数,也可以称为 ufunc ,是一种在 ndarray 数据中进行逐元素操作的函数。某些简单函数接收一个或多个标量值,并产生一个或多个标量化结果,而通用函数就是对这些简单函数的向量化封装。
a = np.arange(5,15)
# a = array([ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
# 开方
np.sqrt(a)
# array([2.23606798, 2.44948974, 2.64575131, 2.82842712, 3. ,
# 3.16227766, 3.31662479, 3.46410162, 3.60555128, 3.74165739])
# 取指数
np.exp(a)
'''
array([1.48413159e+02, 4.03428793e+02, 1.09663316e+03, 2.98095799e+03,
8.10308393e+03, 2.20264658e+04, 5.98741417e+04, 1.62754791e+05,
4.42413392e+05, 1.20260428e+06])
'''
add 和 maximum 会接收2个数组并返回一个数组作为结果,因此称为2元通用函数:
x = np.random.randn(8)
y = np.random.rand(8)
x
'''
array([ 0.14768468, -0.00975376, -1.59685431, -0.63764595, 0.17355362,
-0.98002598, -0.35293618, 0.78962007])
'''
y
'''
array([0.7789983 , 0.78713238, 0.73497334, 0.16070788, 0.15408434,
0.60220624, 0.7037659 , 0.7828968 ])
'''
b = np.add(x,y)
'''
array([ 0.92668298, 0.77737861, -0.86188097, -0.47693807, 0.32763796,
-0.37781974, 0.35082972, 1.57251687])
'''
c = np.maximum(x,y)
'''
array([0.7789983 , 0.78713238, 0.73497334, 0.16070788, 0.17355362,
0.60220624, 0.7037659 , 0.78962007])
'''
在这里,maximum 逐元素地返回 x,y 中最大的部分
也有一些通用函数返回多个数组。比如 modf ,是Python 内建函数 divmod 的向量化版本。它返回了一个浮点值数组的小数部分和整数部分。
a = np.random.randn(5)*5
'''
array([ 9.36107465, 1.7961582 , -3.17566554, 4.81236975, -0.13687402])
'''
a_float,a_int = np.modf(a)
# 接受a的整数部分
a_float
# array([ 0.36107465, 0.7961582 , -0.17566554, 0.81236975, -0.13687402])
# 接受a的整数部分
a_int
# array([ 9., 1., -3., 4., -0.])
a = np.random.randn(4,4)
'''
array([[ 0.12189457, -0.40249024, 1.65568387, -0.68654571],
[ 0.89665272, -0.7631721 , -1.68733328, -0.80300382],
[ 0.47949779, 0.63397883, -0.38847957, -0.7401223 ],
[ 0.49368914, -2.12027668, 0.32092666, -1.07166121]])
'''
a > 0
'''
array([[ True, False, True, False],
[ True, False, False, False],
[ True, True, False, False],
[ True, False, True, False]])
'''
# 将True值替换为2,False值替换为-2
np.where(a>0,2,-2)
'''
array([[ 2, -2, 2, -2],
[ 2, -2, -2, -2],
[ 2, 2, -2, -2],
[ 2, -2, 2, -2]])
'''
# 将True值替换为2,False值保留不动
np.where(a>0,2,a)
'''
array([[ 2. , -0.40249024, 2. , -0.68654571],
[ 2. , -0.7631721 , -1.68733328, -0.80300382],
[ 2. , 2. , -0.38847957, -0.7401223 ],
[ 2. , -2.12027668, 2. , -1.07166121]])
'''
算均值、算求和
a = np.arange(12).reshape(4,3)
'''
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
'''
np.mean(a)
# a.mean()
# 5.5
a.sum()
# 66
sum 求和
cumsum 求累积和
cumprod 求累积积
cumsum 和 cumprod 的结果并不会聚合,它们会产生一个中间结果
a = np.array([1,2,3,4,5,6])
a.sum()
# 21
a.cumsum()
# array([ 1, 3, 6, 10, 15, 21], dtype=int32)
a.cumprod()
# array([ 1, 2, 6, 24, 120, 720], dtype=int32)
bools = np.array([-1,0,3,0,2,0,-5],dtype = bool)
# bools = array([ True, False, True, False, True, False, True])
bools.any()
# True
bools.all()
# False
any 检查数组中是否至少有一个True,而 all 检查是否每个值都为 True
常用的方法是 np.unique ,返回的是数组中唯一值排序后形成的数组:
names = np.array(["Bob","Joe","Will","Bob","Will","Bob","Joe","Joe"])
np.unique(names)
# array(['Bob', 'Joe', 'Will'], dtype='
# 将np.unique 和 纯 python 进行比较
sorted(set(names))
# ['Bob', 'Joe', 'Will']
ints = np.array([3,3,3,4,1,2,3,4,5,3,2])
np.unique(ints)
# array([1, 2, 3, 4, 5])
unique(x) 计算 x 的唯一值,并排序
x = np.array([[1.,2.,3.],[4.,3.,6.]])
y = np.array([[6.,23.],[4.,2.],[7.,4.]])
x
'''
array([[1., 2., 3.],
[4., 3., 6.]])
'''
y
'''
array([[ 6., 23.],
[ 4., 2.],
[ 7., 4.]])
'''
x.dot(y)
'''
array([[ 35., 39.],
[ 78., 122.]])
'''
np.dot(x,y)
'''
array([[ 35., 39.],
[ 78., 122.]])
'''
可以通过 np.random.seed 更改 numpy 的随机数种子
np.random.seed(24)