Pandas 是一個強大的分析結構化數據的工具集,它的使用基礎是Numpy(提供高性能的矩陣運算),用於數據挖掘和數據分析,同時也提供數據清洗功能。git
在往期文章中,已經詳細講解了Pandas作分析數據的四種基本操做:索引、分組、變形及合併。如今,開始正式介紹Pandas的數據結構類型:缺失數據、文本數據、分類數據和時序數據。算法
本文目錄
數據結構
1. 基礎概念app
1.1. 缺失值分類dom
1.2. 缺失值處理方法ide
2. 缺失觀測及其類型函數
2.1. 瞭解缺失信息工具
2.2. 三種缺失符號性能
2.3. Nullable類型與NA符號
優化
2.4. NA的特性
2.5. convert_dtypes方法
3. 缺失數據的運算與分組
3.1. 加號與乘號規則
3.2. groupby方法中的缺失值
4. 填充與剔除
4.1. fillna方法
4.2. dropna方法
5. 插值
5.1. 線性插值
5.2. 高級插值方法 5.3. interpolate中的限制參數 6. 問題及練習6.1. 問題
6.2. 練習
首先,對缺失值分類和缺失值處理方法進行講解。
缺失值的分類
按照數據缺失機制可分爲:
可忽略的缺失
徹底隨機缺失(missing completely at random, MCAR),所缺失的數據發生的機率既與已觀察到的數據無關,也與未觀察到的數據無關
隨機缺失(missing at random, MAR),假設缺失數據發生的機率與所觀察到的變量是有關的,而與未觀察到的數據的特徵是無關的。
不可忽略的缺失(non-ignorable missing ,NIM) 或非隨機缺失(not missing at random, NMAR, or, missing not at random, MNAR),若是不徹底變量中數據的缺失既依賴於徹底變量又依賴於不徹底變量自己,這種缺失即爲不可忽略的缺失。
數據值的處理方法
主要就是兩種方法:
刪除存在缺失值的個案;
缺失值插補。
簡單刪除法是對缺失值進行處理的最原始方法。它將存在缺失值的個案刪除。若是數據缺失問題能夠經過簡單的刪除小部分樣原本達到目標,那麼這個方法是最有效的。
(2)權重法 當缺失值的類型爲非徹底隨機缺失的時候,能夠經過對完整的數據加權來減少誤差。 把數據不徹底的個案標記後,將完整的數據個案賦予不一樣的權重,個案的權重能夠經過logistic或probit迴歸求得。 若是解釋變量中存在對權重估計起決定行因素的變量,那麼這種方法能夠有效減少誤差。 若是解釋變量和權重並不相關,它並不能減少誤差。對於存在多個屬性缺失的狀況,就須要對不一樣屬性的缺失組合賦不一樣的權重,這將大大增長計算的難度,下降預測的準確性,這時權重法並不理想。
二、可能值插補缺失值
【思想來源】:以最可能的值來插補缺失值比所有刪除不徹底樣本所產生的信息丟失要少。
(1)均值插補 屬於單值插補。 數據的屬性分爲定距型和非定距型。若是缺失值是定距型的,就以該屬性存在值的平均值來插補缺失的值;若是缺失值是非定距型的,就用該屬性的衆數來補齊缺失的值。(2)利用同類均值插補
屬於單值插補。 用層次聚類模型預測缺失變量的類型,再以該類型的均值插補。 假設爲信息徹底的變量,爲存在缺失值的變量,那麼首先對或其子集行聚類,而後按缺失個案所屬類來插補不一樣類的均值。 若是在之後統計分析中還需以引入的解釋變量和作分析,那麼這種插補方法將在模型中引入自相關,給分析形成障礙。(3)極大似然估計(Max Likelihood ,ML)
在缺失類型爲隨機缺失的條件下,假設模型對於完整的樣本是正確的,那麼經過觀測數據的邊際分佈能夠對未知參數進行極大似然估計(Little and Rubin)。 這種方法也被稱爲忽略缺失值的極大似然估計,對於極大似然的參數估計實際中常採用的計算方法是指望值最大化(Expectation Maximization,EM)。 該方法比刪除個案和單值插補更有吸引力, 前提是適用於大樣本,有效樣本的數量足夠以保證ML估計值是漸近無偏的並服從正態分佈。這種方法可能會陷入局部極值,收斂速度也不是很快,而且計算很複雜。(4)多重插補(Multiple Imputation,MI)
多值插補的思想來源於貝葉斯估計,認爲待插補的值是隨機的,它的值來自於已觀測到的值。 具體實踐上一般是估計出待插補的值,而後再加上不一樣的噪聲,造成多組可選插補值。根據某種選擇依據,選取最合適的插補值。多重插補方法的三個步驟:
爲每一個空值產生一套可能的插補值,這些值反映了無響應模型的不肯定性;每一個值均可以被用來插補數據集中的缺失值,產生若干個完整數據集合。
每一個插補數據集合都用針對完整數據集的統計方法進行統計分析。
多重插補方法舉例:
假設一組數據,包括三個變量,它們的聯合分佈爲正態分佈,將這組數據處理成三組,A組保持原始數據,B組僅缺失,C組缺失和。在多值插補時,對A組將不進行任何處理,對B組產生的一組估計值(做關於的迴歸),對C組做產生和的一組成對估計值(做關於 的迴歸)。 當用多值插補時,對A組將不進行處理,對B、C組將完整的樣本隨機抽取造成爲組(爲可選擇的組插補值),每組個案數只要可以有效估計參數就能夠了。對存在缺失值的屬性的分佈做出估計,而後基於這組觀測值,對於這組樣本分別產生關於參數的組估計值,給出相應的預測即,這時採用的估計方法爲極大似然法,在計算機中具體的實現算法爲指望最大化法(EM)。對B組估計出一組的值,對C將利用 它們的聯合分佈爲正態分佈這一前提,估計出一組( )。 上例中假定了 的聯合分佈爲正態分佈。這個假設是人爲的,可是已經經過驗證(Graham和Schafer於1999),非正態聯合分佈的變量,在這個假定下仍然能夠估計到很接近真實值的結果。多重插補彌補貝葉斯估計的不足之處:
貝葉斯估計以極大似然的方法估計,極大似然的方法要求模型的形式必須準確,若是參數形式不正確,將獲得錯誤得結論,即先驗分佈將影響後驗分佈的準確性。而多重插補所依據的是大樣本漸近完整的數據的理論,在數據挖掘中的數據量都很大,先驗分佈將極小的影響結果,因此先驗分佈的對結果的影響不大。
貝葉斯估計僅要求知道未知參數的先驗分佈,沒有利用與參數的關係。而多重插補對參數的聯合分佈做出了估計,利用了參數間的相互關係。
首先導入數據:
import pandas as pdimport numpy as npdf = pd.read_csv('data/table_missing.csv')df.head()
df['Physics'].isna().head()
df['Physics'].notna().head()
df.isna().head()
但對於DataFrame咱們更關心到底每列有多少缺失值
df.isna().sum()
此外,能夠經過第1章中介紹的info函數查看缺失信息
df.info()
df[df['Physics'].isna()]
三、挑選出全部非缺失值列
df[df.notna().all(1)]
三種缺失符號
np.nan == np.nan
False
np.nan == 0
False
np.nan == None
False
df.equals(df)
True
type(np.nan)
float
pd.Series([1,2,3]).dtype
dtype('int64')
pd.Series([1,np.nan,3]).dtype
dtype('float64')
pd.Series([1,np.nan,3],dtype='bool')
s = pd.Series([True,False],dtype='bool')s[1]=np.nans
在全部的表格讀取後,不管列是存放什麼類型的數據,默認的缺失值全爲np.nan類型。所以整型列轉爲浮點;而字符因爲沒法轉化爲浮點,所以只能歸併爲object類型('O'),原來是浮點型的則類型不變
df['ID'].dtype
dtype('float64')
df['Math'].dtype
dtype('float64')
df['Class'].dtype
dtype('O')
None == None
True
pd.Series([None],dtype='bool')
0 False
dtype: bool
s = pd.Series([True,False],dtype='bool')s[0]=Nones
0 False
1 False
dtype: bool
s = pd.Series([1,0],dtype='bool')s[0]=Nones
0 False
1 False
dtype: bool
type(pd.Series([1,None])[1])
numpy.float64
type(pd.Series([1,None],dtype='O')[1])
NoneType
pd.Series([None]).equals(pd.Series([np.nan]))
False
s_time = pd.Series([pd.Timestamp('20120101')]*5)s_time
s_time[2] = Nones_time
s_time[2] = np.nans_time
s_time[2] = pd.NaTs_time
type(s_time[2])
pandas._libs.tslibs.nattype.NaTType
s_time[2] == s_time[2]
False
s_time.equals(s_time)
True
s = pd.Series([True,False],dtype='bool')s[1]=pd.NaTs
Nullable類型與NA符號
s_original = pd.Series([1, 2], dtype="int64")s_original
s_new = pd.Series([1, 2], dtype="Int64")s_new
它的好處就在於,其中前面提到的三種缺失值都會被替換爲統一的NA符號,且不改變數據類型。
s_original[1] = np.nans_original
s_new[1] = np.nans_new
s_new[1] = Nones_new
s_new[1] = pd.NaTs_new
s_original = pd.Series([1, 0], dtype="bool")s_original
s_new = pd.Series([0, 1], dtype="boolean")s_new
s_original[0] = np.nans_original
s_original = pd.Series([1, 0], dtype="bool") #此處從新加一句是由於前面賦值改變了bool類型s_original[0] = Nones_original
s_new[0] = np.nans_new
s_new[0] = Nones_new
s_new[0] = pd.NaTs_new
s = pd.Series(['dog','cat'])s[s_new]
三、string類型
s = pd.Series(['dog','cat'],dtype='string')s
s[0] = np.nans
s[0] = Nones
s[0] = pd.NaTs
此外,和object類型的一點重要區別就在於,在調用字符方法後,string類型返回的是Nullable類型,object則會根據缺失類型和數據類型而改變。
s = pd.Series(["a", None, "b"], dtype="string")s.str.count('a')
s2 = pd.Series(["a", None, "b"], dtype="object")s2.str.count("a")
s.str.isdigit()
s2.str.isdigit()
True | pd.NA
True
pd.NA | True
True
False | pd.NA
<NA>
False & pd.NA
False
True & pd.NA
<NA>
#bool(pd.NA)
pd.NA ** 0
1
1 ** pd.NA
1
pd.NA + 1
<NA>
"a" * pd.NA
<NA>
pd.NA == pd.NA
<NA>
pd.NA < 2.5
<NA>
np.log(pd.NA)
<NA>
np.add(pd.NA, 1)
<NA>
pd.read_csv('data/table_missing.csv').dtypes
pd.read_csv('data/table_missing.csv').convert_dtypes().dtypes
s = pd.Series([2,3,np.nan,4])s.sum()
9.0
s.prod()
24.0
s.cumsum()
s.cumprod()
s.pct_change()
df_g = pd.DataFrame({'one':['A','B','C','D',np.nan],'two':np.random.randn(5)})df_g
df_g.groupby('one').groups
df['Physics'].fillna('missing').head()
df['Physics'].fillna(method='ffill').head()
df['Physics'].fillna(method='backfill').head()
二、填充中的對齊特性
df_f = pd.DataFrame({'A':[1,3,np.nan],'B':[2,4,np.nan],'C':[3,5,np.nan]})df_f.fillna(df_f.mean())
返回的結果中沒有C,根據對齊特色不會被填充
df_f.fillna(df_f.mean()[['A','B']])
dropna方法
df_d = pd.DataFrame({'A':[np.nan,np.nan,np.nan],'B':[np.nan,3,2],'C':[3,2,1]})df_d
df_d.dropna(axis=0)
df_d.dropna(axis=1)二、how參數 (能夠選all或者any,表示全爲缺失去除和存在缺失去除)
df_d.dropna(axis=1,how='all')三、subset參數 (即在某一組列範圍中搜索缺失值)¶
df_d.dropna(axis=0,subset=['B','C'])
s = pd.Series([1,10,15,-5,-2,np.nan,np.nan,28])s
s.interpolate()
s.interpolate().plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7fe7df20af50>
s.index = np.sort(np.random.randint(50,300,8))s.interpolate()#值不變
s.interpolate().plot()#後面三個點不是線性的(若是幾乎爲線性函數,請從新運行上面的一個代碼塊,這是隨機性致使的)
<matplotlib.axes._subplots.AxesSubplot at 0x7fe7dfc69890>
s.interpolate(method='index').plot()#能夠看到與上面的區別
<matplotlib.axes._subplots.AxesSubplot at 0x7fe7dca0c4d0>
s_t = pd.Series([0,np.nan,10] ,index=[pd.Timestamp('2012-05-01'),pd.Timestamp('2012-05-07'),pd.Timestamp('2012-06-03')])s_t
s_t.interpolate().plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7fe7dc964850>
s_t.interpolate(method='time').plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7fe7dc8eda10>
ser = pd.Series(np.arange(1, 10.1, .25) ** 2 + np.random.randn(37))missing = np.array([4, 13, 14, 15, 16, 17, 18, 20, 29])ser[missing] = np.nanmethods = ['linear', 'quadratic', 'cubic']df = pd.DataFrame({m: ser.interpolate(method=m) for m in methods})df.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x7fe7dc86f810>
s = pd.Series([1,np.nan,np.nan,np.nan,5])s.interpolate(limit=2)
s = pd.Series([np.nan,np.nan,1,np.nan,np.nan,np.nan,5,np.nan,np.nan,])s.interpolate(limit_direction='backward')
s = pd.Series([np.nan,np.nan,1,np.nan,np.nan,np.nan,5,np.nan,np.nan,])s.interpolate(limit_area='inside')
s = pd.Series([np.nan,np.nan,1,np.nan,np.nan,np.nan,5,np.nan,np.nan,])s.interpolate(limit_area='outside')
問題
【問題一】 如何刪除缺失值佔比超過25%的列?第一步,計算單列缺失值的數量,計算單列總樣本數
第二步,算出比例,獲得一個列的布爾列表
第三步,利用這個布爾列表進行列索引或列刪除
df.loc[:,(df.isna().sum()/df.isna().count()<0.25).values]
【問題二】 什麼是Nullable類型?請談談爲何要引入這個設計?
Nullable類型是一種爲了統一NaN,Null,NaT三類缺失值而誕生的新的類型。是在原來的數值、布爾、字符等類型的基礎上進行小改,優化了當出現缺失值狀況時的應對。引入這個設計時爲了更好的處理缺失值,統一缺失值處理方法
【問題三】 對於一份有缺失值的數據,能夠採起哪些策略或方法深化對它的瞭解?能夠查看缺失值出現的比例;
查看缺失值之間的關聯性;
查看整體的缺失信息;
根據缺失信息判斷是否爲有效數據;
根據缺失信息清洗數據等等。
練習
【練習一】現有一份虛擬數據集,列類型分別爲string/浮點/整型,請解決以下問題。
q1 = pd.read_csv('data/Missing_data_one.csv')q1.head()
A B C0 not_NaN 0.922 4.01 not_NaN 0.700 NaN2 not_NaN 0.503 8.03 not_NaN 0.938 4.04 not_NaN 0.952 10.0
1.1 請以列類型讀入數據,並選出C爲缺失值的行。
q1[q1['C'].isna()]
1.2 現須要將A中的部分單元轉爲缺失值,單元格中的最小轉換機率爲25%,且機率大小與所在行B列單元的值成正比
q1['A'] = pd.Series(list(zip(q1['A'].values,q1['B'].values))).apply(lambda x:x[0] if np.random.rand()>0.25*x[1]/q1['B'].min() else np.nan)【練習二】 現有一份缺失的數據集,記錄了36我的來自的地區、身高、體重、年齡和工資,解決以下問題:
pd.read_csv('data/Missing_data_two.csv').head()
編號 地區 身高 體重 年齡 工資0 1 A 157.50 NaN 47.0 15905.01 2 B 202.00 91.80 25.0 NaN2 3 C 169.09 62.18 NaN NaN3 4 A 166.61 59.95 77.0 5434.04 5 B 185.19 NaN 62.0 4242.0
2.1 統計各列缺失的比例並選出在後三列中至少有兩個非缺失值的行
q2.isna().sum()/q2.shape[0]q2[q2.iloc[:,-3:].isna().sum(1)<=1].head()
2.2 請結合身高列和地區列中的數據,對體重進行合理插值
q2_new = q2.copy()for area,group in q2.groupby('地區'): q2_new.loc[group.index,'體重'] = group[['身高','體重']].sort_values(by='身高').interpolate()['體重'] q2_new = q2_new.round(decimals=2)q2_new.head()