python中numpy怎么改变数组的形状(reshape)?

冰火之心
发布: 2025-09-22 17:02:01
原创
695人浏览过
NumPy中reshape()与resize()的核心差异在于:reshape()返回新形状的视图,不改变原数组,要求元素总数不变;resize()则原地修改数组,可改变元素数量,不足时填充0,多余时截断。

python中numpy怎么改变数组的形状(reshape)?

在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),这意味着新数组和原数组共享底层数据。如果你修改了新数组,原数组的数据也会跟着改变,反之亦然。当然,如果无法返回视图(例如内存布局不连续),它可能会返回一个副本。

立即学习Python免费学习笔记(深入)”;

一个非常方便的特性是,你可以在新形状的元组中使用

-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()
登录后复制

阿里云-虚拟数字人
阿里云-虚拟数字人

阿里云-虚拟数字人是什么? ...

阿里云-虚拟数字人 2
查看详情 阿里云-虚拟数字人

在NumPy中,如何将任意维度的数组展平(flatten)为一维?

将多维数组展平为一维数组,是数据预处理和机器学习中非常常见的操作,比如在将图像数据输入到全连接层之前。NumPy提供了几种灵活的方式来实现这一点,每种方式都有其细微的差别和适用场景。

最直接也是我个人最常用的一种方式是结合

reshape()
登录后复制
-1
登录后复制
占位符:

  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还提供了两个专门用于展平的方法:

  1. 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)
    登录后复制
  2. 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中进行数组形状操作时,虽然看似简单,但一些常见的陷阱可能会让人头疼。理解这些错误并掌握规避策略,能帮助我们更顺畅地处理数据。

  1. 元素总数不匹配(

    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自动计算,这样可以避免手动计算错误。这是我个人最喜欢也最常用的方法,可以大幅减少这类错误。
  2. 视图(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
      登录后复制
      会指向原始数组)。
  3. 内存布局(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的,可以使用这个函数来创建一个副本。
  4. resize()
    登录后复制
    的潜在副作用 前面已经提到,
    resize()
    登录后复制
    会原地修改数组,并可能改变元素总数(填充或截断)。如果在不恰当的时候使用它,比如在函数内部对传入的数组进行
    resize
    登录后复制
    操作,可能会对函数外部的原始数组造成意料之外的修改。

    规避策略

    • 优先使用
      reshape()
      登录后复制
      :除非你明确需要原地修改并接受元素数量的改变,否则优先使用非破坏性的
      reshape()
      登录后复制
    • 谨慎使用
      arr.resize()
      登录后复制
      :如果你确实需要
      resize
      登录后复制
      的功能,请确保你清楚它将如何影响你的数据,并且这正是你想要的行为。在函数内部,如果需要改变数组大小,通常更好的做法是创建一个新数组并返回。

在我看来,掌握这些规避策略,特别是对视图与副本的理解,以及善用

-1
登录后复制
占位符,可以大大提高我们使用NumPy进行数据处理的效率和代码的健壮性。这些细节虽然小,但往往是导致bug的根源。

以上就是python中numpy怎么改变数组的形状(reshape)?的详细内容,更多请关注php中文网其它相关文章!

python速学教程(入门到精通)
python速学教程(入门到精通)

python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号