Извлечение оптимальных функций из рекурсивного устранения признаков (RFE)
У меня есть набор данных, состоящий из категориальных и числовых данных с 124 функциями. Чтобы уменьшить его размерность, я хочу удалить ненужные элементы. Тем не менее, чтобы запустить набор данных по алгоритму выбора объектов, я однажды горячо закодировал его с помощью get_dummies, что увеличило число объектов до 391.
In[16]:
X_train.columns
Out[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: 8
Features 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]
Если я просто LabelEncode целевого столбца, я могу использовать эту цель в качестве "у" см. Пример снова. Однако выходные данные определяют только одну особенность (целевой столбец) как оптимальную. Я думаю, что это может быть из-за одной горячей кодировки, я должен смотреть на создание плотного массива и если так, может ли он работать на RFE?
Спасибо,
Адам
2 ответа
Отвечая на мой собственный вопрос, я понял, что проблема связана с тем, как я быстро кодировал данные. Первоначально я выполнил одну горячую кодировку для всех категориальных столбцов следующим образом:
ohe_df = pd.get_dummies(df[df.columns]) # One-hot encode all columns
Это ввело большое количество дополнительных функций. Используя другой подход, с некоторой помощью отсюда я изменил кодировку, чтобы кодировать несколько столбцов для каждого столбца / функции следующим образом:
cf_df = df.select_dtypes(include=[object]) # Get categorical features
nf_df = df.select_dtypes(exclude=[object]) # Get numerical features
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) # Only showing a subset of the data
+---+---------------------------------------------------+-----------------+-----------------+-----------------------------------+---------------------------------------------------+
| | 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. Затем я подумал, что, возможно, смогу взять кусок всех новых функций и передать их в качестве цели, но это привело к ошибке. Наконец, я понял, что мне придется перебирать все целевые значения и получать максимальные результаты от каждого. В итоге код выглядел примерно так:
for num, feature in enumerate(features, start=0):
X = X_dev_train
y = X_dev_train[feature]
# Create the RFE object and compute a cross-validated score.
svc = SVC(kernel="linear")
# The "accuracy" scoring is proportional to the number of correct classifications
# step is the number of features to remove at each iteration
rfecv = RFECV(estimator=svc, step=1, cv=StratifiedKFold(kfold), scoring='accuracy')
try:
rfecv.fit(X, y)
print("Number of observations in each fold: {}".format(len(X)/kfold))
print("Optimal number of features : {}".format(rfecv.n_features_))
g_scores = rfecv.grid_scores_
indices = np.argsort(g_scores)[::-1]
print('Printing RFECV results:')
for num2, f in enumerate(range(X.shape[1]), start=0):
if g_scores[indices[f]] > 0.80:
if num2 < 10:
print("{}. Number of features: {} Grid_Score: {:0.3f}".format(f + 1, indices[f]+1, g_scores[indices[f]]))
print "\nTop features sorted by rank:"
results = sorted(zip(map(lambda x: round(x, 4), rfecv.ranking_), X.columns.values))
for num3, i in enumerate(results, start=0):
if num3 < 10:
print i
# Plot number of features VS. cross-validation scores
plt.rc("figure", figsize=(8, 5))
plt.figure()
plt.xlabel("Number of features selected")
plt.ylabel("CV score (of correct classifications)")
plt.plot(range(1, len(rfecv.grid_scores_) + 1), rfecv.grid_scores_)
plt.show()
except ValueError:
pass
Я уверен, что это может быть чище, даже может быть нанесено на один график, но это работает для меня.
Ура,
Вы можете сделать это:
`
from sklearn.feature_selection import RFE
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
rfe = RFE(model, 5)
rfe = rfe.fit(X, y)
print(rfe.support_)
print(rfe.ranking_)
f = rfe.get_support(1) #the most important features
X = df[df.columns[f]] # final features`
Затем вы можете использовать X в качестве входных данных в вашей нейронной сети или любой алгоритм