Package: scorecardpipeline
评分卡pipeline建模包scorecardpipeline封装了toad、scorecardpy、optbinning等评分卡建模相关组件，API风格与sklearn高度一致，支持pipeline式端到端评分卡建模、模型报告输出、导出PMML文件、超参数搜索等教程：https://itlubber.art/upload/scorecardpipeline.htmlpipy包：https://pypi.org/project/scorecardpipeline/仓库地址：https://github.com/itlubber/scorecardpipeline博文地址：https://itlubber.art/archives/itlubber-scorecard-end2end微信公共号推文：https://mp.weixin.qq.com/s/eCTp4h0fau77xOgf_V28wQ交流微信微信公众号itlubberitlubber_art引言作为一名金融搬砖工作者，评分卡建模怎么也算是基操。本文主要对笔者日常使用的评分卡建模代码进行讲解，说明如何一步步从原始数据到最终评分卡模型以及如何解读产出的模型报告文档。本文所有代码已全部提交至笔者GITHUB公开仓库，各位看官按需取用，用完记得顺带给个star以鼓励笔者继续开源相关工作。本文使用笔者对toad、scorecardpy、optbinning等库进行二次封装后的代码进行实操，文中会对仓库中的部分代码细节进行说明。本文旨在对仓库评分卡建模流程进行说明，并提供一个可以直接运行的完整示例，让更多金融从业小伙伴掌握整套评分卡模型构建方法。项目说明仓库地址https://github.com/itlubber/scorecardpipeline代码结构该仓库下代码主要用于提供评分卡建模相关的组件，项目结构如下：>> tree
.
├── LICENSE                         # 开源协议
├── README.md                       # 相关说明文档
├── requirements.txt                # 相关依赖包
└── setup.py                        # 打包文件
├── examples                        # 演示样例
│   └── scorecard_samples.ipynb
└── scorecardpipeline               # scorecardpipeline 包文件
    ├── excel_writer.py             # 操作 excel 的公共方法
    ├── template.xlsx               # excel 模版文件
    ├── matplot_chinese.ttf         # 中文字体
    ├── processing.py               # 数据处理相关代码
    ├── model.py                    # 模型相关代码
    └── utils.py                    # 公用方法简要说明processing中提供了数据前处理相关的方法：特征筛选方法（FeatureSelection、StepwiseSelection）、变量分箱方法（Combiner）、变量证据权重转换方法（WOETransformer），方法继承sklearn.base中的BaseEstimator和TransformerMixin，能够支持构建pipeline和超参数搜索model中提供了基于sklearn.linear_model.LogisticRegression实现的ITLubberLogisticRegression，同时重写了toad.ScoreCard，以支持模型相关内容的输出excel_writer中提供了操作excel的一系列公共方法，包含设置条件格式、设置列宽、设置数字格式、插入指定样式的内容（insert_value2sheet）、插入图片数据（insert_pic2sheet）、插入dataframe数据内容（insert_df2sheet）、保存excel文件（save）等方法scorecardpipeline安装pipy安装>>pipinstallscorecardpipeline-ihttps://pypi.Python.org/simple/

