您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關Python numpy視圖與副本怎么理解,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
前言:
下面對 ndarray 內存結構主要分為兩部分:
metdata
:存放數組類型dtype、數組維度ndim、維度數量shape、維間距strides等raw bata
:存放原始數據data
在 metdata
中包含著關于數組相關信息,可以幫助我們在數組ndarray
中快速索引和解釋指定的數據
除此了對數組進行索引操作外,也會對數組的原數據進行類似與之前“拷貝”操作。
眾所周知,在 Python 中大家應該對深淺拷貝有一定的印象吧,在 numpy 中則換成了“視圖”與“副本”的概念了。
相信大家和我一樣對此存在疑問,十萬個為什么涌上心頭了,“視圖是什么?”,“什么是副本?”
因此,我們一起來學習 numpy 模塊中比較新奇的概念視圖與副本,Let's go~
我們之前在學習 Python 賦值、深淺拷貝時,在代碼添加中對比兩個對象的地址id()是否一致。
同理,按照這樣的思路,numpy 中也可以對比兩個數組地址是否一樣。
同時,在 numpy 數組對象ndarray 也提供許多字段,方便讓我們進一步地查看數組內部的差異
ndarray.flags : 查看數組存儲策略、讀寫權限、對象等
C_CONTIGUOUS (C)
行優先存儲
F_CONTIGUOUS
列優先存儲
OWNDATA
數據所有者
WRITEABLE
編寫權限
ALIGNED
數據元素與硬件指針對齊
WRITEBACKIFCOPY
數組是其他數組的副本
UPDATEIFCOPY
已棄用
注:flags 相關屬性名稱可以單獨調用例如 flags.writeable
ndarray.base
: 查看數組中的元素是否來自其他數組
ndarray.nbytes
: 查看數組中數據占用的字節數
getsizeof(item)
: 查看數組占用的內存空點
介紹完上述指標,我們來小試一下:
>>> import numpy as np >>> a = np.array([1,2,3,4]) >>> print(a[1:3]) [2 3] >>> print(a[[1,2]]) [2 3] >>>
查看a[1:3] 與 a[[1,2]] 內存地址,它們倆位置不一樣,a[[1,2]]意味發生了深拷貝本(副本),a[1:3] 是原數組a引用(視圖)
>>> print(id(a[1:3])) 2247482965008 >>> print(id(a[[1,2]])) 2247482964928
查看ndarray.owndata
屬性,發現a[1:3] 數據來自a數組的,而a[[1,2]]是自身數據的
>>> print(a.flags.owndata) True >>> print(a[1:3].flags.owndata) False >>> print(a[[1,2]].flags.owndata) True
我們在看一下 ndarray.base
屬性,果真印證了使用flags.owndata
查詢的結果,a[1:3] 不是數據所有者,而數據來源數組a;
a[[1,2]] 是數據所有者,數據來源本身(None)
>>> print(a[[1,2]].base) None >>> print(a[1:3].base) [1 2 3 4]
我們通過上述簡單例子,可以知道 a[1:3] 不是數據所有者,數據來源于對數組a的引用(淺拷貝)。
因此,我們應該對視圖有了基本的認識了,看一下官方怎么描述視圖的
No copy at All。 Simple assignments make no copy of objects or their data.
視圖,是對原數組進行引用拷貝,共享原始數組的數據。
視圖在numpy中廣泛使用,視圖一般產生有兩種場景:
當對原始數組進行引用時
當自身無數據,與原數組共享數據時
>>> import numpy as np >>> a = np.array([1,2,3,4]) >>> b = a >>> b is a True >>> id(a) 2247207679680 >>> id(b) 2247207679680 >>>
我們可以看到 a 與 b 是 同享同一個數據空間的
在numpy
模塊諸如索引、切片、函數view()
,reshape()
等返回視圖結果
>>> arr = np.arange(10) >>> arr_view = arr.view() >>> arr.shape = (2,5) >>> arr_reshape = arr.reshape(5,2) # ndarray.base 屬性 >>> print(arr.base) None >>> print(arr_view.base) [[0 1 2 3 4] [5 6 7 8 9]] >>> print(arr_reshape.base) [[0 1 2 3 4] [5 6 7 8 9]] # ndarray.flags.owndata 屬性 >>> print(arr.flags.owndata) True >>> print(arr_view.flags.owndata) False >>> print(arr_reshape.flags.owndata) False >>>
在 numpy 中 視圖可以創建的對象可以節省內存空間,并且無需復制,提高查詢速度
在視圖中,創建的對象如果修改數據,原始數據也被修改。
副本是對原數組進行完整拷貝(數據地址也會拷貝新的),與原始數組完全獨立,相對于“深拷本”,不與原始數組共享數據。
同樣截取官網,對副本的描述:
Deep Copy The copy method makes a complete copy of the array and its data
當改變副本的數據元素值時,雖然改變了副本與原數組相互獨立,原始數組中元素值不會發生改變。
當進行切片操作時
當需要與原始數組數據獨立時
副本的實現我們可以直接使用 ndarray.copy()
方法對原數組進行深拷貝
b = np.array([2,5,7]) c = b.copy() c[1] = 8 print("b:",b) print("c:",c) print("c is b:",c is b) # 查看 ndarray.base 屬性? print("b.base:",b.base) print("c.base:",c.base) # 查看 ndarray.flags.owndata print("b.flags.owndata:",b.flags.owndata) print("c.flags.owndata:",c.flags.owndata)
我們對 numpy 模塊中重要的概念視圖和副本。
視圖,相當于淺拷貝,與原數組共享數據。
副本,相當于深拷貝,與原數組數據相互獨立
我們可以通過內存地址id()方法,同時借助ndarray.base、ndarray.flags來進一步分析區別
以上就是Python numpy視圖與副本怎么理解,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。