📊 阅读时长:20分钟 | 关键词:NumPy、数组创建、数据类型、形状操作、索引切片

引言:为什么需要 NumPy?

Python 的列表已经很强大了——那为什么还需要 NumPy 的数组?

如果你用 Python 列表做这个操作:

# 用列表计算:每个数的平方
lst = [1, 2, 3, 4, 5]
result = []
for x in lst:
    result.append(x ** 2)

# 用 NumPy 计算:一行搞定
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
result = arr ** 2

NumPy 的优势还不止于此:

对比维度 Python 列表 NumPy 数组
存储效率 每个元素是独立对象,内存开销大 连续内存块,数据类型统一,内存小
计算速度 逐元素 Python 循环,慢 C 语言底层实现,向量化运算,快 10~100 倍
功能丰富度 基本的增删改查 线性代数、傅里叶变换、随机数等

一句话:只要你做数据分析、机器学习、科学计算,NumPy 是绕不过去的基础。


一、安装和导入

1.1 安装
pip install numpy
# 国内推荐用清华镜像
pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple
1.2 导入惯例
import numpy as np   # 业界标准写法,永远用 np 作为别名

在这里插入图片描述


二、创建数组:从零到一

2.1 np.array():最核心的创建方式
import numpy as np

# 从列表创建一维数组
arr1 = np.array([1, 2, 3, 4, 5])
print(arr1)           # [1 2 3 4 5]
print(type(arr1))     # <class 'numpy.ndarray'>

# 从嵌套列表创建二维数组
arr2 = np.array([[1, 2, 3], [4, 5, 6]])
print(arr2)
# [[1 2 3]
#  [4 5 6]]

# 指定数据类型
arr3 = np.array([1, 2, 3], dtype=np.float64)
print(arr3.dtype)    # float64

关键:NumPy 数组中的所有元素必须是同一种数据类型。这是它比列表快的重要原因之一。

2.2 常用创建函数速查表
函数 功能 示例
np.array() 从现有数据创建 np.array([1,2,3])
np.arange(start, stop, step) 类似 range,返回数组 np.arange(0, 10, 2)[0 2 4 6 8]
np.linspace(start, stop, num) 等间隔取 num 个点 np.linspace(0, 1, 5)[0. 0.25 0.5 0.75 1. ]
np.zeros(shape) 全 0 数组 np.zeros((2,3)) → 2行3列全0
np.ones(shape) 全 1 数组 np.ones((2,3)) → 2行3列全1
np.eye(N) N×N 单位矩阵 np.eye(3) → 3×3单位矩阵
np.random.rand(shape) 0~1 均匀分布随机数 np.random.rand(2,3)
np.random.randn(shape) 标准正态分布随机数 np.random.randn(2,3)
import numpy as np

# arange:指定步长
print(np.arange(0, 10, 2))    # [0 2 4 6 8]

# linspace:指定点数(端点默认包含)
print(np.linspace(0, 1, 5))  # [0.   0.25 0.5  0.75 1.  ]

# 重塑形状
arr = np.arange(12)
print(arr.reshape((3, 4)))
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

在这里插入图片描述


三、数组属性:读懂一个数组

import numpy as np

arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.ndim)    # 2        → 维度(轴的数量)
print(arr.shape)   # (2, 3)   → 形状(每个轴的长度)
print(arr.size)    # 6        → 总元素个数
print(arr.dtype)   # int64    → 数据类型
print(arr.itemsize) # 8        → 每个元素的字节数
属性 含义 示例(shape=(2,3,4))
ndim 维度数(秩) 3
shape 各维度大小 (2, 3, 4)
size 元素总数 2×3×4 = 24
dtype 元素数据类型 int64 / float32 等

在这里插入图片描述


四、数据类型(dtype):省内存 = 省时间

NumPy 支持比 Python 更细粒度的数据类型,合理选择可以大幅减少内存占用。

