zoukankan      html  css  js  c++  java
  • 【12月DW打卡】joyful-pandas

    缺失数据

    脑图大纲

    小结

    import numpy as np
    import pandas as pd
    
    

    【7.2.1 练一练】

    对一个序列以如下规则填充缺失值:如果单独出现的缺失值,就用前后均值填充,如果连续出现的缺失值就不填充,即序列[1, NaN, 3, NaN, NaN]填充后为[1, 2, 3, NaN, NaN],请利用 fillna 函数实现。(提示:利用 limit 参数)

    s = pd.Series([1, np.nan, 3, np.nan, np.nan],
                  list('abcde'))
    
    # s.fillna(method='both', limit=1) 不支持
    
    ValueError: Invalid fill method. Expecting pad (ffill) or backfill (bfill). Got both
    
    (s.fillna(method='ffill', limit=1) + s.fillna(method='bfill', limit=1))/2
    
    
    a    1.0
    b    2.0
    c    3.0
    d    NaN
    e    NaN
    dtype: float64
    
    # 类似的interpolate方法,向后也是不可以的!
    s.interpolate(limit_direction='both', limit=1)
    
    
    a    1.0
    b    2.0
    c    3.0
    d    3.0
    e    NaN
    dtype: float64
    

    Ex1:缺失值与类别的相关性检验

    在数据处理中,含有过多缺失值的列往往会被删除,除非缺失情况与标签强相关。下面有一份关于二分类问题的数据集,其中 X_1, X_2 为特征变量, y 为二分类标签。

    df = pd.read_csv('E:\PycharmProjects\DatawhaleChina\joyful-pandas\data\missing_chi.csv')
    
    df.head()
    
    X_1 X_2 y
    0 NaN NaN 0
    1 NaN NaN 0
    2 NaN NaN 0
    3 43.0 NaN 0
    4 NaN NaN 0
    df.isna().mean()
    
    X_1    0.855
    X_2    0.894
    y      0.000
    dtype: float64
    
    df.y.value_counts(normalize=True)
    
    
    0    918
    1     82
    Name: y, dtype: int64
    

    事实上,有时缺失值出现或者不出现本身就是一种特征,并且在一些场合下可能与标签的正负是相关的。关于缺失出现与否和标签的正负性,在统计学中可以利用卡方检验来断言它们是否存在相关性。按照特征缺失的正例、特征缺失的负例、特征不缺失的正例、特征不缺失的负例,可以分为四种情况,设它们分别对应的样例数为(n_{11}, n_{10}, n_{01}, n_{00})。假若它们是不相关的,那么特征缺失中正例的理论值,就应该接近于特征缺失总数( imes)总体正例的比例,即:

    [E_{11} = n_{11} approx (n_{11}+n_{10}) imesfrac{n_{11}+n_{01}}{n_{11}+n_{10}+n_{01}+n_{00}} = F_{11} ]

    其他的三种情况同理。现将实际值和理论值分别记作(E_{ij}, F_{ij}),那么希望下面的统计量越小越好,即代表实际值接近不相关情况的理论值:

    [S = sum_{iin {0,1}}sum_{jin {0,1}} frac{(E_{ij}-F_{ij})^2}{F_{ij}} ]

    可以证明上面的统计量近似服从自由度为(1)的卡方分布,即(Soverset{cdot}{sim} chi^2(1))。因此,可通过计算(P(chi^2(1)>S))的概率来进行相关性的判别,一般认为当此概率小于(0.05)时缺失情况与标签正负存在相关关系,即不相关条件下的理论值与实际值相差较大。

    上面所说的概率即为统计学上关于(2 imes2)列联表检验问题的(p)值, 它可以通过scipy.stats.chi2(S, 1)得到。请根据上面的材料,分别对X_1, X_2列进行检验。

    """
    2×2 列联表检验问题的 p 值:
    特征缺失的正例  1
    特征缺失的负例  0
    特征不缺失的正例 1
    特征不缺失的负例 0
    """
    
    df = pd.read_csv('E:\PycharmProjects\DatawhaleChina\joyful-pandas\data\missing_chi.csv')
    # where 和 mask ,这两个函数是完全对称的: where 函数在传入条件为 False 的对应行进行替换,而 mask 在传入条件为 True 的对应行进行替换,当不指定替换值时,替换为缺失值。"
    cat_1 = df.X_1.fillna('NaN').mask(df.X_1.notna(), "NotNaN")
    cat_2 = df.X_2.fillna('NaN').mask(df.X_2.notna(), "NotNaN")
    # pd.crosstab计算两个(或多个)因子的简单交叉表。默认情况下,除非传递值数组和聚合函数,否则将计算因子的频率表。
    df_1 = pd.crosstab(cat_1, df.y, margins=True)
    df_2 = pd.crosstab(cat_2, df.y, margins=True)
    # 计算大S值
    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)
    
    0.9712760884395901
    
    from scipy.stats import chi2
    chi2.sf(res1, 1) # X_1检验的p值 # 不能认为相关,剔除
    
    0.9712760884395901
    
    chi2.sf(res2, 1) # X_2检验的p值 # 认为相关,保留(为当此概率小于0.05即符合条件)
    
    7.459641265637543e-166
    

    结果与scipy.stats.chi2_contingency在不使用(Yates)修正的情况下完全一致:

    # 列联表中变量独立性的卡方检验。
    from scipy.stats import chi2_contingency
    chi2_contingency(pd.crosstab(cat_1, df.y), correction=False)[1]
    
    0.9712760884395901
    
    chi2_contingency(pd.crosstab(cat_2, df.y), correction=False)[1]
    
    
    
    7.459641265637543e-166
    

    Ex2:用回归模型解决分类问题

    KNN是一种监督式学习模型,既可以解决回归问题,又可以解决分类问题。对于分类变量,利用KNN分类模型可以实现其缺失值的插补,思路是度量缺失样本的特征与所有其他样本特征的距离,当给定了模型参数n_neighbors=n时,计算离该样本距离最近的(n)个样本点中最多的那个类别,并把这个类别作为该样本的缺失预测类别,具体如下图所示,未知的类别被预测为黄色:

    上面有色点的特征数据提供如下:

    df = pd.read_excel('E:\PycharmProjects\DatawhaleChina\joyful-pandas\data\color.xlsx')
    df.head(3)
    
    X1 X2 Color
    0 -2.5 2.8 Blue
    1 -1.5 1.8 Blue
    2 -0.8 2.8 Blue

    已知待预测的样本点为(X_1=0.8, X_2=-0.2),那么预测类别可以如下写出:

    from sklearn.neighbors import KNeighborsClassifier
    clf = KNeighborsClassifier(n_neighbors=6)
    clf.fit(df.iloc[:,:2], df.Color)
    clf.predict([[0.8, -0.2]])
    
    array(['Yellow'], dtype=object)
    
    1. 对于回归问题而言,需要得到的是一个具体的数值,因此预测值由最近的(n)个样本对应的平均值获得。请把上面的这个分类问题转化为回归问题,仅使用KNeighborsRegressor来完成上述的KNeighborsClassifier功能。

    翻到源码的Examples

        --------
        >>> X = [[0], [1], [2], [3]]
        >>> y = [0, 0, 1, 1]
        >>> from sklearn.neighbors import KNeighborsRegressor
        >>> neigh = KNeighborsRegressor(n_neighbors=2)
        >>> neigh.fit(X, y)
        KNeighborsRegressor(...)
        >>> print(neigh.predict([[1.5]]))
        [0.5]
    

    照葫芦画瓢~~~

    df_dummies = pd.get_dummies(df.Color)
    df_dummies.head()
    
    from sklearn.neighbors import KNeighborsRegressor
    X = df[['X1', 'X2']]
    # y = [0, 0, 1, 1]
    stack_list = []
    for col in df_dummies.columns:
        print(col)
        neigh = KNeighborsRegressor(n_neighbors=6)
        neigh.fit(X, df_dummies[col])
        # 转为单列数据
        res = neigh.predict([[0.8, -0.2]]).reshape(-1,1)
        print(neigh.predict([[0.8, -0.2]]))
        stack_list.append(res)
    stack_list
    
    Blue
    [0.16666667]
    Green
    [0.33333333]
    Yellow
    [0.5]
    
    
    
    
    
    [array([[0.16666667]]), array([[0.33333333]]), array([[0.5]])]
    

    由上可知: 预测成蓝/绿/黄三个颜色的概率分别是0.16666667,33.3%和50%。
    取最大的概率作为最终预测结果,该位置最终预测为黄色。

    # np.hstack : 水平(按列)顺序堆叠数组。 [这里返回一个单列数组]
    # argmax : Return indices of the maximum values along the given axis.
    color_res = pd.Series(np.hstack(stack_list).argmax(axis=1))
    df_dummies.columns[color_res[0]]
    # 输出为'Yellow'
    
    'Yellow'
    
    1. 请根据第1问中的方法,对audit数据集中的Employment变量进行缺失值插补。
    df = pd.read_csv('E:\PycharmProjects\DatawhaleChina\joyful-pandas\data\audit.csv')
    df.head(3)
    
    from sklearn.neighbors import KNeighborsRegressor
    
    # df = pd.read_csv('data/audit.csv')
    
    res_df = df.copy()
    
    #将婚姻状况、性别变成one-hot向量,和年龄、收入、时间、雇用拼接在一起
    # 年龄、收入、时间这三个属性还做了标准化处理
    df = pd.concat([pd.get_dummies(df[['Marital', 'Gender']]),
            df[['Age','Income','Hours']].apply(
                lambda x:(x-x.min())/(x.max()-x.min())), df.Employment],1)
    
    
    X_train = df[df.Employment.notna()]
    
    X_test = df[df.Employment.isna()]
    
    
    
    df_dummies = pd.get_dummies(X_train.Employment)
    
    stack_list = []
    
    for col in df_dummies.columns:
            clf = KNeighborsRegressor(n_neighbors=6)
            clf.fit(X_train.iloc[:,:-1], df_dummies[col])
            res = clf.predict(X_test.iloc[:,:-1]).reshape(-1,1)
            stack_list.append(res)
    
    code_res = pd.Series(np.hstack(stack_list).argmax(1))
    
    code_res
    
    
    0     2
    1     0
    2     4
    3     4
    4     4
         ..
    95    4
    96    4
    97    4
    98    4
    99    4
    Length: 100, dtype: int64
    
    cat_res = code_res.replace(
        dict(
        zip(list(range(df_dummies.shape[0])), df_dummies.columns))
    )
    
    res_df.loc[res_df.Employment.isna(), 'Employment'] = cat_res.values
    
    res_df.isna().sum()
    
    ID            0
    Age           0
    Employment    0
    Marital       0
    Income        0
    Gender        0
    Hours         0
    dtype: int64
  • 相关阅读:
    Java学习图形界面+网络编程案例---------网络简易通讯
    Java图形界面学习---------简易登录界面
    Python-Collections模块之Counter
    Python-面试题-字符串(str)
    Python-面试题-数学运算(math)
    Python-面试题-列表(list)
    python-数据类型-字符串(Str)
    Pytest框架实现一些前后置(固件、夹具)的处理
    Pytest框架运行方式(主函数、命令行、配置、执行顺序)
    Jenkins配置maven+Allure
  • 原文地址:https://www.cnblogs.com/zhazhaacmer/p/14227492.html
Copyright © 2011-2022 走看看