zoukankan      html  css  js  c++  java
  • 17、NumPy——副本和视图

    副本是一个数据的完整的拷贝,如果我们对副本进行修改,它不会影响到原始数据,物理内存不在同一位置。

    视图是数据的一个别称或引用,通过该别称或引用亦便可访问、操作原有数据,但原有数据不会产生拷贝。如果我们对视图进行修改,它会影响到原始数据,物理内存在同一位置。

    视图一般发生在:

    • 1、numpy 的切片操作返回原数据的视图。
    • 2、调用 ndarray 的 view() 函数产生一个视图。

    副本一般发生在:

    • Python 序列的切片操作,调用deepCopy()函数。
    • 调用 ndarray 的 copy() 函数产生一个副本。

    1、无复制

    简单的赋值不会创建数组对象的副本。 相反,它使用原始数组的相同id()来访问它。 id()返回 Python 对象的通用标识符,类似于 C 中的指针。

    此外,一个数组的任何变化都反映在另一个数组上。 例如,一个数组的形状改变也会改变另一个数组的形状。

     1 import numpy as np
     2 a = np.arange(6)
     3 print('我们的数组是:')
     4 print(a)
     5 print('调用 id() 函数:')
     6 print(id(a))
     7 print('a 赋值给 b:')
     8 b = a
     9 print(b)
    10 print('b 拥有相同 id():')
    11 print(id(b))
    12 print('修改 b 的形状:')
    13 b.shape = (3, 2)
    14 print(b)
    15 print('a 的形状也修改了:')
    16 print(a)

    执行结果:

    我们的数组是:
    [0 1 2 3 4 5]
    调用 id() 函数:
    1463892179824
    a 赋值给 b:
    [0 1 2 3 4 5]
    b 拥有相同 id():
    1463892179824
    修改 b 的形状:
    [[0 1]
     [2 3]
     [4 5]]
    a 的形状也修改了:
    [[0 1]
     [2 3]
     [4 5]]

    2、视图或浅拷贝

    ndarray.view() 方会创建一个新的数组对象,该方法创建的新数组的维数更改不会更改原始数据的维数。

     1 import numpy as np
     2 
     3 # 最开始 a 是个 3X2 的数组
     4 a = np.arange(6).reshape(3, 2)
     5 print('数组 a:')
     6 print(a)
     7 print('创建 a 的视图:')
     8 b = a.view()
     9 print(b)
    10 print('两个数组的 id() 不同:')
    11 print('a 的 id():')
    12 print(id(a))
    13 print('b 的 id():')
    14 print(id(b))
    15 # 修改 b 的形状,并不会修改 a
    16 b.shape = (2, 3)
    17 print('b 的形状:')
    18 print(b)
    19 print('a 的形状:')
    20 print(a)

    执行结果:

    数组 a:
    [[0 1]
     [2 3]
     [4 5]]
    创建 a 的视图:
    [[0 1]
     [2 3]
     [4 5]]
    两个数组的 id() 不同:
    a 的 id():
    2213940021408
    b 的 id():
    2213969165728
    b 的形状:
    [[0 1 2]
     [3 4 5]]
    a 的形状:
    [[0 1]
     [2 3]
     [4 5]]

    3、使用切片创建视图修改数据会影响到原始数组:

     1 import numpy as np
     2 arr = np.arange(12)
     3 print('我们的数组:')
     4 print(arr)
     5 print('创建切片:')
     6 a = arr[3:]
     7 b = arr[3:]
     8 a[1] = 123
     9 b[2] = 234
    10 print(arr)
    11 print(id(a), id(b), id(arr[3:]))

    执行结果:

    我们的数组:
    [ 0  1  2  3  4  5  6  7  8  9 10 11]
    创建切片:
    [  0   1   2   3 123 234   6   7   8   9  10

    变量 a,b 都是 arr 的一部分视图,对视图的修改会直接反映到原数据中。但是我们观察 a,b 的 id,他们是不同的,也就是说,视图虽然指向原数据,但是他们和赋值引用还是有区别的。

    4、副本或深拷贝

    ndarray.copy() 函数创建一个副本。 对副本数据进行修改,不会影响到原始数据,它们物理内存不在同一位置。

     1 import numpy as np
     2 a = np.array([[10, 10], [2, 3], [4, 5]])
     3 print('数组 a:')
     4 print(a)
     5 print('创建 a 的深层副本:')
     6 b = a.copy()
     7 print('数组 b:')
     8 print(b)
     9 # b 与 a 不共享任何内容
    10 print('我们能够写入 b 来写入 a 吗?')
    11 print(b is a)
    12 print('修改 b 的内容:')
    13 b[0, 0] = 100
    14 print('修改后的数组 b:')
    15 print(b)
    16 print('a 保持不变:')
    17 print(a)

    执行结果:

    数组 a:
    [[10 10]
     [ 2  3]
     [ 4  5]]
    创建 a 的深层副本:
    数组 b:
    [[10 10]
     [ 2  3]
     [ 4  5]]
    我们能够写入 b 来写入 a 吗?
    False
    修改 b 的内容:
    修改后的数组 b:
    [[100  10]
     [  2   3]
     [  4   5]]
    a 保持不变:
    [[10 10]
     [ 2  3]
     [ 4  5]]

    拓展:Python 中 list 的拷贝与 numpy 的 array 的拷贝

    1.python中列表list的拷贝,会有什么需要注意的呢?

    Python 变量名相当于标签名。

    list2=list1 直接赋值,实质上指向的是同一个内存值。任意一个变量 list1(或list2)发生改变,都会影响另一个 list2(或list1)。

    list1 = [i for i in range(4)]
    list2 = list1
    print('原列表为:
    ', list1)
    print('修改list2:')
    list2[0] = 100
    print('list1={}
    list2={}'.format(list1, list2))

    执行结果:

    原列表为:
     [0, 1, 2, 3]
    修改list2:
    list1=[100, 1, 2, 3]
    list2=[100, 1, 2, 3]
  • 相关阅读:
    (原创)神舟笔记本bios设置——神船战神ZX7-CP7S2 <一>
    Kali笔记<三> 安装中文输入法
    (原创)Kali笔记<二>root权限的使用和启用
    (原创)Kali笔记<一>虚拟机安装Kali
    加快vmware虚拟机运行速度的方法(大牛勿笑)
    PR/AE/PS 素材模板网站
    批量查杀该死的VBscript “svchost.exe” 脚本挂马
    echarts统计图Y轴(或X轴)文字过长问题解决
    正则实例
    Angular.js的自定义功能
  • 原文地址:https://www.cnblogs.com/weststar/p/11592669.html
Copyright © 2011-2022 走看看