简介
NumPy(Numerical Python)是Python的一种开源的数值计算扩展。这种工具可用来存储和处理大型矩阵,比Python自身的嵌套列表(nested list structure)结构要高效的多(该结构也可以用来表示矩阵(matrix)),支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。 -- 百度百科
NumPy 目前已经成为Python中用于科学计算的基础包。
NumPy提供了高性能的向量、矩阵以及多维数据结构及计算方法。
NumPy包的核心是ndarray对象。它封装了与Python原生的数据类型相同的n维数组,其中有许多操作以C语言及Fortran语言编写并编译来实现,从而提供了极佳的性能。
由于NumPy封装了大量的复杂计算方法,因此使代码变得极为简洁、高效。例如,对于两个数组a和b的加法操作,如果用C语言实现,则需要通过两层循环求和,代码如下:
而用NumPy实现,只需要写作:
c = a+b
代码非常简洁、易读,且性能高效。当然,计算机进行c = a + b的数组求和操作,本质上还是由上述C语言的循环方式完成的,只是NumPy已经在内部实现了这些复杂的操作,我们只需引用而已。
使用NumPy前,首先需要安装和导入NumPy。
安装 numpy
除了 NumPy 之外,我们还需要安装matplotlib用于简单的数据可视化。
pip install numpy
pip install matplotlib
import numpy
# 查看numpy版本号
numpy.version.version
'1.18.5'
快速入门
学习目标
-
理解NumPy中一维、二维和n维数组的区别;
-
了解如何在不使用 for 循环的情况下将一些线性代数运算应用于 n 维数组;
-
了解 n 维数组的轴和形状属性。
基础知识
NumPy的主要数据对象是同构多维数组。
它是一个元素表(通常是数字),所有类型都相同,由非负整数元组索引。在 NumPy 中,维度称为轴。
例如,3D 空间中一个点的坐标[1, 2, 1]只有一个轴。该轴有 3 个元素,因此我们说它的长度为 3。
在下图中的示例中,数组有 2 个轴。第一个轴的长度为 2,第二个轴的长度为 3。
# 维度为(2,3)的数组
[[1., 0., 0.],
[0., 1., 2.]]
[[1.0, 0.0, 0.0], [0.0, 1.0, 2.0]]
NumPy中的数组称为ndarray,它的别名是array。
ndarray的属性介绍: * ndarray.ndim 数组的轴数(维度) * ndarray.shape 数组的维度。结果是一个元组。(n,m)表示数组有n行m列。数组中元素总数为n*m. * ndarray.dtype 数组中元素的类型. * ndarray.itemsize 数组每个元素的大小(以字节为单位) * ndarray.data 包含实际元组的缓冲区。
import numpy as np
# 生成数组值范围0-14,维度为3行5列的数组
a = np.arange(15).reshape(3,5)
a
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
# 维度
a.shape
(3, 5)
# 轴数
a.ndim
2
# 元素类型
a.dtype
# a.dtype.name
dtype('int32')
# 每个元素所占字节数
a.itemsize
4
# 数组类型是ndarray
type(a)
numpy.ndarray
# 修改数组维度为5行。3列
a.reshape(5,3)
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11],
[12, 13, 14]])
数组的创建
方法1.使用array函数创建数组。转换Python的列表为ndarrray。
b = np.array([1,2,3])
b
array([1, 2, 3])
c = np.array([1.2,2.4,4.8])
c
array([1.2, 2.4, 4.8])
b.dtype
dtype('int32')
c.dtype
dtype('float64')
#数组也可以指定格式
e = np.array([[1,2],[3,4]],dtype=complex)
e
array([[1.+0.j, 2.+0.j],
[3.+0.j, 4.+0.j]])
# 全零数组
np.zeros((2,3))
array([[0., 0., 0.],
[0., 0., 0.]])
# 全一数组
np.ones((3,2))
array([[1., 1.],
[1., 1.],
[1., 1.]])
# arange() 范围数组
np.arange(10,20,2)
array([10, 12, 14, 16, 18])
np.arange(1,2,0.1)
array([1. , 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9])
# linspace 等分
np.linspace(1,3,7)
array([1. , 1.33333333, 1.66666667, 2. , 2.33333333,
2.66666667, 3. ])
x = np.linspace(0,2*np.pi,100)
x
array([0. , 0.06346652, 0.12693304, 0.19039955, 0.25386607,
0.31733259, 0.38079911, 0.44426563, 0.50773215, 0.57119866,
0.63466518, 0.6981317 , 0.76159822, 0.82506474, 0.88853126,
0.95199777, 1.01546429, 1.07893081, 1.14239733, 1.20586385,
1.26933037, 1.33279688, 1.3962634 , 1.45972992, 1.52319644,
1.58666296, 1.65012947, 1.71359599, 1.77706251, 1.84052903,
1.90399555, 1.96746207, 2.03092858, 2.0943951 , 2.15786162,
2.22132814, 2.28479466, 2.34826118, 2.41172769, 2.47519421,
2.53866073, 2.60212725, 2.66559377, 2.72906028, 2.7925268 ,
2.85599332, 2.91945984, 2.98292636, 3.04639288, 3.10985939,
3.17332591, 3.23679243, 3.30025895, 3.36372547, 3.42719199,
3.4906585 , 3.55412502, 3.61759154, 3.68105806, 3.74452458,
3.8079911 , 3.87145761, 3.93492413, 3.99839065, 4.06185717,
4.12532369, 4.1887902 , 4.25225672, 4.31572324, 4.37918976,
4.44265628, 4.5061228 , 4.56958931, 4.63305583, 4.69652235,
4.75998887, 4.82345539, 4.88692191, 4.95038842, 5.01385494,
5.07732146, 5.14078798, 5.2042545 , 5.26772102, 5.33118753,
5.39465405, 5.45812057, 5.52158709, 5.58505361, 5.64852012,
5.71198664, 5.77545316, 5.83891968, 5.9023862 , 5.96585272,
6.02931923, 6.09278575, 6.15625227, 6.21971879, 6.28318531])
f = np.sin(x)
f
array([ 0.00000000e+00, 6.34239197e-02, 1.26592454e-01, 1.89251244e-01,
2.51147987e-01, 3.12033446e-01, 3.71662456e-01, 4.29794912e-01,
4.86196736e-01, 5.40640817e-01, 5.92907929e-01, 6.42787610e-01,
6.90079011e-01, 7.34591709e-01, 7.76146464e-01, 8.14575952e-01,
8.49725430e-01, 8.81453363e-01, 9.09631995e-01, 9.34147860e-01,
9.54902241e-01, 9.71811568e-01, 9.84807753e-01, 9.93838464e-01,
9.98867339e-01, 9.99874128e-01, 9.96854776e-01, 9.89821442e-01,
9.78802446e-01, 9.63842159e-01, 9.45000819e-01, 9.22354294e-01,
8.95993774e-01, 8.66025404e-01, 8.32569855e-01, 7.95761841e-01,
7.55749574e-01, 7.12694171e-01, 6.66769001e-01, 6.18158986e-01,
5.67059864e-01, 5.13677392e-01, 4.58226522e-01, 4.00930535e-01,
3.42020143e-01, 2.81732557e-01, 2.20310533e-01, 1.58001396e-01,
9.50560433e-02, 3.17279335e-02, -3.17279335e-02, -9.50560433e-02,
-1.58001396e-01, -2.20310533e-01, -2.81732557e-01, -3.42020143e-01,
-4.00930535e-01, -4.58226522e-01, -5.13677392e-01, -5.67059864e-01,
-6.18158986e-01, -6.66769001e-01, -7.12694171e-01, -7.55749574e-01,
-7.95761841e-01, -8.32569855e-01, -8.66025404e-01, -8.95993774e-01,
-9.22354294e-01, -9.45000819e-01, -9.63842159e-01, -9.78802446e-01,
-9.89821442e-01, -9.96854776e-01, -9.99874128e-01, -9.98867339e-01,
-9.93838464e-01, -9.84807753e-01, -9.71811568e-01, -9.54902241e-01,
-9.34147860e-01, -9.09631995e-01, -8.81453363e-01, -8.49725430e-01,
-8.14575952e-01, -7.76146464e-01, -7.34591709e-01, -6.90079011e-01,
-6.42787610e-01, -5.92907929e-01, -5.40640817e-01, -4.86196736e-01,
-4.29794912e-01, -3.71662456e-01, -3.12033446e-01, -2.51147987e-01,
-1.89251244e-01, -1.26592454e-01, -6.34239197e-02, -2.44929360e-16])
import matplotlib.pyplot as plt
Matplotlib is building the font cache; this may take a moment.
plt.plot(x,f)
[<matplotlib.lines.Line2D at 0x190209d15c8>]
打印数组
显示布局: * 最后一个轴从左到右打印, * 倒数第二个是从上到下打印的, * 其余的也从上到下打印,每个切片与下一个切片用空行分隔。
# 一维数组
print(np.arange(6))
[0 1 2 3 4 5]
# 二维数组
print(np.arange(12).reshape(4, 3))
[[ 0 1 2]
[ 3 4 5]
[ 6 7 8]
[ 9 10 11]]
# 三维数组
print(np.arange(24).reshape(2,3,4))
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]]
# 四维数组
print(np.arange(120).reshape(2,3,4,5))
[[[[ 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 32 33 34]
[ 35 36 37 38 39]]
[[ 40 41 42 43 44]
[ 45 46 47 48 49]
[ 50 51 52 53 54]
[ 55 56 57 58 59]]]
[[[ 60 61 62 63 64]
[ 65 66 67 68 69]
[ 70 71 72 73 74]
[ 75 76 77 78 79]]
[[ 80 81 82 83 84]
[ 85 86 87 88 89]
[ 90 91 92 93 94]
[ 95 96 97 98 99]]
[[100 101 102 103 104]
[105 106 107 108 109]
[110 111 112 113 114]
[115 116 117 118 119]]]]
# 如果数组太大而无法打印,NumPy 会自动跳过数组的中心部分,只打印角落
print(np.arange(10000))
[ 0 1 2 ... 9997 9998 9999]
print(np.arange(10000).reshape(100, 100))
[[ 0 1 2 ... 97 98 99]
[ 100 101 102 ... 197 198 199]
[ 200 201 202 ... 297 298 299]
...
[9700 9701 9702 ... 9797 9798 9799]
[9800 9801 9802 ... 9897 9898 9899]
[9900 9901 9902 ... 9997 9998 9999]]
# 要禁用此行为并强制 NumPy 打印整个数组,您可以使用set_printoptions.
# np.set_printoptions(threshold=sys.maxsize)
数组算术运算
数组上的算术运算符按元素应用。创建一个新数组并填充结果。
a = np.array([1,2,3])
b = np.arange(3)
a + b
array([1, 3, 5])
a - b
array([1, 1, 1])
a * b
array([0, 2, 6])
a / b
D:\work\python3.7\lib\site-packages\ipykernel_launcher.py:1: RuntimeWarning: divide by zero encountered in true_divide
"""Entry point for launching an IPython kernel.
array([inf, 2. , 1.5])
a * 2
array([2, 4, 6])
a ** 3
array([ 1, 8, 27], dtype=int32)
np.sin(a)
array([0.84147098, 0.90929743, 0.14112001])
a > 2
array([False, False, True])
a == 1
array([ True, False, False])
# @矩阵乘法
a * b
array([0, 2, 6])
a @ b
8
# +=and *=,会修改现有数组而不是创建新数组。
rg = np.random.default_rng(1)
rg
Generator(PCG64) at 0x1902109B7C8
a = np.ones((2,3))
b = rg.random((2,3))
a *=3
a
array([[3., 3., 3.],
[3., 3., 3.]])
b += a
b
array([[3.82770259, 3.40919914, 3.54959369],
[3.02755911, 3.75351311, 3.53814331]])
a+=b
a
array([[6.82770259, 6.40919914, 6.54959369],
[6.02755911, 6.75351311, 6.53814331]])
# 当处理不同类型的数组时,结果数组的类型对应于更一般或更精确的类型(一种称为向上转换的行为)。
a = np.ones(3,dtype=np.int32)
b = np.linspace(0,np.pi,3)
a
array([1, 1, 1])
b
array([0. , 1.57079633, 3.14159265])
b.dtype
dtype('float64')
c = a+b
c.dtype
dtype('float64')
c
array([1. , 2.57079633, 4.14159265])
d = np.exp(c * 1j)
d
array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,
-0.54030231-0.84147098j])
d.dtype
dtype('complex128')
# ndarray常用方法
a = rg.random((2,3))
a
array([[0.32973172, 0.7884287 , 0.30319483],
[0.45349789, 0.1340417 , 0.40311299]])
a.sum()
2.412007822394087
a.max()
0.7884287034284043
a.min()
0.13404169724716475
# axis 沿数组轴数操作
b = np.arange(12).reshape(3,4)
b
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
b.sum()
66
# 按列求和
b.sum(axis=0)
array([12, 15, 18, 21])
# 按行求和
b.sum(axis=1)
array([ 6, 22, 38])
# exp 高等数学里以自然常数e为底的指数函数
c = np.arange(3)
c
array([0, 1, 2])
np.exp(c)
array([1. , 2.71828183, 7.3890561 ])
# sqrt 开方
np.sqrt(c)
array([0. , 1. , 1.41421356])
# add 加法
d = np.array([3,4,5])
np.add(c,d)
array([3, 5, 7])
索引、切片和迭代
一维数组可以被索引、切片和迭代,就像 列表 和其他 Python 序列一样。
多维数组的每个轴可以有一个索引。这些索引在用逗号分隔的元组中给出。
a = np.arange(10) ** 3
a
array([ 0, 1, 8, 27, 64, 125, 216, 343, 512, 729], dtype=int32)
a[2]
8
a[4:7]
array([ 64, 125, 216], dtype=int32)
a[::-1]
array([729, 512, 343, 216, 125, 64, 27, 8, 1, 0], dtype=int32)
a[:6:2] = 1024
a
array([1024, 1, 1024, 27, 1024, 125, 216, 343, 512, 729],
dtype=int32)
for i in a:
print(i ** (1/3))
10.079368399158984
1.0
10.079368399158984
3.0
10.079368399158984
5.0
5.999999999999999
6.999999999999999
7.999999999999999
8.999999999999998
b = np.arange(16)
b = b.reshape(4,4)
b
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
b[2]
array([ 8, 9, 10, 11])
b[2,3]
11
b[0:3]
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
b[0:3,0]
array([0, 4, 8])
b[::2][1,1]
9
b[0,...]
array([0, 1, 2, 3])
b[...,1]
array([ 1, 5, 9, 13])
for row in b:
print(row)
[0 1 2 3]
[4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]
for element in b.flat:
print(element)
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
形状操作
数组的形状由沿每个轴的元素数量决定
a = np.floor(10 * rg.random((3, 4)))
a
array([[5., 1., 6., 7.],
[6., 9., 0., 5.],
[4., 0., 6., 8.]])
a.shape
(3, 4)
# 下列方法返回一个修改过的数组,但不改变原来的数组
# 转一维
a.ravel()
array([5., 1., 6., 7., 6., 9., 0., 5., 4., 0., 6., 8.])
# 任意转
a.reshape(6,2)
array([[5., 1.],
[6., 7.],
[6., 9.],
[0., 5.],
[4., 0.],
[6., 8.]])
# 变形,行变列,列变行
a.T
array([[5., 6., 4.],
[1., 9., 0.],
[6., 0., 6.],
[7., 5., 8.]])
# 功能同reshape, ndarray.resize方法修改数组本身
a.resize((2,6))
a
array([[5., 1., 6., 7., 6., 9.],
[0., 5., 4., 0., 6., 8.]])
# reshape参数为如果-1在重塑操作中给出了一个维度,则会自动计算其他维度
a.reshape(4,-1)
array([[5., 1., 6.],
[7., 6., 9.],
[0., 5., 4.],
[0., 6., 8.]])
将不同的数组堆叠在一起
多个数组可以沿不同的轴堆叠在一起
a = np.floor(10 * rg.random((2,2)))
a
array([[5., 2.],
[8., 5.]])
b = np.floor(10 * rg.random((2, 2)))
b
array([[5., 7.],
[1., 8.]])
# 上下叠
np.vstack((a,b))
array([[5., 2.],
[8., 5.],
[5., 7.],
[1., 8.]])
# 左右叠
np.hstack((a,b))
array([[5., 2., 5., 7.],
[8., 5., 1., 8.]])