采坑 - 字符串的 "" 與 pd.isnull()


主要是記錄一個采坑的過程. 當字符串 的 " " 和 pandas 中的 " " , NaN不是一個概念 .

需求

一個小伙伴要用 pandas 來處理一個, 表格填充的的問題, 脫敏數據大致是這樣的.

區域名稱 門店 店組
龍華新城大區 壹城中心店 壹城中心一組
益田大區 皇崗口岸店 皇崗口岸一組
雙龍大區 龍城中央旗艦店 AAA店
深西大區 德佑麒麟A組
A宏暢房地產經紀有限責任公司 A地產經紀有限責任公司門店
宏暢房地產經紀有限責任公司 B地產經紀有限責任公司門店
東部 微地產瑞凱洪湖A店
景恆房地產有限公司 D景恆房地產有限公司門店
龍華新城大區 豐潤花園店 豐潤花園一組

現在想取一個 門店 字段, 新增或者覆蓋 都可以, 取的邏輯是: "獲取 門店 字段的值, 如果是值, 則選擇 店組 字段的值.

咋一看, (不考慮性能, 只管實現哈), 這不簡單嘛,都不想考慮用什么 apply, 遍歷 DataFrame 的每一行, 然后判斷就好了.

踩過過程

通常我是先測試下, 與其說是測試, 其實就是百度下api, 根本就記不住的, 要是沒有搜索引擎, 寫代碼立刻就廢掉了.

先來波測試

import pandas as pd 
df = pd.DataFrame({
    
    "a":[1,2,3,4,5,6],
    "門店": ["甲店", "", "", "丙店", "", "丁店"],
    "店組": ["DD", "", "AA", "", "丁店", ""]
})

print(df)
a	門店	    店組
0	1	甲店	DD
1	2		
2	3		 AA
3	4	丙店	
4	5		 丁店
5	6	丁店	

為了演示方便, 這里選擇新增 "新門店"字段, 不覆蓋原來的哦 (如果 "門店", 沒有值, 就取 "店組" 的值)

for 行號, 行值 in df.iterrows():   
    
    df.loc[行號, "新門店"] =  行值['門店'] or 行值["店組"]
    
print(df)
    a	門店	店組	新門店
0	1	甲店	DD	  甲店
1	2			
2	3		  AA	AA
3	4	丙店		  丙店
4	5		  丁店  丁店
5	6	丁店		  丁店

測試完美通過, 然后就開始整了.

翻車1次

df = pd.read_excel("門店選擇.xlsx")

# 新增 "新門店"字段 也行 如果 "門店", 沒有值, 就取 "店組" 的值
for 行號, 行值 in df.iterrows():   
    
    df.loc[行號, "新門店"] =  行值['門店'] or 行值["店組"]
    
print(df)
區域名稱 門店 店組 新門店
0 龍華新城大區 壹城中心店 壹城中心一組 壹城中心店
1 益田大區 皇崗口岸店 皇崗口岸一組 皇崗口岸店
2 雙龍大區 龍城中央旗艦店 AAA店 龍城中央旗艦店
3 深西大區 NaN 德佑麒麟A組 NaN
4 A宏暢房地產經紀有限責任公司 A地產經紀有限責任公司門店 NaN A地產經紀有限責任公司門店
5 深圳市宏暢房地產經紀有限責任公司 NaN B地產經紀有限責任公司門店 NaN
6 東部 微地產瑞凱洪湖A店 NaN 微地產瑞凱洪湖A店
7 深圳市景恆房地產有限公司 NaN D景恆房地產有限公司門店 NaN
8 龍華新城大區 豐潤花園店 豐潤花園一組 豐潤花園店

新門店字段, 出大事了, 並沒有匹配到空值, 但是我上面的測試是沒有問題. 突然有點緊張, 這就是 所謂的 bug 呀.

又想吐槽下 關於 bug 了. 我認為什么是 bug 呢, 測試沒有問題, 真正用的時候, 有問題了, 而且不太輕易發現. 但更多時候, 我發現小伙伴總是喜歡濫用這個詞, 都是寫代碼還好, 都明白, 很多是功能沒有實現, 就暫時敷衍下, 說是bug, 其實就是寫完, 很多時候. 但, 更有趣的是, 跟我們對接的業務卻總愛說 bug, 動不動就說是 bug, 一行代碼都沒參與過的人, 卻整天說 bug, 就莫名想吐槽下, 也沒有別的意思, 有點滑稽哈哈.

