我有一个包含分类和数值数据的数据集,共有124个特征。为了降低其维度,我希望删除不相关的特征。然而,为了在特征选择算法上运行数据集,我使用了get_dummies进行独热编码,这使得特征数量增加到了391个。
In[16]:X_train.columnsOut[16]:Index([u'port_7', u'port_9', u'port_13', u'port_17', u'port_19', u'port_21', ... u'os_cpes.1_2', u'os_cpes.1_1'], dtype='object', length=391)
使用生成的数据,我可以运行带有交叉验证的递归特征消除,按照Scikit Learn示例进行操作:
这会产生以下结果:
鉴于确定的最优特征数量为8,我如何识别这些特征的名称?我假设我可以将它们提取到一个新的DataFrame中,用于分类算法中?
[编辑]
我通过以下方式实现了这一点,得到了这篇文章的帮助:
def column_index(df, query_cols): cols = df.columns.values sidx = np.argsort(cols) return sidx[np.searchsorted(cols, query_cols, sorter = sidx)]feature_index = []features = []column_index(X_dev_train, X_dev_train.columns.values)for num, i in enumerate(rfecv.get_support(), start=0): if i == True: feature_index.append(str(num))for num, i in enumerate(X_dev_train.columns.values, start=0): if str(num) in feature_index: features.append(X_dev_train.columns.values[num])print("Features Selected: {}\n".format(len(feature_index)))print("Features Indexes: \n{}\n".format(feature_index))print("Feature Names: \n{}".format(features))
这会产生以下输出:
Features Selected: 8Features Indexes: ['5', '6', '20', '26', '27', '28', '67', '98']Feature Names: ['port_21', 'port_22', 'port_199', 'port_512', 'port_513', 'port_514', 'port_3306', 'port_32768']
由于独热编码引入了多重共线性,我认为目标列的选择并不理想,因为它选择的特征是未编码的连续数据特征。我尝试重新添加未编码的目标列,但RFE抛出了以下错误,因为数据是分类数据:
ValueError: could not convert string to float: Wireless Access Point
我是否需要将多个独热编码的特征列组合起来作为目标?
[编辑2]
如果我只是对目标列进行标签编码,我可以使用这个目标作为’y’,参见再次查看示例。然而,输出仅确定一个特征(目标列)为最优。我认为这可能是由于独热编码的原因,我是否应该考虑生成一个密集数组,如果是的话,它可以运行在RFE上吗?
回答:
回答我自己的问题,我发现问题出在对数据进行独热编码的方式上。最初,我对所有分类列进行了如下独热编码:
ohe_df = pd.get_dummies(df[df.columns]) # 对所有列进行独热编码
这引入了大量的额外特征。采取不同的方法,在这里得到了一些帮助,我修改了编码方式,以按列/特征为基础对多个列进行编码,如下所示:
cf_df = df.select_dtypes(include=[object]) # 获取分类特征nf_df = df.select_dtypes(exclude=[object]) # 获取数值特征ohe_df = nf_df.copy()for feature in cf_df: ohe_df[feature] = ohe_df.loc[:,(feature)].str.get_dummies().values.tolist()
生成的结果如下:
ohe_df.head(2) # 仅显示数据的一部分+---+---------------------------------------------------+-----------------+-----------------+-----------------------------------+---------------------------------------------------+| | os_name | os_family | os_type | os_vendor | os_cpes.0 |+---+---------------------------------------------------+-----------------+-----------------+-----------------------------------+---------------------------------------------------+| 0 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... | [0, 1, 0, 0, 0] | [1, 0, 0, 0, 0] | [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0] | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, ... || 1 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... | [0, 0, 0, 1, 0] | [0, 0, 0, 1, 0] | [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0] | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ... |+---+---------------------------------------------------+-----------------+-----------------+-----------------------------------+---------------------------------------------------+
不幸的是,尽管这是我一直在寻找的,但它无法在RFECV上执行。接下来我想或许我可以取所有新特征的一个切片并将其作为目标传递,但这导致了错误。最后,我意识到我必须遍历所有目标值并从每个目标值中提取最佳输出。代码最终看起来像这样: