詳解Pandas如何高效對比處理DataFrame的兩列數(shù)據(jù)
楔子
我們在用 pandas 處理數(shù)據(jù)的時候,經(jīng)常會遇到用其中一列數(shù)據(jù)替換另一列數(shù)據(jù)的場景。比如 A 列和 B 列,對 A 列中不為空的數(shù)據(jù)不作處理,對 A 列中為空的數(shù)據(jù)使用 B 列對應索引的數(shù)據(jù)進行替換。這一類的需求估計很多人都遇到,當然還有其它更復雜的。
解決這類需求的辦法有很多,這里我們來推薦幾個。
combine_first
這個方法是專門用來針對空值處理的,我們來看一下用法。
import?pandas?as?pd df?=?pd.DataFrame( ????{"A":?["001",?None,?"003",?None,?"005"], ?????"B":?["1",?"2",?"3",?"4",?"5"]} ) print(df) """ ??????A??B 0???001??1 1??None??2 2???003??3 3??None??4 4???005??5 """ #?我們現(xiàn)在需求如下,如果?A?列中的數(shù)據(jù)不為空,那么不做處理 #?如果為空,則用?B?列中對應的數(shù)據(jù)進行替換 df["A"]?=?df["A"].combine_first(df["B"]) print(df) """ ?????A??B 0??001??1 1????2??2 2??003??3 3????4??4 4??005??5 """
使用方法很簡單,首先是兩個 Series 對象,假設叫 s1 和 s2,那么 s1.combine_first(s2) 就表示用 s2 替換掉 s1 中為空的數(shù)據(jù)。如果 s1 和 s2 的某個相同索引對應的數(shù)據(jù)都是空,那么結(jié)果只能是空。當然這個方法不是在原地操作,而是會返回一個新的 Series 對象。
另外這個方法的理想前提是兩個 Series 對象的索引是一致的,因為替換是根據(jù)索引來指定位置的,舉個例子。
import?pandas?as?pd s1?=?pd.Series(["001",?None,?None,?"004"],? ???????????????index=['a',?'b',?'c',?'d']) s2?=?pd.Series(["2",?"3",?"4"],? ???????????????index=['b',?'d',?"e"]) print(s1) """ a?????001 b????None c????None d?????004 dtype:?object """ print(s2) """ b????2 d????3 e????4 dtype:?object """ print(s1.combine_first(s2)) """ a????001 b??????2 c????NaN d????004 e??????4 dtype:?object """
解釋一下,首先替換的都是 s1 中值為空的數(shù)據(jù),如果不為空那么不做任何處理。s1 中值為空的數(shù)據(jù)有兩個,索引分別為 b、c,那么會用 s2 中索引為 b、c 的數(shù)據(jù)進行替換。但 s2 中只存在索引為 b、不存在索引為 c 的數(shù)據(jù),那么就只能替換一個值。
另外我們看到結(jié)尾還多了個索引為 e 的數(shù)據(jù),是的,如果 s2 中的數(shù)據(jù),s1 沒有,那么會直接加上去。
注意:pandas 的很多操作都是基于自帶的索引進行的,并不是簡單的從上往下一一對應。即便是很多 pandas 老手,偶爾也會犯這個錯誤。
當然大部分情況下我們處理的都是同一個 DataFrame 的兩列,對于同一個 DataFrame 中的兩列,它們的索引顯然是一致的,所以就是簡單的從上到下,不會有太多花里胡哨的。
combine
combine 和 combine_first 類似,只是需要指定一個函數(shù)。
import?pandas?as?pd df?=?pd.DataFrame( ????{"A":?["001",?None,?"003",?None,?"005"], ?????"B":?["1",?"2",?"3",?"4",?"5"]} ) print(df) """ ??????A??B 0???001??1 1??None??2 2???003??3 3??None??4 4???005??5 """ df["A"]?=?df["A"].combine(df["B"],? ??????????????????????????lambda?a,?b:?a?if?pd.notna(a)?else?b) print(df) """ ?????A??B 0??001??1 1????2??2 2??003??3 3????4??4 4??005??5 """
我們指定了一個匿名函數(shù),參數(shù) a、b 就代表 df["A"] 和 df["B"] 中對應的每一個數(shù)據(jù)。如果 a 不為空,那么返回 a,否則返回 b。
所以我們使用 combine 實現(xiàn)了 combine_first 的功能,combine_first 是專門對空值進行替換的,但 combine 則是可以讓我們自己指定邏輯。我們可以實現(xiàn) combine_first 的功能,也可以實現(xiàn)其它的功能。
import?pandas?as?pd s1?=?pd.Series([1,?22,?3,?44]) s2?=?pd.Series([11,?2,?33,?4]) #?哪個元素大就保留哪一個 print(s1.combine(s2,?lambda?a,?b:?a?if?a?>?b?else?b)) """ 0????11 1????22 2????33 3????44 dtype:?int64 """ #?兩個元素進行相乘 #?當然,對于目前這個需求,最好的辦法是?s1?*?s2 print(s1.combine(s2,?lambda?a,?b:?a?*?b)) """ 0?????11 1?????44 2?????99 3????176 dtype:?int64 """
combine 用起來還是很方便的,當然它同樣是針對索引來操作的。此外combine和combine_first內(nèi)部都會先對索引進行處理,如果兩個 Series 對象的索引不一樣,那么會先讓它們索引變得一致。
import?pandas?as?pd s1?=?pd.Series([1,?22,?3,?44],?index=['a',?'b',?'c',?'d']) s2?=?pd.Series([11,?2,?33,?4],?index=['c',?'d',?'e',?'f']) #?先對兩個索引取并集 index?=?s1.index.union(s2.index) print(index)? """ Index(['a',?'b',?'c',?'d',?'e',?'f'],?dtype='object') """ #?然后通過reindex,獲取指定索引的元素 #?索引不存在就用?NaN?代替 s1?=?s1.reindex(index) s2?=?s2.reindex(index) print(s1) """ a?????1.0 b????22.0 c?????3.0 d????44.0 e?????NaN f?????NaN dtype:?float64 """ print(s2) """ a?????NaN b?????NaN c????11.0 d?????2.0 e????33.0 f?????4.0 dtype:?float64 """
combine 和 combine_first 都是先讓 s1 和 s2 的索引變得一致之后,再進行操作。
import?pandas?as?pd s1?=?pd.Series([1,?22,?3,?44], ???????????????index=['a',?'b',?'c',?'d']) s2?=?pd.Series([11,?2,?33,?4], ???????????????index=['c',?'d',?'e',?'f']) print(s1.combine_first(s2)) """ a?????1.0 b????22.0 c?????3.0 d????44.0 e????33.0 f?????4.0 dtype:?float64 """
所以你會發(fā)現(xiàn),s1 和 s2 里面都沒有空值,返回的結(jié)果也沒有空值,但是類型卻從整型變成了浮點型。就是因為 s1 和 s2 在 reindex 的過程中出現(xiàn)了 NaN,所以類型變成了浮點型。
所以在使用 combine 和 combine_first 這兩個方法的時候,一定要記住索引,否則可能會造成陷阱。事實上,包括 pandas 很多的其它操作也是,它們都是基于索引來的,并不是簡單的依次從左到右或者從上到下。
update
update 比較野蠻,我們來看一下。
import?pandas?as?pd s1?=?pd.Series([1,?2,?3,?4]) s2?=?pd.Series([11,?22,?33,?44]) s1.update(s2) print(s1) """ 0????11 1????22 2????33 3????44 dtype:?int64 """
首先我們看到這個方法是在本地進行操作的,功能還是用 s2 的元素替換 s1 的元素,并且只要 s2 中的元素不為空,那么就進行替換。
import?pandas?as?pd s1?=?pd.Series([1,?2,?3,?4]) s2?=?pd.Series([11,?22,?None,?44]) s1.update(s2) print(s1) """ 0????11 1????22 2?????3 3????44 dtype:?int64 """
所以這個函數(shù)叫 update,意思就是更新。用 s2 中的元素換掉 s1 中的元素。但如果 s2 中的元素為空,那么可以認為新版本還沒出來,那么還是使用老版本,所以 s1 中的 3 沒有被換掉。
因此 update 和 combine_first 比較類似,但它們的區(qū)別在于:
- combine_first:如果 s1 中的值為空,用 s2 的值替換,否則保留 s1 的值;
- update:如果 s2 中的值不為空,那么替換 s1,否則保留 s1 的值;
另外在 combine_first 的時候,我們反復強調(diào)了索引的問題,如果 s1 和 s2 索引不一樣,那么生成的結(jié)果的元素個數(shù)會增多。但是 update 不同,因為它是在本地進行操作的,也就是直接本地修改 s1,所以最終 s1 的元素個數(shù)是不會發(fā)生變化的。
import?pandas?as?pd s1?=?pd.Series([1,?2,?3,?4],? ???????????????index=['a',?'b',?'c',?'d']) s2?=?pd.Series([11,?22,?33,?44],? ???????????????index=['c',?'d',?'e',?'f']) s1.update(s2) print(s1) """ a?????1 b?????2 c????11 d????22 dtype:?int64 """
s2 中不存在 index 為 a、b 的元素,那么可以認為新版本沒有出現(xiàn),因此不更新、保留原來的值。但 s2 中存在 index 為 c、d 的元素,所以有新版本,那么就更新。所以 s1 由 [1 2 3 4] 變成了 [1 2 11 22]。
至于 s2 中 index 為 e、f 的元素,它們和 s1 沒有關系,因為 s1 中壓根沒有 index 為 e、f 的元素,s2 提供了新版本也是沒用的。所以使用 update,是在 s1 本地操作的,操作前后 s1 的索引以及元素個數(shù)不會改變。
當然 update 也適用于對兩個 DataFrame 進行操作,有興趣可以自己去了解,但大部分時候我們都用在 Series 上面。
到此這篇關于詳解Pandas如何高效對比處理DataFrame的兩列數(shù)據(jù)的文章就介紹到這了,更多相關Pandas處理DataFrame數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python利用Flask-Mail實現(xiàn)發(fā)送郵件詳解
Flask?的擴展包?Flask?-?Mail?通過包裝了?Python?內(nèi)置的smtplib包,可以用在?Flask?程序中發(fā)送郵件。本文將利用這特性實現(xiàn)郵件發(fā)送功能,感興趣的可以了解一下2022-08-08Python數(shù)據(jù)可視化圖實現(xiàn)過程詳解
這篇文章主要介紹了Python數(shù)據(jù)可視化圖實現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-06-06Python調(diào)用SQLPlus來操作和解析Oracle數(shù)據(jù)庫的方法
這篇文章主要介紹了Python調(diào)用SQLPlus來操作和解析Oracle數(shù)據(jù)庫的方法,這樣用SQL*Plus方式來分析Oracle中的數(shù)據(jù)就變得十分方便,需要的朋友可以參考下2016-04-04解決Pycharm在Debug的時候一直“Connected”沒有下一步動作問題
這篇文章主要介紹了解決Pycharm在Debug的時候一直“Connected”沒有下一步動作問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08Python面向?qū)ο笾鄳B(tài)原理與用法案例分析
這篇文章主要介紹了Python面向?qū)ο笾鄳B(tài)原理與用法,結(jié)合具體案例形式分析了Python多態(tài)的具體功能、原理、使用方法與操作注意事項,需要的朋友可以參考下2019-12-12