numpyreshape函数使用教程
时间:2025-10-12 08:51:29 146浏览 收藏
大家好,今天本人给大家带来文章《numpy如何用reshape改变数组形状》,文中内容主要涉及到,如果你对文章方面的知识点感兴趣,那就请各位朋友继续看下去吧~希望能真正帮到你们,谢谢!
NumPy中reshape()与resize()的核心差异在于:reshape()返回新形状的视图,不改变原数组,要求元素总数不变;resize()则原地修改数组,可改变元素数量,不足时填充0,多余时截断。

在Python中,NumPy数组改变形状(或者说重塑)最核心、最常用的方法是使用reshape()函数。它能够根据你指定的新维度,返回一个拥有相同数据但形状不同的新数组视图,而不会修改原始数组。
解决方案
当我们需要改变NumPy数组的形状时,numpy.reshape()方法是我们的首选工具。它的基本用法是接收一个元组作为参数,这个元组定义了你希望数组变成的新形状。
举个例子,假设你有一个一维数组,里面有12个元素,你想把它变成一个3行4列的二维数组:
import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
print("原始数组:", arr)
print("原始形状:", arr.shape) # 输出 (12,)
# 使用 reshape 改变形状
new_arr = arr.reshape((3, 4))
print("\n重塑后的数组:\n", new_arr)
print("新形状:", new_arr.shape) # 输出 (3, 4)
# 验证原始数组未被修改
print("\n原始数组(确认未修改):", arr)这里需要注意的是,reshape()通常会返回一个视图(view),这意味着新数组和原数组共享底层数据。如果你修改了新数组,原数组的数据也会跟着改变,反之亦然。当然,如果无法返回视图(例如内存布局不连续),它可能会返回一个副本。
一个非常方便的特性是,你可以在新形状的元组中使用-1作为其中一个维度。NumPy会根据数组的总元素数量和其余维度自动推断出这个维度的大小。这在处理不确定其中一个维度时特别有用。
# 使用 -1 让 NumPy 自动推断维度
arr_2d = arr.reshape((2, -1)) # 变成2行,列数自动推断
print("\n使用 -1 重塑为 (2, -1):\n", arr_2d)
print("形状:", arr_2d.shape) # 输出 (2, 6)
arr_3d = arr.reshape((-1, 2, 2)) # 变成 x 层,每层2行2列
print("\n使用 -1 重塑为 (-1, 2, 2):\n", arr_3d)
print("形状:", arr_3d.shape) # 输出 (3, 2, 2)但无论如何重塑,一个基本原则是:新形状的元素总数必须与原始数组的元素总数保持一致。否则,NumPy会抛出一个ValueError。
NumPy中reshape()与resize()方法的核心差异是什么?
说实话,刚开始接触NumPy时,我个人也常常会混淆reshape()和resize()这两个方法。它们听起来都像是“改变大小”,但实际操作起来,核心区别非常大,理解这一点对于避免一些意想不到的问题至关重要。
reshape()方法,就像我们前面提到的,它的主要功能是返回一个具有新形状的数组视图,而不会修改原始数组。它要求新旧数组的元素总数必须严格相等。这使得reshape()成为一个非常“安全”的操作,因为它不会破坏你原有的数据结构,你总是可以得到一个新的、形状不同的数组,而原始数据保持不变。在数据分析和处理流程中,我们经常需要对数据进行不同维度的观察,reshape()的非破坏性使得它成为首选。
import numpy as np
original_arr = np.arange(6) # [0, 1, 2, 3, 4, 5]
reshaped_arr = original_arr.reshape((2, 3))
print("原始数组:", original_arr)
print("重塑后的数组:\n", reshaped_arr)
# 尝试修改重塑后的数组
reshaped_arr[0, 0] = 99
print("\n修改重塑后的数组后,原始数组:", original_arr) # 原始数组也会被修改,因为是视图而numpy.resize()(无论是作为函数np.resize()还是数组方法arr.resize())则完全不同。它的主要特点是原地修改数组的形状,并且可以改变数组的元素总数。如果新形状的元素总数大于原始数组,NumPy会用零来填充新增的部分;如果小于原始数组,则会截断多余的元素。这听起来可能很方便,但在实际使用中,它的“破坏性”往往需要我们更加小心。
# np.resize() 作为函数,返回一个新数组
arr_func_resize = np.arange(4) # [0, 1, 2, 3]
resized_by_func = np.resize(arr_func_resize, (3, 3)) # 元素总数从4变为9,会填充0
print("\n使用 np.resize() 函数重塑并填充:\n", resized_by_func)
print("原始数组(函数操作不影响):", arr_func_resize)
# arr.resize() 作为数组方法,原地修改
arr_method_resize = np.arange(4) # [0, 1, 2, 3]
print("\n原地修改前:", arr_method_resize)
arr_method_resize.resize((2, 3)) # 元素总数从4变为6,填充0
print("原地修改后:\n", arr_method_resize)
arr_method_truncate = np.arange(6) # [0, 1, 2, 3, 4, 5]
print("\n原地截断前:", arr_method_truncate)
arr_method_truncate.resize((2, 2)) # 元素总数从6变为4,截断
print("原地截断后:\n", arr_method_truncate)在我看来,resize()方法更像是“改变数组的大小并适应新大小”,而reshape()更像是“在保持数据不变的前提下,重新组织数据的观察方式”。由于resize()会改变元素数量并原地修改,我个人在大部分情况下会倾向于使用reshape(),因为它更可控,不易产生副作用。只有当我明确需要改变数组大小并接受其填充或截断行为时,才会考虑resize()。
在NumPy中,如何将任意维度的数组展平(flatten)为一维?
将多维数组展平为一维数组,是数据预处理和机器学习中非常常见的操作,比如在将图像数据输入到全连接层之前。NumPy提供了几种灵活的方式来实现这一点,每种方式都有其细微的差别和适用场景。
最直接也是我个人最常用的一种方式是结合reshape()和-1占位符:
arr.reshape(-1): 这是将数组展平为一维的最简洁方式。通过指定一个维度为-1,NumPy会自动计算出这个维度的大小,而其他维度则被隐式地“压缩”掉。这种方法通常会返回一个视图,这意味着它不会复制数据,因此效率很高。import numpy as np matrix = np.array([[1, 2, 3], [4, 5, 6]]) print("原始矩阵:\n", matrix) flattened_by_reshape = matrix.reshape(-1) print("\n通过 reshape(-1) 展平:\n", flattened_by_reshape) print("形状:", flattened_by_reshape.shape)
除了reshape(-1),NumPy还提供了两个专门用于展平的方法:
arr.flatten(): 这个方法会返回一个新的数组副本,其中包含了原始数组的所有元素,并以一维形式排列。由于它创建了一个副本,对展平后的数组的修改不会影响原始数组。这在你需要独立操作展平数据而不想影响原数据时非常有用。它默认以C-order(行优先)进行展平,但你可以通过order参数指定为F-order(列优先)。flattened_by_flatten = matrix.flatten() print("\n通过 flatten() 展平 (副本):\n", flattened_by_flatten) flattened_by_flatten[0] = 99 # 修改副本 print("修改副本后:", flattened_by_flatten) print("原始矩阵(未受影响):\n", matrix) # 以F-order展平 flattened_f_order = matrix.flatten(order='F') print("\n通过 flatten() 以 F-order 展平:\n", flattened_f_order)arr.ravel():ravel()方法与flatten()非常相似,它也返回一个一维数组。但关键区别在于,ravel()会尽可能地返回一个视图。只有当无法创建视图(例如,数组不是C-contiguous或F-contiguous时),它才会返回一个副本。这意味着ravel()在大多数情况下比flatten()更高效,因为它避免了数据复制。与flatten()一样,它也支持order参数。flattened_by_ravel = matrix.ravel() print("\n通过 ravel() 展平 (视图或副本):\n", flattened_by_ravel) flattened_by_ravel[0] = 100 # 如果是视图,原始矩阵会改变 print("修改 ravel() 结果后:", flattened_by_ravel) print("原始矩阵(可能受影响):\n", matrix) # 这里的 matrix 会变成 [[100, 2, 3], [4, 5, 6]]
在我个人实践中,如果我需要一个独立的数据副本,我可能会明确使用flatten()。但如果我只是想以一维方式处理数据,并且不介意它是一个视图(或者知道我不会修改它),那么reshape(-1)或ravel()通常是更高效的选择。特别是在处理大型数据集时,避免不必要的数据复制可以显著提升性能。
NumPy数组形状操作中常见的错误与规避策略有哪些?
在NumPy中进行数组形状操作时,虽然看似简单,但一些常见的陷阱可能会让人头疼。理解这些错误并掌握规避策略,能帮助我们更顺畅地处理数据。
元素总数不匹配(
ValueError) 这是最常见也最直接的错误。当你尝试将一个数组重塑成一个新的形状,但新形状所能容纳的元素总数与原始数组的元素总数不一致时,NumPy会抛出ValueError: cannot reshape array of size X into shape Y。import numpy as np arr = np.arange(10) # 10个元素 # 错误示例:尝试重塑为 (3, 3),只有9个元素空间 try: arr.reshape((3, 3)) except ValueError as e: print(f"\n捕获到错误: {e}")规避策略:
- 检查元素总数:在重塑之前,始终确保
arr.size(原始数组的元素总数)与你目标形状的乘积相等。例如,np.prod(new_shape)。 - 使用
-1占位符:如果有一个维度的大小不确定,使用-1让NumPy自动计算,这样可以避免手动计算错误。这是我个人最喜欢也最常用的方法,可以大幅减少这类错误。
- 检查元素总数:在重塑之前,始终确保
视图(View)与副本(Copy)的混淆 如前所述,
reshape()和ravel()通常返回视图,而flatten()返回副本。如果你不清楚这一点,可能会导致原始数据被意外修改,或者在预期修改副本时却修改了原始数据。original = np.array([[1, 2], [3, 4]]) reshaped_view = original.reshape(-1) flattened_copy = original.flatten() reshaped_view[0] = 99 # 修改视图 print("\n修改视图后,原始数组:", original) # original 变成了 [[99, 2], [3, 4]] flattened_copy[0] = 88 # 修改副本 print("修改副本后,原始数组:", original) # original 仍然是 [[99, 2], [3, 4]]规避策略:
- 明确何时需要副本:如果你需要一个独立的数据集进行操作,而不影响原始数据,请显式地使用
.copy()方法,或者选择flatten()。 - 理解操作的返回值:记住
reshape()和ravel()倾向于返回视图,而flatten()返回副本。当不确定时,可以通过arr.base is None来判断一个数组是否是另一个数组的视图(如果是视图,base会指向原始数组)。
- 明确何时需要副本:如果你需要一个独立的数据集进行操作,而不影响原始数据,请显式地使用
内存布局(C-order vs. F-order)的影响 NumPy数组在内存中可以是行优先(C-order,默认)或列优先(F-order)存储。在大多数情况下,这不会直接导致错误,但在进行重塑时,特别是从一个维度跳到另一个维度时,它会影响元素的读取顺序。如果你从其他语言(如MATLAB)或库中获取数据,这可能会导致数据的意外排列。
arr_c = np.arange(6).reshape((2, 3), order='C') arr_f = np.arange(6).reshape((2, 3), order='F') print("\nC-order 数组:\n", arr_c) print("F-order 数组:\n", arr_f) # 尝试将 F-order 数组重塑为不同形状,可能会导致元素顺序的误解 reshaped_from_f = arr_f.reshape((3, 2), order='C') # 以C-order方式重塑 print("\n从 F-order 数组以 C-order 重塑:\n", reshaped_from_f)规避策略:
- 保持一致性:尽可能在整个数据处理流程中保持一致的内存顺序。
- 明确指定
order参数:在reshape()、flatten()和ravel()中,你可以使用order='C'(默认)或order='F'来明确指定元素的读取顺序。当与外部数据交互或需要特定性能优化时,这尤其重要。 np.ascontiguousarray():如果你需要确保数组是C-contiguous的,可以使用这个函数来创建一个副本。
resize()的潜在副作用 前面已经提到,resize()会原地修改数组,并可能改变元素总数(填充或截断)。如果在不恰当的时候使用它,比如在函数内部对传入的数组进行resize操作,可能会对函数外部的原始数组造成意料之外的修改。规避策略:
- 优先使用
reshape():除非你明确需要原地修改并接受元素数量的改变,否则优先使用非破坏性的reshape()。 - 谨慎使用
arr.resize():如果你确实需要resize的功能,请确保你清楚它将如何影响你的数据,并且这正是你想要的行为。在函数内部,如果需要改变数组大小,通常更好的做法是创建一个新数组并返回。
- 优先使用
在我看来,掌握这些规避策略,特别是对视图与副本的理解,以及善用-1占位符,可以大大提高我们使用NumPy进行数据处理的效率和代码的健壮性。这些细节虽然小,但往往是导致bug的根源。
以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于文章的相关知识,也可关注golang学习网公众号。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
296 收藏
-
351 收藏
-
157 收藏
-
485 收藏
-
283 收藏
-
349 收藏
-
291 收藏
-
204 收藏
-
401 收藏
-
227 收藏
-
400 收藏
-
327 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习