5. Numpy 简介#


Numpy (Numerical Python) 是 Python 语言一个重要的扩展库,支持大量的数组与矩阵运算,此外也提供大量的数学函数库,用于模仿数学软件 MatLab 的功能。Numpy 通常与其他库 SciPy(Scientific Python)和 Matplotlib(绘图库)一起使用。

Numpy 的主要特点是:

  • 一个强大的 N 维数组对象 ndarray

  • 矩阵运算、傅里叶变换、生成随机数功能等

使用 numpy 需要首先导入 numpy 包:

import numpy as np

5.1. 创建数组#


用 Numpy 创建数组有多种方法。首先,Numpy 中的array函数可以直接将 Python 的 list 类型转化为 Numpy 的数组类型 ndarray。例如,一个一维数组:

a = np.array([1, 2, 3, 4])
a
array([1, 2, 3, 4])

一个二维数组:

b = [[1, 2], [3, 4]]
a = np.array(b)
a
array([[1, 2],
       [3, 4]])

注意,array函数中的小括号中要包括一个用中括号括起来的 list,不能直接写成 np.array(1, 2, 3, 4)。

Numpy 中的zeros函数可以创建元素值全为 0 的矩阵,ones函数可以创建元素值全为 1 的矩阵,而empty函数可以创建一个元素值任意的一个空矩阵。例如:

np.zeros((3, 4))  # 3 行 4 列的零矩阵
array([[0., 0., 0., 0.],
       [0., 0., 0., 0.],
       [0., 0., 0., 0.]])
np.ones((3, 4))  # 3 行 4 列的一个矩阵
array([[1., 1., 1., 1.],
       [1., 1., 1., 1.],
       [1., 1., 1., 1.]])
np.empty((2, 3))  # 2 行 3 列的空矩阵
array([[0., 0., 0.],
       [0., 0., 0.]])

Numpy 中的arange函数可以生成一个等差数列的数组,例如:

np.arange(10)  # 生成一个从 0 到 9 之间的数组,默认步长为 1
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.arange(5, 10)  # 生成一个从 5 到 9 之间的数组,默认步长为 1
array([5, 6, 7, 8, 9])
np.arange(5, 10, 2)  # 生成一个从 5 到 9 之间的数组,且步长为 2
array([5, 7, 9])

另外一个类似的函数为linespace,不同的地方在于:arange函数中第三个参数表示等差数组的步长,而linespace函数第三个参数表示一共生成的元素个数。若生成一系列等差的浮点数,则用linespace更好些。

np.linspace(0, 2, 9)  # 生成从 0 到 2 之间共 9 个数
array([0.  , 0.25, 0.5 , 0.75, 1.  , 1.25, 1.5 , 1.75, 2.  ])

Python 的 list 类型可以与 Numpy 的数组类型 ndarray 互换,例如:

a = np.arange(10)
list(a)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

numpy 库中常见的数组创建函数如下表所示:

函数

描述

np.arrange(x, y, i)

创建一个由 x 到 y,以 i 为步长的数组

np.linspace(x, y, n)

创建一个由 x 到 y,等分为 n 个元素的数组

np.ones((m,n))

创建一个 m 行 n 列全是 1 的数组

np.empty((m,n))

创建一个 m 行 n 列全是 0 的数组

numpy 创建的数组类型为 ndarray类型,它的常用属性如下表所示:

函数

描述

ndarray.ndim

数组的行数

ndarray.shape

数组在每个维度上大小的整数元组

ndarray.size

数组中元素的个数

ndarray.dtype

数组中元素的数据类型

a = np.ones((2, 3))
a.ndim
2
a.shape
(2, 3)
a.size
6
a.dtype
dtype('float64')

5.2. 数组索引和切片#


对于一维数组,numpy 的索引切片类似 Python list 类型的索引切片,例如:

