NumPy是什么?
NumPy
的全称叫 Numerical Python
,它是 Python
科学计算最重要的基础包之一。很多提供科学计算的包都是基于 NumPy
之上建立的,著名的 pandas
也是。
NumPy
核心的数据结构叫 ND array
,也就是多维数组。和 Python
里的列表有点相似,但又不一样。NumPy
的多维数组比 Python
的列表更高效,因为它底层是用C语言编写的。
NumPy
在数据分析领域是一个热门工具,它可以用于数据整理、清洗、过滤、排序、转换和计算。NumPy
的数据类型需要统一,所以在进行大规模数学运算时它的执行效率会非常高。在做数据分析时,通常会对数值型和布尔型数据进行操作。如果数组中既有文本又有数字就不能进行算数运算了,而且NumPy
也会将整个数组的数据类型变成 object
。
学习 NumPy
最重要掌握向量化、广播和通用函数。这些内容本文都会讲到。
安装并使用NumPy
安装 NumPy
使用以下命令安装 NumPy
pip install numpy
引入 NumPy
在使用 NumPy
之前,要先引入它。
import numpy as np
创建数组
手动传值
NumPy
的核心数据结构是多维数组,要创建数组可以用 array
方法。
array
函数能接收任意序列型的对象,然后生成一个包含传入数据的 NumPy
数组。
# 一维数组
arr = np.array([1, 2, 3])
# 二维数组
arr = np.array([[1, 2, 3],
[4, 5, 6]])
多少维数组,数左边的方括号数量就知道了。
你也可以这么写。
代码语言:javascript复制data = [1, 2, 3]
arr = np.array(data)
除了上面这种手动传入值的方法,还可以用 NumPy
提供的方法创建特殊数组。
zeros: 全0数组
创建元素全为0的数组,可以用 zeros
方法
arr = np.zeros(6)
print(arr) # 输出:array([0., 0., 0., 0., 0., 0.])
如果你需要创建多维数组,且值全为0,可以这么做:
代码语言:javascript复制np.zeros((行数, 列数))
需要注意,此时 zeros
后面跟着2层括号。
arr = np.zeros((3, 4))
print(arr)
```
输出:
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
```
ones: 全1数组
创建元素全为1的数组,可以用 ones
方法
arr = np.ones(6)
print(arr) # 输出:array([1., 1., 1., 1., 1., 1.])
要使用 ones
创建多维数组,且值全为1,和 zeros
创建多维数组的语法是一样的。
np.ones((行数, 列数))
需要注意,在使用 zeros
和 ones
方法创建数组时,所有元素都是有小数点的,创建出来的元素都是浮点数。
empty: 空值数组
创建空值数组,可以使用 empty
方法
语法如下:
代码语言:javascript复制# 一维
np.empty(元素个数)
# 多维
np.empyt((行数, 列数))
arange: 范围数组
arange
是 NumPy
提供的一种快速创建数组的方法,它和 Python
的 range
有点像。
语法如下:
代码语言:javascript复制np.arange(起始值, 结束值, 步长)
举个例子,创建一个0~10,步长为2的数组。
代码语言:javascript复制arr = np.arange(0, 10, 2)
print(arr) # 输出:array([0, 2, 4, 6, 8])
arange
创建的数组是不包含结束值的。
如果你只传1个值也行,那数组的值会从0开始,到你指定的值结束(不包含指定值)。比如:
代码语言:javascript复制arr = np.arange(10)
print(arr) # 输出:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
随机数多维数组
使用 np.random.randn(行数, 列数)
可以创建一个指定行数和列数,元素值为随机数的数组。
比如生成一个2行3列,值为随机数的数组。
代码语言:javascript复制arr = np.random.randn(2, 3)
print(arr)
```
输出:
array([[-1.40881835, 0.13351722, -1.46305705],
[-0.1046862 , 0.63644499, 0.4796577 ]])
```
访问数组元素
数字索引
访问 NumPy
数组元素的方法和 Python
访问列表元素的方法一样,都是使用“方括号”和“下标”进行访问。下标从0开始。
arr = np.array([1, 2, 3])
print(arr[1]) # 输出:2
如果要访问二维数组的某个元素,可以这样写:
代码语言:javascript复制arr = np.array([[10, 2, 3, 40],
[50, 60, 7, 8]])
print(arr[0][3]) # 输出:40
访问多维数组也是同样原理。
NumPy
也支持切片的方式访问,切片需要传入一个起始索引(包含自身)和一个结束索引(不包含自身),两个索引之间用一个冒号分隔。
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
print(arr[1:4]) # 输出:[2 3 4]
多维数组的切片方法:
代码语言:javascript复制arr = np.array([[10, 2, 3, 40],
[50, 60, 7, 8]])
print(arr[1:2, 1:2]) # 输出:60
既然能获取,那就能修改。
代码语言:javascript复制arr = np.array([1, 2, 3, 4])
arr[0] = 100
print(arr) # 输出:[100 2 3 4]
通过切片的方式获取到的元素,修改值时也会影响原数组的值。
布尔型索引
NumPy
的数组还支持布尔型索引。
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([True, False, True, False, False])
print(arr1[arr2]) # 输出:[1 3]
布尔型索引的相关应用稍后会讲到。
向量化和广播
向量化和广播都是在解决“遍历”问题。
比如你需要让数组的每个元素值增加1,你可以直接用数组 1,不需要手动一个个元素进行遍历。这叫向量化。
NumPy
会将标量值传播到数组的各个元素。标量指的是一种数据类型,比如浮点型和字符串。
arr = np.array([[1, 2, 3, 4],
[5, 6, 7, 8]])
print(arr 1)
```
输出:
[[2 3 4 5]
[6 7 8 9]]
```
在处理两个形状相同的数组也是同样道理。
代码语言:javascript复制arr1 = np.array([[1, 2, 3, 4],
[5, 6, 7, 8]])
arr2 = np.array([[10, 20, 30, 40],
[50, 60, 70, 80]])
print(arr1 arr2)
```
输出:
[[11 22 33 44]
[55 66 77 88]]
```
如果大小相同的数组做比较的话,会生成一个布尔值数组。
代码语言:javascript复制arr1 = np.array([[1, 20, 30, 4],
[5, 6, 70, 80]])
arr2 = np.array([[10, 2, 3, 40],
[50, 60, 7, 8]])
print(arr1 > arr2)
```
输出:
[[False True True False]
[False False True True]]
```
如果两个数组的形状不一样,NumPy
会自动将较小的数组扩展成较大数组的形状,这叫广播。
arr1 = np.array([10, 20, 30, 40])
arr2 = np.array([[10, 2, 3, 40],
[50, 60, 7, 8]])
print(arr1 arr2)
```
输出:
[[20 22 33 80]
[60 80 37 48]]
```
常用方法
接下来会讲一些 NumPy
的常用方法,包含大家说的“通用函数”。
ndim: 获取数组维度
前面提到可以通过数方括号的方式知道数组的维度,除此之外,NumPy
也提供了一个 ndim
属性可以获取数组维度。
arr1 = np.array([1, 2, 3])
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr1.ndim) # 输出:1
print(arr2.ndim) # 输出:2
shape: 获取各个维度的元素的个数
使用 shape
可以获取数组各个维度的元素个数,并以元组的方式放回。
arr1 = np.array([1, 2, 3])
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr1.shape) # 输出:(3,)。只有1个数值,表示arr1只有1个维度,第1维度有3个元素。
print(arr2.shape) # 输出:(2, 3)。有2个数值,表示arr2有2个维度,第一个维度有2个元素,第2个维度有3个元素。
size: 获取数组元素的总数
只要不是九漏鱼应该都知道 size
这个单词的意思。
arr1 = np.array([1, 2, 3])
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr1.size) # 输出:3
print(arr2.size) # 输出:6
dtype: 返回数组元素的类型
使用 dtype
可以获取数组元素的数据类型。
arr1 = np.array([1., 2., 3.])
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
arr3 = np.array([True, False])
print(arr1.dtype) # 输出:float64
print(arr2.dtype) # 输出:int32
print(arr3.dtype) # 输出:bool
max(): 求最大值
使用 max()
方法可以求出数组元素的最大值,多维数组也可以。
arr1 = np.array([1., 2., 3.])
arr2 = np.array([[10, 20, 30], [4, 5, 6]])
print(arr1.max()) # 输出:3.0
print(arr2.max()) # 输出:30
min(): 求最小值
代码语言:javascript复制arr1 = np.array([1., 2., 3.])
arr2 = np.array([[10, 20, 30], [4, 5, 6]])
print(arr1.min()) # 输出:1.0
print(arr2.min()) # 输出:4
mean(): 求平均值
代码语言:javascript复制arr1 = np.array([1., 2., 3.])
arr2 = np.array([[10, 20, 30], [4, 5, 6]])
print(arr1.mean()) # 输出:2.0
print(arr2.mean()) # 输出:12.5
sum(): 求和
代码语言:javascript复制arr1 = np.array([1., 2., 3.])
arr2 = np.array([[10, 20, 30], [4, 5, 6]])
print(arr1.sum()) # 输出:6.0
print(arr2.sum()) # 输出:75
sort(): 排序
代码语言:javascript复制
NumPy
提供了一个排序方法,用的时候需要 np.sort(数组)
这样用。
arr = np.array([10, 4, 2, 11, 3])
print(np.sort(arr)) # 输出:[ 2 3 4 10 11]
print(arr) # 输出:[10 4 2 11 3]
sorted(): 排序,Python内置方法
使用 sorted()
方法可以对数组进行排序,而且不会改变原数组。sorted()
是 Python
内置的排序方法。
arr = np.array([10, 4, 2, 11, 3])
print(sorted(arr)) # 输出:[2, 3, 4, 10, 11]
print(arr) # 输出: [10 4 2 11 3]
sorted()
方法第一个参数接收一个数组,默认是从小到大排序。
如果想从大到小排序,可以将 reverse
参数设置为 True
。
arr = np.array([10, 4, 2, 11, 3])
print(sorted(arr, reverse=True)) # 输出:[11, 10, 4, 3, 2]
条件筛选
假如需要返回大于10的元素,可以这样写。
代码语言:javascript复制arr = np.array([10, 40, 2, 11, 3])
print(arr > 10) # 输出:[False True False True False]
此时会返回一个布尔类型的数组,我们再将这个数组用前面提到的“布尔型索引”方法就能获取到大于10的元素了。
代码语言:javascript复制arr = np.array([10, 40, 2, 11, 3])
print(arr[arr > 10]) # 输出:[40 11]
如果有多个筛选条件,我们需要使用 &(与)
和 |(或)
,不能用 Python
关键字 and
和 or
。
比如我们要筛选出大于10且小于20的值,可以这样写:
代码语言:javascript复制arr = np.array([10, 40, 2, 11, 3])
print(arr[(arr > 10) & (arr < 20)]) # 输出:[11]
T: 轴对换
如果我们想将一个2行3列的数组变成3行2列,可以这样写:
代码语言:javascript复制arr = np.array([[10, 20, 30],
[303, 202, 101]])
arr.T
```
返回:
array([[ 10, 303],
[ 20, 202],
[ 30, 101]])
```