我使用sklearn和有一个问题的亲和传播。我已经建立了一个输入矩阵,我一直得到以下错误。

ValueError: Input contains NaN, infinity or a value too large for dtype('float64').

我已经跑了

np.isnan(mat.any()) #and gets False
np.isfinite(mat.all()) #and gets True

我试着用

mat[np.isfinite(mat) == True] = 0

去除掉无限值,但这也没用。 我要怎么做才能去掉矩阵中的无穷大值,这样我就可以使用亲和传播算法了?

我使用anaconda和python 2.7.9。


当前回答

泡芙! !在我的情况下,问题是关于NaN值…

您可以使用此函数列出具有NaN的列

your_data.isnull().sum()

然后你可以在数据集文件中填充这些NAN值。

下面是如何“将NaN替换为零,将无穷大替换为大的有限数”的代码。

your_data[:] = np.nan_to_num(your_data)

从numpy.nan_to_num

其他回答

移除所有无限值:

(并替换为该列的min或Max)

import numpy as np

# generate example matrix
matrix = np.random.rand(5,5)
matrix[0,:] = np.inf
matrix[2,:] = -np.inf
>>> matrix
array([[       inf,        inf,        inf,        inf,        inf],
       [0.87362809, 0.28321499, 0.7427659 , 0.37570528, 0.35783064],
       [      -inf,       -inf,       -inf,       -inf,       -inf],
       [0.72877665, 0.06580068, 0.95222639, 0.00833664, 0.68779902],
       [0.90272002, 0.37357483, 0.92952479, 0.072105  , 0.20837798]])

# find min and max values for each column, ignoring nan, -inf, and inf
mins = [np.nanmin(matrix[:, i][matrix[:, i] != -np.inf]) for i in range(matrix.shape[1])]
maxs = [np.nanmax(matrix[:, i][matrix[:, i] != np.inf]) for i in range(matrix.shape[1])]

# go through matrix one column at a time and replace  + and -infinity 
# with the max or min for that column
for i in range(matrix.shape[1]):
    matrix[:, i][matrix[:, i] == -np.inf] = mins[i]
    matrix[:, i][matrix[:, i] == np.inf] = maxs[i]

>>> matrix
array([[0.90272002, 0.37357483, 0.95222639, 0.37570528, 0.68779902],
       [0.87362809, 0.28321499, 0.7427659 , 0.37570528, 0.35783064],
       [0.72877665, 0.06580068, 0.7427659 , 0.00833664, 0.20837798],
       [0.72877665, 0.06580068, 0.95222639, 0.00833664, 0.68779902],
       [0.90272002, 0.37357483, 0.92952479, 0.072105  , 0.20837798]])

在python 3的这个版本中:

/opt/anaconda3/bin/python --version
Python 3.6.0 :: Anaconda 4.3.0 (64-bit)

查看错误的详细信息,我发现导致失败的代码行:

/opt/anaconda3/lib/python3.6/site-packages/sklearn/utils/validation.py in _assert_all_finite(X)
     56             and not np.isfinite(X).all()):
     57         raise ValueError("Input contains NaN, infinity"
---> 58                          " or a value too large for %r." % X.dtype)
     59 
     60 

ValueError: Input contains NaN, infinity or a value too large for dtype('float64').

由此,我能够提取正确的方法来测试我的数据所发生的事情,使用由错误消息给出的失败的相同测试:

然后,通过一个快速而肮脏的循环,我能够发现我的数据确实包含nan:

print(p[:,0].shape)
index = 0
for i in p[:,0]:
    if not np.isfinite(i):
        print(index, i)
    index +=1

(367340,)
4454 nan
6940 nan
10868 nan
12753 nan
14855 nan
15678 nan
24954 nan
30251 nan
31108 nan
51455 nan
59055 nan
...

现在我要做的就是去掉这些下标处的值。

这是它失败的检查:

https://github.com/scikit-learn/scikit-learn/blob/0.17.X/sklearn/utils/validation.py#L51

def _assert_all_finite(X):
    """Like assert_all_finite, but only for ndarray."""
    X = np.asanyarray(X)
    # First try an O(n) time, O(1) space solution for the common case that
    # everything is finite; fall back to O(n) space np.isfinite to prevent
    # false positives from overflow in sum method.
    if (X.dtype.char in np.typecodes['AllFloat'] and not np.isfinite(X.sum())
            and not np.isfinite(X).all()):
        raise ValueError("Input contains NaN, infinity"
                         " or a value too large for %r." % X.dtype)

所以确保你的输入中有非NaN值。所有这些值实际上都是浮点值。这些值也不应该是Inf。

注意:此解决方案仅适用于有意在数据集中保留NaN条目的情况。

这个错误发生在我使用一些scikit-learn功能时(在我的情况下:GridSearchCV)。在底层,我使用了一个xgboost XGBClassifier,它可以优雅地处理NaN数据。然而,GridSearchCV使用sklearn.utils.validation模块,通过调用_assert_all_finite函数强制缺少输入数据中的缺失数据。这最终导致了一个错误:

ValueError: Input contains NaN, infinity or a value too large for dtype('float64')

旁注:_assert_all_finite接受allow_nan参数,如果设置为True,则不会引起问题。但是,scikit-learn API不允许我们控制这个参数。

解决方案

我的解决方案是使用patch模块静默_assert_all_finite函数,这样它就不会引发ValueError。下面是一个片段

import sklearn
with mock.patch("sklearn.utils.validation._assert_all_finite"):
    # your code that raises ValueError

这将用一个虚拟模拟函数替换_assert_all_finite,因此它不会被执行。

请注意,补丁不是一个推荐的做法,可能会导致不可预知的行为!


编辑: 这个Pull Request应该可以解决这个问题(尽管截至2022年1月修复程序还没有发布)

在我的例子中,算法要求数据在(0,1)之间不包含。我非常残酷的解决方案是在所有期望值中添加一个小随机数:

y_train = pd.DataFrame(y_train).applymap(lambda x: x + np.random.rand()/100000.0)["col_name"]
y_train[y_train >= 1] = 0.999999

而y_train在[0,1]的范围内。

这当然不适合所有的情况,因为你会弄乱你的输入数据,但如果你有稀疏的数据,只需要一个快速的预测,这是一个解决方案