NumPy数组创建完全指南:从零搭建你的数字积木城
六月的风带着点甜味,朋友圈被各种童真刷屏。趁着这个万物皆可"玩"的季节,咱们也来玩点硬核的------用NumPy搭积木。说真的,NumPy的数组和乐高没什么本质区别:都是用最简单的单元,拼出你想得到的一切。
为什么要学NumPy?
如果把机器学习比作精彩的冒险旅程,那 NumPy 就是出发前必学的基础技能课,缺一不可。
写Python处理数据,你大概率会遇到这行"神咒":
python
import numpy as np
为什么绕不开它?两个字:快 和简。
- 向量化运算:告别for循环,一行代码干完十行的活
- 广播机制:形状不同的数组也能直接算,Python原生列表做不到
今天这篇,从数组创建 到变形运算,一次性把NumPy的基础打扎实------地基稳了,后面盖楼才不慌。
一、np.array:从列表到数组,一步之遥
最直觉的方式,把一个Python列表扔进去:
python
arr = np.array([1, 2, 3])
print(arr) # [1 2 3]
等等,Python列表[1, 2, 3]不也能用吗?为什么要多此一举?
因为它们压根不是一回事:
| Python列表 | NumPy数组 | |
|---|---|---|
| 类型 | 来者不拒,int、str、dict混着装 | 认死理,一个数组只认一种类型 |
| 运算 | [1,2]+[3,4] → [1,2,3,4](拼接) |
np.array([1,2])+np.array([3,4]) → [4 6](逐元素加) |
| 速度 | 循环处理,慢 | 底层C实现,快到飞起 |
python
# Python列表:+ 是拼接
[1, 2, 3] + [4, 5, 6] # [1, 2, 3, 4, 5, 6]
# NumPy数组:+ 是数学运算
np.array([1, 2, 3]) + np.array([4, 5, 6]) # [5 7 9]
一个管"装东西",一个管"算东西"。功能不同,别混为一谈。
二、嵌套列表:给积木加个维度
一维数组是条线,二维是张表,三维就是个箱子。用嵌套列表可以一层层搭上去:
python
list1 = [list(range(i, i+3)) for i in [2, 4, 6]]
print(list1)
# [[2, 3, 4], [6, 7, 8], [10, 11, 12]]
c = np.array([range(i, i+3) for i in [2, 4, 6]])
print(c)
# [[ 2 3 4]
# [ 6 7 8]
# [10 11 12]]
每一层列表就是积木的一层,叠起来就成了立体结构。道理就这么朴素。
三、快速创建:NumPy的"模板工厂"
有些数组不需要你一个个填值------全0、全1、等差数列,NumPy早就帮你备好了模板。
np.zeros:全0数组
python
nz = np.zeros(10, dtype=int)
print(nz) # [0 0 0 0 0 0 0 0 0 0]
十个零,整整齐齐。dtype=int让它输出整数而不是浮点数。
np.ones:全1数组
python
no = np.ones((3, 5))
print(no)
# [[1. 1. 1. 1. 1.]
# [1. 1. 1. 1. 1.]
# [1. 1. 1. 1. 1.]]
3行5列,默认浮点型(1.不是1)。需要整型就加dtype=int。
np.arange:等差数列
和Python的range是亲兄弟,但直接返回NumPy数组:
python
na = np.arange(0, 20, 2)
print(na) # [ 0 2 4 6 8 10 12 14 16 18]
对比一下:
python
list(range(0, 20, 2)) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] ← 列表
np.arange(0, 20, 2) # [ 0 2 4 6 8 10 12 14 16 18] ← 数组
长得像,但底层完全不同。一个是Python对象,一个是NumPy的连续内存块。
四、随机数组:开盲盒时间
随机数是NumPy里最好玩的部分------你永远不知道下一个数是什么(除非你设了种子)。
基础随机
python
a1 = np.random.random() # 一个[0,1)的随机浮点数
a2 = np.random.random(1) # 包含一个元素的数组
a3 = np.random.random((3, 3)) # 3×3的随机数组
a4 = np.random.random((2, 3, 4)) # 2层×3行×4列,三维随机数组
指定范围
python
a5 = np.random.uniform(5, 7, (2, 2)) # [5,7)之间的随机浮点,2×2
a6 = np.random.randint(5, 7, (2, 2)) # [5,7)之间的随机整数,2×2
uniform管浮点,randint管整数,参数格式一样。
正态分布
正态分布的本质:大部分数据挤在中间,越往两头越稀疏。人的身高、考试成绩、测量误差,都近似这个分布。
python
# 均值0,标准差1,3×3的正态分布随机数组
np.random.normal(0, 1, (3, 3))
# 简写版:标准正态分布
np.random.randn(3, 3)
种子:给随机数写剧本
随机数其实是"伪随机"------由算法按固定规则生成。设种子就是把规则锁死,让每次运行结果一模一样。
python
np.random.seed(0)
a = np.random.random(3)
print(a) # 每次运行都输出相同的值
什么时候用?调试的时候。你的代码出了bug,想复现它,就得保证输入数据不变。种子就是你的"存档点"。
五、特殊数组:预制件
np.eye:单位矩阵
python
ne = np.eye(3)
print(ne)
# [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]
对角线是1,其余是0。线性代数里的"乘法单位元"------任何矩阵乘以它,等于没乘。
np.empty:未初始化的数组
python
ney = np.empty(3)
print(ney) # 值是内存里的残留,不确定
像开盲盒------你不知道里面是什么。但它创建速度极快,因为跳过了初始化步骤。适合你确定后面会逐个赋值的场景。
六、数组属性:读懂你的积木
数组创建好了,怎么了解它?看属性:
python
x = np.random.randint(10, size=(3, 4, 5)) # 3层×4行×5列
| 属性 | 含义 | 本例值 |
|---|---|---|
ndim |
维度数 | 3 |
shape |
各维度大小 | (3, 4, 5) |
size |
元素总数 | 60 |
dtype |
数据类型 | int64 |
itemsize |
单个元素占的字节数 | 8 |
nbytes |
总字节数 | 480 |
python
print('维度:', x.ndim) # 3
print('形状:', x.shape) # (3, 4, 5)
print('大小:', x.size) # 60
print('类型:', x.dtype) # int64
nbytes = itemsize × size,记住这个关系就行。
七、切片:精准取值,小心副作用
切片是NumPy最常用的操作之一,但有个坑:切片返回的是视图,不是副本。
python
x = np.array([[3, 5, 2, 4],
[7, 6, 8, 8],
[1, 6, 7, 7]])
x_sub = x[:2, :2] # 前两行、前两列
print(x_sub)
# [[3 5]
# [7 6]]
视图的意思是:你改切片,原数组也跟着变。
python
x_sub[0, :] = 9
print(x_sub) # [[9 9] [7 6]]
print(x) # 原数组也被改了!
# [[9 9 2 4]
# [9 9 8 8]
# [1 6 7 7]]
这就像你通过窗户看房间------你在窗外摆了个花瓶,房间里也多了一个。
想独立操作?用.copy():
python
x_sub_copy = x[:2, :2].copy()
x_sub_copy[0, :] = 1
print(x) # 原数组不受影响
print(x_sub_copy) # 副本独立变化
拍了张照片,照片里的改动不会影响真实的房间。
八、变形:reshape与newaxis
reshape:改变形状,不改内容
python
grid = np.arange(1, 10) # [1 2 3 4 5 6 7 8 9]
grid_reshape = grid.reshape((3, 3))
print(grid_reshape)
# [[1 2 3]
# [4 5 6]
# [7 8 9]]
9个元素可以排成3×3,但排不成4×3------元素总数必须不变。
np.newaxis:增加一个维度
把一维变二维,本质是用None插入一个长度为1的维度:
python
x = np.array([1, 2, 3, 4, 5])
# 变成一行(1×5)
x.reshape(1, 5) # [[1 2 3 4 5]]
x[np.newaxis, :] # 效果一样
# 变成一列(5×1)
x.reshape(5, 1) # [[1] [2] [3] [4] [5]]
x[:, np.newaxis] # 效果一样
什么时候用?做矩阵运算需要对齐维度的时候。比如一个(5,)的向量要和一个(3,5)的矩阵运算,得先把向量变成(1,5)。
九、拼接与分裂:合体与分身
拼接:多个变一个
python
x = np.array([1, 2, 3])
y = np.array([3, 2, 1])
z = np.array([99, 99, 99])
# 一维拼接
np.concatenate([x, y, z]) # [ 1 2 3 3 2 1 99 99 99]
二维数组要指定方向:
python
grid = np.array([[1, 2, 3],
[4, 5, 6]])
# axis=0:上下叠(行方向)
np.concatenate([grid, grid])
# [[1 2 3]
# [4 5 6]
# [1 2 3]
# [4 5 6]]
# axis=1:左右拼(列方向)
np.concatenate([grid, grid], axis=1)
# [[1 2 3 1 2 3]
# [4 5 6 4 5 6]]
还有两个快捷函数:
python
np.vstack([x, y, z, grid]) # 垂直栈,等价于axis=0
np.hstack([grid, grid]) # 水平栈,等价于axis=1
分裂:一个变多个
python
x = [0, 1, 2, 3, 4, 5, 6, 7, 8]
x1, x2, x3 = np.split(x, [3, 5])
print(x1, x2, x3) # [0 1 2] [3 4] [5 6 7 8]
规则:np.split(数组, [断点列表]),N个断点切出N+1段。
二维的分裂:
python
grid = np.arange(16).reshape(4, 4)
# 垂直切:按行分
upper, lower = np.vsplit(grid, [2])
# 水平切:按列分
left, right = np.hsplit(grid, [1])
十、通用函数:向量化的魔法
NumPy的运算不需要for循环,直接对整个数组操作------这就是向量化。
python
x = np.arange(4)
print('x =', x)
print('x + 5 =', x + 5) # [5 6 7 8]
print('x - 5 =', x - 5) # [-5 -4 -3 -2]
print('x * 2 =', x * 2) # [0 2 4 6]
print('x / 2 =', x / 2) # [0. 0.5 1. 1.5]
print('x // 2 =', x // 2) # [0 0 1 1] 取商
print('x % 2 =', x % 2) # [0 1 0 1] 取余
print('x ** 2 =', x ** 2) # [0 1 4 9] 幂运算
print('-x =', -x) # [0 -1 -2 -3]
每种运算都有对应的函数版本:np.add、np.subtract、np.multiply、np.divide、np.power......
绝对值
python
x = np.array([-2, -1, 0, 1, 2])
print(np.abs(x)) # [2 1 0 1 2]
print(np.absolute(x)) # 效果一样
复数的模
python
y = np.array([3 - 4j, 4 - 3j, 2 + 0j, 0 + 1j])
print(abs(y)) # [5. 5. 2. 1.]
复数取绝对值返回的是模 ------实部和虚部平方和再开根号。3-4j的模就是√(9+16)=5。
小时候玩积木,一块一块往上垒,最后能搭出城堡、飞船、整个城市。现在玩NumPy,一个数组一个数组地创建、变形、拼接,最后能处理海量数据、训练模型、解决真实问题。
工具变了,本质没变:从最简单的单元出发,耐心搭建,直到看见全貌。
写在最后
回顾一下今天搭的"积木":
- 基础创建 :
np.array从列表一步到位,zeros/ones/arange快速生成模板 - 随机数组 :
random、uniform、normal各有用途,seed是调试的存档点 - 变形与操作 :
reshape改形状、切片取视图、拼接分裂玩组合 - 向量化运算 :告别
for循环,一行代码搞定批量计算
数组创建是 NumPy 的起点,不是终点。上面的速查表可以收藏备用,接下来你可以继续探索:
- 索引与切片进阶 --- 花式索引、布尔索引
- 广播机制 --- 不同形状的数组如何对齐运算
- 线性代数 --- 矩阵乘法、特征值分解
- 实战项目 --- 用 NumPy 做图像处理、数据分析
速查表
| 场景 | 函数 | 一句话说明 |
|---|---|---|
| 从列表创建 | np.array() |
最基础,什么都往里塞 |
| 全零 | np.zeros() |
初始化占位 |
| 全一 | np.ones() |
同上 |
| 等差数列 | np.arange() |
类似range,但返回数组 |
| 随机浮点 | np.random.random() |
[0,1)区间 |
| 指定范围随机 | np.random.uniform() |
自定义区间 |
| 随机整数 | np.random.randint() |
整数版 |
| 正态分布 | np.random.normal() |
高斯分布 |
| 固定种子 | np.random.seed() |
让随机不随机 |
| 单位矩阵 | np.eye() |
对角线1,其余0 |
| 未初始化 | np.empty() |
快,但值不确定 |
| 变形 | reshape |
改形状不改内容 |
| 加维度 | np.newaxis |
一维变二维 |
| 拼接 | concatenate/vstack/hstack |
合体 |
| 分裂 | split/vsplit/hsplit |
分身 |
大家在实际项目中用过哪些 NumPy 的创建技巧?有没有踩过什么坑?
欢迎在评论区分享你的经验 👇
如果觉得有帮助,点个赞👍 支持一下,后续会继续更新 NumPy 系列~