类型 含义 字节数 适用场景
np.int8 8位有符号整数 1 图像像素(0~255)
np.int32 32位有符号整数 4 默认整数(一般够用)
np.int64 64位有符号整数 8 大数计算
np.float32 32位单精度浮点 4 深度学习(省显存)
np.float64 64位双精度浮点 8 默认浮点(精度高)
np.bool_ 布尔值 1 掩码、条件索引
np.str_ 字符串 变长 不推荐(用 Pandas)
import numpy as np

# 默认 dtype(根据系统自动选)
arr1 = np.array([1, 2, 3])
print(arr1.dtype)   # int64(64位系统)

# 指定 dtype(显式控制)
arr2 = np.array([1, 2, 3], dtype=np.float32)
print(arr2.dtype)   # float32

# 类型转换
arr3 = arr1.astype(np.float64)
print(arr3.dtype)   # float64

省内存小技巧

import numpy as np

# 图像像素值 0~255,用 int8 就够了!
pixels = np.array([255, 128, 0, 64], dtype=np.uint8)
print(pixels.nbytes)   # 4 字节(如果用 int64 要 32 字节)

# 深度学习推理时用 float32,比 float64 省一半显存
weights = np.random.rand(1000, 1000).astype(np.float32)

五、形状操作:给数组"整形"

5.1 reshape():改变形状,不改变数据
import numpy as np

arr = np.arange(12)
print(arr.reshape((3, 4)))
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

# -1 让 NumPy 自动推断该维度大小
print(arr.reshape((3, -1)))  # 等同于 (3, 4),因为 12/3=4
print(arr.reshape((-1, 2)))  # 等同于 (6, 2),因为 12/2=6

重要reshape 不改变原数组,而是返回一个新的视图(如果可能的话)。

5.2 flatten() vs ravel():扁平化
import numpy as np

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

# flatten():返回副本(修改不影响原数组)
flat1 = arr.flatten()
flat1[0] = 999
print(arr[0, 0])   # 1(原数组未改变)

# ravel():返回视图(修改会影响原数组)
flat2 = arr.ravel()
flat2[0] = 999
print(arr[0, 0])   # 999(原数组被改变了!)
方法 返回类型 修改是否影响原数组 速度
flatten() 副本 ❌ 不影响 稍慢(需要复制)
ravel() 视图(尽量) ✅ 可能影响 更快(尽量不复制)
5.3 转置:.Ttranspose()
import numpy as np

arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.T)
# [[1 4]
#  [2 5]
#  [3 6]]

# 高维数组的 transpose(指定轴的顺序)
arr3d = np.arange(24).reshape((2, 3, 4))
print(arr3d.transpose((2, 0, 1)).shape)  # (4, 2, 3)

在这里插入图片描述


六、索引和切片:比列表更强大

6.1 一维数组的索引切片(和列表几乎一样)
import numpy as np

arr = np.arange(10)       # [0 1 2 3 4 5 6 7 8 9]

print(arr[0])              # 0
print(arr[-1])             # 9
print(arr[2:5])           # [2 3 4]
print(arr[:5])             # [0 1 2 3 4]
print(arr[::2])            # [0 2 4 6 8]
6.2 二维数组的索引切片(核心重点!)
import numpy as np

arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
# 形状:(3, 3)
# 行索引:0,1,2
# 列索引:0,1,2

# 方式一:用逗号分隔(推荐!)
print(arr[0, 1])          # 2        → 第0行第1列
print(arr[1, :])          # [4 5 6]  → 第1行所有列
print(arr[:, 2])          # [3 6 9]  → 所有行第2列

# 方式二:用多个 [](不推荐,冗长)
print(arr[0][1])          # 2

# 同时切行和切列
print(arr[0:2, 1:3])
# [[2 3]
#  [5 6]]

在这里插入图片描述

6.3 布尔索引(超级实用!)
import numpy as np

arr = np.array([3, 7, 2, 9, 5])

