第七章 缺失數(shù)據(jù)

參考:https://datawhalechina.github.io/joyful-pandas/build/html/%E7%9B%AE%E5%BD%95/ch7.html

一、缺失值的統(tǒng)計(jì)和刪除

1. 缺失信息的統(tǒng)計(jì) isnaisnull

函數(shù) 例子 備注
isna或isnull df.isna().mean() # 查看缺失的比例 isnaisnull (兩個(gè)函數(shù)沒(méi)有區(qū)別)
isna或者notna df[df.Height.isna()] 應(yīng)用于series,只能統(tǒng)計(jì)一列的缺失信息
isna,notnaany, all 的組合 sub_set = df[['Height', 'Weight', 'Transfer']]<br />df[sub_set.isna().all(1)]# 全部缺失<br />df[sub_set.isna().any(1)].head() # 至少有一個(gè)缺失<br />df[sub_set.notna().all(1)].head() # 沒(méi)有缺失 同時(shí)對(duì)幾個(gè)列,檢索出全部為缺失或者至少有一個(gè)缺失或者沒(méi)有缺失的行

2. 缺失信息的刪除

函數(shù) 參數(shù) 例子 備注
dropna axis(默認(rèn)為0,即刪除行)
how(刪除方式)主要有 anyall 兩種參數(shù)可以選擇 df.dropna(how = 'any', subset = ['Height', 'Weight']) 刪除身高體重至少有一個(gè)缺失的行
thresh(刪除的非缺失值個(gè)數(shù)閾值) res = df.dropna(1, thresh=df.shape[0]-15) 刪除超過(guò)15個(gè)缺失值的列
subset(備選的刪除子集) res = df.loc[df[['Height', 'Weight']].notna().all(1)]<br />res = df.loc[:, ~(df.isna().sum()>15)] 上述的兩個(gè)操作,也可以使用布爾索引來(lái)完成

二、缺失值的填充和插值

1. 利用fillna進(jìn)行填充

函數(shù) 參數(shù) 例子
fillna method:填充方法(ffill: 用缺失值前面的元素填充;bfill:用后面的元素填充) s.fillna(method='ffill') # 用前面的值向后填充
limit:連續(xù)缺失值的最大填充次數(shù) s.fillna(method='ffill', limit=1) # 連續(xù)出現(xiàn)的缺失,最多填充一次
value:填充值,可以是標(biāo)量,也可以是索引到元素的字典映射 s.fillna(s.mean()) # value為標(biāo)量<br />s.fillna({'a': 100, 'd': 200}) # 通過(guò)索引映射填充的值

練一練

對(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])
s1 = s.fillna(method='ffill',limit=1)
s2 = s.fillna(method='bfill',limit=1)
s = pd.Series(list(map(lambda x,y: (x+y)/2 if not np.isnan(x) and not np.isnan(y) else np.nan, s1,s2)))
s
'''
0    1.0
1    2.0
2    3.0
3    NaN
4    NaN
'''

2. 插值函數(shù)

這里只討論比較常用且簡(jiǎn)單的三類(lèi)情況,即線(xiàn)性插值、最近鄰插值和索引插值。

函數(shù) 插值類(lèi)型 參數(shù) 例子 備注
interpolate 線(xiàn)性插值 limit_direction:控制方向,默認(rèn)為 forward,還有backward或both(雙向限制插值) s.interpolate(limit_direction='backward', limit=1)
limit:控制最大連續(xù)缺失值插值個(gè)數(shù)
最近鄰插補(bǔ) method s.interpolate('nearest').values 缺失值的元素和離它最近的非缺失值元素一樣
索引插值 s.interpolate(method='index') 根據(jù)索引大小進(jìn)行線(xiàn)性插值

三、Nullable類(lèi)型

1. 缺失記號(hào)及其缺陷

缺失記號(hào) 說(shuō)明
None python 中的缺失值用 None 表示,該元素除了等于自己本身之外,與其他任何元素不相等
np.nan 和所有元素都不相等,包括自己;但在兩個(gè)序列使用equals進(jìn)行比較時(shí),會(huì)跳過(guò)nan來(lái)比較
pd.NaT 時(shí)間序列對(duì)象的缺失值,作用和np.nan一樣

np.nan的缺陷:np.nan屬于浮點(diǎn)類(lèi)型,和任何其他類(lèi)型一列,這一列就會(huì)變成其他類(lèi)型:

  • 和整數(shù)一列:整列變成float類(lèi)型
  • 和bool一列:整列變成object類(lèi)型
  • 和datetime一列:整列變成object類(lèi)型

所以出現(xiàn)了pd.NaT。1.0.0版本后,pandas設(shè)計(jì)了新的缺失類(lèi)型pd.NA以及3種Nullable序列類(lèi)型。

2. Nullable類(lèi)型的性質(zhì)

