Bootstrap

史上最详细的Numpy介绍

一、Numpy简介

NumPy 是一个用于科学计算的基础 Python 库。它支持多维数组和矩阵运算,并提供了丰富的数学函数库,可以高效地操作这些数组。

核心概念

  • 多维数组 (ndarray): NumPy 的核心是ndarray对象,它是一个多维数组,可以存储单一数据类型的元素。
  • 向量化计算: NumPy 的操作通常是向量化的,能够以接近底层 C 或 Fortran 语言的速度进行运算。
  • 广播机制: 允许形状不同的数组在某些运算中以特定方式对齐形状,进行高效计算。

二、Numpy的安装

pip install numpy

三、基本用法

1.创建数组

使用numpy.array将列表或元组转换为Numpy数组:

import numpy as np

# 从列表创建
arr = np.array([1, 2, 3, 4, 5])
print(arr)  # 输出:[1 2 3 4 5]

# 创建多维数组
arr2d = np.array([[1, 2, 3], [4, 5, 6]])
print(arr2d)
# 输出:
# [[1 2 3]
#  [4 5 6]]

2.数组的基本属性

arr = np.array([
    [1,2,3], 
    [4,5,6], 
    [7,8,9], 
    [10,11,12]
])

print(arr.ndim)  # 数组的维度
# 输出:2
print(arr.shape) # 数组的形状 (行, 列)
# 输出:(4, 3)
print(arr.size)  # 数组的元素总数
# 输出:12
print(arr.dtype) # 数组的数据类型
# 输出:int32
print(arr.itemsize)  # 单个元素所占字节
# 输出:4

在这段代码里面需要强调的一点就是,能够使用arr.dtype的原因就是因为numpy数组里面的元素都是相同类型的,这一点是需要强调的,有很多人容易将numpy和list弄混淆,我觉得可以从这一点上进行本质的区分,因为list列表是允许里面的元素是不同类型的。当然,这两者肯定是不只这个区别的,下面我将通过一个表格来进行简单的总结: 

特性NumPy ndarrayPython list
数据类型统一不要求统一
性能高效较低
内存占用较低较高
多维支持原生支持需要嵌套实现
数学运算原生支持(快速)不支持
广播机制支持不支持
应用场景科学计算、数据分析通用目的

3.常见的数组创建方式

# 创建全零数组
zeros = np.zeros((3, 3))  # 3x3 矩阵
print(zeros)
# 创建全一数组
ones = np.ones((2, 4))    # 2x4 矩阵
print(ones)
# 创建指定值的数组
full = np.full((2, 2), 7) # 全为 7 的2x2数组
print(full)
# 创建随机数组
rand = np.random.rand(3, 2)  # 3x2 随机数数组
print(rand)
# 创建连续数组
seq = np.arange(0, 10, 2)  # [0, 2, 4, 6, 8]
print(seq)
# 创建等间隔数组
linspace = np.linspace(0, 1, 5)  # [0.  0.25  0.5  0.75  1. ]
print(linspace)

在这个里面我觉得最有必要讲一下的就是np.linspace(start, end, number),这个函数的意思是在start到end(包括start和end),等间距的创建number个数,可以是浮点数,例如np.linspace(0, 160, 41),就会生成一个[0, 4, 8, ...,156, 160]的数组,这个函数在绘制直方图时会经常使用,在观察数据时具有很好的效果。

4.数组运算

NumPy 支持多种运算,且速度比 Python 循环快得多。

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

# 加法
print(a + b)  # [5 7 9]
# 乘法
print(a * b)  # [4 10 18]
# 数乘
print(a * 2)  # [2 4 6]
# 指数
print(a ** 2) # [1 4 9]
# 广播
c = np.array([[1], [2], [3]])
print(a + c)  # 广播加法

数组加法就是对应位置做加法,如上面的例子就是[1+4, 2+5, 3+6],结果就是[5, 7, 9],乘法、数乘、指数同理;下面的高级功能中会着重讲一下广播机制。

5.数组索引和切片

arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])

# 索引
print(arr[0, 1])  # 第一行第二列的值,结果为 2

# 切片
print(arr[:, 1])  # 所有行的第二列 [2, 5, 8]
print(arr[1:, :2])  # 第二行及以后的前两列
# [[4,5],
#  [7,8]]

加入arr是一个一维数组,例如arr=np.array([1, 2, 3, 4, 5, 6]),那么索引就只需要一个参数,比如我要找arr里面的数字2,就用arr[1]即可(请注意,由于索引是从0开始的,所以大家要注意下标的位置);切片的话则是要注意前闭后开(即包含前面下标所对应的值,而不包括后面下标对应的值),如arr[2:5],那么取值就是[3,4,5];因为一维相对来说是比较好理解的,所以这里就是拿一维数组来举例子,其实二维和更高维都是一样的,只是二维就要注意行和列,n维就相当于取n个参数。

6.条件过滤

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

# 返回一个全是bool值的列表,符合条件的值为True,否则为False
print(arr > 3) # [False False False  True  True]

# 筛选出大于 3 的值
print(arr[arr > 3])  # [4 5]

如果是列表的话则需要写一个列表推导式

lst = [1,2,3,4,5]
print([i for i in lst if i > 3]) # [4,5]

四、高级功能

1.数学函数

NumPy 提供丰富的数学函数。

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

# 求和
print(np.sum(arr))  # 15
# 均值
print(np.mean(arr))  # 3.0
# 标准差
print(np.std(arr))  # 1.414
# 最大最小值
print(np.max(arr), np.min(arr))  # 5, 1

