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 字)

最新发布