使用scikit-learn进行特征选择

39

我是机器学习的新手。我正在使用Scikit Learn SVM对我的数据进行分类准备。为了选择最佳特征,我使用了以下方法:

SelectKBest(chi2, k=10).fit_transform(A1, A2)

由于我的数据集包含负值,我会收到以下错误:

ValueError                                Traceback (most recent call last)

/media/5804B87404B856AA/TFM_UC3M/test2_v.py in <module>()
----> 1 
      2 
      3 
      4 
      5 

/usr/local/lib/python2.6/dist-packages/sklearn/base.pyc in fit_transform(self, X, y,     **fit_params)
    427         else:
    428             # fit method of arity 2 (supervised transformation)

--> 429             return self.fit(X, y, **fit_params).transform(X)
    430 
    431 

/usr/local/lib/python2.6/dist-packages/sklearn/feature_selection/univariate_selection.pyc in fit(self, X, y)
    300         self._check_params(X, y)
    301 
--> 302         self.scores_, self.pvalues_ = self.score_func(X, y)
    303         self.scores_ = np.asarray(self.scores_)
    304         self.pvalues_ = np.asarray(self.pvalues_)

/usr/local/lib/python2.6/dist-  packages/sklearn/feature_selection/univariate_selection.pyc in chi2(X, y)
    190     X = atleast2d_or_csr(X)
    191     if np.any((X.data if issparse(X) else X) < 0):
--> 192         raise ValueError("Input X must be non-negative.")
    193 
    194     Y = LabelBinarizer().fit_transform(y)

ValueError: Input X must be non-negative.

有人能告诉我如何转换我的数据吗?


1
你可以将值归一化到0到1之间,或者可能取绝对值。 - EdChum
4
如果你的数据不是非负的,那么卡方检验可能不是一个好的方法。你可以使用F分数。你的数据的性质是什么? - Andreas Mueller
感谢EdChum和Andreas。我的数据包括加速度信号的最小值、最大值、平均值、中位数和FFT。 - sara
2个回答

45

错误信息输入X必须为非负数已经说明了一切:Pearson卡方拟合检验不适用于负值。这是合乎逻辑的,因为卡方检验假定频率分布,而频率不能是负数。因此,sklearn.feature_selection.chi2断言输入为非负数。

您说您的特征是"加速度信号的最小值、最大值、平均值、中位数和FFT"。在许多情况下,将每个特征移动以使其全部为正数,甚至将其归一化到[0, 1]区间可能是相当安全的,正如EdChum所建议的那样。

如果由于某种原因无法进行数据转换(例如,负值是一个重要因素),则应选择另一个统计量来评分您的特征:

由于这个过程的整体目的是为了准备另一种方法的特性,因此选择任何一个人都不是什么大问题,最终结果通常相同或非常接近。


8
使用 sklearn.preprocessing.MinMaxScaler().fit_transform(YOUR_TRAINING_FEATURES_HERE),默认参数将训练特征值标准化到0到1之间。 - DonieM
“挑选任何一个都不是什么大问题”,我只是想确认我理解你的意思 - 你的意思是选择 f_classifmutual_info_classif 或者 SelectKBest 都不是什么大问题,对吗? - baxx
@DonieM 我现在正在使用它,但是我遇到了相同的错误:...scaler = MinMaxScaler() df1[self.num_features] = scaler.fit_transform(df1[self.num_features]) 返回 df1 - spacedustpi
@Maxim - 我遇到了类似的错误。但是我过滤了我的数据框,只包括具有正值的列,但我仍然遇到相同的错误。你能帮我吗?https://stackoverflow.com/questions/71338163/chi2-score-error-input-x-must-be-non-negative - The Great

0

正如其他人提到的那样,为了避免错误,您可以将数据缩放到0到1之间,从缩放后的数据中选择特征并用其来训练模型。

import numpy as np
from sklearn.feature_selection import SelectKBest, chi2
from sklearn.preprocessing import MinMaxScaler
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression

X, y = make_classification(random_state=0)
topk = 5

# scale the data to be between 0 and 1
sc = MinMaxScaler()
X_sc = sc.fit_transform(X)

# select from the scaled data
skb = SelectKBest(chi2, k=topk)
X_sc_selected = skb.fit_transform(X_sc, y)

# build model using (X_sc_selected, y)
lr = LogisticRegression(random_state=0)
lr.fit(X_sc_selected, y)

lr.score(X_sc_selected, y)  # 0.87

如果原始数据非常重要(您想保留负值),您还可以使用SelectKBest从前k个分数中选择数据,即不是对数据进行transform,而是对其进行切片。

# fit feature selector with the scaled data
skb = SelectKBest(chi2, k=topk)
skb.fit(X_sc, y)

# column index of top-k features
cols = np.sort(skb.scores_.argsort()[-topk:])
# index the top-k features from X
X_selected = X[:, cols]

# build model using (X_selected, y)
lr = LogisticRegression(random_state=0)
lr.fit(X_selected, y)

lr.score(X_selected, y)  # 0.92

请注意,skb.transform() 实际上也很像对列进行索引。例如,(X_sc[:, cols] == X_sc_selected).all() 返回 True。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接