【问题标题】:How can I get treeinterpreter's Tree Contributions, if we are using a Pipeline?如果我们使用管道,我如何获得 treeinterpreter 的 Tree Contributions?
【发布时间】:2021-03-10 09:47:58
【问题描述】:

我正在使用sklearns' pipeline 函数、one hot encodemodel。几乎与this 帖子中的完全一样。

使用Pipeline 后,我无法再获得树的贡献。收到此错误:

AttributeError: 'Pipeline' 对象没有属性 'n_outputs_'

我尝试使用treeinterpreter 的参数,但我被卡住了。

因此我的问题是:当我们使用 sklearns Pipeline 时,有什么方法可以从树中获取贡献?

编辑 2 - Venkatachalam 要求的真实数据:

# Data DF to train model
df = pd.DataFrame(
  [['SGOHC', 'd',   'onetwothree',  'BAN',  488.0580347,    960 ,841,   82, 0.902497027,    841 ,0.548155625    ,0.001078211,   0.123958333 ,1],
   ['ABCDEFGHIJK',  'SOC'   ,'CON','CAN',   680.84, 1638,   0,  0,  0   ,0  ,3.011140743    ,0.007244358,   1   ,0],
   ['Hello',    'AA',   'onetwothree',  'SPEAKER',  5823.230967,    2633,   1494    ,338    ,0.773761714    ,1494,  12.70144386 ,0.005743015,   0.432586403,    8]], 
  columns=['B','C','D','E','F','G','H','I','J','K','L','M', 'N', 'target'])

# Create test and train set (useless, but for the example...) 
from sklearn.model_selection  import train_test_split

# Define X and y 
X = df.drop('target', axis=1)
y = df['target']

# Create Train and Test Sets 
X_train, X_validation, Y_train, Y_validation = train_test_split(X, y, test_size=0.20, random_state=1)


 # Make the pipeline and model 
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import OneHotEncoder
import numpy as np
import pandas as pd
from sklearn import set_config
from sklearn.model_selection import ParameterGrid
from sklearn.ensemble import RandomForestRegressor
import matplotlib.pyplot as plt

rfr = Pipeline([('preprocess',
                   ColumnTransformer([('ohe',
                                       OneHotEncoder(handle_unknown='ignore'), [1])])),
                  ('rf', RandomForestRegressor())])

rfr.fit(X_train, Y_train)


# The New, Real data that we need to predict & explain! 

new_data = pd.DataFrame(
  [['DEBTYIPL', 'de',   'onetwothreefour',  'BANAAN',   4848.0580347,   923460  ,823441,    5,  0.902497027,    43  ,0.548155625    ,0.001078211,   0.123958333 ],
   ['ABCDEFGHIJK',  'SOC'   ,'CON','CAN23', 680.84, 1638,   0,  0,  0   ,0  ,1.011140743    ,4.007244358,   1   ],
   ['Hello_NO', 'AAAAa',    'onetwothree',  'SPEAKER',  5823.230967,    123,    32  ,22 ,0.773761714    ,1678,  12.70144386 ,0.005743015,   0.432586403]], 
  columns=['B','C','D','E','F','G','H','I','J','K','L','M', 'N'])
new_data.head()

# Predicting the values 
rfr.predict(new_data)

# Now the error... the contributions: 
from treeinterpreter import treeinterpreter as ti
prediction, bias, contributions = ti.predict(rfr[-1], rfr[:-1].fit_transform(new_data))

#ValueError: Number of features of the model must match the input. Model n_features is 2 and input n_features is 3 

【问题讨论】:

    标签: python numpy scikit-learn random-forest


    【解决方案1】:

    要访问管道的拟合模型,只需从管道中检索 ._final_estimator 属性

    from treeinterpreter import treeinterpreter as ti
    prediction, bias, contributions = ti.predict(model._final_estimator, model[0].fit_transform(df))
    

    请注意,可以通过调用 sklearn util check_is_fitted 来验证估算器是否适合

    from sklearn.utils.validation import check_is_fitted
    check_is_fitted(model._final_estimator)
    

    【讨论】:

    • 谢谢@Miguel。我用上面的例子试过你的解决方案,但它会导致: ValueError: could not convert string to float: 'female'
    • 是的,df 上缺少一个热编码器,model[0].fit_transform(df) 应该可以工作
    • 感谢@Miguel!不知道为什么,但它在真实数据上也失败了(请参阅编辑 2)。有什么想法吗?
    • 考虑到rfr[:-1].fit_transform(X_train)rfr[:-1].fit_transform(df),请注意df 中有一个X_train 没有的功能,例如dfC 列中具有d, SOC, AA ,而X_train 只有SOC, AA。因此,在将数据拆分为测试时,只需确保两个集合都包含相同的类别。
    • 谢谢!因此我使用了管道功能(带有忽略参数)。能够处理“现实世界”数据(可能包含新类)。您可以找到该示例here。这导致了问题,我无法从管道模型中获得树的贡献(管道是虚拟的并对数据进行建模)。希望你能帮助我
    【解决方案2】:

    您可以通过索引管道对象model[-1] 来获得最终估算器。 同样,我们得到一个新的管道(以捕获所有转换步骤),不包括 model[:-1] 的分类器。

    因此,这就是你需要做的!

    prediction, bias, contributions = ti.predict(model[-1], model[:-1].transform(df))
    

    【讨论】:

    • 再次感谢。它适用于虚拟数据,但是如果我在我的真实数据上运行它(在 test_data 中有许多新的唯一值),我会得到下一个错误:ValueError:模型的特征数必须与输入匹配。模型 n_features 是 108,输入 n_features 是 90 是不是这样,在管道中,我们缺少跳过部分?正如您在之前的回答中提到的here
    • 不,它也应该适用于任意数量的唯一值。你能提供一些可重现的例子吗?
    • 抱歉我的回复晚了(花了很长时间来生成一个可重复的例子)。请参阅 EDIT2。非常感谢@Venkatachalam
    • 在我的解决方案中发现了错误。它必须是 .transform 而不是 fit_transform。这意味着它将重用它在训练阶段学到的类,而不是从给定的数据中学习新的类。
    • 太棒了!赏金添加。也许最后一个问题(希望您能提供帮助),在获得贡献之后,我尝试将它们放入 DF:contributions_df = pd.DataFrame(data=contributions, columns= df.columns) ,现在我在这里遇到同样的问题( df.columns 与“转换后的”df 不匹配。你知道我怎样才能得到正确形状的 df 吗?错误是:ValueError:传递值的形状是(20277、108),索引暗示(20277、14) )
    猜你喜欢
    • 2023-02-10
    • 1970-01-01
    • 2023-04-02
    • 2021-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多