B18_NumPy副本和视图(视图或浅拷贝、副本或深拷贝、深浅拷贝)
NumPy副本和視圖
副本是一個數(shù)據(jù)的完整的拷貝,如果我們對副本進(jìn)行修改,它不會影響到原始數(shù)據(jù),物理內(nèi)存不在同一位置。
視圖是數(shù)據(jù)的一個別稱或引用,通過該別稱或引用亦便可訪問、操作原有數(shù)據(jù),但原有數(shù)據(jù)不會產(chǎn)生拷貝。如果我們對視圖進(jìn)行修改,它會影響到原始數(shù)據(jù),物理內(nèi)存在同一位置。
視圖一般發(fā)生在:
-
1、numpy的切片操作返回原數(shù)據(jù)的視圖。
-
2、調(diào)用ndarray的view()函數(shù)產(chǎn)生一個視圖。
副本一般發(fā)生在: -
Python序列的切片操作,調(diào)用deepCopy()函數(shù)。
-
調(diào)用ndarray的copy()函數(shù)產(chǎn)生一個副本。
無復(fù)制
簡單的賦值不會創(chuàng)建數(shù)組對象的副本。 相反,它使用原始數(shù)組的相同id()來訪問它。 id()返回 Python 對象的通用標(biāo)識符,類似于 C 中的指針。
此外,一個數(shù)組的任何變化都反映在另一個數(shù)組上。 例如,一個數(shù)組的形狀改變也會改變另一個數(shù)組的形狀。
實(shí)例
輸出結(jié)果為:
我們的數(shù)組是: [0 1 2 3 4 5] 調(diào)用 id() 函數(shù): 2160389265488 a 賦值給 b: [0 1 2 3 4 5] b 擁有相同 id(): 2160389265488 修改 b 的形狀: [[0 1][2 3][4 5]]視圖或淺拷貝
ndarray.view() 方會創(chuàng)建一個新的數(shù)組對象,該方法創(chuàng)建的新數(shù)組的維數(shù)更改不會更改原始數(shù)據(jù)的維數(shù)。
實(shí)例
輸出結(jié)果為:
數(shù)組 a: [[0 1][2 3][4 5]] 創(chuàng)建 a 的視圖: [[0 1][2 3][4 5]] 兩個數(shù)組的 id() 不同: a 的 id(): 2336918390944 b 的 id(): 2336918391184 b 的形狀: [[0 1 2][3 4 5]] a 的形狀: [[0 1][2 3][4 5]]使用切片創(chuàng)建視圖修改數(shù)據(jù)會影響到原始數(shù)組:
import numpy as nparr = np.arange(12) print('我們的數(shù)組:') print(arr) print('創(chuàng)建切片:') a = arr[3:] b = arr[3:] a[1] = 123 b[2] = 234 print(arr) print(id(a), id(b), id(arr[3:]))輸出結(jié)果為:
我們的數(shù)組: [ 0 1 2 3 4 5 6 7 8 9 10 11] 創(chuàng)建切片: [ 0 1 2 3 123 234 6 7 8 9 10 11] 2897481484528 2897481484448 2897481484688變量 a,b 都是 arr 的一部分視圖,對視圖的修改會直接反映到原數(shù)據(jù)中。但是我們觀察 a,b 的 id,他們是不同的,也就是說,視圖雖然指向原數(shù)據(jù),但是他們和賦值引用還是有區(qū)別的。
副本或深拷貝
ndarray.copy() 函數(shù)創(chuàng)建一個副本。 對副本數(shù)據(jù)進(jìn)行修改,不會影響到原始數(shù)據(jù),它們物理內(nèi)存不在同一位置。
import numpy as npa = np.array([[10, 10], [2, 3], [4, 5]]) print('數(shù)組 a:') print(a) print('創(chuàng)建 a 的深層副本:') b = a.copy() print('數(shù)組 b:') print(b) # b 與 a 不共享任何內(nèi)容 print('我們能夠?qū)懭?b 來寫入 a 嗎?') print(b is a) print('修改 b 的內(nèi)容:') b[0, 0] = 100 print('修改后的數(shù)組 b:') print(b) print('a 保持不變:') print(a)輸出結(jié)果為:
數(shù)組 a: [[10 10][ 2 3][ 4 5]] 創(chuàng)建 a 的深層副本: 數(shù)組 b: [[10 10][ 2 3][ 4 5]] 我們能夠?qū)懭?b 來寫入 a 嗎? False 修改 b 的內(nèi)容: 修改后的數(shù)組 b: [[100 10][ 2 3][ 4 5]] a 保持不變: [[10 10][ 2 3][ 4 5]]深淺拷貝
在 Python 中,對象賦值實(shí)際上是對象的引用。當(dāng)創(chuàng)建一個對象,然后把它賦給另一個變量的時候,Python 并沒有拷貝這個對象,而只是拷貝了這個對象的引用,我們稱之為淺拷貝。
在 Python 中,為了使當(dāng)進(jìn)行賦值操作時,兩個變量互補(bǔ)影響,可以使用 copy 模塊中的 deepcopy 方法,稱之為深拷貝。
append()函數(shù)
當(dāng) list 類型的對象進(jìn)行 append 操作時,實(shí)際上追加的是該對象的引用。
id() 函數(shù):返回對象的唯一標(biāo)識,可以類比成該對象在內(nèi)存中的地址。
如上例所示,當(dāng) num 發(fā)生變化時(前提是 id(num) 不發(fā)生變化),alist 的內(nèi)容隨之會發(fā)生變化。往往會帶來意想不到的后果,想避免這種情況,可以采用深拷貝解決:
alist.append( copy.deepcopy( num ) )總結(jié)
以上是生活随笔為你收集整理的B18_NumPy副本和视图(视图或浅拷贝、副本或深拷贝、深浅拷贝)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 云南人为什么爱吃米线?
- 下一篇: 02_pandas获取数据(指定列获取、