序列類(lèi)型不受nan影響,在聲明序列時(shí)指定序列的類(lèi)型為Int, boolean 和 string

  • pd.Series([np.nan, 1], dtype = 'Int64') # "i"是大寫(xiě)的
  • pd.Series([np.nan, True], dtype = 'boolean')
  • pd.Series([np.nan, 'my_str'], dtype = 'string')
類(lèi)型 計(jì)算 NA類(lèi)型返回 序列類(lèi)型
Int pd.Series([np.nan, 0], dtype = 'Int64') + 1 NA Int64
pd.Series([np.nan, 0], dtype = 'Int64') == 0 NA boolean
pd.Series([np.nan, 0], dtype = 'Int64') * 0.5 NA Float64

boolean和bool的區(qū)別:

s = pd.Series(['a', 'b'])
s_bool = pd.Series([True, np.nan])
s_boolean = pd.Series([True, np.nan]).astype('boolean')
bool bool結(jié)果 boolean boolean結(jié)果
s[s_bool] 報(bào)錯(cuò); nan不能作為索引器的選擇 s[s_boolean] 0 a <br />dtype: object 把nan當(dāng)成False
s_bool & True bool類(lèi)型在缺失處返回的永遠(yuǎn)是False<br />0 True <br />1 False s_boolean & True boolean 會(huì)根據(jù)邏輯運(yùn)算是否能確定唯一結(jié)果來(lái)返回相應(yīng)的值<br />0 True <br />1 <NA>
s_bool | True 0 True <br />1 False s_boolean | True 0 True <br />1 True
~s_bool 0 False <br />1 False ~s_boolean 0 False <br />1 <NA>

一般在實(shí)際數(shù)據(jù)處理時(shí),可以在數(shù)據(jù)集讀入后,先通過(guò) convert_dtypes 轉(zhuǎn)為 Nullable 類(lèi)型:

df = df.convert_dtypes()

3. 缺失數(shù)據(jù)的計(jì)算和分組

sum, prob 使用加法和乘法的時(shí)候,缺失數(shù)據(jù)等價(jià)于被分別視作0和1,即不改變?cè)瓉?lái)的計(jì)算結(jié)果。當(dāng)使用累計(jì)函數(shù)時(shí),會(huì)自動(dòng)跳過(guò)缺失值所處的位置。

單個(gè)標(biāo)量運(yùn)算:

運(yùn)算 結(jié)果
np.nan ** 0 1.0
1 ** np.nan 1.0
pd.NA ** 0 1
1 ** pd.NA 1
其他所有涉及np.nan的運(yùn)算 False
其他所有涉及pd.NA的運(yùn)算 NA

對(duì)于一些函數(shù)而言,缺失可以作為一個(gè)類(lèi)別處理,例如在 groupby, get_dummies 中可以設(shè)置相應(yīng)的參數(shù)來(lái)進(jìn)行增加缺失類(lèi)別:

  • df_nan.groupby('category', dropna=False)['value'].mean() # pandas版本大于1.1.0
  • pd.get_dummies(df_nan.category, dummy_na=True)

四、練習(xí)

Ex1:缺失值與類(lèi)別的相關(guān)性檢驗(yàn)

統(tǒng)計(jì)學(xué)的概念不太記得了,題目不太讀得懂。。。Orz

答案:

df = pd.read_csv('../data/missing_chi.csv')
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")
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):
    S = []
    for i in range(2):
        for j in range(2):
            E = my_df.iat[i, j]
            F = my_df.iat[i, 2]*my_df.iat[2, j]/my_df.iat[2,2]
            S.append((E-F)**2/F)
    return sum(S)
res1 = compute_S(df_1)
res2 = compute_S(df_2)
from scipy.stats import chi2
chi2.sf(res1, 1) # X_1檢驗(yàn)的p值 # 不能認(rèn)為相關(guān),剔除
chi2.sf(res2, 1) # X_2檢驗(yàn)的p值 # 認(rèn)為相關(guān),保留

Ex2:用回歸模型解決分類(lèi)問(wèn)題

對(duì)KNN的類(lèi)不太了解,題目好難。。。Orz

  1. 對(duì)于回歸問(wèn)題而言,需要得到的是一個(gè)具體的數(shù)值,因此預(yù)測(cè)值由最近的 n 個(gè)樣本對(duì)應(yīng)的平均值獲得。請(qǐng)把上面的這個(gè)分類(lèi)問(wèn)題轉(zhuǎn)化為回歸問(wèn)題,僅使用 KNeighborsRegressor 來(lái)完成上述的 KNeighborsClassifier 功能。

答案:

from sklearn.neighbors import KNeighborsRegressor
df = pd.read_excel('../data/color.xlsx')
df_dummies = pd.get_dummies(df.Color)
stack_list = []
for col in df_dummies.columns:
    clf = KNeighborsRegressor(n_neighbors=6)
    clf.fit(df.iloc[:,:2], df_dummies[col])
    res = clf.predict([[0.8, -0.2]]).reshape(-1,1)
    stack_list.append(res)
code_res = pd.Series(np.hstack(stack_list).argmax(1))
df_dummies.columns[code_res[0]]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容