NumPy 副本和視圖
副本是一個數據的完整的拷貝,如果我們對副本進行修改,它不會影響到原始數據,物理記憶體不在同一位置。
視圖是數據的一個別稱或引用,通過該別稱或引用亦便可訪問、操作原有數據,但原有數據不會產生拷貝。如果我們對視圖進行修改,它會影響到原始數據,物理記憶體在同一位置。
視圖一般發生在:
- 1、numpy 的切片操作返回原數據的視圖。
- 2、調用 ndarray 的 view() 函數產生一個視圖。
副本一般發生在:
- Python 序列的切片操作,調用deepCopy()函數。
- 調用 ndarray 的 copy() 函數產生一個副本。
無複製
簡單的賦值不會創建數組對象的副本。 相反,它使用原始數組的相同id()來訪問它。 id()返回 Python 對象的通用識別字,類似於 C 中的指針。
此外,一個數組的任何變化都反映在另一個數組上。 例如,一個數組的形狀改變也會改變另一個數組的形狀。
實例
import numpy as np
a = np.arange(6)
print ('我們的數組是:')
print (a)
print ('調用 id() 函數:')
print (id(a))
print ('a 賦值給 b:')
b = a
print (b)
print ('b 擁有相同 id():')
print (id(b))
print ('修改 b 的形狀:')
b.shape = 3,2
print (b)
print ('a 的形狀也修改了:')
print (a)
輸出結果為:
我們的數組是: [0 1 2 3 4 5] 調用 id() 函數: 4349302224 a 賦值給 b: [0 1 2 3 4 5] b 擁有相同 id(): 4349302224 修改 b 的形狀: [[0 1] [2 3] [4 5]] a 的形狀也修改了: [[0 1] [2 3] [4 5]]
視圖或淺拷貝
ndarray.view() 方會創建一個新的數組對象,該方法創建的新數組的維數更改不會更改原始數據的維數。
實例
import numpy as np
# 最開始 a 是個 3X2 的數組
a = np.arange(6).reshape(3,2)
print ('數組 a:')
print (a)
print ('創建 a 的視圖:')
b = a.view()
print (b)
print ('兩個數組的 id() 不同:')
print ('a 的 id():')
print (id(a))
print ('b 的 id():' )
print (id(b))
# 修改 b 的形狀,並不會修改 a
b.shape = 2,3
print ('b 的形狀:')
print (b)
print ('a 的形狀:')
print (a)
輸出結果為:
數組 a: [[0 1] [2 3] [4 5]] 創建 a 的視圖: [[0 1] [2 3] [4 5]] 兩個數組的 id() 不同: a 的 id(): 4314786992 b 的 id(): 4315171296 b 的形狀: [[0 1 2] [3 4 5]] a 的形狀: [[0 1] [2 3] [4 5]]
使用切片創建視圖修改數據會影響到原始數組:
實例
import numpy as np
arr = np.arange(12)
print ('我們的數組:')
print (arr)
print ('創建切片:')
a=arr[3:]
b=arr[3:]
a[1]=123
b[2]=234
print(arr)
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 11] 4545878416 4545878496 4545878576
變數 a,b 都是 arr 的一部分視圖,對視圖的修改會直接反映到原數據中。但是我們觀察 a,b 的 id,他們是不同的,也就是說,視圖雖然指向原數據,但是他們和賦值引用還是有區別的。
副本或深拷貝
ndarray.copy() 函數創建一個副本。 對副本數據進行修改,不會影響到原始數據,它們物理記憶體不在同一位置。
實例
import numpy as np
a = np.array([[10,10], [2,3], [4,5]])
print ('數組 a:')
print (a)
print ('創建 a 的深層副本:')
b = a.copy()
print ('數組 b:')
print (b)
# b 與 a 不共用任何內容
print ('我們能夠寫入 b 來寫入 a 嗎?')
print (b is a)
print ('修改 b 的內容:')
b[0,0] = 100
print ('修改後的數組 b:')
print (b)
print ('a 保持不變:')
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]]