Numpy是一个开源的Python科学计算库,用于快速处理任意维度的数组。Numpy支持常见的数组和矩阵操作,对于同样的数值计算任务,使用NumPy不仅代码要简洁的多,而且NumPy的性能远远优于原生Python,基本是一个到两个数量级的差距,而且数据量越大,NumPy的优势就越明显。
Numpy最为核心的数据类型是ndarray
,使用ndarray
可以处理一维、二维和多维数组,该对象相当于是一个快速而灵活的大数据容器。NumPy底层代码使用C语言编写,解决了GIL的限制,ndarray
在存储数据的时候,数据与数据的地址都是连续的,这样就给使得批量操作速度很快,远远优于Python中的list
;另一方面ndarray
对象提供了更多的方法来处理数据,尤其是和统计相关的方法,这些方法也是Python原生的list
没有的。
-
启动Notebook
jupyter notebook
提示:在启动Notebook之前,建议先安装好数据分析相关依赖项,包括之前提到的三大神器以及相关依赖项,包括:
numpy
、pandas
、matplotlib
、openpyxl
、xlrd
、xlwt
等。如果使用Anaconda,则无需单独安装。 -
导入
import numpy as np import pandas as pd import matplotlib.pyplot as plt
说明:如果已经启动了Notebook但尚未安装相关依赖库,例如NumPy,可以在Notebook的单元格中输入
!pip install numpy
并运行该单元格来安装NumPy,其他库如法炮制。安装成功后选择“Kernel”(服务)菜单的“Restart”(重启)选项来重启Notebook内核(前面有讲到重启的快捷键)来使新安装的库生效。上面我们不仅导入了NumPy,还将pandas和matplotlib库一并导入了。
创建ndarray
对象有很多种方法,下面就如何创建一维数组、二维数组和多维数组进行说明。
-
方法一:使用
array
函数,通过list
创建数组对象代码:
array1 = np.array([1, 2, 3, 4, 5]) array1
输出:
array([1, 2, 3, 4, 5])
-
方法二:使用
arange
函数,指定取值范围创建数组对象代码:
array2 = np.arange(0, 20, 2) array2
输出:
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])
-
方法三:使用
linspace
函数,用指定范围均匀间隔的数字创建数组对象代码:
array3 = np.linspace(-5, 5, 101) array3
输出:
array([-5. , -4.9, -4.8, -4.7, -4.6, -4.5, -4.4, -4.3, -4.2, -4.1, -4. , -3.9, -3.8, -3.7, -3.6, -3.5, -3.4, -3.3, -3.2, -3.1, -3. , -2.9, -2.8, -2.7, -2.6, -2.5, -2.4, -2.3, -2.2, -2.1, -2. , -1.9, -1.8, -1.7, -1.6, -1.5, -1.4, -1.3, -1.2, -1.1, -1. , -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1, 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. , 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3. , 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4. , 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5. ])
-
方法四:使用
numpy.random
模块的函数生成随机数创建数组对象产生10个$[0, 1)$范围的随机小数,代码:
array4 = np.random.rand(10) array4
输出:
array([0.45556132, 0.67871326, 0.4552213 , 0.96671509, 0.44086463, 0.72650875, 0.79877188, 0.12153022, 0.24762739, 0.6669852 ])
产生10个$[1, 100)$范围的随机整数,代码:
array5 = np.random.randint(1, 101, 10) array5
输出:
array([29, 97, 87, 47, 39, 19, 71, 32, 79, 34])
产生20个$\mu=50$,$\sigma=10$的正态分布随机数,代码:
array6 = np.random.normal(50, 10, 20) array6
输出:
array([55.04155586, 46.43510797, 20.28371158, 62.67884053, 61.23185964, 38.22682148, 53.17126151, 43.54741592, 36.11268017, 40.94086676, 63.27911699, 46.92688903, 37.1593374 , 67.06525656, 67.47269463, 23.37925889, 31.45312239, 48.34532466, 55.09180924, 47.95702787])
-
方法一:使用
array
函数,通过嵌套的list
创建数组对象代码:
array7 = np.array([[1, 2, 3], [4, 5, 6]]) array7
输出:
array([[1, 2, 3], [4, 5, 6]])
-
方法二:使用
zeros
、ones
、full
函数指定数组的形状创建数组对象使用
zeros
函数,代码:array8 = np.zeros((3, 4)) array8
输出:
array([[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]])
使用
ones
函数,代码:array9 = np.ones((3, 4)) array9
输出:
array([[1., 1., 1., 1.], [1., 1., 1., 1.], [1., 1., 1., 1.]])
使用
full
函数,代码:array10 = np.full((3, 4), 10) array10
输出:
array([[10, 10, 10, 10], [10, 10, 10, 10], [10, 10, 10, 10]])
-
方法三:使用eye函数创建单位矩阵
代码:
array11 = np.eye(4) array11
输出:
array([[1., 0., 0., 0.], [0., 1., 0., 0.], [0., 0., 1., 0.], [0., 0., 0., 1.]])
-
方法四:通过
reshape
将一维数组变成二维数组代码:
array12 = np.array([1, 2, 3, 4, 5, 6]).reshape(2, 3) array12
输出:
array([[1, 2, 3], [4, 5, 6]])
提示:
reshape
是ndarray
对象的一个方法,使用reshape
方法时需要确保调形后的数组元素个数与调形前数组元素个数保持一致,否则将会产生异常。 -
方法五:通过
numpy.random
模块的函数生成随机数创建数组对象产生$[0, 1)$范围的随机小数构成的3行4列的二维数组,代码:
array13 = np.random.rand(3, 4) array13
输出:
array([[0.54017809, 0.46797771, 0.78291445, 0.79501326], [0.93973783, 0.21434806, 0.03592874, 0.88838892], [0.84130479, 0.3566601 , 0.99935473, 0.26353598]])
产生$[1, 100)$范围的随机整数构成的3行4列的二维数组,代码:
array14 = np.random.randint(1, 100, (3, 4)) array14
输出:
array([[83, 30, 64, 53], [39, 92, 53, 43], [43, 48, 91, 72]])
-
使用随机的方式创建多维数组
代码:
array15 = np.random.randint(1, 100, (3, 4, 5)) array15
输出:
array([[[94, 26, 49, 24, 43], [27, 27, 33, 98, 33], [13, 73, 6, 1, 77], [54, 32, 51, 86, 59]], [[62, 75, 62, 29, 87], [90, 26, 6, 79, 41], [31, 15, 32, 56, 64], [37, 84, 61, 71, 71]], [[45, 24, 78, 77, 41], [75, 37, 4, 74, 93], [ 1, 36, 36, 60, 43], [23, 84, 44, 89, 79]]])
-
将一维二维的数组调形为多维数组
一维数组调形为多维数组,代码:
array16 = np.arange(1, 25).reshape((2, 3, 4)) array16
输出:
array([[[ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12]], [[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]])
二维数组调形为多维数组,代码:
array17 = np.random.randint(1, 100, (4, 6)).reshape((4, 3, 2)) array17
输出:
array([[[60, 59], [31, 80], [54, 91]], [[67, 4], [ 4, 59], [47, 49]], [[16, 4], [ 5, 71], [80, 53]], [[38, 49], [70, 5], [76, 80]]])
-
读取图片获得对应的三维数组
代码:
array18 = plt.imread('guido.jpg')
array18 ```
输出:
```
array([[[ 36, 33, 28],
[ 36, 33, 28],
[ 36, 33, 28],
...,
[ 32, 31, 29],
[ 32, 31, 27],
[ 31, 32, 26]],
[[ 37, 34, 29],
[ 38, 35, 30],
[ 38, 35, 30],
...,
[ 31, 30, 28],
[ 31, 30, 26],
[ 30, 31, 25]],
[[ 38, 35, 30],
[ 38, 35, 30],
[ 38, 35, 30],
...,
[ 30, 29, 27],
[ 30, 29, 25],
[ 29, 30, 25]],
...,
[[239, 178, 123],
[237, 176, 121],
[235, 174, 119],
...,
[ 78, 68, 56],
[ 75, 67, 54],
[ 73, 65, 52]],
[[238, 177, 120],
[236, 175, 118],
[234, 173, 116],
...,
[ 82, 70, 58],
[ 78, 68, 56],
[ 75, 66, 51]],
[[238, 176, 119],
[236, 175, 118],
[234, 173, 116],
...,
[ 84, 70, 61],
[ 81, 69, 57],
[ 79, 67, 53]]], dtype=uint8)
```
> **说明**:上面的代码读取了当前路径下名为`guido.jpg` 的图片文件,计算机系统中的图片通常由若干行若干列的像素点构成,而每个像素点又是由红绿蓝三原色构成的,所以能够用三维数组来表示。读取图片用到了matplotlib库的`imread`函数。
-
size
属性:数组元素个数代码:
array19 = np.arange(1, 100, 2) array20 = np.random.rand(3, 4) print(array19.size, array20.size)
输出:
50 12
-
shape
属性:数组的形状代码:
print(array19.shape, array20.shape)
输出:
(50,) (3, 4)
-
dtype
属性:数组元素的数据类型代码:
print(array19.dtype, array20.dtype)
输出:
int64 float64
ndarray
对象元素的数据类型可以参考如下所示的表格。 -
ndim
属性:数组的维度代码:
print(array19.ndim, array20.ndim)
输出:
1 2
-
itemsize
属性:数组单个元素占用内存空间的字节数代码:
array21 = np.arange(1, 100, 2, dtype=np.int8) print(array19.itemsize, array20.itemsize, array21.itemsize)
输出:
8 8 1
说明:在使用
arange
创建数组对象时,通过dtype
参数指定元素的数据类型。可以看出,np.int8
代表的是8位有符号整数,只占用1个字节的内存空间,取值范围是$[-128,127]$。 -
nbytes
属性:数组所有元素占用内存空间的字节数代码:
print(array19.nbytes, array20.nbytes, array21.nbytes)
输出:
400 96 50
-
flat
属性:数组(一维化之后)元素的迭代器代码:
from typing import Iterable print(isinstance(array20.flat, np.ndarray), isinstance(array20.flat, Iterable))
输出:
False True
-
base属性:数组的基对象(如果数组共享了其他数组的内存空间)
代码:
array22 = array19[:] print(array22.base is array19, array22.base is array21)
输出:
True False
说明:上面的代码用到了数组的切片操作,它类似于Python中
list
类型的切片,但在细节上又不完全相同,下面会专门讲解这个知识点。通过上面的代码可以发现,ndarray
切片后得到的新的数组对象跟原来的数组对象共享了内存中的数据,因此array22
的base
属性就是array19
对应的数组对象。
和Python中的列表类似,NumPy的ndarray
对象可以进行索引和切片操作,通过索引可以获取或修改数组中的元素,通过切片可以取出数组的一部分。
-
索引运算
一维数组,代码:
array23 = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9]) print(array23[0], array23[array23.size - 1]) print(array23[-array23.size], array23[-1])
输出:
1 9 1 9
二维数组,代码:
array24 = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) print(array24[2]) print(array24[0][0], array24[-1][-1]) print(array24[1][1], array24[1, 1])
输出:
[7 8 9] 1 9 5 5 [[ 1 2 3] [ 4 10 6] [ 7 8 9]]
代码:
array24[1][1] = 10 print(array24) array24[1] = [10, 11, 12] print(array24)
输出:
[[ 1 2 3] [ 4 10 6] [ 7 8 9]] [[ 1 2 3] [10 11 12] [ 7 8 9]]
-
切片运算
代码:
print(array24[:2, 1:])
输出:
[[2 3] [5 6]]
代码:
print(array24[2]) print(array24[2, :])
输出:
[7 8 9] [7 8 9]
代码:
print(array24[2:, :])
输出:
[[7 8 9]]
代码:
print(array24[:, :2])
输出:
[[1 2] [4 5] [7 8]]
代码:
print(array24[1, :2])
输出:
[4 5]
代码:
print(array24[1:2, :2])
输出:
[[4 5]]
关于数组的索引和切片运算,大家可以通过下面的两张图来增强印象,这两张图来自《利用Python进行数据分析》一书,它是pandas的作者Wes McKinney撰写的Python数据分析领域的经典教科书,有兴趣的读者可以购买和阅读原书。
ndarray
对象的统计方法主要包括:sum
、mean
、std
、var
、min
、max
、argmin
、argmax
、cumsum
等,分别用于对数组中的元素求和、求平均、求标准差、求方差、找最大、找最小、求累积和等,请参考下面的代码。
array25 = np.array([1, 2, 3, 4, 5, 5, 4, 3, 2, 1])
print(array25.sum())
print(array25.mean())
print(array25.max())
print(array25.min())
print(array25.std())
print(array25.var())
print(array25.cumsum())
输出:
30
3.0
5
1
1.4142135623730951
2.0
[ 1 3 6 10 15 20 24 27 29 30]
####其他方法
-
all()
/any()
方法:判断数组是否所有元素都是True / 判断数组是否有为True的元素。 -
astype()
方法:拷贝数组,并将数组中的元素转换为指定的类型。 -
dot()
方法:实现一个数组和另一个数组的点乘运算。输出:
-
dump()
/load()
方法:保存数组到文件中/从文件中加载数组。输出:
-
fill()
方法。输出:
-
flatten()
方法:将多维数组扁平化为一维数组。输出:
-
nonzero()
方法:返回非0元素的索引。 -
round()
方法:对数组中的元素做四舍五入操作。 -
sort()
方法:对数组进行就地排序。输出:
-
swapaxes()
和transpose()
方法:交换数组指定的轴 -
take()
方法:从数组中取指定索引的元素。 -
tolist()
方法:将数组转成Python中的list
。