使用scikit-learn进行特征选择

40 投票
2 回答
54265 浏览
提问于 2025-04-21 03:24

我刚接触机器学习,正在用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.

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

2 个回答

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来选择数据,也就是说,不是对数据进行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。

45

错误信息 Input X must be non-negative 说明了一切:皮尔逊卡方检验 不适用于负值。这是有道理的,因为卡方检验是基于频率分布的,而频率不可能是负数。因此,sklearn.feature_selection.chi2 要求输入必须是非负的。

你提到你的特征是“加速度计信号的最小值、最大值、平均值、中位数和快速傅里叶变换(FFT)”。在很多情况下,可以安全地将每个特征进行平移,使它们都变成正数,或者像EdChum建议的那样,归一化到 [0, 1] 的区间。

如果因为某种原因无法进行数据转换(例如,负值是一个重要因素),你应该选择其他统计方法来评估你的特征:

因为这个过程的主要目的是为其他方法准备特征,所以选择哪种方法并不重要,最终结果通常是相似的或非常接近的。

撰写回答