Lookinginindexes:https://pypi.Python.org/simple/
CollectingscorecardpipelineDownloadingscorecardpipeline-0.1.5-py3-none-any.whl(36kB)......
Installingcollectedpackages:sklearn-pandas,scorecardpy,sklearn2pmml,scorecardpipeline
Successfullyinstalledscorecardpipeline-0.1.5scorecardpy-0.1.9.2sklearn-pandas-2.2.0sklearn2pmml-0.92.2源码编译pythonsetup.pysdistbdist_wheel
pipinstalldist/scorecardpipeline-0.1.11-py3-none-any.whl# twine upload dist/*特别说明评分卡转PMML目前部分依赖java，如果需要解锁这部分功能，需要先安装jdk环境，推荐jdk 1.8 +评分卡建模数据准备笔者仓库下几乎所有评分卡相关项目默认使用scorecardpy库中提供的germancredit数据集进行示例，数据集中包含类别型变量、数值型变量、样本好坏标签，共1000条数据，数据集中不包含缺失值，在部分示例中会随机替换数据集中的内容为缺失值，模拟实际生产中的真实数据。target="creditability"data=sc.germancredit()data[target]=data[target].map({"good":0,"bad":1})数据集拆分通常建模过程中会将数据集拆分成训练数据集和测试数据集集，训练数据集用于模型参数的训练，测试数据集用于评估模型好坏，且在整个建模过程中实际上只能使用一次（任何针对测试数据集调模型的，都存在模型过拟合的情况，除非你的数据不包含任何噪声数据）。而为了弥补测试数据集只能用一次用于评估模型好坏的尴尬，大多都会再拆分一个验证数据集，用于模型训练过程中判别模型是否向好的方向进行优化。在金融建模场景中，上述三个数据集通常被称为训练数据集、测试数据集（即上述三个数据集中的验证集）、跨时间验证集（即上述三个数据集中的测试集）。同时，在金融场景中，跨时间验证集的拆分方式通常使用类似时间序列数据集的拆分方法，按照时间将数据集拆分为建模集（包含训练集和测试集）、跨时间验证集（Out of Time，OOT），以保证模型在不同时间段内的泛化能力。本文为了简单起见，只拆分了训练集、测试集，OOT直接拷贝训练集来演示评分卡建模完整过程。数据集拆分示例train,test=train_test_split(data,test_size=0.3,shuffle=True,stratify=data[target])oot=data.copy()特征粗筛（可选）通常当数据特征数量较多时，针对每个特征做分箱太耗时间的情况下，可以在分箱之前针对数据集进行一次简单的特征筛选工作。剔除数据集中空值或唯一值占比较高、变量之间相关性过高、变量IV值（Information Value）过低的特征。方法简介classFeatureSelection(TransformerMixin,BaseEstimator):def__init__(self,target="target",empty=0.95,iv=0.02,corr=0.7,exclude=None,return_drop=True,identical=0.95,remove=None,engine="scorecardpy",target_rm=False):"""ITLUBBER提供的特征筛选方法Args:target: 数据集中标签名称，默认 targetempty: 空值率，默认 0.95, 即空值占比超过 95% 的特征会被剔除iv: IV值，默认 0.02，即iv值小于 0.02 时特征会被剔除corr: 相关性，默认 0.7，即特征之间相关性大于 0.7 时会剔除iv较小的特征identical: 唯一值占比，默认 0.95，即当特征的某个值占比超过 95% 时，特征会被剔除engine: 特征筛选使用的引擎，可选 "toad", "scorecardpy" 两种，默认 scorecardpyremove: 引擎使用 scorecardpy 时，可以传入需要强制删除的变量return_drop: 是否返回删除信息，默认 True，即默认返回删除特征信息target_rm: 是否剔除标签，默认 False，即不剔除exclude: 是否需要强制保留某些特征"""使用方法# 常规使用方法selection=FeatureSelection(target=target,engine="toad",return_drop=True,corr=0.9,iv=0.01)train=selection.fit_transform(train)# pipeline 使用方法feature_pipeline=Pipeline([("preprocessing_select",FeatureSelection(target=target,engine="scorecardpy")),......])feature_pipeline.fit(train)特征分箱在评分卡建模过程中，为了保证模型效果的稳定性，需要对变量进行一定的前处理。对于数值型变量，常规的处理是使用等频分箱、等距分箱、决策树分箱、卡方分箱、最优KS分箱等方式对数值型变量进行离散化处理，以保证特征稳定的同时，能够从业务上有一定的逻辑依据和解释性。对数值型变量进行分箱还可以减少异常值对模型的影响，降低模型复杂度。对于类别型变量，很多类别的客群属性比较相似，客户违约概率相近，将这些客群合并能够增加变量稳定性、降低模型的复杂程度和增强特征可解释性。为了对上述两类特征进行分箱，笔者将toad和optbinning两个库的分箱功能结合，合并进了processing.Combiner，能够支持变量单调分箱、“U”型分箱以及optbinning支持的所有形式的最优特征分箱方案，同时保留缺失值单独一箱，保证了评分卡模型后期上线后缺失值不知道如何填充的尴尬。方法简介classCombiner(TransformerMixin,BaseEstimator):def__init__(self,target="target",method='chi',engine="toad",empty_separate=False,min_samples=0.05,min_n_bins=2,max_n_bins=3,max_n_prebins=10,min_prebin_size=0.02,min_bin_size=0.05,max_bin_size=None,gamma=0.01,monotonic_trend="auto_asc_desc",rules={},n_jobs=1):"""特征分箱封装方法Args:target: 数据集中标签名称，默认 targetmethod: 特征分箱方法，可选 "chi", "dt", "quantile", "step", "kmeans", "cart", "mdlp", "uniform", 参考 toad.Combiner & optbinning.OptimalBinningengine: 分箱引擎，可选 "optbinning", "toad"empty_separate: 是否空值单独一箱, 默认 False，推荐设置为 Truemin_samples: 最小叶子结点样本占比，参考对应文档进行设置，默认 5%min_n_bins: 最小分箱数，默认 2，即最小拆分2箱max_n_bins: 最大分像素，默认 3，即最大拆分3箱，推荐设置 3 ～ 5，不宜过多，偶尔使用 optbinning 时不起效max_n_prebins: 使用 optbinning 时预分箱数量min_prebin_size: 使用 optbinning 时预分箱叶子结点（或者每箱）样本占比，默认 2%min_bin_size: 使用 optbinning 正式分箱叶子结点（或者每箱）最小样本占比，默认 5%max_bin_size: 使用 optbinning 正式分箱叶子结点（或者每箱）最大样本占比，默认 Nonegamma: 使用 optbinning 分箱时限制过拟合的正则化参数，值越大惩罚越多，默认 0。01monotonic_trend: 使用 optbinning 正式分箱时的坏率策略，默认 auto，可选 "auto", "auto_heuristic", "auto_asc_desc", "ascending", "descending", "convex", "concave", "peak", "valley", "peak_heuristic", "valley_heuristic"rules: 自定义分箱规则，toad.Combiner 能够接收的形式n_jobs: 使用多进程加速的worker数量，默认单进程"""使用方法combiner=Combiner(min_samples=0.2,empty_separate=True,target=target)combiner.fit(train)train=combiner.transform(train)# pipelinefeature_pipeline=Pipeline([......("combiner",Combiner(target=target,min_samples=0.2)),......])feature_pipeline.fit(train)# save all bin_plot_combiner=feature_pipeline.named_steps["combiner"]forcolinwoe_train.columns:ifcol!=target:_combiner.bin_plot(train,col,labels=True,save=f"outputs/bin_plots/train_{col}.png")_combiner.bin_plot(test,col,labels=True,save=f"outputs/bin_plots/test_{col}.png")_combiner.bin_plot(oot,col,labels=True,save=f"outputs/bin_plots/oot_{col}.png")特征编码特征分箱后，本质上只是将特征离散化为几箱，每一箱的值被赋予了一个标签，例如0、1、2、3、...，尽管这些标签在一定程度上也能够表征客户的风险水平，能够作为输入建立一个模型，但基于上述标签构建的模型在评估客户风险状况时比较局限，很难精准刻画客户的风险状况。对于上述离散化后的特征，常规的处理方式有ONE-HOT编码、顺序编码、TARGET编码、COUNT编码等方式。在金融建模场景，尤其是评分卡建模时，通常使用WOE编码对离散化后的特征进行编码。WOE编码将每个分箱内的坏样本比例除以好样本比例后取对数来编码，能够反映每个分箱内客户的坏客户分布与好客户分布之间的差异以及该箱内坏好比(odds)相对于总体的坏好比之间的差异性。笔者基于toad.transform.WOETransformer重写了相关的方法，方法如下：classWOETransformer(TransformerMixin,BaseEstimator):def__init__(self,target="target",exclude=None):"""WOE转换器Args:target: 数据集中标签名称，默认 targetexclude: 不需要转换 woe 的列"""使用方法# 常规使用方式transformer=WOETransformer(target=target)train=transformer.fit_transform(train)# pipelinefeature_pipeline=Pipeline([......("transformer",WOETransformer(target=target)),......])feature_pipeline.fit(train)特征精筛通常对特征WOE编码转换后，特征之间的相关性会上升、唯一值占比会增加、变量IV值会下降（同一特征分箱数越多IV值越大），为了避免入模特征相关性过高、唯一值占比过高、IV过低等问题的出现，需要在转换编码后进行特征精筛，筛选的限制条件相较分箱前的粗筛更严，以保证模型稳定性和泛化能力。相关方法参照特征粗筛，在此不过多赘述。逐步回归特征筛选特征在进行完前面的步骤后，在正式建模前，通常还会使用逐步回归对特征做进一步的筛选。通过假设检验的方法来得到最优的入模特征组合，能够有效的解决特征之间的多重共线性。笔者基于toad.selection.stepwise重新实现了StepwiseSelection，参数与toad包中的所有参数一致，方法如下：classStepwiseSelection(TransformerMixin,BaseEstimator):def__init__(self,target="target",estimator="ols",direction="both",criterion="aic",max_iter=None,return_drop=True,exclude=None,intercept=True,p_value_enter=0.2,p_remove=0.01,p_enter=0.01,target_rm=False):"""逐步回归筛选方法Args:target: 数据集中标签名称，默认 targetestimator: 预估器，默认 ols，可选 "ols", "lr", "lasso", "ridge"，通常默认即可direction: 逐步回归方向，默认both，可选 "forward", "backward", "both"，通常默认即可criterion: 评价指标，默认 aic，可选 "aic", "bic"，通常默认即可max_iter: 最大迭代次数，sklearn中使用的参数，默认为 Nonereturn_drop: 是否返回特征剔除信息，默认 Trueexclude: 强制保留的某些特征intercept: 是否包含截距，默认为 Truep_value_enter: 特征进入的 p 值，用于前向筛选时决定特征是否进入模型p_remove: 特征剔除的 p 值，用于后向剔除时决定特征是否要剔除p_enter: 特征 p 值，用于判断双向逐步回归是否剔除或者准入特征target_rm: 是否剔除数据集中的标签，默认为 False，即剔除数据集中的标签"""使用方法# 常规使用方法stepwise=StepwiseSelection(target=target)train=stepwise.fit_transform(train)# pipelinefeature_pipeline=Pipeline([......("stepwise",StepwiseSelection(target=target,target_rm=False)),......])feature_pipeline.fit(train)逻辑回归建模逻辑回归基本上都是使用的sklearn.linear_model模块里的LogisticRegression(偏模型)或者statsmodels.api提供的Logit(偏统计)，两者各有优点。sklearn库提供了可以自行调整超参数的逻辑回归模型，statsmodels库提供了很完整的模型摘要输出，两者类似鱼与熊掌一样，不可兼得。笔者参考社区搜寻了很多评分卡建模相关的仓库，最终在skorecard.liner_model中LogisticRegression的实现上进行优化，增加了一些相关的统计信息输出，实现了类似statsmodels的模型输出的效果，同时保留了sklearn版LogisticRegression可以手工设置超参数或者基于超参数搜索框架搜寻最有超参数组合的特性。同时，也对statsmodels库中的Logit进行了一定的封装，以满足笔者评分卡建模的pipeline组件要求以及更详细的模型摘要信息输出和保存。方法简介classITLubberLogisticRegression(LogisticRegression):"""Extended Logistic Regression.Extends [sklearn.linear_model.LogisticRegression](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html).This class provides the following extra statistics, calculated on `.fit()` and accessible via `.summary()`:- `cov_matrix_`: covariance matrix for the estimated parameters.- `std_err_intercept_`: estimated uncertainty for the intercept- `std_err_coef_`: estimated uncertainty for the coefficients- `z_intercept_`: estimated z-statistic for the intercept- `z_coef_`: estimated z-statistic for the coefficients- `p_value_intercept_`: estimated p-value for the intercept- `p_value_coef_`: estimated p-value for the coefficientsExample:```pythonfeature_pipeline = Pipeline([("preprocessing_select", FeatureSelection(target=target, engine="scorecardpy")),("combiner", Combiner(target=target, min_samples=0.2)),("transform", WOETransformer(target=target)),("processing_select", FeatureSelection(target=target, engine="scorecardpy")),("stepwise", StepwiseSelection(target=target)),# ("logistic", LogisticClassifier(target=target)),("logistic", ITLubberLogisticRegression(target=target)),])feature_pipeline.fit(train)summary = feature_pipeline.named_steps['logistic'].summary()```An example output of `.summary()`:| | Coef. | Std.Err | z | P>|z| | [ 0.025 | 0.975 ] | VIF ||:------------------|----------:|----------:|---------:|------------:|-----------:|----------:|--------:|| const | -0.844037 | 0.0965117 | -8.74544 | 2.22148e-18 | -1.0332 | -0.654874 | 1.05318 || duration.in.month | 0.847445 | 0.248873 | 3.40513 | 0.000661323 | 0.359654 | 1.33524 | 1.14522 |"""def__init__(self,target="target",penalty="l2",calculate_stats=True,dual=False,tol=0.0001,C=1.0,fit_intercept=True,intercept_scaling=1,class_weight=None,random_state=None,solver="lbfgs",max_iter=100,multi_class="auto",verbose=0,warm_start=False,n_jobs=None,l1_ratio=None,):"""Extends [sklearn.linear_model.LogisticRegression.fit()](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html).Args:target (str): your dataset's target namecalculate_stats (bool): If true, calculate statistics like standard error during fit, accessible with .summary()"""使用方法# 常规使用方法logistic=ITLubberLogisticRegression(target=target)logistic.fit(woe_train)logistic.plot_weights(save="outputs/logistic_train.png")summary=logistic.summary().reset_index().rename(columns={"index":"Features"})train_corr=logistic.corr(woe_train,save="outputs/train_corr.png")train_report=logistic.report(woe_train)# pipelinefeature_pipeline=Pipeline([......("logistic",ITLubberLogisticRegression(target=target)),])feature_pipeline.fit(train)y_pred_train=feature_pipeline.predict(train.drop(columns=target))评分卡转换笔者重写了toad.ScoreCard以适配pipeline模式的端到端的评分卡建模，同时支持传入训练好的逻辑回归模型、输出评分排序性、评分分布、评分稳定性等。相关代码说明classScoreCard(toad.ScoreCard,TransformerMixin):def__init__(self,target="target",pdo=60,rate=2,base_odds=35,base_score=750,combiner={},transer=None,pretrain_lr=None,pipeline=None,**kwargs):"""评分卡模型转换Args:target: 数据集中标签名称，默认 targetpdo: odds 每增加 rate 倍时减少 pdo 分，默认 60rate: 倍率base_odds: 基础 odds，通常根据业务经验设置的基础比率（违约概率/正常概率），估算方法：（1-样本坏客户占比）/坏客户占比，默认 35，即 35:1 => 0.972 => 坏样本率 2.8%base_score: 基础 odds 对应的分数，默认 750combiner: 分箱转换器，传入 pipeline 时可以为Nonetranser: woe转换器，传入 pipeline 时可以为Nonepretrain_lr: 预训练好的逻辑回归模型，可以不传pipeline: 训练好的 pipeline，必须包含 Combiner 和 WOETransformer**kwargs: 其他相关参数，具体参考 toad.ScoreCard"""使用方法# 使用方法feature_pipeline=Pipeline([("preprocessing_select",FeatureSelection(target=target,engine="scorecardpy")),("combiner",Combiner(target=target,min_samples=0.2)),("transformer",WOETransformer(target=target)),("processing_select",FeatureSelection(target=target,engine="scorecardpy")),("stepwise",StepwiseSelection(target=target,target_rm=False)),])woe_train=feature_pipeline.fit_transform(train)combiner=feature_pipeline.named_steps['combiner'].combinertransformer=feature_pipeline.named_steps['transformer'].transformerscore_card=ScoreCard(target=target,combiner=combiner,transer=transformer,)score_card.fit(woe_train)data["score"]=score_card.transform(data)# 评分效果clip=50clip_start=max(math.ceil(train["score"].min()/clip)*clip,math.ceil(train["score"].quantile(0.01)/clip)*clip)clip_end=min(math.ceil(train["score"].max()/clip)*clip,math.ceil(train["score"].quantile(0.99)/clip)*clip)score_clip=[iforiinrange(clip_start,clip_end,clip)]train_score_rank=feature_bin_stats(train,"score",target=target,rules=score_clip,verbose=0,method="step",ks=True)ks_plot(train["score"],train[target],title="Train Dataset",save="model_report/train_ksplot.png")score_hist(train["score"],train[target],save="model_report/train_scorehist.png",bins=30,figsize=(13,10))超参数优化笔者根据sklearn.pipeline的构造规则，重写了评分卡建模相关模块，并在此基础上加入了部分笔者认为可能会有用的方法。通过对相关模块重写后，可以支持评分卡端到端pipeline式的超参数搜索方案。使用方法feature_pipeline=Pipeline([("preprocessing_select",FeatureSelection(target=target,engine="scorecardpy")),("combiner",Combiner(target=target,min_samples=0.2)),("transformer",WOETransformer(target=target)),("processing_select",FeatureSelection(target=target,engine="scorecardpy")),("stepwise",StepwiseSelection(target=target,target_rm=False)),# ("logistic", StatsLogisticRegression(target=target)),("logistic",ITLubberLogisticRegression(target=target)),])# pipeline 超参数搜索参数：{pipeline_step_name}__{param}params_grid={"logistic__C":[i/1.foriinrange(1,10,2)],"logistic__penalty":["l2"],"logistic__class_weight":[None,"balanced"],# + [{1: i / 10.0, 0: 1 - i / 10.0} for i in range(1, 10)],"logistic__max_iter":[100],"logistic__solver":["sag"]# ["liblinear", "sag", "lbfgs", "newton-cg"],"logistic__intercept":[True,False],}clf=GridSearchCV(feature_pipeline,params_grid,cv=5,scoring='roc_auc',verbose=-1,n_jobs=2,return_train_score=True)clf.fit(train,train[target])y_pred_train=clf.best_estimator_.predict(train)print(clf.best_params_)模型报告报告说明输出评分卡模型报告的意义在于能够对其他人呈现评分卡模型的好坏以及相关的模型信息。过去在评分卡建模过程中必须将各种表格和图片汇总到某个文件夹内或者几个文件中，格式每次都需要进行调整和优化，很耽误时间，如果中途有改动的话有需要重新再造一遍轮子。笔者基于日常评分卡建模工作中的需求，通过openpyxl实现了向excel文件中写入制定样式的内容（文本、图片、数据表、条件格式、设定宽度、字体对齐等），并在此基础上将评分卡建模过程中需要输出的内容以设定的格式全部保存至excel文件中，以减少后续建模过程中的重复性工作。相关代码说明classExcelWriter:def__init__(self,style_excel='报告输出模版.xlsx',style_sheet_name="初始化",fontsize=10,font='楷体',theme_color='2639E9'):"""excel 文件内容写入公共方法:param style_excel: 样式模版文件，默认当前路径下的 报告输出模版.xlsx ，如果项目路径调整需要进行相应的调整:param style_sheet_name: 模版文件内初始样式sheet名称，默认即可:param fontsize: 插入excel文件中内容的字体大小，默认 10:param font: 插入excel文件中内容的字体，默认 楷体:param theme_color: 主题色，默认 2639E9，注意不包含 #"""defadd_conditional_formatting(self,worksheet,start_space,end_space):"""设置条件格式:param worksheet: 当前选择设置条件格式的sheet:param start_space: 开始单元格位置:param end_space: 结束单元格位置"""@staticmethoddefset_column_width(worksheet,column,width):"""调整excel列宽:param worksheet: 当前选择调整列宽的sheet:param column: 列，可以直接输入 index 或者 字母:param width: 设置列的宽度"""@staticmethoddefset_number_format(worksheet,space,_format):"""设置数值显示格式:param worksheet: 当前选择调整数值显示格式的sheet:param space: 单元格范围:param _format: 显示格式，参考 openpyxl"""defget_sheet_by_name(self,name):"""获取sheet名称为name的工作簿，如果不存在，则从初始模版文件中拷贝一个名称为name的sheet:param name: 需要获取的工作簿名称"""definsert_value2sheet(self,worksheet,insert_space,value="",style="content",auto_width=False):"""向sheet中的某个单元格插入某种样式的内容:param worksheet: 需要插入内容的sheet:param insert_space: 内容插入的单元格位置，可以是 "B2" 或者 (2, 2) 任意一种形式:param value: 需要插入的内容:param style: 渲染的样式，参考 init_style 中初始设置的样式:param auto_width: 是否开启自动调整列宽"""definsert_pic2sheet(self,worksheet,fig,insert_space,figsize=(600,250)):"""向excel中插入图片内容:param worksheet: 需要插入内容的sheet:param fig: 需要插入的图片路径:param insert_space: 插入图片的起始单元格:param figsize: 图片大小设置"""definsert_df2sheet(self,worksheet,data,insert_space,merge_column=None,header=True,index=False,auto_width=False):"""向excel文件中插入制定样式的dataframe数据:param worksheet: 需要插入内容的sheet:param data: 需要插入的dataframe:param insert_space: 插入内容的起始单元格位置:param merge_column: 需要分组显示的列，index或者列明:param header: 是否存储dataframe的header，暂不支持多级表头:param index: 是否存储dataframe的index:param auto_width: 是否自动调整列宽:return 返回插入元素最后一列之后、最后一行之后的位置"""defsave(self,filename):"""保存excel文件:param filename: 需要保存 excel 文件的路径"""使用方法writer=ExcelWriter(style_excel="./utils/报告输出模版.xlsx",theme_color="2639E9")# 评分卡刻度scorecard_kedu=pd.DataFrame([["base_odds",card.base_odds,"根据业务经验设置的基础比率（违约概率/正常概率），估算方法：（1-样本坏客户占比）/坏客户占比"],["base_score",card.base_score,"基础ODDS对应的分数"],["rate",card.rate,"设置分数的倍率"],["pdo",card.pdo,"表示分数增长PDO时，ODDS值增长到RATE倍"],["B",card.offset,"补偿值，计算方式：pdo / ln(rate)"],["A",card.factor,"刻度，计算方式：base_score - B * ln(base_odds)"],],columns=["刻度项","刻度值","备注"],)worksheet=writer.get_sheet_by_name("评分卡结果")start_row,start_col=2,2end_row,end_col=writer.insert_value2sheet(worksheet,(start_row,start_col),value="评分卡刻度",style="header")end_row,end_col=writer.insert_df2sheet(worksheet,scorecard_kedu,(end_row+1,start_col))end_row,end_col=writer.insert_value2sheet(worksheet,(end_row+2,start_col),value="训练数据集评分模型效果",style="header")ks_row=end_rowend_row,end_col=writer.insert_pic2sheet(worksheet,"model_report/train_ksplot.png",(ks_row,start_col))end_row,end_col=writer.insert_pic2sheet(worksheet,"model_report/train_scorehist.png",(ks_row,end_col))end_row,end_col=writer.insert_df2sheet(worksheet,train_score_rank,(end_row+1,start_col))forcin["坏样本率","LIFT值","分档KS值"]:conditional_column=get_column_letter(start_col+train_score_rank.columns.get_loc(c))writer.add_conditional_formatting(worksheet,f'{conditional_column}{end_row-len(train_score_rank)}',f'{conditional_column}{end_row}')汇总信息汇总信息包含评分卡模型相关的背景说明、取样说明、数据集划分方式以及不同时点数据分布情况。LR拟合结果逻辑回归拟合结果主要包含了LR模型的拟合情况、稳定性、模型AUC、KS等指标。入模特征信息入模特征信息包含了入模特征的数据字典、分布情况、相关性、分箱信息以及分箱图等信息，主要为了展示评分卡入模变量相关的信息。评分卡结果评分卡模型结果主要包含评分卡参数信息、变量分箱及对应分数、评分AUC和KS指标、评分分布情况、评分排序性、各个评分区间相关指标信息。补充说明后续准备有闲暇时加上shap、bad case等相关的内容，并将支持lightgbm、catboost、xgboost等模型的报告输出。评分卡PMML转换背景说明关于评分卡上线部署方案，目前现有的大致有四种提需求给公司开发部门上线部署将评分卡模型保存为pickle文件提供开发部署直接使用python提供api服务部署或者定时更新评分卡转PMML文件部署前几种相对简单，提供API服务可能有一定技术门槛，但基本上网上有现成的方案，但评分卡转换PMML文件部署有一定难度，网上能够参考的实现方案比较难找，本章就笔者提供的评分卡转PMML相关的实现进行说明。相关代码说明classScoreCard(toad.ScoreCard,TransformerMixin):......defscorecard2pmml(self,pmml:str='scorecard.pmml',debug:bool=False):"""export a scorecard to pmmlArgs:pmml (str): io to write pmml file.debug (bool): If true, print information about the conversion process."""使用说明# 保存 PMML 评分卡模型card.scorecard2pmml(pmml='scorecard.pmml',debug=True)# 模型验证frompypmmlimportModelmodel=Model.fromFile("scorecard.pmml")data["score"]=model.predict(data[model.inputNames]).values参考资料https://github.com/itlubber/LogisticRegressionPipelinehttps://github.com/itlubber/itlubber-excel-writerhttps://github.com/itlubber/openpyxl-excel-style-templatehttps://github.com/itlubber/scorecard2pmmlhttps://pypi.org/project/pdtr/https://github.com/amphibian-dev/toadhttps://github.com/ShichenXie/scorecardpyhttps://github.com/ing-bank/skorecardhttp://gnpalencia.org/optbinninghttps://github.com/yanghaitian1/risk_control