NumPy 从已有的数组创建数组(保姆级教程)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
在数据科学和数值计算领域,NumPy 是 Python 生态中最核心的库之一。它提供了高效的数组操作能力,而从已有的数组创建数组是 NumPy 的核心功能之一。无论是进行数据预处理、算法优化,还是构建复杂的数据结构,开发者都需要掌握如何灵活地从现有数组生成新数组。本文将从基础到进阶,结合实际案例,系统讲解这一主题,帮助读者理解不同方法的适用场景,并避免常见陷阱。
一、基础方法:直接复制与视图操作
1.1 使用 array()
函数直接复制
最直观的方式是通过 numpy.array()
函数将现有数组作为输入参数,生成一个完全独立的新数组。例如:
import numpy as np
original = np.array([1, 2, 3])
new_array = np.array(original)
print("Original:", original)
print("New Array:", new_array)
输出结果:
Original: [1 2 3]
New Array: [1 2 3]
这种做法类似于“复印文件”,新数组与原数组的内存地址完全独立,修改一方不会影响另一方。
1.2 视图(View)与浅拷贝
通过 view()
方法可以创建原数组的“镜像”:
view_array = original.view()
view_array[0] = 100
print("Original after modification:", original)
输出结果:
Original after modification: [100 2 3]
此时,view_array
是原数组的视图,共享同一块内存。这种“镜像”关系类似于两人共用同一本书,修改内容会同步到所有人。
1.3 深拷贝:完全独立的副本
若希望彻底隔离原数组与新数组,需使用 copy()
方法:
deep_copy = original.copy()
deep_copy[1] = 200
print("Original remains unchanged:", original) # 输出仍为 [100 2 3]
这类似于将一本书复印一份,修改复印件不会影响原书。
二、基于形状变换的数组创建
2.1 reshape()
:调整数组维度
通过 reshape()
可以将原数组“变形”为指定形状,同时保持数据内容不变。例如:
matrix = np.array([[1, 2, 3], [4, 5, 6]])
flattened = matrix.reshape(1, 6) # 转为 1×6 的二维数组
print(flattened) # 输出 [[1 2 3 4 5 6]]
此操作类似于将一张纸折叠成不同的形状,但内容并未改变。
2.2 flatten()
与 ravel()
:展平数组
flatten()
会返回一个完全独立的副本:flat1 = matrix.flatten() flat1[0] = 0 print("Original matrix remains:", matrix[0, 0]) # 输出 1
ravel()
返回的是原数组的视图,修改会影响原数组:flat2 = matrix.ravel() flat2[0] = 10 print("Original matrix changed:", matrix[0, 0]) # 输出 10
三、基于数据重复的数组扩展
3.1 repeat()
:重复元素
通过 repeat()
可以对数组元素进行重复操作,例如:
repeated = np.array([1, 2]).repeat(3) # 每个元素重复3次
print(repeated) # 输出 [1 1 1 2 2 2]
这类似于将一个乐高积木块复制多份,按顺序排列。
3.2 tile()
:重复整个数组
tile()
可以将整个数组作为“瓷砖”重复拼接:
tiled = np.tile(np.array([0, 1]), 2) # 沿轴0重复2次
print(tiled) # 输出 [0 1 0 1]
这类似于将图案瓷砖铺满整个墙面。
四、基于索引与切片的数组构建
4.1 切片操作
通过切片可以提取原数组的子集,并生成新数组:
subset = original[1:] # 提取索引1及之后的元素
print(subset) # 输出 [2 3]
切片操作默认返回视图,因此修改子集会影响原数组:
subset[0] = 5
print(original) # 输出 [1 5 3]
4.2 take()
与 put()
:高级索引
take()
根据索引列表提取元素:indices = [0, 2] selected = original.take(indices) # 输出 [1 3]
put()
根据索引列表修改元素:original.put([1], 6) # 将索引1的元素设为6 print(original) # 输出 [1 6 3]
五、基于数学运算的数组生成
5.1 向量化操作
通过向量化运算,可以快速生成基于原数组的新数组:
new_array = original * 2 + 1 # 每个元素乘2加1
print(new_array) # 输出 [3 13 7]
这类似于对每个积木块进行加工,生成新形态。
5.2 广播(Broadcasting)
当数组形状不同时,NumPy 会自动进行广播操作,例如:
a = np.array([[1], [2], [3]]) # 3×1
b = np.array([4, 5, 6]) # 1×3
result = a + b
print(result)
广播机制类似于将不同尺寸的画布对齐,自动扩展数据以匹配形状。
六、进阶技巧与注意事项
6.1 判断数组是否共享内存
通过 base
属性或 numpy.may_share_memory()
可以检测数组间的关系:
print(view_array.base is original) # 输出 True
print(deep_copy.base is None) # 输出 True
6.2 处理高维数组的技巧
对于多维数组,可通过 ndarray.T
转置或 swapaxes()
调整轴顺序:
matrix = np.array([[[1], [2]], [[3], [4]]]) # 2×2×1
transposed = matrix.swapaxes(0, 2) # 转换轴0和轴2
print(transposed.shape) # 输出 (1, 2, 2)
6.3 避免常见陷阱
- 视图的修改风险:若误操作视图,可能导致原数据意外改变。
- 内存泄漏:频繁创建大数组的视图可能占用额外内存。
- 广播规则限制:非兼容的形状会导致广播失败,需通过
reshape()
调整。
七、实际案例:图像处理中的数组操作
7.1 图像灰度化
假设有一个 RGB 图像数组 image
(形状为 height×width×3
),可通过以下方式提取灰度值:
gray = image.mean(axis=2).astype(np.uint8) # 沿通道轴求均值
这将生成一个二维数组,表示灰度图像。
7.2 数据标准化
在机器学习中,常需将数据标准化到均值为0、方差为1:
data = np.array([[1, 2], [3, 4]])
mean = data.mean(axis=0)
std = data.std(axis=0)
normalized = (data - mean) / std
结论
NumPy 从已有的数组创建数组是数据操作的核心技能。通过本文介绍的 view()
、copy()
、reshape()
、repeat()
等方法,开发者可以灵活地生成新数组,并根据需求选择独立副本或共享视图。无论是处理图像、分析数据,还是构建复杂算法,掌握这些技巧都能显著提升效率与代码的可读性。建议读者通过实际项目练习,逐步熟悉不同方法的应用场景,并通过调试工具验证数组间的内存关系,避免潜在问题。
(全文约 1800 字)