a = np.arange(4, 10)  # 生成一个从 4 到 9 之间的数组
a
array([4, 5, 6, 7, 8, 9])
a[2]  # 数组 a 的第 3 个元素
6
a[2:4]  # 数组 a 的第 3 与第 4 个元素
array([6, 7])
a[-1]  # 数组 a 的最后一个元素
9
a[::-1]  # 数组 a 倒序
array([9, 8, 7, 6, 5, 4])

对于多维数组,Numpy 数组的索引和切片在一个中括号里面用逗号分隔不同维度,例如:

b = np.arange(12).reshape(3, 4)  # 创建一个 3 行 4 列的二维数组,reshape函数不改变数值,将原数组重组为一个指定行数列数的数组
b
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
b[1, 2]  # 二维数组第 2 行第 3 列中的元素
6
b[1:3, 2]  # 二维数组第 3 列中, 第 2 行到第 3 行的元素
array([ 6, 10])
b[2, :]  # 第 3 行的全部元素
array([ 8,  9, 10, 11])
list(b)
[array([0, 1, 2, 3]), array([4, 5, 6, 7]), array([ 8,  9, 10, 11])]

5.3. 数组拼接#


Numpy 中拼接两个数组用append函数。

a = np.arange(5)
a
array([0, 1, 2, 3, 4])
b = np.arange(3)
b
array([0, 1, 2])
np.append(a, b)
array([0, 1, 2, 3, 4, 0, 1, 2])

多个数组拼接,可以用concatenate

c = np.arange(4)
c
array([0, 1, 2, 3])
np.concatenate((a, b, c))  # 注意里面还有一对小括号
array([0, 1, 2, 3, 4, 0, 1, 2, 0, 1, 2, 3])

5.4. 数组运算#


Numpy 可以对数组进行多种代数运算,例如:

a = np.arange(4)
a
array([0, 1, 2, 3])
b = np.arange(3, 7)
b
array([3, 4, 5, 6])
a - b  # 两数组相减
array([-3, -3, -3, -3])
a + b  # 两数组相加
array([3, 5, 7, 9])
a * 2  # 数组每个元素乘以一个数值
array([0, 2, 4, 6])
a**2  # 数组每个元素都平方
array([0, 1, 4, 9])
a > 2  # 数组每个元素与一个数值比较大小
array([False, False, False,  True])
c = np.array([[4.0, 5.0], [6.0, 7.0]])
c
array([[4., 5.],
       [6., 7.]])
c.transpose()  # c 的转置矩阵
array([[4., 6.],
       [5., 7.]])
np.linalg.inv(c)  # c 的逆矩阵
array([[-3.5,  2.5],
       [ 3. , -2. ]])
eigenvalues, eigenvectors = np.linalg.eig(c)  # c 的特征值与特征向量
print("eigenvalues are ", eigenvalues)
print("eigenvectors are", eigenvectors)
eigenvalues are  [-0.17890835 11.17890835]
eigenvectors are [[-0.76729658 -0.57152478]
 [ 0.64129241 -0.82058481]]
d = np.array([[1.0, 2.0], [3.0, 4.0]])
d
array([[1., 2.],
       [3., 4.]])
np.dot(c, d)  # 矩阵 c 和 d 的乘积
array([[19., 28.],
       [27., 40.]])
np.multiply(c, d)  # 矩阵 c 和 d 对应元素相乘
array([[ 4., 10.],
       [18., 28.]])

numpy 库还有一些其他常用的函数,如下表所示:

函数

描述

np.abs(x)

计算每个元素的绝对值

np.sqrt(x)

计算每个元素的平方根

np.squre(x)

计算每个元素的平方

np.sign(x)

计算每个元素的正负号

np.ceil(x)

计算每个元素向上取整的数值

np.floor(x)

计算每个元素向下取整的数值

np.exp(x)

计算每个元素的指数值

np.log(x),np.log10(x),np.log2(x)

计算每个元素的自然对数值,基于10、2的对数值

另外,Numpy 还有专门的二维数组的类型 Matrix,可以更方便地进行一些矩阵运算,感兴趣的读者可以参见官网。

5.5. 生成随机数#


