Tôi đang cố gắng hiểu làm thế nào tôi có thể có được tầm quan trọng tính năng của một biến phân loại đã được chia thành các biến giả. Tôi đang sử dụng scikit-learn không xử lý các biến phân loại cho bạn theo cách R hoặc h2o làm.
Nếu tôi chia một biến phân loại thành các biến giả, tôi sẽ nhận được các tính năng quan trọng riêng biệt cho mỗi lớp trong biến đó.
Câu hỏi của tôi là, nó có ý nghĩa để kết hợp lại các quan trọng biến giả đó thành một giá trị quan trọng cho một biến phân loại bằng cách đơn giản là tóm tắt chúng?
Từ trang 368 của Các yếu tố của học thống kê:
Tầm quan trọng tương đối bình phương của biến là tổng của các cải tiến bình phương như vậy đối với tất cả các nút bên trong mà nó được chọn làm biến tách
Điều này khiến tôi nghĩ rằng vì giá trị quan trọng đã được tạo bằng cách tính tổng số liệu ở mỗi nút, biến được chọn, nên tôi có thể kết hợp các giá trị quan trọng của biến giả để "phục hồi" tầm quan trọng cho biến phân loại. Tất nhiên tôi không mong đợi nó chính xác, nhưng những giá trị này thực sự là giá trị chính xác vì chúng được tìm thấy thông qua một quá trình ngẫu nhiên.
Tôi đã viết mã python sau đây (trong jupyter) như một cuộc điều tra:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import animation, rc
from sklearn.datasets import load_diabetes
from sklearn.ensemble import RandomForestClassifier
import re
#%matplotlib inline
from IPython.display import HTML
from IPython.display import set_matplotlib_formats
plt.rcParams['figure.autolayout'] = False
plt.rcParams['figure.figsize'] = 10, 6
plt.rcParams['axes.labelsize'] = 18
plt.rcParams['axes.titlesize'] = 20
plt.rcParams['font.size'] = 14
plt.rcParams['lines.linewidth'] = 2.0
plt.rcParams['lines.markersize'] = 8
plt.rcParams['legend.fontsize'] = 14
# Get some data, I could not easily find a free data set with actual categorical variables, so I just created some from continuous variables
data = load_diabetes()
df = pd.DataFrame(data.data, columns=[data.feature_names])
df = df.assign(target=pd.Series(data.target))
# Functions to plot the variable importances
def autolabel(rects, ax):
"""
Attach a text label above each bar displaying its height
"""
for rect in rects:
height = rect.get_height()
ax.text(rect.get_x() + rect.get_width()/2.,
1.05*height,
f'{round(height,3)}',
ha='center',
va='bottom')
def plot_feature_importance(X,y,dummy_prefixes=None, ax=None, feats_to_highlight=None):
# Find the feature importances by fitting a random forest
forest = RandomForestClassifier(n_estimators=100)
forest.fit(X,y)
importances_dummy = forest.feature_importances_
# If there are specified dummy variables, combing them into a single categorical
# variable by summing the importances. This code assumes the dummy variables were
# created using pandas get_dummies() method names the dummy variables as
# featurename_categoryvalue
if dummy_prefixes is None:
importances_categorical = importances_dummy
labels = X.columns
else:
dummy_idx = np.repeat(False,len(X.columns))
importances_categorical = []
labels = []
for feat in dummy_prefixes:
feat_idx = np.array([re.match(f'^{feat}_', col) is not None for col in X.columns])
importances_categorical = np.append(importances_categorical,
sum(importances_dummy[feat_idx]))
labels = np.append(labels,feat)
dummy_idx = dummy_idx | feat_idx
importances_categorical = np.concatenate((importances_dummy[~dummy_idx],
importances_categorical))
labels = np.concatenate((X.columns[~dummy_idx], labels))
importances_categorical /= max(importances_categorical)
indices = np.argsort(importances_categorical)[::-1]
# Plotting
if ax is None:
fig, ax = plt.subplots()
plt.title("Feature importances")
rects = ax.bar(range(len(importances_categorical)),
importances_categorical[indices],
tick_label=labels[indices],
align="center")
autolabel(rects, ax)
if feats_to_highlight is not None:
highlight = [feat in feats_to_highlight for feat in labels[indices]]
rects2 = ax.bar(range(len(importances_categorical)),
importances_categorical[indices]*highlight,
tick_label=labels[indices],
color='r',
align="center")
rects = [rects,rects2]
plt.xlim([-0.6, len(importances_categorical)-0.4])
ax.set_ylim((0, 1.125))
return rects
# Create importance plots leaving everything as categorical variables. I'm highlighting bmi and age as I will convert those into categorical variables later
X = df.drop('target',axis=1)
y = df['target'] > 140.5
plot_feature_importance(X,y, feats_to_highlight=['bmi', 'age'])
plt.title('Feature importance with bmi and age left as continuous variables')
#Create an animation of what happens to variable importance when I split bmi and age into n (n equals 2 - 25) different classes
# %%capture
fig, ax = plt.subplots()
def animate(i):
ax.clear()
# Split one of the continuous variables up into a categorical variable with i balanced classes
X_test = X.copy()
n_categories = i+2
X_test['bmi'] = pd.cut(X_test['bmi'],
np.percentile(X['bmi'], np.linspace(0,100,n_categories+1)),
labels=[chr(num+65) for num in range(n_categories)])
X_test['age'] = pd.cut(X_test['age'],
np.percentile(X['age'], np.linspace(0,100,n_categories+1)),
labels=[chr(num+65) for num in range(n_categories)])
X_test = pd.get_dummies(X_test, drop_first=True)
# Plot the feature importances
rects = plot_feature_importance(X_test,y,dummy_prefixes=['bmi', 'age'],ax=ax, feats_to_highlight=['bmi', 'age'])
plt.title(f'Feature importances for {n_categories} bmi and age categories')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)
return [rects,]
anim = animation.FuncAnimation(fig, animate, frames=24, interval=1000)
HTML(anim.to_html5_video())
Dưới đây là một số kết quả:
Chúng ta có thể quan sát rằng tầm quan trọng của biến chủ yếu phụ thuộc vào số lượng danh mục, điều này khiến tôi đặt câu hỏi về tiện ích của các biểu đồ này nói chung. Đặc biệt là tầm quan trọng của việc age
đạt được giá trị cao hơn nhiều so với đối tác liên tục của nó.
Và cuối cùng, một ví dụ nếu tôi để chúng là các biến giả (chỉ bmi):
# Split one of the continuous variables up into a categorical variable with i balanced classes
X_test = X.copy()
n_categories = 5
X_test['bmi'] = pd.cut(X_test['bmi'],
np.percentile(X['bmi'], np.linspace(0,100,n_categories+1)),
labels=[chr(num+65) for num in range(n_categories)])
X_test = pd.get_dummies(X_test, drop_first=True)
# Plot the feature importances
rects = plot_feature_importance(X_test,y, feats_to_highlight=['bmi_B','bmi_C','bmi_D', 'bmi_E'])
plt.title(f"Feature importances for {n_categories} bmi categories")