实用机器学习-随机森林如何作科研分析及讨论 EDA

“当模型建立后,如何解释和分析模型,往往是科研中必不可很少的一部分。机器学习模型往往被成为黑箱子,如何在传统领域的分析方法上进行一定解释,是我们学者们要进一步探索的课题。我们在这里列举了不同的 EDA 方式,希望能够帮助模型解释,以及 EDA 分析的进一步建立。“

在随机森林模型建立之后,我们的模型可以被用于更高级的模型分析,当然这个都是在信任模型的基础上,如同科学实验中,我们通过线性回归得到一些特征关系,之后可以用来讨论对这些关系的认知以及对其他现象的理解,我们同样也能够从随机森林 RF 里面得到一些洞察,用以了解我们的数据库关系。

1. One-hot coding 还是 categorical coding

One-hot coding


上述就是 one hot coding 的示意图,每个子集都会单独的成立一列,用 1/0 来表示是不是属于这个列,实际操作的时候,你会发现这个部分就是把原先的列删掉之后,增加了跟 categories 数量一样多的列数。

def transfer_dummies(df, max_dummies=6)

    ''' Function to transfer dataframe df into dummies, where category number is less than max_dummies.

    Input: df - dataframe, max_dummies - integer

    Output: dataframe after transformation

    '''

    cols = df.select_dtypes(include='category')

    change_col = []

    for col in cols:

        if len(df[col].cat.categories) <= max_dummies: change_col.append(col)

    return pd.get_dummies(df, columns=change_col)

Categorized Coding

同样的通过 A、B、C、D、E 的一列,如果我们实用 categorized coding 的方法,就是在统一列上通过数字的顺序的方式来给予数字编号。这样就是实用数字编码的一列来替换原始的 str 列。

---

通过上述的示例,我们可以看到 one-hot coding 会对每一个类别增加一行,因此在最终分析 feature importance 的时候,每个 feature group 的重要性都会被计算。

最终得到的结果会是所有的 category 都提供其 feature importance。

2. Feature Importance 陷阱

我们在做 feature importance 的时候,其实是把每个 feature 去掉之后,计算最终 score 降低了多少来看这个 feature 的影响有多大。但是这里其实只是计算了单个的 feature 的影响。

如果其中两个 features 其实是相关的,去掉一个之后,另一个依然能够帮助整个模型获得比较好的 score。因此这个 fearure importance 在这个状况下就不是十分准确的提供了单个 feature 的贡献。我们在 feature 之间关系的时候,依然可以继续使用传统统计学的方式来计算各种 feature 之间的相关性,作为 feature 特征的分析结果,而不是仅仅通过 feature importance 来判断各个特征的贡献情况。

3. Feature 相似性 - cluster

当我们认为这个 模型可靠之后,我们会希望来解译模型里面的 insights。因此,我们可以通过计算feature cluster 的方式来查阅其距离,在这里我们使用 hierarchy 结构,但是你要记得你的模型可能是经过 fillna 的,这个部分是否会影响模型特征相似性的分析,需要单独个案的讨论,当然也是会被 reviewer challenge 的地方。

def rf_feat_importance(m, df):

    return pd.DataFrame({'cols':df.columns, 'imp':m.feature_importances_} ).sort_values('imp', ascending=False)


fi = rf_feat_importance(model, x_train); fi[:10]

上面这个是针对模型的 feature importance 获取,随后我们取出其中一部分,因为如果选择所有的 feature,会形成过于稀疏的矩阵而无法计算距离。

to_keep = fi[fi.imp>0.005].cols; len(to_keep)

x_keep = x_train[to_keep].copy()

---

import scipy

from scipy.cluster import hierarchy as hc

import matplotlib.pyplot as plt

corr = np.round(scipy.stats.spearmanr(x_keep).correlation, 4)

corr_condensed = hc.distance.squareform(1-corr)

z = hc.linkage(corr_condensed, method='average')

fig = plt.figure(figsize=(16,10))

dendrogram = hc.dendrogram(z, labels=x_keep.columns, orientation='left', leaf_font_size=16)

plt.show()


这里就能刻画出哪些模型 feature 关系比较接近,距离比较相似。

同时要注意的是,我们这里的距离计算公式是 rank distance,就是说根据顺序来看,他们之间的距离是什么样的,而不是绝对距离。

那么,我们就可以进一步测试,把相同的 feature 去掉,是不是会影响这个 model 的 train 精度。

4. Partial Dependence 部分依赖

在这里我们可以使用一个 库 来专门作这个部分的显示和分析。

from pdpbox import pdp

from plotnine import *

def get_sample(df,n):

    idxs = sorted(np.random.permutation(len(df))[:n])

    return df.iloc[idxs].copy()


x_all = get_sample(df_cat[df_cat.YearMade>1930], 500)

ggplot(x_all, aes('YearMade', 'SalePrice'))+stat_smooth(se=True, method='loess')


这是 ggplot 通过真实数据的拟合效果,类似一个 polyfit 的效果,但是要知道我们的模型已经经过训练,我需要了解当模型构建完之后,模型看到的 YearMade 和 SalePrice 之间有什么关系,我们可以直接让模型来帮我们作出判断。

这里所要作的就是利用模型来做融合数据,我们假设500 个点,每个点都在每一年(也就是每个YearMade)的SalePrice都能通过模型来计算,那么他们的趋势会是什么样的。

def plot_pdp(feat, m, x, clusters=None, feat_name=None):

    feat_name = feat_name or feat

    p = pdp.pdp_isolate(m, x, feat)

    return pdp.pdp_plot(p, feat_name, plot_lines=True, cluster=clusters is not None, n_cluster_centers=clusters)


x = get_sample(x_train[x_train.YearMade>1930], 500)

plot_pdp('YearMade', model, x)


可以看到,通过模型的估算,我们的 saleprice 与 yearmade 之间有了一个比较平滑递增关系,这是通过大量的及其学习获得的关系,而不是 500 个数据点的 polyfit 拟合。同样,我们可以对 500 个数据点进行 cluster 来分析一下不同的递增关系。

plot_pdp('YearMade', model, x, clusters=5)


这里可以看出我们的产品增长会大致分为 5 种不同的方式,自动帮助我们聚合分类,给出 yearmade 和 price 之间的关系。

你可能感兴趣的:(实用机器学习-随机森林如何作科研分析及讨论 EDA)