# 异常值处理

# None和NaN

  • None被看作一个object对象,需要消耗更多的资源,处理速度更慢。不支持一些数学操作,因为None+数字是错误的语法。很多时候None会自动转换成NaN。
  • NaN是float64类型,虽然名字叫做‘不是一个数’,但却属于数字类,可以进行数学运算不会报错,虽然所有和它进行计算的最终结果依然是NaN。它的运算速度更快,还支持全局性的操作。

# 缺失值的处理方法

  • isnull:判断哪些值是缺失值,返回布尔
  • notnull:isnull的反函数

主要的缺失值处理方法:

  1. dropna:删除缺失值

    • 对于DataFrame默认会删除所在行(DataFrame默认的场景中大量样本删除一条关系不大,但每个列都是一个特征,删除一个特征则对整个样本集的影响非常大)
    • 设置how="all"指定只将整行都是缺失值的删除
    • 设置axis=1指定以列的形式删除
    • 设置thresh参数指定行或列中非缺失值的最小数量,在此数量以下的将被删除
    In [12]: from numpy import nan as NA  # 导入惯例
    
    In [13]: s = pd.Series([1, NA, 3.5, NA, 7])
    
    In [15]: s.dropna()  # 本质上就是把缺失值删除
    Out[15]:
    0    1.0
    2    3.5
    4    7.0
    dtype: float64
    
    In [20]: df = pd.DataFrame([[1, 6.5, 3],[1, NA, NA],[NA, NA, NA],[NA, 6.5,3]])
    
    In [21]: df
    Out[21]:
         0    1    2
    0  1.0  6.5  3.0
    1  1.0  NaN  NaN
    2  NaN  NaN  NaN
    3  NaN  6.5  3.0
    
    In [22]: df.dropna() # 只剩1行了
    Out[22]:
         0    1    2
    0  1.0  6.5  3.0
    
  2. fillna: 用某些值填充缺失的数据或使用插值方法(比如ffill\bfill)

    • 可以提供一个字典为不同的列设定不同的填充值

      df.fillna({1:1, 2:2})
      
    • 可以为缺失值指定填充方式method参数,比如ffill表示向前填充,bfill表示向后填充

    • 设置limit参数限制填充次数

    In [36]: df
    Out[36]:
              0         1         2
    0 -0.229682       NaN       NaN
    1  0.716649       NaN       NaN
    2 -1.362614       NaN -1.617992
    3  1.128828       NaN -0.657313
    4  1.078143  1.136835 -0.427125
    5  0.441696  0.219477  0.695700
    6 -0.501183  1.453678 -2.734985
    
    In [37]: df.fillna(0)
    Out[37]:
              0         1         2
    0 -0.229682  0.000000  0.000000
    1  0.716649  0.000000  0.000000
    2 -1.362614  0.000000 -1.617992
    3  1.128828  0.000000 -0.657313
    4  1.078143  1.136835 -0.427125
    5  0.441696  0.219477  0.695700
    6 -0.501183  1.453678 -2.734985
    
    
  3. 根据另一个对象的值来填充自己的缺失值

    • combine_first 根据传入的对象来修补调用对象的缺失值。

      In [81]: df1 = pd.DataFrame({'a': [1., np.nan, 5., np.nan],
          ...:                     'b': [np.nan, 2., np.nan, 6.],
          ...:                     'c': range(2, 18, 4)})
          ...:
      
      In [82]: df2 = pd.DataFrame({'a': [5., 4., np.nan, 3., 7.],
          ...:                     'b': [np.nan, 3., 4., 6., 8.]})
          ...:
      
      In [83]: df1
      Out[83]:
           a    b   c
      0  1.0  NaN   2
      1  NaN  2.0   6
      2  5.0  NaN  10
      3  NaN  6.0  14
      
      In [84]: df2
      Out[84]:
           a    b
      0  5.0  NaN
      1  4.0  3.0
      2  NaN  4.0
      3  3.0  6.0
      4  7.0  8.0
      
      In [85]: df1.combine_first(df2)
      Out[85]:
           a    b     c
      0  1.0  NaN   2.0
      1  4.0  2.0   6.0
      2  5.0  4.0  10.0
      3  3.0  6.0  14.0
      4  7.0  8.0   NaN
      
    • np.where(pd.isnull(a), b, a)

      • 首先去pd.isnull(a)种判断元素,如果是True,从b里拿数据,否则从a里拿,得到最终结果。

# 删除重复值

  • 使用duplicated方法判断各行是否有重复,并返回一个布尔值Series。

  • 使用drop_duplicates方法将重复行删除,留下那些不重复的。

  • 可以指定列名根据某列的数据进行去重判断和操作

    df.drop_duplicates(['k1'])
    
  • 设置keep="last"保留最后一个值,默认保留的是第一个观察到的值

In [51]: df = pd.DataFrame({'k1':['one','two']*3 + ['two'], 'k2':[1,1,2,3,3,4,4]})

In [52]: df  # 最后一行是重复的
Out[52]:
    k1  k2
0  one   1
1  two   1
2  one   2
3  two   3
4  one   3
5  two   4
6  two   4

In [53]: df.duplicated()  # 
Out[53]:
0    False
1    False
2    False
3    False
4    False
5    False
6     True
dtype: bool

In [54]: df.drop_duplicates()
Out[54]:
    k1  k2
0  one   1
1  two   1
2  one   2
3  two   3
4  one   3
5  two   4

In [55]: df # 并没有改变原数据
Out[55]:
    k1  k2
0  one   1
1  two   1
2  one   2
3  two   3
4  one   3
5  two   4
6  two   4