# 条件过滤:选出所有 > 5 的元素
mask = arr > 5
print(mask)          # [False  True False  True False]
print(arr[mask])     # [7 9]

# 一行搞定
print(arr[arr > 5])       # [7 9]
print(arr[(arr > 3) & (arr < 8)])  # [7 5]  → 注意要用 & 不是 and!

# 复杂条件(用括号!)
condition = (arr > 3) | (arr == 2)   # 大于3 或者等于2
print(arr[condition])          # [3 7 2 9 5]

⚠️ 超级大坑:布尔索引中必须用位运算符& | ~),不能用逻辑运算符(and or not)!

# ❌ 错误写法(会报错或结果不对)
# print(arr[arr > 3 and arr < 8])   # ValueError!

# ✅ 正确写法
print(arr[(arr > 3) & (arr < 8)])  # [7 5]
6.4 花式索引(用整数数组来索引)
import numpy as np

arr = np.array([10, 20, 30, 40, 50])

# 用整数列表/数组来取元素
print(arr[[0, 2, 4]])     # [10 30 50]
print(arr[np.array([1, 3, 0]])  # [20 40 10]

# 二维花式索引
arr2d = np.array([[1, 2], [3, 4], [5, 6]])
print(arr2d[[0, 2], [0, 1]])  # [1 6]  → 取 (0,0) 和 (2,1)

七、动手练习

练习 1:用 NumPy 计算均方误差(MSE)

均方误差是机器学习中最常用的损失函数,公式为:
MSE=1n∑i=1n(ypred−ytrue)2\text{MSE} = \frac{1}{n}\sum_{i=1}^{n}(y_{pred} - y_{true})^2MSE=n1i=1n(ypredytrue)2

请不要用循环,用 NumPy 向量化运算一行写出:

import numpy as np

y_true = np.array([3.0, 2.5, 4.0, 5.0])
y_pred = np.array([2.8, 2.7, 3.9, 5.2])

# 在这里写你的代码(提示:用 np.mean() 和 ** 运算符)
mse = None  # 替换成你的代码
print(f"MSE = {mse:.4f}")   # 期望输出:MSE = 0.0475

练习 2:图片像素值归一化

import numpy as np

# 模拟一张 2×2 的灰度图片,像素值范围 0~255
img = np.array([[120, 200], [80, 255]], dtype=np.uint8)

# 请将像素值归一化到 0~1 范围(公式:pixel / 255.0)
# 注意:必须先转换成 float,否则整数除法会截断!
img_normalized = None  # 替换成你的代码
print(img_normalized)
print(img_normalized.dtype)  # 应该是 float64 或 float32

练习 3:布尔索引实战——找出所有不及格的分数

import numpy as np

scores = np.array([85, 92, 58, 73, 45, 99, 61])

# 1. 找出所有不及格(< 60)的分数
failing = None  # 替换
print(f"不及格分数:{failing}")

# 2. 把这些不及格的分数改成 60(补考及格线)
# 在这里写代码(提示:用布尔索引作为左值)
print(f"补考后:{scores}")

小结

今天这篇文章,我们搞定了 NumPy 的基础核心:

知识点 一句话总结
为什么用 NumPy 快(C 底层)、省内存(统一 dtype)、功能强
创建数组 array() 从现有数据;arange()/linspace() 快速生成序列
数组属性 ndim(维度数)、shape(形状)、dtype(数据类型)
数据类型 合理选 dtype 能省大量内存;用 astype() 转换
形状操作 reshape() 整形;flatten()/ravel() 扁平化;.T 转置
索引切片 逗号分隔多维索引 arr[i, j];布尔索引超实用
大坑预警 布尔索引中用 & `

下一篇文章,我们将深入 NumPy 的向量化运算、广播机制、聚合函数——这些是 NumPy 真正强大的地方,也是 Pandas 的底层基础。


本文是「Python从入门到数据分析」系列的第 16 篇,共 24 篇。关注我,不错过后续更新。

更多推荐