在 Scikit 特征选择之后保留特征名称

Posted

技术标签:

【中文标题】在 Scikit 特征选择之后保留特征名称【英文标题】:Retain feature names after Scikit Feature Selection 【发布时间】:2017-02-10 07:02:01 【问题描述】:

在对一组数据运行 Scikit-Learn 的方差阈值后,它会删除几个特征。我觉得我在做一些简单而愚蠢的事情,但我想保留其余功能的名称。以下代码:

def VarianceThreshold_selector(data):
    selector = VarianceThreshold(.5) 
    selector.fit(data)
    selector = (pd.DataFrame(selector.transform(data)))
    return selector
x = VarianceThreshold_selector(data)
print(x)

更改以下数据(这只是行的一小部分):

Survived    Pclass  Sex Age SibSp   Parch   Nonsense
0             3      1  22   1        0        0
1             1      2  38   1        0        0
1             3      2  26   0        0        0

进入这个(同样只是行的一小部分)

     0         1      2     3
0    3      22.0      1     0
1    1      38.0      1     0
2    3      26.0      0     0

使用 get_support 方法,我知道它们是 Pclass、Age、Sibsp 和 Parch,所以我宁愿返回类似的东西:

     Pclass         Age      Sibsp     Parch
0        3          22.0         1         0
1        1          38.0         1         0
2        3          26.0         0         0

有没有简单的方法来做到这一点?我对 Scikit Learn 很陌生,所以我可能只是在做一些愚蠢的事情。

【问题讨论】:

Scikit 本身不支持带有命名列等的pandas 数据类型,所以任何时候你使用类似scikit 对象的.transform 方法,你将失去所有该信息。如果您可以单独跟踪它(即,按照您的描述检索列名),您可以在重新创建新的 DataFrame 后将其传回以指定新的列名。 【参考方案1】:

可能有更好的方法可以做到这一点,但对于那些感兴趣的人来说,我就是这样做的:

def VarianceThreshold_selector(data):

    #Select Model
    selector = VarianceThreshold(0) #Defaults to 0.0, e.g. only remove features with the same value in all samples

    #Fit the Model
    selector.fit(data)
    features = selector.get_support(indices = True) #returns an array of integers corresponding to nonremoved features
    features = [column for column in data[features]] #Array of all nonremoved features' names

    #Format and Return
    selector = pd.DataFrame(selector.transform(data))
    selector.columns = features
    return selector

【讨论】:

除了变换与使用 fit_transform 之外,我们的想法基本相同。很高兴你明白了。 我是 Python 菜鸟,但features = data.columns.values[selector.get_support(indices = True)] 也是正确的吗?我无法让你的方法处理我的数据。【参考方案2】:

这样的东西会有帮助吗?如果您向它传递一个 pandas 数据框,它将获取列并使用 get_support 就像您提到的那样通过其索引遍历列列表以仅提取满足方差阈值的列标题。

>>> df
   Survived  Pclass  Sex  Age  SibSp  Parch  Nonsense
0         0       3    1   22      1      0         0
1         1       1    2   38      1      0         0
2         1       3    2   26      0      0         0

>>> from sklearn.feature_selection import VarianceThreshold
>>> def variance_threshold_selector(data, threshold=0.5):
    selector = VarianceThreshold(threshold)
    selector.fit(data)
    return data[data.columns[selector.get_support(indices=True)]]

>>> variance_threshold_selector(df, 0.5)
   Pclass  Age
0       3   22
1       1   38
2       3   26
>>> variance_threshold_selector(df, 0.9)
   Age
0   22
1   38
2   26
>>> variance_threshold_selector(df, 0.1)
   Survived  Pclass  Sex  Age  SibSp
0         0       3    1   22      1
1         1       1    2   38      1
2         1       3    2   26      0

【讨论】:

你能编辑你的答案吗? selector.get_support(indices=True) 返回一个索引数组。因此,这一行: labels = [columns[x] for x in selector.get_support(indices=True) if x] 有一个潜在的错误,其中第 0 列将被跳过 看起来正确! columns 变量不再使用,但无关【参考方案3】:

我来这里是为了寻找让transform()fit_transform() 返回数据框的方法,但我怀疑它不受支持。

但是,您可以像这样更清晰地对数据进行子集化:

data_transformed = data.loc[:, selector.get_support()]

【讨论】:

这应该是更高层、优雅和简单的问题解决方案。【参考方案4】:

由于我对 Jarad 的功能有一些问题,我将它与 pteehan 的解决方案混合在一起,我发现它更可靠。我还添加了 NA 替换作为标准,因为 VarianceThreshold 不喜欢 NA 值。

def variance_threshold_select(df, thresh=0.0, na_replacement=-999):
    df1 = df.copy(deep=True) # Make a deep copy of the dataframe
    selector = VarianceThreshold(thresh)
    selector.fit(df1.fillna(na_replacement)) # Fill NA values as VarianceThreshold cannot deal with those
    df2 = df.loc[:,selector.get_support(indices=False)] # Get new dataframe with columns deleted that have NA values

    return df2

【讨论】:

【参考方案5】:

您也可以使用 Pandas 进行阈值处理

data_new = data.loc[:, data.std(axis=0) > 0.75]

【讨论】:

【参考方案6】:

这个代码怎么样?

columns = [col for col in df.columns]

low_var_cols = []

for col in train_file.columns:
if statistics.variance(df[col]) <= 0.1:
    low_var_cols.append(col)

然后从数据框中删除列?

【讨论】:

以上是关于在 Scikit 特征选择之后保留特征名称的主要内容,如果未能解决你的问题,请参考以下文章

scikit-learn:4.2. Feature extraction(特征提取,不是特征选择)

scikit 中的特征选择学习多个变量和数千个特征

Scikit-learn RandomForestClassifier() 特征选择,只选择训练集?

结合Scikit-learn介绍几种常用的特征选择方法

Scikit-Learn RFECV 仅基于网格分数的特征数量

如何使用热门词创建特征向量(scikit-learn 中的特征选择)