NumPy数组创建完全指南:从零搭建你的数字积木城

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.addnp.subtractnp.multiplynp.dividenp.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 快速生成模板
  • 随机数组randomuniformnormal 各有用途,seed 是调试的存档点
  • 变形与操作reshape 改形状、切片取视图、拼接分裂玩组合
  • 向量化运算 :告别 for 循环,一行代码搞定批量计算

数组创建是 NumPy 的起点,不是终点。上面的速查表可以收藏备用,接下来你可以继续探索:

  1. 索引与切片进阶 --- 花式索引、布尔索引
  2. 广播机制 --- 不同形状的数组如何对齐运算
  3. 线性代数 --- 矩阵乘法、特征值分解
  4. 实战项目 --- 用 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 系列~

相关推荐
王小菲1 小时前
你能在泰坦尼克号上活下来吗-利用python进行探索性数据分析
python
FBI HackerHarry浩1 小时前
在Python中TCP网络程序开发的步骤流程
运维·服务器·开发语言·网络·python·pycharm
Cosmoshhhyyy1 小时前
《Effective Java》解读第54条:返回零长度的数组或者集合,而不是null
java·开发语言·python
sleven fung1 小时前
GPT4All 本地大语言模型运行环境介绍
python·gpt·ai·langchain
zyl837211 小时前
Python 四大核心数据结构:列表、字典、元组、集合
数据结构·windows·python
燐妤1 小时前
现代 Python Web 框架:FastAPI实战指南
python·fastapi
清风一徐1 小时前
Python函数基础
开发语言·python
花落yu1 小时前
【无标题】
pytorch·python·深度学习
zhangfeng11331 小时前
htc 中minconda 明明安装了 Python 3.10显示 python 3.8 因为 `conda activate` 没有真正切换成功
开发语言·python·conda