虚拟变量的功能重要性


17

我试图了解如何获得已分解为虚拟变量的分类变量的功能重要性。我正在使用scikit-learn,它不像R或h2o那样为您处理分类变量。

如果将分类变量分解为虚拟变量,则该变量中每个类的功能重要性都不同。

我的问题是,将这些虚拟变量的重要性通过简单地求和重新组合为分类变量的重要性值是否有意义?

从《统计学习的要素》第368页开始:

变量的平方相对重要性X是在所有的内部节点,例如平方改进它为之选择作为分割变量的总和

这使我认为,由于重要性值已经通过在每个节点上选择一个变量的总和来创建,因此我应该能够组合虚拟变量的变量重要性值以“恢复”分类变量的重要性。当然,我不希望它是完全正确的,但是无论如何这些值实际上都是准确的值,因为它们是通过随机过程找到的。

我已经编写了以下python代码(以jupyter格式)作为调查:

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())

以下是一些结果:

在此处输入图片说明

在此处输入图片说明

我们可以观察到,变量的重要性主要取决于类别的数量,这使我对这些图表的实用性产生了普遍的质疑。尤其是age 要获得比连续不断更高的价值更高的价值。

最后,是一个示例,如果我将其保留为伪变量(仅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")

在此处输入图片说明

Answers:


8

通常,在处理“功能重要性”时,请记住,在大多数情况下,正规化方法通常是一个不错的选择。它将针对即将出现的问题自动“选择最重要的功能”。现在,如果我们不想遵循正则化的概念(通常在回归的上下文中),则随机森林分类器和置换检验的概念自然会为解决一组变量的重要性提供解决方案。实际上,在此之前已经有人问过:“ 几年前,在R的随机森林分类中,一组预测变量的相对重要性 ”。更严格的方法,例如Gregorutti等人的方法:“将变量重要性与随机森林分组并应用于多元功能数据分析“。Chakraborty&Pal's 在Connectionist框架中选择有用的功能组在多层感知器的上下文中研究了这一任务。回到Gregorutti等人的论文,他们的方法可直接应用于任何种类的分类/回归算法简而言之,我们在训练期间使用的每个自购样本中使用随机排列的版本。

综上所述,虽然置换测试最终是一种启发式方法,但过去已准确解决的问题是在正则回归的情况下对虚拟变量进行惩罚。该问题的答案是Group-LASSOGroup-LARSGroup-Garotte。这项工作的开创性论文是Yuan和Lin的:“ 具有分组变量的回归中的模型选择和估计 ”(2006年)和Meier等人的:“ 用于逻辑回归的组套索 ”(2008年)。这种方法使我们能够在以下情况下工作:“ 每个因素可能有多个层次,并且可以通过一组虚拟变量来表示 ”(Y&L 2006)。效果是“1个ķĴĴ={1个Ĵ}Ĵpyglmnet分组套索正则化。]

总而言之,简单地从单个虚拟变量中“累加”变量的重要性是没有意义的,因为这将无法捕获它们之间的关联并导致潜在的无意义的结果。就是说,组惩罚方法和置换变量重要性方法都给出了一个连贯的(特别是在置换重要性程序的情况下)这样做的框架。

最后要说清楚不要对连续数据进行分箱。这是不好的做法,在这里(和这里)有一个很好的解决方案。我们在连续变量离散化后观察到虚假结果,这一事实age不足为奇。弗兰克•哈雷尔(Frank Harrell)还对连续变量的分类问题进行了广泛的写作。


您链接R中的随机森林分类中的一组预测变量的相对重要性直接回答了这个问题。如果您将对该链接的引用移到开头,我会很乐意接受,因为我认为其余链接并不直接相关,并且该链接很容易在答案中迷失。

没问题。我做了一些相关的编辑。正如我在本文中提到的,不要忽略正则回归的概念,正则化方法为特征重要性/排名提供了一种完全有效的替代方法。
usεr11852恢复单胞菌说,

正则回归不是此问题的答案,它可能会回答一个不同的问题,即要素重要性的替代方法,但该问题是关于将要素聚合为要素重要性图中的单个分类要素。我真的认为您应该将实际回答问题的链接从头开始。

2

问题是:

通过简单地将虚拟变量的重要性求和重新组合为分类变量的重要性值是否有意义?

简短的答案:

一世pØ[RŤ一种ñCËX=一世
一世2=Ť=1个Ĵ-1个一世2一世vŤ=
一世=Ť=1个Ĵ-1个一世2一世vŤ=

更长,更实际的答案。

您不能简单地将虚拟变量的各个变量重要性值相加,因为您可能会冒险

重要变量与其他人之间的高度关联。(第368页)

诸如可能的多重共线性之类的问题可能会使变量的重要性值和排名失真。

理解多重共线性等问题如何影响变量的重要性实际上是一个非常有趣的问题。该文件确定预测变量重要性多元回归变下相关性和分配细则讨论计算变量重要性的各种方法和比较了数据违反典型的统计假设的性能。作者发现

尽管多重共线性确实影响了相对重要性方法的性能,但多元非正态性却没有。(WHITTAKER p366)


我认为您的第二个报价不重要。这些不是高度相关的变量,它们是相同的变量,决策树的良好实现不需要OHE,但可以将它们视为单个变量。如果有的话,多共线性是由OHE人为引入的。

关于您的第一点,这就像布雷曼提出的相对重要性数是平方值一样,这让我很伤心。因此,我不相信sklearn像您建议的那样首先扎根。另外,如果有,我是否不应该先对值进行平方,将它们相加,然后对和求平方根?我不确定我是否理解您的建议先扎根。

@ecedavis你的教科书是什么意思?您能提供一个链接或更完整的引用吗?
参阅

嗨,谢谢您的批评和作为我的新成员的第一次赞美。您的评论指出了我将在修订本中解决的特定细节,但是我是否也对我的回答的总体质量有意见?这是我的第一篇文章,我打算成为一名常规撰稿人。至少,我希望我的回答总体上有帮助并且样式良好。你怎么看?
ecedavis

您的回答风格很好,但是某些信息和内容似乎并不完全正确。您链接的文章是关于多元回归中预测变量的重要性,而问题是关于随机森林中的重要性。我还发现您对引号的提取是有问题的,因为完整的句子是“而且,由于缩水(见10.12.1节),与重要变量高度相关的其他人对重要变量的掩盖也不再是问题”。这有非常不同的含义。
see24
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.