前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >sklearn.feature_selection.VarianceThreshold 方差过滤踩过的坑

sklearn.feature_selection.VarianceThreshold 方差过滤踩过的坑

作者头像
数据STUDIO
发布2021-06-24 10:07:14
7790
发布2021-06-24 10:07:14
举报
文章被收录于专栏:数据STUDIO

报错信息: Input contains NaN, infinity or a value too large for dtype('float64'). Input X must be non-negative.

输入值中包含空值,无穷值或超出dtype('float64')的范围!

输入值必须为正数。

源代码解析:

代码语言:javascript
复制
>>> X = array([[ 0.,  0.,  0., ..., nan, nan, nan],
          [ 1.,  0.,  1., ..., nan, nan, nan],
          [ 0.,  0.,  0., ...,  1.,  0.,  0.],
          ...,
          [ 0.,  0.,  0., ...,  1.,  0.,  0.],
          [ 0.,  0.,  0., ...,  1.,  0.,  1.],
          [ 0.,  0.,  0., ...,  1.,  0.,  0.]])

>>> from sklearn.feature_selection import VarianceThreshold
>>> selector = VarianceThreshold()  #实例化,不填参数默认方差为0 
>>> x_var = selector.fit_transform(X)

>>> x_fillna = pd.DataFrame(x_var).fillna(2)

>>> score = []
>>> for i in range(1400,499,-10):
...     X_chi = SelectKBest(chi2, k=i).fit_transform(x_fillna, y)
...     once = cross_val_score(RFC(n_estimators=10,random_state=0),X_chi,y,cv=5).mean()
...     score.append(once)
...     print((i,once))
>>> plt.plot(range(1400,499,-10),score)
>>> plt.show()

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

报错显示“输入值中包含空值,无穷值或超出dtype('float64')的范围!”,但明明已经填充缺失值了。

问题排查:

代码语言:javascript
复制
# 检查是否包含缺失值
>>> any(x_fillna.isnull().any())
False 

#检查是否包含无穷数据
>>> any(np.isinf(x_fillna).all())
False

all(x)x元素都不为False、''、0或者x为空,则all(x)为True,也就是说只要x元素有一个为"假",则all(x)为False。"全 ‘真’ 为True,有 ‘假’ 为False"。 any(x)x的任何元素都为False、0,'',或者x全为空,则any(x)为False,也就是说所有的x都为'假',则any(x)为False。"全‘假’为False,有‘真’为True"。

np.isfinite(x).all()x 元素是否有限,全部为True 即为没有无限值。包含无限值为False,不包含无限值为True np.isinf(x).all()x 元素是否无限,全部为True 即为都是无限值。包含有限值为False,不包含有限值为True

有网友踩过的坑:

解决方案:

若写出以下方式就会报错,因为此处只是输出x_fillna填充后的副本,原变量并未更改。

代码语言:javascript
复制
x_fillna = pd.DataFrame(x_var)
x_fillna.fillna(2)

正确写法,以下三个均可行:

代码语言:javascript
复制
x_fillna = pd.DataFrame(x_var).fillna(2)
代码语言:javascript
复制
x_fillna = pd.DataFrame(x_var)
x_fillna.fillna(-2,inplace=True)
代码语言:javascript
复制
x_fillna = pd.DataFrame(x_var)
x_fillna = x_fillna.fillna(2)

一个问题已解决,但另一个问题出现:Input X must be non-negative.

但我并没有踩这个坑,毕竟我这么聪明....

继续问题排查:

在做方差过滤时出现一个警告:

因为有输出,就没有留意...

代码语言:javascript
复制
# 方差过滤报错
>>> from sklearn.feature_selection import VarianceThreshold
>>> selector = VarianceThreshold()  #实例化,不填参数默认方差为0 
>>> x_var = selector.fit_transform(X)
C:\Users\HP\anaconda3\lib\site-packages\sklearn\feature_selection\_variance_threshold.py:77: RuntimeWarning: Degrees of freedom <= 0 for slice.
  self.variances_ = np.nanvar(X, axis=0)
C:\Users\HP\anaconda3\lib\site-packages\numpy\core\fromnumeric.py:52: RuntimeWarning: invalid value encountered in reduce
  return getattr(obj, method)(*args, **kwds)
C:\Users\HP\anaconda3\lib\site-packages\sklearn\feature_selection\_variance_threshold.py:85: RuntimeWarning: All-NaN slice encountered
  self.variances_ = np.nanmin(compare_arr, axis=0)
C:\Users\HP\anaconda3\lib\site-packages\sklearn\feature_selection\_variance_threshold.py:88: RuntimeWarning: invalid value encountered in less_equal
  (self.variances_ <= self.threshold)):
C:\Users\HP\anaconda3\lib\site-packages\sklearn\feature_selection\_variance_threshold.py:99: RuntimeWarning: invalid value encountered in greater
  return self.variances_ > self.threshold
代码语言:javascript
复制
>>> np.all(X > 0)
False

>>> np.all(X_var > 0)
False

而且

代码语言:javascript
复制
>>> np.var(X_var)
nan

报错原因:原始数据csv文件中存在negative, NaN, inf.(负数、空值或者无穷数)

解决方案:

NaN --> 缺失值填补

代码语言:javascript
复制
X.fillna(0, inplace=True)

negative --> Max-Min 归一化 (一种线性变换方法,标准化后数据完全落入[0,1]区间,能够较好的保持原有数据结构)

代码语言:javascript
复制
from sklearn import preprocessing
minmax_scaler = preprocessing.MinMaxScaler()  # 建立模型对象
data_scale = minmax_scaler.fit_transform(data)  # 标准化处理

inf. --> 当作异常值处理

异常值处理方法

方法描述

删除含有异常值的记录

直接将含有异常值的记录删除

视为缺失值

利用缺失值的方法进行处理

平均值修正

可用前后两个观测值的平均值修正该异常值

不处理

伪异常数据直接在有异常值的数据集上进行挖掘建模

另一种解决方案:

用python自带var()函数替代sklearn.feature_selection.VarianceThreshold:

代码语言:javascript
复制
x_col = X.columns[X.var() == 0]  # 提取方差为0的字段
x_var = X.loc[:,[i for i in X.columns if i not in x_col]] # 列表表达式过滤方差为0的字段
X_var = pd.DataFrame(x_var).fillna(2) # 用2填补缺失值

score = []
for i in range(1400,499,-10):
    X_chi = SelectKBest(chi2, k=i).fit_transform(x_fillna, y)
    once = cross_val_score(RFC(n_estimators=10,random_state=0),X_chi,y,cv=5).mean()
    score.append(once)
    print((i,once))
plt.plot(range(1400,499,-10),score)
plt.show()

结果是一样的,在需要知道删除了哪些变量时,运用var()sklearn更加实用

问题解决!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-11-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 数据STUDIO 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档