網(wǎng)站首頁 編程語言 正文
楔子
我們在用 pandas 處理數(shù)據(jù)的時候,經(jīng)常會遇到用其中一列數(shù)據(jù)替換另一列數(shù)據(jù)的場景。比如 A 列和 B 列,對 A 列中不為空的數(shù)據(jù)不作處理,對 A 列中為空的數(shù)據(jù)使用 B 列對應(yīng)索引的數(shù)據(jù)進(jìn)行替換。這一類的需求估計很多人都遇到,當(dāng)然還有其它更復(fù)雜的。
解決這類需求的辦法有很多,這里我們來推薦幾個。
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?列中對應(yīng)的數(shù)據(jù)進(jìn)行替換
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 對象,假設(shè)叫 s1 和 s2,那么?s1.combine_first(s2)?就表示用 s2 替換掉 s1 中為空的數(shù)據(jù)。如果 s1 和 s2 的某個相同索引對應(yīng)的數(shù)據(jù)都是空,那么結(jié)果只能是空。當(dāng)然這個方法不是在原地操作,而是會返回一個新的 Series 對象。
另外這個方法的理想前提是兩個 Series 對象的索引是一致的,因?yàn)樘鎿Q是根據(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ù)進(jìn)行替換。但 s2 中只存在索引為 b、不存在索引為 c 的數(shù)據(jù),那么就只能替換一個值。
另外我們看到結(jié)尾還多了個索引為 e 的數(shù)據(jù),是的,如果 s2 中的數(shù)據(jù),s1 沒有,那么會直接加上去。
注意:pandas 的很多操作都是基于自帶的索引進(jìn)行的,并不是簡單的從上往下一一對應(yīng)。即便是很多 pandas 老手,偶爾也會犯這個錯誤。
當(dāng)然大部分情況下我們處理的都是同一個 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"] 中對應(yīng)的每一個數(shù)據(jù)。如果 a 不為空,那么返回 a,否則返回 b。
所以我們使用 combine 實(shí)現(xiàn)了 combine_first 的功能,combine_first 是專門對空值進(jìn)行替換的,但 combine 則是可以讓我們自己指定邏輯。我們可以實(shí)現(xiàn) combine_first 的功能,也可以實(shí)現(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
"""
#?兩個元素進(jìn)行相乘
#?當(dāng)然,對于目前這個需求,最好的辦法是?s1?*?s2
print(s1.combine(s2,?lambda?a,?b:?a?*?b))
"""
0?????11
1?????44
2?????99
3????176
dtype:?int64
"""
combine 用起來還是很方便的,當(dāng)然它同樣是針對索引來操作的。此外combine和combine_first內(nèi)部都會先對索引進(jìn)行處理,如果兩個 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 的索引變得一致之后,再進(jìn)行操作。
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é)果也沒有空值,但是類型卻從整型變成了浮點(diǎn)型。就是因?yàn)?s1 和 s2 在 reindex 的過程中出現(xiàn)了 NaN,所以類型變成了浮點(diǎn)型。
所以在使用 combine 和 combine_first 這兩個方法的時候,一定要記住索引,否則可能會造成陷阱。事實(shí)上,包括 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
"""
首先我們看到這個方法是在本地進(jìn)行操作的,功能還是用 s2 的元素替換 s1 的元素,并且只要 s2 中的元素不為空,那么就進(jìn)行替換。
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 中的元素?fù)Q掉 s1 中的元素。但如果 s2 中的元素為空,那么可以認(rèn)為新版本還沒出來,那么還是使用老版本,所以 s1 中的 3 沒有被換掉。
因此 update 和 combine_first 比較類似,但它們的區(qū)別在于:
- combine_first:如果 s1 中的值為空,用 s2 的值替換,否則保留 s1 的值;
- update:如果 s2 中的值不為空,那么替換 s1,否則保留 s1 的值;
另外在 combine_first 的時候,我們反復(fù)強(qiáng)調(diào)了索引的問題,如果 s1 和 s2 索引不一樣,那么生成的結(jié)果的元素個數(shù)會增多。但是 update 不同,因?yàn)樗窃诒镜剡M(jìn)行操作的,也就是直接本地修改 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 的元素,那么可以認(rèn)為新版本沒有出現(xiàn),因此不更新、保留原來的值。但 s2 中存在 index 為 c、d 的元素,所以有新版本,那么就更新。所以 s1 由?[1 2 3 4]?變成了?[1 2 11 22]。
至于 s2 中 index 為 e、f 的元素,它們和 s1 沒有關(guān)系,因?yàn)?s1 中壓根沒有 index 為?e、f 的元素,s2 提供了新版本也是沒用的。所以使用 update,是在 s1 本地操作的,操作前后 s1 的索引以及元素個數(shù)不會改變。
當(dāng)然 update 也適用于對兩個 DataFrame 進(jìn)行操作,有興趣可以自己去了解,但大部分時候我們都用在 Series 上面。
原文鏈接:https://mp.weixin.qq.com/s/MXkDYM504Z1R-W1R3poyvA
相關(guān)推薦
- 2022-05-13 eigen交叉編譯
- 2024-03-01 【Promise】promise關(guān)鍵問題和解決辦法
- 2023-04-18 antd中form表單的wrapperCol和labelCol問題詳解_React
- 2022-05-26 Python?if?else條件語句形式詳解_python
- 2022-07-15 VBScript編寫Windows防止鎖屏腳本程序_vbs
- 2022-05-12 adb 導(dǎo)出android目錄下的文件
- 2022-01-30 tortoiseGit推送每次需要輸入密碼,解決方案
- 2022-07-12 Linux命令之美|linux使用tar誤解壓之后,如何刪除解壓后的文件
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支