Pandas之缺失數(shù)據(jù)的實(shí)現(xiàn)
前言
本章介紹pandas中的缺失數(shù)據(jù),主要內(nèi)容有:
- pandas中對(duì)np.nan的操作: 統(tǒng)計(jì) 、 刪除 、 填充 、 插值
- pandas中的Nullable類型及相關(guān)操作
在無特殊說明時(shí),本章主要采用的df數(shù)據(jù)如下,不再重復(fù)說明:
df = pd.read_csv('./data/learn_pandas.csv',usecols=['Grade','Name','Gender','Height','Weight','Transfer']) df
一、缺失值的統(tǒng)計(jì)和刪除
1.缺失值的統(tǒng)計(jì)
我們可以使用isna()和isnull()方法來統(tǒng)計(jì)數(shù)據(jù)中的np.nan數(shù)據(jù):
df.isna()
返回的是相同形狀的數(shù)據(jù),對(duì)于非np.nan的元素返回 Fasle ,否則返回 True 。
接下來讓我們驗(yàn)證這兩種方法的等效性:
>>> df.isna().equals(df.isnull()) True
notna()和notnull()方法與isna()方法正好相反,它對(duì)非缺失值返回的是True,缺失值返回Fasle:
同樣地,我們來驗(yàn)證一下它們之間的關(guān)系:
>>> df.notna().equals(df.notnull()) True >>> df.notna().equals(~df.isna()) True
證明這四個(gè)方法確實(shí)是兩兩相同,兩兩相反。
1)配合其他統(tǒng)計(jì)方法使用
我們可以將isna()方法與一些其他統(tǒng)計(jì)方法一起使用,如統(tǒng)計(jì)每行數(shù)據(jù)缺失值的數(shù)量:
df.isna().sum(axis = 1)
axis = 1
代表沿著每列去統(tǒng)計(jì),結(jié)果返回的是每行的缺失值數(shù)
也可以統(tǒng)計(jì)每列缺失值所占的比例:
df.isna().sum(axis = 0)/df.shape[0]
其中,axis = 0
代表代表沿著每行去統(tǒng)計(jì),結(jié)果返回的是每列的缺失值數(shù),df.shape[0]
代表數(shù)據(jù)列的長度。
2)配合索引使用
也可以將isna()方法與索引一起使用,如返回體重為缺失值的行:
df[df['Weight'].isna()]
3)配合邏輯方法使用
如果要返回身高體重同時(shí)缺失的行,就需要邏輯方法配合:
df[df[['Height','Weight']].isna().all(axis = 1)]
也可以統(tǒng)計(jì)df中有缺失值的列:
df.isna().any(axis = 0)
返回False代表該列無缺失值,True代表該列至少有一個(gè)缺失值。
總結(jié)規(guī)律如下:
缺失值方法 | 邏輯方法 | 結(jié)果 | 含義 |
---|---|---|---|
isna() or isnull() | all | True | 都是缺失值 情況4 |
isna() or isnull() | all | False | 不都是缺失值 情況3 |
isna() or isnull() | any | True | 至少有一個(gè)缺失值 情況2 |
isna() or isnull() | any | False | 都不是缺失值 情況1 |
notna() or notnull() | all | True | 都是非缺失值 情況1 |
notna() or notnull() | all | False | 不都是非缺失值 情況2 |
notna() or notnull() | any | True | 至少有一個(gè)非缺失值 情況3 |
notna() or notnull() | any | False | 都不是非缺失值 情況4 |
進(jìn)一步總結(jié),上面的含義可以劃分為4種情況,即isna()和notna()在邏輯方法不同,結(jié)果不同時(shí),代表含義相同。
2.缺失值的刪除
在pandas中利用dropna方法對(duì)缺失值進(jìn)行刪除:
res = df.dropna(how = 'all',subset=['Height','Weight']) res
how參數(shù)可以設(shè)置成‘a(chǎn)ll'或‘a(chǎn)ny',默認(rèn)是‘a(chǎn)ny',subset參數(shù)代表刪除考慮的列名,作用和利用df索引進(jìn)行訪問等同。
來跟上面例子聯(lián)動(dòng)一下,查看一下行索引為91和102的同學(xué):
>>> res.loc[91] KeyError: 91 >>> res.loc[102] KeyError: 102
可以看到確實(shí)是成功刪除了。
1)thresh參數(shù)
thresh參數(shù)代表數(shù)據(jù)不被刪除至少需要的非缺失值數(shù)量:
df.dropna(axis = 1,thresh = df.shape[0] - 15)
這里的axis參數(shù)跟上面sum方法中的axis參數(shù)相比,有一些不一樣。我們知道sum方法中axis參數(shù)為1代表 沿著列 進(jìn)行求和,最終返回的是 每行 的和,而dropna中axis參數(shù)為1僅代表對(duì) 每列 的非缺失值進(jìn)行thresh值比較,意義是不同的,這也警告我們不要對(duì)所有方法中的axis參數(shù)統(tǒng)一去看待,要視情況而定。
2)自定義方法代替dropna方法
其實(shí)dropna的返回結(jié)果可以理解成按條件篩選,所以我們可以利用缺失值統(tǒng)計(jì)的相關(guān)方法進(jìn)行自定義方法來代替方法:
#刪除身高體重均為缺失值的行(保留身高體重至少有一個(gè)為非缺失值的行) >>> res2 = df[df[['Height','Weight']].notna().any(axis = 1)] >>> res2.equals(res) True >>> res = df.dropna(how = 'any',subset=['Height','Weight']) >>> res2 = df[df[['Height','Weight']].notna().all(axis = 1)] >>> res2.equals(res) True
對(duì)于無thresh參數(shù)的簡單dropna使用,總結(jié)如下:
dropna的how參數(shù) | 對(duì)應(yīng)的缺失值統(tǒng)計(jì)方法和邏輯方法 |
---|---|
all | notna + any |
any | notna + all |
這是由于,dropna()代表刪除isna()在all判斷下為True的數(shù)據(jù),等價(jià)于保留notna()在any判斷下為True的數(shù)據(jù)。
在來看如何代替帶有thresh參數(shù)的dropna方法:
df.loc[:,df.notna().sum(axis = 0) >= df.shape[0]-15]
即利用notna方法和loc索引,返回非缺失值大于等于thresh的列。
二、缺失值的填充和插值
1.填充
我們利用fillna方法對(duì)缺失值進(jìn)行填充,以Series舉例,比較重要的參數(shù)有:
- value:標(biāo)量或字典(索引到元素的映射)
- method:ffill代表由前面的非缺失值來填充,bfill代表由后面的來填充,默認(rèn)是None
- limit:代表連續(xù)缺失值最多填充次數(shù)
- inplace:是否替換原數(shù)據(jù)
在這里使用的Series數(shù)據(jù)如下:
>>> s = pd.Series([np.nan,2,np.nan,np.nan,0,np.nan],list('Xiaomy')) >>> s X NaN i 2.0 a NaN o NaN m 0.0 y NaN dtype: float64
1)利用value參數(shù)進(jìn)行填充
#使用標(biāo)量進(jìn)行填充 >>> s.fillna(1) X 1.0 i 2.0 a 1.0 o 1.0 m 0.0 y 1.0 dtype: float64 #使用字典進(jìn)行填充 >>> s.fillna({'X':1,'y':100,'c':1}) X 1.0 i 2.0 a NaN o NaN m 0.0 y 100.0 dtype: float64
我們可以看到在使用字典進(jìn)行填充時(shí)字典不需要包含所有缺失值的索引,且字典里面可以包含其他非索引值。
2)利用method方法進(jìn)行填充
也可以利用method方法進(jìn)行連續(xù)填充:
#由前面的非缺失值向后填充 >>> s.fillna(method='ffill') X NaN i 2.0 a 2.0 o 2.0 m 0.0 y 0.0 dtype: float64 #由后面的非缺失值向前填充 >>> s.fillna(method='bfill') X 2.0 i 2.0 a 0.0 o 0.0 m 0.0 y NaN dtype: float64
這里可以看到,對(duì)于ffill方式,開始的缺失值是不能填充的;對(duì)于bfill方式,結(jié)尾的缺失值也是不能填充的。
3)分組和缺失值填充的配合
對(duì)于df數(shù)據(jù)中身高的缺失項(xiàng),最好利用對(duì)應(yīng)年級(jí)的相同性別的平均身高來填充:
>>> df.groupby(['Grade','Gender'])['Height'].transform(lambda x:x.fillna(x.mean())) 0 158.900000 1 166.500000 2 188.900000 3 158.363158 4 174.000000 ... 195 153.900000 196 160.900000 197 153.900000 198 175.300000 199 155.700000 Name: Height, Length: 200, dtype: float64
這里利用的是分組中的自定義變換方法配合缺失值填充使用。
另外,limit參數(shù)可以限制填充的次數(shù),以配合method參數(shù)為例:
>>> s.fillna(method='ffill',limit=1) X NaN i 2.0 a 2.0 o NaN m 0.0 y 0.0 dtype: float64
當(dāng)然,limit參數(shù)也可以配合其他參數(shù)進(jìn)行使用,這里不再贅述。
練一練
題目:對(duì)一個(gè)序列以如下規(guī)則填充缺失值:如果單獨(dú)出現(xiàn)的缺失值,就用前后均值填充,如果連續(xù)出現(xiàn)的缺失值就不填充,即序列[1, NaN, 3, NaN, NaN]填充后為[1, 2, 3, NaN, NaN],請(qǐng)利用fillna函數(shù)實(shí)現(xiàn)。(提示:利用`limit``參數(shù))
>>> s = pd.Series([1,np.nan,3,np.nan,np.nan]) >>> res = (s.fillna(method='ffill',limit=1)+s.fillna(method='bfill',limit=1))/2 >>> res 0 1.0 1 2.0 2 3.0 3 NaN 4 NaN dtype: float64
思路:對(duì)于不滿足題設(shè)條件的位置包括處于兩端的位置,利用np.nan和其他值相加為本身的特性,依然保持為np.nan;對(duì)于左右均為非缺失值的位置,即可求得左右兩側(cè)之和,然后最后除2即可。
2.插值方法
在pandas中一般使用interpolate方法進(jìn)行插值,重要的參數(shù)有:
- limit_direction:‘forward'代表由前面的非缺失值進(jìn)行插值,‘backward'代表由前面的非缺失值進(jìn)行插值,‘both'代表二者兼有
- method:插值方法,包括‘nearest', ‘zero', ‘slinear', ‘quadratic', ‘cubic', ‘spline', ‘barycentric', ‘polynomial',默認(rèn)為‘linear'
- inplace:是否替換原數(shù)據(jù)
- limit:插值次數(shù)
本節(jié)使用的Series數(shù)據(jù)如下:
>>> s = pd.Series([np.nan, np.nan, 1, np.nan, np.nan, np.nan, 2, np.nan, np.nan]) >>> s 0 NaN 1 NaN 2 1.0 3 NaN 4 NaN 5 NaN 6 2.0 7 NaN 8 NaN dtype: float64
1)線性插值
>>> s.interpolate(limit_direction='backward') 0 1.00 1 1.00 2 1.00 3 1.25 4 1.50 5 1.75 6 2.00 7 NaN 8 NaN dtype: float64 >>> s.interpolate(limit_direction='both') 0 1.00 1 1.00 2 1.00 3 1.25 4 1.50 5 1.75 6 2.00 7 2.00 8 2.00 dtype: float64
這里舉了向前和向兩端分別進(jìn)行線性插值的例子,這里注意如果缺失值的左側(cè)或右側(cè)完全沒有非缺失值,那么它會(huì)由最近的非缺失值來填充。
2)最鄰近插值
注意要提前install scipy庫,否則會(huì)報(bào)錯(cuò):
>>> s.interpolate(method = 'nearest') 0 NaN 1 NaN 2 1.0 3 1.0 4 1.0 5 2.0 6 2.0 7 NaN 8 NaN dtype: float64
注意,這里會(huì)忽視兩端,且距離兩側(cè)非缺失值相同的位置會(huì)默認(rèn)插入前一個(gè)非缺失值。
3)索引插值
索引插值可以理解成不等比線性插值,它是根據(jù)索引的相對(duì)距離進(jìn)行插入,有點(diǎn)百分位數(shù)的意思:
>>> s = pd.Series([0,np.nan,100],index=[0,1,10]) >>> s.interpolate(method = 'index') 0 0.0 1 10.0 10 100.0 dtype: float64 >>> s.interpolate() 0 0.0 1 50.0 10 100.0 dtype: float64
注意它和線性插值的區(qū)別。
三、Nullable類型
1.缺失值的本質(zhì)和缺陷
python中用None表示缺失值,Numpy中用np.nan表示缺失值,它倆的共同點(diǎn)都是與其他值不等,而不同點(diǎn)是后者與自己也不等且沒有用于關(guān)鍵字,需要通過numpy.nan來使用:
>>> None == True False >>> np.nan == True False >>> np.nan == [] False >>> None == [] False >>> np.nan == '' False >>> None == '' False >>> None == None True >>> np.nan == np.nan False >>> pd.Series([1, np.nan]) == pd.Series([1, np.nan]) True
雖然兩個(gè)np.nan是不等的,但是對(duì)于包含np.nan變量的s或df數(shù)據(jù),它們會(huì)跳過比較對(duì)應(yīng)位置的np.nan變量。
np.nan的缺陷在于,它的本質(zhì)是一種float類型的變量,當(dāng)它和其他類型同時(shí)存在于數(shù)據(jù)中時(shí),會(huì)改變整個(gè)數(shù)據(jù)的類型,如:
>>> pd.Series([100,np.nan]).dtype dtype('float64') >>> pd.Series(['1',np.nan]).dtype dtype('O') >>> pd.Series([False,np.nan]).dtype dtype('O')
當(dāng)np.nan和int型變量放在一起時(shí),會(huì)使整個(gè)數(shù)據(jù)序列變成float64型;當(dāng)np.nan和其他類型變量放在一起時(shí),會(huì)使整個(gè)數(shù)據(jù)序列變成object型。
2.pandas中的Nullable類型
pandas設(shè)計(jì)了新的缺失類型pd.NA以及三種Nullable序列類型嘗試解決這些缺陷
它們的作用之一是在比較時(shí)返回pd.NA本身而不是False:
>>> s = pd.Series(['a', 'b']) >>> s_bool = pd.Series([True, np.nan]) >>> s_boolean = pd.Series([True, np.nan]).astype('boolean') >>> s_bool & True 0 True 1 False dtype: bool >>> s_boolean & True 0 True 1 <NA> dtype: boolean
即不會(huì)改變比較前后的結(jié)果。
3.缺失數(shù)據(jù)的計(jì)算和分組
對(duì)np.nan和pd.NA進(jìn)行標(biāo)量運(yùn)算時(shí),除了1的np.nan次冪和np.nan的0次冪兩種情況以外,均返回其自身:
>>> np.nan + 1 nan >>> pd.NA + 1 <NA> >>> np.nan * 10 nan >>> pd.NA * 10 <NA> >>> np.nan ** 0 1.0 >>> 1 ** np.nan 1.0
在對(duì)含有np.nan的數(shù)據(jù)進(jìn)行操作時(shí),默認(rèn)會(huì)忽略它們,如:
>>> s = pd.Series([7,6,np.nan,5,4]) >>> s.sum() 22.0
注意雖然忽視了np.nan,但由于np.nan的存在,還是讓結(jié)果變?yōu)榱薴loat類型。
練習(xí)
Ex1:缺失值與類別的相關(guān)性檢驗(yàn)
在數(shù)據(jù)處理中,含有過多缺失值的列往往會(huì)被刪除,除非缺失情況與標(biāo)簽強(qiáng)相關(guān)。下面有一份關(guān)于二分類問題的數(shù)據(jù)集,其中X_1, X_2為特征變量,y為二分類標(biāo)簽:
df = pd.read_csv('./data/missing_chi.csv') df
from scipy.stats import chi2 df = pd.read_csv('./data/missing_chi.csv') #分別將兩列的缺失值和非缺失值替換為字符‘NaN'和‘NotNaN' cat_1 = df.X_1.fillna('NaN').mask(df.X_1.notna()).fillna("NotNaN") cat_2 = df.X_2.fillna('NaN').mask(df.X_2.notna()).fillna("NotNaN") #分別進(jìn)行行列匯總 方便計(jì)算Eij和Fij df_1 = pd.crosstab(cat_1, df.y, margins=True) df_2 = pd.crosstab(cat_2, df.y, margins=True) def compute_S(my_df): #雙層遍歷,利用列表推導(dǎo)生成式去做 res = [((my_df.iat[i, j]-(my_df.iat[i, 2]*my_df.iat[2, j]/my_df.iat[2,2]))**2/(my_df.iat[i, 2]*my_df.iat[2, j]/my_df.iat[2,2])) for i in range(2) for j in range(2)] #返回總和 return sum(res) res1 = compute_S(df_1) res2 = compute_S(df_2) >>> print(chi2.sf(res1, 1) < 0.05) False >>> print(chi2.sf(res2, 1) < 0.05) True
思路:照著參考答案寫的,對(duì)每一步進(jìn)行注釋,并對(duì)循環(huán)進(jìn)行了一定的優(yōu)化。
Ex2:用回歸模型解決分類問題
KNN是一種監(jiān)督式學(xué)習(xí)模型,既可以解決回歸問題,又可以解決分類問題。對(duì)于分類變量,利用KNN分類模型可以實(shí)現(xiàn)其缺失值的插補(bǔ),思路是度量缺失樣本的特征與所有其他樣本特征的距離,當(dāng)給定了模型參數(shù)n_neighbors=n時(shí),計(jì)算離該樣本距離最近的n個(gè)樣本點(diǎn)中最多的那個(gè)類別,并把這個(gè)類別作為該樣本的缺失預(yù)測(cè)類別,具體如下圖所示,未知的類別被預(yù)測(cè)為黃色:
df = pd.read_excel('./data/color.xlsx') df.head()
from sklearn.neighbors import KNeighborsClassifier clf = KNeighborsClassifier(n_neighbors=6) #傳入前兩列和預(yù)測(cè)值 clf.fit(df.iloc[:,:2], df.Color) clf.predict([[0.8, -0.2]])
1.分類轉(zhuǎn)回歸 2.缺失值插補(bǔ)
df = pd.read_csv('./data/audit.csv') df.head()
參考文獻(xiàn)1.pandas中Dataframe的查詢方法([], loc, iloc, at, iat, ix)
到此這篇關(guān)于Pandas之缺失數(shù)據(jù)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Pandas之缺失數(shù)據(jù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
PyCharm無法調(diào)用numpy(報(bào)錯(cuò)ModuleNotFoundError:No?module?named?&a
本文主要介紹了PyCharm無法調(diào)用numpy(報(bào)錯(cuò)ModuleNotFoundError:No?module?named?'numpy'),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02Python利用PyMuPDF模塊實(shí)現(xiàn)快速轉(zhuǎn)換PDF文件
PDF是一種廣泛使用的文件格式,可以在任何設(shè)備上查看和打印,那么如何用Python和PyMuPDF制作你想要大小的PDF文件呢,本文就來和大家詳細(xì)講講2023-08-08python將ip地址轉(zhuǎn)換成整數(shù)的方法
這篇文章主要介紹了python將ip地址轉(zhuǎn)換成整數(shù)的方法,涉及Python針對(duì)IP地址的轉(zhuǎn)換技巧,需要的朋友可以參考下2015-03-03Python3如何日志同時(shí)輸出到控制臺(tái)和文件
這篇文章主要介紹了Python3如何日志同時(shí)輸出到控制臺(tái)和文件問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11Python數(shù)學(xué)建模PuLP庫線性規(guī)劃實(shí)際案例編程詳解
本節(jié)以一個(gè)實(shí)際數(shù)學(xué)建模案例,來為大家講解PuLP求解線性規(guī)劃問題的建模與編程。來鞏固加深大家對(duì)Python數(shù)學(xué)建模PuLP庫線性規(guī)劃的運(yùn)用理解2021-10-10python獲得linux下所有掛載點(diǎn)(mount points)的方法
這篇文章主要介紹了python獲得linux下所有掛載點(diǎn)(mount points)的方法,涉及Python操作Linux下掛載點(diǎn)的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04對(duì)Django項(xiàng)目中的ORM映射與模糊查詢的使用詳解
今天小編就為大家分享一篇對(duì)Django項(xiàng)目中的ORM映射與模糊查詢的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-07-07Python 通過爬蟲實(shí)現(xiàn)GitHub網(wǎng)頁的模擬登錄的示例代碼
這篇文章主要介紹了Python 通過爬蟲實(shí)現(xiàn)GitHub網(wǎng)頁的模擬登錄的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08