兩大步驟,29行代碼學會數(shù)據(jù)清洗
本文轉(zhuǎn)載自微信公眾號「數(shù)倉寶貝庫」,作者王愷 等。轉(zhuǎn)載本文請聯(lián)系數(shù)倉寶貝庫公眾號。
01處理缺失數(shù)據(jù)
缺失數(shù)據(jù)是數(shù)據(jù)文件中最常見的問題之一。在Pandas中的缺失值表示為NA,其中數(shù)值類型的缺失值標記為NaN(Not a Number),datetime類型的缺失值標記為NaT(Not a Time)。缺失值的存在可能會引起后續(xù)的數(shù)據(jù)分析錯誤。
在清洗數(shù)據(jù)之前,首先要確定數(shù)據(jù)中是否存在缺失值以及缺失值的確切位置。Pandas提供了isna()和notna()方法,用于快速確定Series和DataFrame對象中缺失值的位置,其語法格式如下:
- pd.isna(data) 或者 data.isna()
- pd.notna(data) 或者 data.notna()
data可以是一個Series對象,返回值為布爾Series對象;也可以是一個DataFrame對象,返回值為布爾DataFrame對象;還可以是一個標量值,此時返回一個布爾值。對于isna方法,data中如果包含NA值,則返回值對應(yīng)的位置為True,其余正常元素對應(yīng)的位置為False。notna方法與isna方法相反,data中如果包含NA值,則返回值對應(yīng)的位置為False,其余正常元素對應(yīng)的位置為True。
Pandas提供了幾種處理缺失值的方法,即為缺失值重新賦值、刪除缺失值所在的行、刪除數(shù)據(jù)缺失率較高的列等。刪除缺失值的方法一般用于缺失值較少、對整體數(shù)據(jù)影響不大的情況。
1)Pandas提供了fillna方法用于將缺失值重新賦值為新的元素值,常用的語法格式如下:
- result=data.fillna(value,method=None,…)
其中data既可以是Series對象,也可以是DataFrame對象。value可以是一個固定的元素,比如0;value也可以是一個字典對象、Series對象或DataFrame對象,用于將data中匹配標簽(Series對象)或匹配列標簽(DataFrame對象)所對應(yīng)的缺失值替換為不同的值,未與value匹配的data中的缺失值則不會被替換。method表示填充NA值的方法,缺省時默認為None。method='ffill'或者'method=pad'時使用上一個有效值填充NA值,而method='bfill'或者'method=backfill'時使用下一個有效值來填充NA值。fillna的返回值為新賦值的Series或DataFrame對象。
2)Pandas提供了dropna方法,實現(xiàn)按行或列刪除NA值的功能,其語法格式如下:
- result =data.dropna(axis=0,how='any',…)
如果data是Series對象,則axis只能等于0,直接刪除所有的NA值。如果data是DataFrame對象,參數(shù)axis為0或'index',實現(xiàn)刪除缺失值所在的行;如果設(shè)置axis為1或'columns',則刪除缺失值所在的列;axis缺省時默認為0。how = 'any'表示只要有NA值存在,就會刪除所在的行或列;how='all'表示只有當全部元素都是NA值時才會執(zhí)行刪除操作;how缺省時默認為'any'。dropna的返回值為刪掉缺失值的Series或DataFrame對象。
3)Pandas還為Series和DataFrame提供了interpolate()方法,通過插值法補充缺失的數(shù)據(jù)點,其語法格式如下:
- result=data.interpolate(method='linear',axis=0,…)
method表示使用的插值方法,缺省時默認為線性插值'linear'。常用的還有
'time',即根據(jù)時間間隔進行插值。除此之外,method還提供了更高級的插值方法,比如Scipy庫中的'nearest'、'zero'、'slinear'、'quadratic'、'cubic'、
'spline'、'barycentric'、'polynomial'等。axis參數(shù)的用法與dropna方法相同。
下面通過代碼清單演示Pandas提供的處理缺失數(shù)據(jù)方法的用法。
- 代碼清單 Pandas處理缺失數(shù)據(jù)方法的用法示例
- 1 import pandas as pd
- 2 import numpy as np
- 3 df = pd.DataFrame({'A': [1, 2.1, np.nan, 4.7, 5.6], 'B': [.25, np.nan,
- np.nan, 4, 12.2]})
- 4 print('df:\n',df)
- 5 print('df中的元素是否為缺失值:\n',pd.isna(df))
- 6 df1 = df.fillna(0)#用固定值來填充
- 7 print('用0填充缺失值后的數(shù)據(jù):\n',df1)
- 8 df2 = df.fillna(value={'A': 1, 'B': 2}) #將A、B列中的NaN分別替換為1、2
- 9 print('用字典填充缺失值后的數(shù)據(jù):\n',df2)
- 10 df3 = df.fillna(df.mean()) #用每列的平均值來填充
- 11 print('用每列的平均值填充缺失值后的數(shù)據(jù):\n',df3)
- 12 df4 = df.dropna()
- 13 print('刪除缺失值后的數(shù)據(jù):\n',df4)
- 14 df5=df.interpolate()
- 15 print('線性插值法填充缺失值后的數(shù)據(jù):\n',df5)
- 16 df6= df.interpolate(method='polynomial',order=2)
- 17 print('多項式插值法填充缺失值后的數(shù)據(jù):\n',df6)
程序執(zhí)行結(jié)束后,輸出結(jié)果如下:
- df:
- A B
- 0 1.0 0.25
- 1 2.1 NaN
- 2 NaN NaN
- 3 4.7 4.00
- 4 5.6 12.20
- df中的元素是否為缺失值:
- A B
- 0 False False
- 1 False True
- 2 True True
- 3 False False
- 4 False False
- 用0填充缺失值后的數(shù)據(jù):
- A B
- 0 1.0 0.25
- 1 2.1 0.00
- 2 0.0 0.00
- 3 4.7 4.00
- 4 5.6 12.20
- 用字典填充缺失值后的數(shù)據(jù):
- A B
- 0 1.0 0.25
- 1 2.1 2.00
- 2 1.0 2.00
- 3 4.7 4.00
- 4 5.6 12.20
- 用每列的平均值填充缺失值后的數(shù)據(jù):
- A B
- 0 1.00 0.250000
- 1 2.10 5.483333
- 2 3.35 5.483333
- 3 4.70 4.000000
- 4 5.60 12.200000
- 刪除缺失值后的數(shù)據(jù):
- A B
- 0 1.0 0.25
- 3 4.7 4.00
- 4 5.6 12.20
- 線性插值法填充缺失值后的數(shù)據(jù):
- A B
- 0 1.0 0.25
- 1 2.1 1.50
- 2 3.4 2.75
- 3 4.7 4.00
- 4 5.6 12.20
- 多項式插值法填充缺失值后的數(shù)據(jù):
- A B
- 0 1.000000 0.250
- 1 2.100000 -1.975
- 2 3.433333 -0.725
- 3 4.700000 4.000
- 4 5.600000 12.200
下面對代碼清單中的代碼做簡要說明。
- 第3行代碼通過字典創(chuàng)建了一個5行2列的DataFrame對象df,其中使用Numpy庫中的np.nan設(shè)置了幾個缺失值,如第4行print函數(shù)的輸出結(jié)果所示。
- 第5行代碼通過isna方法來確認df中的哪些元素是缺失值,返回的結(jié)果中,True表示df中對應(yīng)位置為缺失值,F(xiàn)alse則表示對應(yīng)位置為正常值。
- 第6行代碼通過fillna方法使用固定值0對df中的缺失值進行填充,并將返回結(jié)果賦值給新的DataFrame對象df1,如第7行print函數(shù)的輸出結(jié)果所示。
- 第8行代碼通過fillna方法使用字典{'A': 1, 'B': 2}對df中的缺失值進行填充,A列中的NaN填充為1,B列中的NaN填充為2,并將返回結(jié)果賦值給新的DataFrame對象df2,如第9行print函數(shù)的輸出結(jié)果所示。
- 第10行代碼通過fillna方法,使用df.mean()對df中的缺失值進行填充。df.mean()的返回值是Series對象類型,表示df每列的平均值,fillna方法再用該平均值對df每列的缺失值依次進行填充,并將返回結(jié)果賦值給新的DataFrame對象df3,如第11行print函數(shù)的輸出結(jié)果所示。
- 第12行代碼通過dropna方法對df中的缺失值進行刪除,采用默認的參數(shù)設(shè)置,即刪除所有至少包含一個缺失值的行,并將返回結(jié)果賦值給新的DataFrame對象df4,如第13行print函數(shù)的輸出結(jié)果所示。
- 第14行代碼通過interpolate方法對df中的缺失值進行插值處理,采用默認的參數(shù)設(shè)置,即以列為單位進行線性插值,并將返回結(jié)果賦值給新的DataFrame對象df5,如第15行print函數(shù)的輸出結(jié)果所示。
- 第16行代碼通過interpolate方法對df中的缺失值進行了插值處理,參數(shù)method='polynomial'表示采用多項式插值法,order=2指定多項式的階數(shù)為2,并將返回結(jié)果賦值給新的DataFrame對象df6,如第17行print函數(shù)的輸出結(jié)果所示。
Tips
上文介紹的fillna、dropna、interpolate等處理缺失值的方法都是在數(shù)據(jù)的拷貝上進行處理,不會改變原數(shù)據(jù)。
02刪除重復(fù)數(shù)據(jù)
除數(shù)據(jù)缺失之外,數(shù)據(jù)文件中還可能存在重復(fù)的數(shù)據(jù),這會對分析結(jié)果產(chǎn)生影響,因此,在數(shù)據(jù)清洗階段還需要刪除重復(fù)數(shù)據(jù)。
要識別數(shù)據(jù)中是否存在重復(fù)行,可以使用Pandas提供的duplicated方法。常用的語法格式如下:
- data.duplicated(subset=None,keep='first',…)
data可以是一個Series對象,也可以是一個DataFrame對象,返回值為一個表示重復(fù)行的布爾類型Series對象。當data是Series對象時,duplicated方法中沒有subset參數(shù)。subset是列標簽參數(shù),表示考慮某些特定列來標識重復(fù)數(shù)據(jù),缺省時默認為考慮全部列。keep決定標記哪個重復(fù)數(shù)據(jù),缺省時默認為'first',即對于data中的每一組重復(fù)數(shù)據(jù),第一次出現(xiàn)的位置標記為False,其他重復(fù)出現(xiàn)的位置則標記為True。keep='last'時則表示重復(fù)數(shù)據(jù)最后一次出現(xiàn)的位置才標記為False,其余位置為True。
可以使用drop_duplicates方法刪除重復(fù)的行,常用的語法格式如下:
- result=data.drop_duplicates(subset=None,keep='first',…)
drop_duplicates方法的參數(shù)含義與duplicated方法相同。keep參數(shù)決定保留哪一行重復(fù)數(shù)據(jù)。返回值為刪掉重復(fù)數(shù)據(jù)的Series或DataFrame對象。
Pandas還可以利用drop_duplicates方法處理數(shù)據(jù)標簽中存在重復(fù)項的情況,具體方法是:先使用Index.duplicated方法確定數(shù)據(jù)標簽中是否存在重復(fù)值,然后再利用得到的布爾數(shù)組對數(shù)據(jù)執(zhí)行行切片。
下面通過如下代碼清單演示Pandas提供的處理重復(fù)數(shù)據(jù)方法的用法。
- 代碼清單 Pandas處理重復(fù)數(shù)據(jù)方法的用法示例
- 1 import pandas as pd
- 2 df = pd.DataFrame({'brand': ['YumYum', 'YumYum', 'Indomie', 'Indomie',
- 'Indomie'], 'style': ['cup', 'cup', 'cup', 'pack', 'pack'], 'rating': [4,
- 4, 3.5, 15, 5]},index=['a', 'a', 'b', 'c', 'd'])
- 3 print('df:\n',df)
- 4 print('對于全列,df的行中是否存在重復(fù)項:\n',df.duplicated())
- 5 df1=df.drop_duplicates()
- 6 print('刪除上述重復(fù)項后的df:\n',df1)
- 7 print('對于brand和style列,df的行中是否存在重復(fù)項:\n',df.duplicated(subset= ['brand', 'style']))
- 8 df2=df.drop_duplicates(subset= ['brand', 'style'])
- 9 print('刪除上述重復(fù)項后的df:\n',df2)
- 10 print('df的index是否存在重復(fù)項:\n',df.index.duplicated(keep='last'))
- 11 df3=df[~df.index.duplicated(keep='last')]
- 12 print('刪除index重復(fù)項后的df:\n',df3)
程序執(zhí)行結(jié)束后,輸出結(jié)果如下:
- df:
- brand style rating
- a YumYum cup 4.0
- a YumYum cup 4.0
- b Indomie cup 3.5
- c Indomie pack 15.0
- d Indomie pack 5.0
- 對于全列,df的行中是否存在重復(fù)項:
- a False
- a True
- b False
- c False
- d False
- dtype: bool
- 刪除上述重復(fù)項后的df:
- brand style rating
- a YumYum cup 4.0
- b Indomie cup 3.5
- c Indomie pack 15.0
- d Indomie pack 5.0
- 對于brand和style列,df的行中是否存在重復(fù)項:
- a False
- a True
- b False
- c False
- d True
- dtype: bool
- 刪除上述重復(fù)項后的df:
- brand style rating
- a YumYum cup 4.0
- b Indomie cup 3.5
- c Indomie pack 15.0
- df的index是否存在重復(fù)項:
- [ True False False False False]
- 刪除index重復(fù)項后的df:
- brand style rating
- a YumYum cup 4.0
- b Indomie cup 3.5
- c Indomie pack 15.0
- d Indomie pack 5.0
下面對代碼清單中的代碼做簡要說明。
- 第2行代碼通過字典創(chuàng)建了一個5行3列的DataFrame對象df,并設(shè)置index參數(shù)為['a', 'a', 'b', 'c', 'd'],如第3行print函數(shù)的輸出結(jié)果所示。
- 第4行代碼通過duplicated方法來確認df中是否存在重復(fù)數(shù)據(jù),采用了默認的參數(shù)設(shè)置,即根據(jù)df的所有列來標識重復(fù)數(shù)據(jù)。對于df中的每一組重復(fù)數(shù)據(jù),第一次出現(xiàn)的位置標記為False,其他重復(fù)出現(xiàn)的位置則標記為True,返回值為Series對象。從print函數(shù)的輸出結(jié)果分析得到,df中的第2行為重復(fù)數(shù)據(jù)。
- 第5行代碼通過drop_duplicates方法刪除了第4行代碼中確定的重復(fù)數(shù)據(jù)所在的行,并將返回結(jié)果賦值給新的DataFrame對象df1,如第6行print函數(shù)的輸出結(jié)果所示。
- 第7行代碼通過duplicated方法來確認df中是否存在重復(fù)數(shù)據(jù),subset= ['brand', 'style']表示根據(jù)df的brand和style兩列來標識重復(fù)數(shù)據(jù)。對于df中的每一組重復(fù)數(shù)據(jù),第一次出現(xiàn)的位置標記為False,其他重復(fù)出現(xiàn)的位置則標記為True,返回值為Series對象。從print函數(shù)的輸出結(jié)果分析得到,df中的第2行和第5行為重復(fù)數(shù)據(jù)。
- 第8行代碼通過drop_duplicates方法刪除了第6行代碼中確定的重復(fù)數(shù)據(jù)所在的行,并將返回結(jié)果賦值給新的DataFrame對象df2,如第9行print函數(shù)的輸出結(jié)果所示。
- 第10行代碼通過duplicated方法來確認df.index(即df的行標簽)中是否存在重復(fù)項,keep='last'表示對于df.index中的每一組重復(fù)數(shù)據(jù),最后一次出現(xiàn)的位置標記為Fasle,其他重復(fù)出現(xiàn)的位置則標記為True,返回值為一維布爾數(shù)組。從print函數(shù)的輸出結(jié)果分析得到,df中第1行的行標簽為重復(fù)項。
- 第11行代碼通過布爾數(shù)組切片的方法刪除了df中行標簽重復(fù)的行。首先對第10行代碼得到的布爾數(shù)組進行取反操作,即將第1行重復(fù)項標記為Fasle,其他項標記為True;然后再利用得到的新布爾數(shù)組對df進行切片,截取True對應(yīng)的行,并將返回結(jié)果賦值給新的DataFrame對象df3,如第12行print函數(shù)的輸出結(jié)果所示。
Tips
本文摘編于《Python數(shù)據(jù)分析與應(yīng)用》,經(jīng)出版方授權(quán)發(fā)布。