numpy 包的random方法基本支持所有分布,并且能够一次生成多行多列的随机数, 例如:

import numpy as np

np.random.uniform(1, 10, [2, 2])  # 生成 [1, 10] 内的均匀分布随机数, 2 行 2 列
array([[7.09263517, 5.89191539],
       [1.93501512, 9.28497785]])
np.random.uniform(1, 10, 5)  # 生成 5 个 [1, 10] 内的均匀分布随机数
array([9.75077397, 2.43118187, 1.98607369, 1.07047913, 2.07363988])
np.random.randint(1, 10, [2, 2])  # 生成 [1, 10] 内的随机整数, 2 行 2 列
array([[4, 2],
       [2, 9]])
np.random.normal(5, 1, [2, 2])  # 生成一个正态分布的随机数,均值为 5, 标准差为 1, 2 行 2 列
array([[5.69060984, 5.15048724],
       [3.51455947, 5.03125812]])
np.random.poisson(5, [2, 2])  # 生成一个泊松分布的随机数,均值为 5, 2 行 2 列
array([[7, 1],
       [3, 0]])

numpy 还可以通过random.seed()参数设定随机数生成器的种子,同样的种子生成的随机数应该是相同的。

np.random.seed(500)
np.random.normal(5, 1, 6)  # 生成 6 个正态分布的随机数,均值为 5, 标准差为 1
array([4.62263642, 5.16675892, 5.68280238, 6.92137877, 4.8029632 ,
       4.24012124])

另外 numpy 还可以通过RandomState()来定义一个随机数生成器对象,小括号里面的参数为随机数种子,然后用这个对象调用具体的各个随机分布生成器函数。例如:

rvs = np.random.RandomState(500)
rvs.normal(5, 1, 6)  # 生成 6 个正态分布的随机数,均值为 5, 标准差为 1
array([4.62263642, 5.16675892, 5.68280238, 6.92137877, 4.8029632 ,
       4.24012124])

5.6. Numpy 数组与列表 list 运算速度的对比#


Numpy 对于数值型数据的运算速度远快于 Python 自带的 list 列表。对于大规模的数学计算,优先使用 Numpy 处理。

import numpy as np
import time

# 使用 Python 原生 list
size = 1_000_000
py_list = list(range(size))

start = time.time()
py_list_squared = [x ** 2 for x in py_list]  # 普通 Python 列表计算
print("Python List 耗时:", time.time() - start)

# 使用 NumPy 数组
np_array = np.arange(size)

start = time.time()
np_array_squared = np_array ** 2  # NumPy 直接进行向量化运算
print("NumPy 耗时:", time.time() - start)
Python List 耗时: 0.029808998107910156
NumPy 耗时: 0.001039266586303711

5.7. time, datatime 模块#


5.7.1. time 模块#


time 模块提供了许多与时间相关的函数,如获取当前时间、暂停程序、测量执行时间等。

  • 获取当前时间

import time

# 获取当前时间戳
timestamp = time.time()
print(timestamp)
1747833729.3150542
# 获取当前时间的结构化格式
current_time = time.localtime()
print(current_time)
time.struct_time(tm_year=2025, tm_mon=5, tm_mday=21, tm_hour=14, tm_min=22, tm_sec=9, tm_wday=2, tm_yday=141, tm_isdst=1)
# 格式化时间
formatted_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
print(formatted_time)
2025-05-21 14:22:09
  • 时间转换

# 时间戳转时间字符串
timestamp = 1708193257
time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timestamp))
print(time_str)
2024-02-17 18:07:37

常见的 strftime 格式:

代码

含义

%Y

4 位数年份(如 2025)

%m

2 位数月份(01-12)

%d

2 位数日期(01-31)

%H

24 小时制小时(00-23)

%M

分钟(00-59)

%S

秒(00-59)

# 时间字符串转时间戳
time_string = "2025-02-17 10:30:57"
time_tuple = time.strptime(time_string, "%Y-%m-%d %H:%M:%S")
timestamp = time.mktime(time_tuple)
print(timestamp)
1739788257.0
  • 线程休眠

print("Start")
time.sleep(3)  # 休眠 3 秒
print("End")
Start
End
  • 计算程序运行时间

# 使用 time.time()
start = time.time()
for _ in range(1000000):
    pass
end = time.time()
print(f"Execution time: {end - start:.6f} seconds")
Execution time: 0.039733 seconds
# 使用 time.perf_counter() 获取高精度时间
start = time.perf_counter()
for _ in range(1000000):
    pass
end = time.perf_counter()
print(f"Execution time: {end - start:.6f} seconds")
Execution time: 0.027269 seconds
  • 获取 CPU 运行时间

start = time.process_time()
for _ in range(1000000):
    pass
end = time.process_time()
print(f"CPU time used: {end - start:.6f} seconds")
CPU time used: 0.022966 seconds
  • 获取 UTC 时间

utc_time = time.gmtime()
print(time.strftime("%Y-%m-%d %H:%M:%S", utc_time))
2025-05-21 13:22:12

5.7.2. datetime 模块#


datetime 是 Python 标准库中的一个模块,提供日期、时间处理的功能,包括获取当前时间、日期计算、时区处理等。

  • 获取当前时间

from datetime import datetime

# 获取当前本地时间
now = datetime.now()
print(now)  # 输出示例: 2025-02-17 10:30:57.123456
2025-05-21 14:22:12.448168
from datetime import datetime, timezone

# 获取当前 UTC 时间
utc_now = datetime.now(timezone.utc)
print(utc_now)  # 2025-02-17 10:30:57.123456+00:00
2025-05-21 13:22:12.451064+00:00
  • 创建自定义时间

from datetime import datetime

# 创建指定时间
dt = datetime(2025, 2, 17, 10, 30, 57)
print(dt)  # 2025-02-17 10:30:57
2025-02-17 10:30:57
from datetime import datetime

# 从时间戳创建时间
timestamp = 1708193457  # 2025-02-17 10:30:57 对应的时间戳
dt = datetime.fromtimestamp(timestamp)  # 本地时间
utc_dt = datetime.utcfromtimestamp(timestamp)  # UTC 时间
print(dt)
print(utc_dt)
2024-02-17 18:10:57
2024-02-17 18:10:57
/var/folders/qz/d57_41f55ylf02cqq8twh3540000gn/T/ipykernel_7217/2033922435.py:6: DeprecationWarning: datetime.datetime.utcfromtimestamp() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.fromtimestamp(timestamp, datetime.UTC).
  utc_dt = datetime.utcfromtimestamp(timestamp)  # UTC 时间
  • 时间格式化

from datetime import datetime

dt = datetime(2025, 2, 17, 10, 30, 57)

# datetime 转字符串
formatted_str = dt.strftime("%Y-%m-%d %H:%M:%S")
print(formatted_str)
2025-02-17 10:30:57
from datetime import datetime

# 字符串 转 datetime
time_str = "2025-02-17 10:30:57"
dt = datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S")
print(dt)
2025-02-17 10:30:57
  • 时间计算

from datetime import datetime, timedelta

dt = datetime(2025, 2, 17, 10, 30, 57)
new_dt = dt + timedelta(days=5, hours=3)
print(new_dt)
2025-02-22 13:30:57
from datetime import datetime

dt1 = datetime(2025, 2, 17, 10, 30, 57)
dt2 = datetime(2025, 2, 20, 15, 0, 0)

diff = dt2 - dt1
print(diff)
print(diff.total_seconds())
3 days, 4:29:03
275343.0
  • 处理时区

from datetime import datetime, timezone, timedelta

utc_now = datetime.now(timezone.utc)
beijing_time = utc_now.astimezone(timezone(timedelta(hours=8)))
print(beijing_time)
2025-05-21 21:22:12.471625+08:00
from datetime import datetime, timezone

local_time = datetime.now()
utc_time = local_time.astimezone(timezone.utc)
print(utc_time)
2025-05-21 13:22:12.474293+00:00