BUG 定位

初級判斷, 就是, 明明是空值, 卻被認為是 True 唄.

for 行號, 行值 in df.iterrows():   
    
    print(行號, 行值) if 行值["門店"] == "" else print("沒匹到空值") 
沒匹到空值
沒匹到空值
沒匹到空值
沒匹到空值
沒匹到空值
沒匹到空值
沒匹到空值
沒匹到空值
沒匹到空值

卧槽, 真的是報警了, 明明有空值, 去哪了了呢???

for 行號, 行值 in df.iterrows():
    
    # if 行值["門店"] == '': print(行號, 行值)
    #if 行值["門店"] == None: print(行號, 行值) 
    # if 行值["門店"] == 'nan': print(行號, 行值)
    
    if 行值["門店"] == 'NaN': print(行號, 行值) 

可以看到, 字符串的 " ", 在 pandas 里面, " ", None, 'NaN', 'nan' 都是匹不上的.

臨時解決

當時有有點蒙圈, 只想這, 立馬先解決, 不匹了, 直接填充, 然后判斷吧.

df = pd.read_excel("門店選擇.xlsx")

# 將整個表的的 缺失值 都填充為 "缺失值"
df = df.fillna("缺失值")

for 行號, 行值 in df.iterrows():   
    
    df.loc[行號, "新門店"] = 行值["門店"] if (行值["門店"] != "缺失值") else 行值["店組"]
    
print(df)
區域名稱 門店 店組 新門店
0 龍華新城大區 壹城中心店 壹城中心一組 壹城中心店
1 益田大區 皇崗口岸店 皇崗口岸一組 皇崗口岸店
2 雙龍大區 龍城中央旗艦店 AAA店 龍城中央旗艦店
3 深西大區 缺失值 德佑麒麟A組 德佑麒麟A組
4 A宏暢房地產經紀有限責任公司 A地產經紀有限責任公司門店 缺失值 A地產經紀有限責任公司門店
5 深圳市宏暢房地產經紀有限責任公司 缺失值 B地產經紀有限責任公司門店 B地產經紀有限責任公司門店
6 東部 微地產瑞凱洪湖A店 缺失值 微地產瑞凱洪湖A店
7 深圳市景恆房地產有限公司 缺失值 D景恆房地產有限公司門店 D景恆房地產有限公司門店
8 龍華新城大區 豐潤花園店 豐潤花園一組 豐潤花園店

可以, 算是臨時解決了這個 BUG. 但這並非是一個好的方式. 原因還是在於 pandas 的 NaN 和 咱平常的 "" 缺失值不是類對象.

BUG 根源 - NaN 和 ""

查了下文檔才出坑. 在 Pandas 中, 對於缺失值, 默認會以 NaN 這個 pandas 專屬的標志來表示. 但它並不是一個 數字, 或字符串 或 None, 因此, 是 不能和字符串 "" 來比較的.

pandas 中, 只能用 pd.isnull(), .. 等幾個相關的方法來判斷 '空值' NaN

  • pd.isnull ( ) ; pd.notnull ( )

  • pd.isna ( ) ; pd.notna( )

關於缺失值處理, 有兩個極為重要的方法: dropna(), fillna()

真正解決:

# 直接覆蓋原有的 "門店" 也行 如果 "門店", 沒有值, 就取 "店組" 的值
df = pd.read_excel("門店選擇.xlsx")

for 行號, 行值 in df.iterrows():   
    
    df.loc[行號, "新門店"] =  行值['門店'] if pd.notnull(行值['門店']) else 行值["店組"]

最后呢, 再測試一下, 這下用 pd.isnull () 或者 pd.isna() 就能匹配上 空值了.

df = pd.read_excel("門店選擇.xlsx")

for 行號, 行值 in df.iterrows():   
    
    print(行號) if pd.isnull(行值["門店"]) else print("沒匹到空值") 
沒匹到空值
沒匹到空值
沒匹到空值
3
沒匹到空值
5
沒匹到空值
7
沒匹到空值

就記錄下這個采坑, 記住空判斷, 在 pandas 中一定要**用 pd.isna() 或者 pd.isnull() **, 尤其在遍歷行的時候, 經常習慣性用 " " 或, "NaN" 或 None 等來處理.

雖然這個問題小, 但也是經驗的累積嘛, 所謂, 吃一塹, 長一智嘛, 一點點積累起來, 就是經驗了.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM