去除含有NaN、inf等数值的样本的方法

关于删除数据集中含有NaNinf等异常值,有很多种方法,在stackoverflow的这个问题下,高票回答中使用的方法

df[~df.isin([np.nan, np.inf, -np.inf]).any(1)]

在某些情况下并不可行,原因在于所使用的isin是基于等号==进行判断数值是否相等的,而在Python中运行np.nan == np.nan时,结果为False,故而在有些数据集下无法删除含有NaN的样本(按理说应该在所有数据集下均无法删除含有NaN的样本才对,但是在某些数据集下又能够删除,比如上述stackoverflow帖子中的情况,目前还是没有完全弄懂)。
  如果一定要用类似于上述isin的方式删除含有NaN的样本,可以自己写一个NaN类(见参考链接3最后一个回答),用np.isnan()来判断两个NaN值是否相等,因为np.isnan(np.nan)返回的是True。具体方法如下:

import numpy as np

class NaN():
    def __eq__(self, v):
        return np.isnan(v)

    def __hash__(self):
        return hash(np.nan)

nan = NaN()
df[~df.isin([nan]).any(1)]

  另外,虽然np.nan == np.nan时,结果为False,但是np.inf == np.inf时,结果为True。所以可以直接用df[~df.isin([inf]).any(1)]来删除含有inf的样本,无须单独写一个类。
  如果不想像上面那样自己写一个类来删除含有NaN的样本,最简单也比较保险的做法就是在

df[~df.isin([np.nan, np.inf, -np.inf]).any(1)]

后面再加一个dropna(),即用

df[~df.isin([np.nan, np.inf, -np.inf]).any(1)].dropna()

便可同时清除含有NaNinf-inf等异常值的样本,当然isin里面的np.nan可要可不要。
  还有一种处理方式是将除NaN的其余异常值均替换成NaN,最后统一dropna()一下即可,

df.replace([np.inf, -np.inf], np.nan).dropna()

  最后,这里有一篇文章详细地介绍了Python中NoneNaN的区别,有兴趣的可以学习学习。

参考

[1] https://stackoverflow.com/questions/45745085/python-pandas-how-to-remove-nan-and-inf-values
[2] https://stackoverflow.com/questions/1565164/what-is-the-rationale-for-all-comparisons-returning-false-for-ieee754-nan-values
[3] https://stackoverflow.com/questions/31833635/pandas-checking-for-nan-not-working-using-isin

猜你喜欢

转载自www.cnblogs.com/excellent-ship/p/10304070.html