close
拯救pandas計劃(9)——淺談pandas中的深淺拷貝

最近發現周圍的很多小夥伴們都不太樂意使用pandas,轉而投向其他的數據操作庫,身為一個數據工作者,基本上是張口pandas,閉口pandas了,故而寫下此系列以讓更多的小夥伴們愛上pandas。

系列文章說明:

系列名(系列文章序號)——此次系列文章具體解決的需求

平台:

windows 10
python 3.8
pandas >=1.2.4
/ 數據需求

有時在修改pandas對象中不想改變原數據框會使用.copy()給原數據框做一份拷貝,但數據內容中包含可變對象時,使用卻不會按本意進行,官方也在函數中給出說明,這裡一起了解下pandas中的深淺複製。

/ .copy(deep=True)

函數詳解文檔:

Signature:df.copy(deep:'bool_t'=True)->'FrameOrSeries'Docstring:Makeacopyofthisobject'sindicesanddata.When``deep=True``(default),anewobjectwillbecreatedwithacopyofthecallingobject'sdataandindices.Modificationstothedataorindicesofthecopywillnotbereflectedintheoriginalobject(seenotesbelow).When``deep=False``,anewobjectwillbecreatedwithoutcopyingthecallingobject'sdataorindex(onlyreferencestothedataandindexarecopied).Anychangestothedataoftheoriginalwillbereflectedintheshallowcopy(andviceversa).Parameters----------deep:bool,defaultTrueMakeadeepcopy,includingacopyofthedataandtheindices.With``deep=False``neithertheindicesnorthedataarecopied.Returns-------copy:SeriesorDataFrameObjecttypematchescaller.Notes-----When``deep=True``,dataiscopiedbutactualPythonobjectswillnotbecopiedrecursively,onlythereferencetotheobject.Thisisincontrastto`copy.deepcopy`intheStandardLibrary,whichrecursivelycopiesobjectdata(seeexamplesbelow).While``Index``objectsarecopiedwhen``deep=True``,theunderlyingnumpyarrayisnotcopiedforperformancereasons.Since``Index``isimmutable,theunderlyingdatacanbesafelysharedandacopyisnotneeded.

在該函數文檔中可以看出,默認為深複製(deep=True),會創建一個與原數據框不同的數據對象,在副本中修改數據均不會使原數據發生修改,在下面的Notes部分提到,如果數據內容是可變對象依然會改變原數據框內容,原因是pandas的深複製僅是引用python對象使用,也有部分減少性能的消耗,如Index不可變對象可以安全無誤的複製到新對象中,不同於copy.deepcopy會遞歸複製python對象,所以使用pandas.copy複製pandas對象,如果數據內容包含可變對象,仍然是不安全的,修改其內的數據會使原數據發生改變。

(手動水印:原創CSDN宿者朽命,https://blog.csdn.net/weixin_46281427?spm=1011.2124.3001.5343,公眾號A11Dot派)

/ 函數使用
數據:
importpandasaspddata={'A':[1,2,3],'B':[['厲害','真棒'],['值得鼓勵','繼續加油'],['相信未來--勇闖天涯']],'C':[{'key':'試一試','value':'try'},{'key':'看一看','value':'look'},{'key':'拍一拍','value':'tickle'}]}df=pd.DataFrame(data)df_shallow=df.copy(deep=False)#淺複製df_copy=df.copy()#深複製

生成df,包含3列數據,A列為數值型,不可變對象, B和C都是可變對象。

查看深淺複製對象,都與原對象不同,說明完成拷貝。

修改df中的A列數據
df.loc[0,'A']=50

df_shallow會跟着df的改變而發生改變,而df_copy不會發生變化,也證實了df.copy(deep=False)是淺層複製,新建了一個與df數據內容及索引相同的但對象不同的數據框。

修改B列數據
df.loc[0,'B'][0]='lihai'

在B列修改過程中所有複製出來的數據框都發生了變化,正如Notes所說,是對對象的引用,是直接修改引用到的數據,那麼在數據框顯示部分看到B列的內容發生變化,原始數據內容是否也已經改變,打印data:

data中的B所對應的值也已經發生改變,那麼有什麼方法可以僅改變深複製後的數據對象,又不改變原始數據,這裡需要藉助copy模塊,C列的數據層次與B列一樣,下面修改C列數據。

修改C列數據
fromcopyimportcopy,deepcopydefvalue_upper(dic):"""將傳入的dic使用深淺拷貝複製給另一個新的對象"""dic=copy(dic)#如果層級大於一層,請考慮使用deepcopydic['value']=dic['value'].upper()#返回修改後的字典對象returndicdf_copy['C'].apply(value_upper)#未實際改變df_copy['C']

熟悉pandas的會明白這樣僅讓df_copy中的C列參與了函數執行,沒有實際改變C列數據,但如果沒有第5行中的copy操作,即使沒有return語句也會使df_copy發生改變,原因見修改B列數據部分。如果需要改變C列數據將運行後的結果賦值給C列,由於C列被重新賦值也就不存在修改df_copy中C列數據會影響到df或df_shallow乃至data中的C列數據。

df_copy['C']=df_copy['C'].apply(value_upper)

可以看到僅df_copy['C']發生了變化。

/ 總結

偶爾修改pandas對象中的數據時會被提醒所修改的數據視圖會影響原數據框,可以考慮使用df.copy方法避免修改,而當數據中含有可變對象,且只修改其中的一部分內容,卻不會產生這樣的警告,而這樣的結果又不能被接受時,可以查看下函數文檔,pandas中的copy與python對象的複製在使用上有部分不同,例如deepcopy是會對python進行遞歸操作,而pandas.copy僅將數據引用及索引進行複製。如果你問我deepcopy(df)是否可以避免上述情況發生,很遺憾的告訴你不行,對該篇有任何疑問歡迎聯繫作者,簡述你的見解。

當你難以分辨兩者之間是否有某種關聯時,最好的辦法是改變其中一個的特徵。

於二〇二二年三月二十日作

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 鑽石舞台 的頭像
    鑽石舞台

    鑽石舞台

    鑽石舞台 發表在 痞客邦 留言(0) 人氣()