2.矩阵运算

这里如果不理解的话可以去看一下线性代数的矩阵篇,只要了解了基本概念就能懂,不用深入学。

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

# 矩阵乘法
print(np.dot(a, b))  # [[4 6]
                     #  [10 12]]
# 转置
print(a.T)  # [[1 3]
            #  [2 4]]

3.数组变形与拼接

# 改变形状
arr = np.array([1, 2, 3, 4])
reshaped = arr.reshape((2, 2))  # [[1, 2], [3, 4]]

# 拼接
a = np.array([1, 2])
b = np.array([3, 4])
print(np.concatenate((a, b)))  # [1 2 3 4]

这里面reshape的意思就是将之前的1x4矩阵转换成2x2矩阵,不仅可以实现同维度间的转换,也可以实现不同维度之间的转换,比如将一个一维数组转换成三维数组,如下:

arr=np.array([1,2,3,4,5,6,7,8])

print(arr.reshape((2,2,2)))
# [[[1 2]
#   [3 4]]

#  [[5 6]
#   [7 8]]]

这一前提就是转换前数组里面的个数(以这个例子为例,有8个值)要等于需要转换成的数组的形状相乘得到的结果(这里就是想转换成2x2x2矩阵,2x2x2=8,故可以转换),否则会报错。

4.广播机制

(1)广播机制的原理

NumPy 的广播机制是一种简化操作的规则,使形状不同的数组能够在某些特定条件下进行算术运算,而无需显式地复制数据。广播机制可以让代码更简洁,同时提高运算效率。广播的核心思想是“将较小的数组扩展为与较大的数组相同的形状”,但这个扩展并不真正复制数据,而是通过内存映射实现。

(2)广播机制的规则

广播机制遵循以下规则来对齐两个数组的形状:

①.如果数组的维度数不同:

  • 在较低维度的数组前面添加长度为1的维度,直到两个数组的维度数相同。

②.如果两个数组在某个维度的大小不同:

  • 如果其中一个数组在该维度的大小是1,则可以扩展为与另一个数组在该维度的大小相同。
  • 如果两个数组在某个维度的大小既不同且都不为1,则无法广播,会报错。

③.两个数组的维度从后向前对齐:

  • 从最后一个维度开始比较,逐步向前对齐,确保满足上述规则。
(3)广播的形状匹配

假设两个数组的形状为A.shape和B.shape:

①.右对齐两个数组的形状。

②.比较每一对维度:

  • 如果相等,则保持该维度。
  • 如果其中一个是1,则扩展为另一个维度的大小。
  • 否则无法广播。
(4)广播机制的使用条件

①.一个数组是标量:

  • 标量与数组的形状兼容,可以直接广播。
  • 例如,标量与任意数组进行加法、乘法等。

②.数组在某些维度的大小是1:

  • 维度大小为1的数组可以广播到另一个数组的维度。

③.两个数组的形状在每个维度上都满足规则:

  • 一个数组的大小为1,或者两个数组的大小相同。
(5)广播的示例

①.标量与数组运算:标量会扩展为与数组相同的形状。

import numpy as np

arr = np.array([1, 2, 3])
result = arr + 10
print(result)  # [11 12 13]

# 广播过程:
# · arr.shape = (3,)
# · 10.shape = () → 扩展为 (3,)

②.一维数组与多维数组:

a = np.array([1, 2, 3])
b = np.array([[10], [20], [30]])
result = a + b
print(result)
# [[11 12 13]
#  [21 22 23]
#  [31 32 33]]

# 广播过程:
# · a.shape = (3,) → 扩展为 (1, 3)
# · b.shape = (3, 1) → 扩展为 (3, 3)

③.不同形状的多维数组:

x = np.array([[1, 2, 3], [4, 5, 6]])
y = np.array([10, 20, 30])
result = x + y
print(result)
# [[11 22 33]
#  [14 25 36]]

# 广播过程:
# · x.shape = (2, 3)
# · y.shape = (3,) → 扩展为 (1, 3),然后广播为 (2, 3)

④.不同维度数组:

a = np.array([1, 2, 3])
b = np.array([[1], [2], [3]])
result = a * b
print(result)
# [[1 2 3]
#  [2 4 6]
#  [3 6 9]]

# 广播过程:
# · a.shape = (3,) → 扩展为 (1, 3)
# · b.shape = (3, 1) → 无需扩展
(6)广播失败的情况

如果两个数组的形状在某个维度既不相等又都不是1,则无法广播。

a = np.array([1, 2])
b = np.array([[1, 2], [3, 4], [5, 6]])
# print(a + b)  # 报错:operands could not be broadcast together

# 原因:
# · a.shape = (2,) → 扩展为 (1, 2)
# · b.shape = (3, 2),在第一个维度无法对齐。

5.文件读写

# 保存数组
np.save('array.npy', arr)
# 读取数组
loaded = np.load('array.npy')

五、应用案例

1.统计分析

data = np.random.randn(1000)  # 生成 1000 个随机数
print("均值:", np.mean(data))
print("标准差:", np.std(data))

2.数值分析

x = np.linspace(0, np.pi, 100)
y = np.sin(x)
area = np.trapz(y, x)  # 使用梯形法计算积分
print("面积:", area)  # ~2 (sin 的积分)

3.图像处理(与matplotlib结合)

import numpy as np
from matplotlib import pyplot as plt

image = np.random.rand(100, 100)  # 生成随机图像
plt.imshow(image, cmap='gray')
plt.show()

以上便是Numpy数组的常见用法,希望能对你有所帮助!

;