来源:Python数据科学
如若转载请联系原公众号
大家都知道, Python 和 SAS 是两个很常用的数据挖掘工具。Python 开源、免费、有丰富的三方库,一般在互联网公司广泛使用。而SAS需付费,且费用较高,一般互联网公司无法承担,更多的是在银行等传统金融机构中使用,不过这两年由于Python太火,原本使用SAS的也开始逐渐转向Python了。
拥抱开源,越来越多的爱好者造出优秀的Python轮子,比如当下比较流行的万金油模型 Xgboost 、 LightGBM ,在各种竞赛的top级方案中均有被使用。而SAS的脚步就比较慢了,对于一些比较新的东西都无法直接提供,所以对于那些使用SAS的朋友,就很难受了。
一直以来很多粉丝问过东哥这个问题:
有没有一种可以将Python模型转成SAS的工具?
因为我本身是两个技能都具备的,实际工作中一般都是配合使用,也很少想过进行转换。但是,最近东哥逛技术论坛刚好发现了一个骚操作,借助Python的三方库
m2cgen
和Python脚本即可完成Python模型到SAS的转换。
m2cgen是什么?
m2cgen 是一个Python的第三方库,主要功能就是将Python训练过的模型转换为其它语言,比如 R 和 VBA 。遗憾的是,目前 m2cgen 尚不支持 SAS ,但这并不影响我们最终转换为 SAS 。
我们仍然使用 m2cgen ,需要借助它间接转换成SAS。具体的方案就是先将Python模型转换为 VBA代码 ,然后再将VBA代码更改为 SAS脚本 ,曲线救国。
如何使用m2cgen?
我直接用一个例子说明下如何操作。
数据我们使用sklearn自带的 iris dataset ,链接如下:
https://scikit-learn.org/stable/auto_examples/datasets/plot_iris_dataset.html
下面,演示一下如何将Python的XGBoost模型转成SAS代码。
首先导入所需的库包和数据。
# 导入库
import
pandas
as
pd
import
numpy
as
np
import
os
import
re
from
sklearn
import
datasets
from
xgboost
import
XGBClassifier
from
sklearn.model_selection
import
train_test_split
from
sklearn.metrics
import
accuracy_score
import
m2cgen
as
m2c
# 导入数据
iris = datasets.load_iris
X = iris.data
Y = iris.target
然后,我们划分数据集,直接扔进 XGBoost 里面,建立base模型。
# 划分数据为训练集和测试集
seed =
2020
test_size =
0.3
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=test_size, random_state=seed)
# 训练数据
model = XGBClassifier
model.fit(X_train, y_train)
然后,再将XGBoost模型转换为VBA。使用 m2cgen 的 export_to_visual_basic 方法就可以直接转成VBA了。转换成其他语言脚本也是同理,非常简单。
code = m2c.export_to_visual_basic(model, function_name =
'pred'
)
核心的骚操作来了!
m2cgen不支持SAS,但我们可以把VBA代码稍加改动,就能变成符合SAS标准的代码了。而这个改动也无需手动一个个改,
写一段Python脚本即可实现VBA脚本转换为SAS脚本。
改动的地方不多,主要包括:删除在SAS环境中不能使用的代码,像上面结果中的 Module xxx , Function yyy , Dim var Z As Double ,还有在语句结尾加上 ; ,这些为的就是遵循SAS的语法规则。
下面就是转换的Python脚本,可以自动执行上面所说的转换操作。
# 1、移除SAS中不能使用的代码
code = re.sub(
'Dim var.* As Double'
,
''
, code)
code = re.sub(
'End If'
,
''
, code)
# 下面操作将修改成符合SAS的代码
# 2、修改起始
code = re.sub(
'Module ModelnFunction pred(ByRef inputVector As Double) As Doublen'
,
'DATA pred_result;nSET dataset_name;'
, code)
# 3、修改结尾
code = re.sub(
'End FunctionnEnd Modulen'
,
'RUN;'
, code)
# 4、在结尾加上分号';'
all_match_list = re.findall(
'[0-9]+n'
, code)
for
idx
in
range(len(all_match_list)):
original_str = all_match_list[idx]
new_str = all_match_list[idx][:
-1
]+
';n'
code = code.replace(original_str, new_str)
all_match_list = re.findall(
')n'
, code)
for
idx
in
range(len(all_match_list)):
original_str = all_match_list[idx]
new_str = all_match_list[idx][:
-1
]+
';n'
code = code.replace(original_str, new_str)
# 用var来替代inputVector
dictionary = {
'inputVector(0)'
:
'sepal_length'
,
'inputVector(1)'
:
'sepal_width'
,
'inputVector(2)'
:
'petal_length'
,
'inputVector(3)'
:
'petal_width'
}
for
key
in
dictionary.keys:
code = code.replace(key, dictionary[key])
# 修改预测标签
code = re.sub(
'Math.Exp'
,
'Exp'
, code)
code = re.sub(
'pred = .*n'
,
''
, code)
temp_var_list = re.findall(
r"var[0-9]+(d)"
, code)
for
var_idx
in
range(len(temp_var_list)):
code = re.sub(re.sub(
'('
,
'('
, re.sub(
')'
,
')'
, temp_var_list[var_idx])), iris.target_names[var_idx]+
'_prob'
, code)
对以上脚本分步解释说明一下。
1、开头、结尾、输出名称
前三个部分非常简单。使用正则表达式删除多余的行,然后将脚本的开头更改为 DATA pred_result; nSETdataset_name; 。
使用过SAS的同学就很熟悉了, pred_result 是运行SAS脚本后的输出表名称, dataset_name 是我们需要预测的输入表名称。
最后再将脚本的结尾更改为 RUN; 。
# 移除SAS中不能使用的代码
code = re.sub(
'Dim var.* As Double'
,
''
, code)
code = re.sub(
'End If'
,
''
, code)
# 下面操作将修改成符合SAS的代码
# 修改起始
code = re.sub(
'Module ModelnFunction pred(ByRef inputVector As Double) As Doublen'
,
'DATA pred_result;nSET dataset_name;'
, code)
# 修改结尾
code = re.sub(
'End FunctionnEnd Modulen'
,
'RUN;'
, code)
2、语句末尾添加分号
为遵循SAS中的语法规则,还需将每个语句的结尾加上 ; 。仍用正则表达式,然后for循环在每一行最后添加字符 ; 即可。
# 在结尾加上分号';'
all_match_list = re.findall(
'[0-9]+n'
, code)
for
idx
in
range(len(all_match_list)):
original_str = all_match_list[idx]
new_str = all_match_list[idx][:
-1
]+
';n'
code = code.replace(original_str, new_str)
all_match_list = re.findall(
')n'
, code)
for
idx
in
range(len(all_match_list)):
original_str = all_match_list[idx]
new_str = all_match_list[idx][:
-1
]+
';n'
code = code.replace(original_str, new_str)
3、映射变量名称
使用字典将 InputVector 与变量名称映射到输入数据集中,一次性更改所有 InputVector 。
# 用var来替代inputVector
dictionary = {
'inputVector(0)'
:
'sepal_length'
,
'inputVector(1)'
:
'sepal_width'
,
'inputVector(2)'
:
'petal_length'
,
'inputVector(3)'
:
'petal_width'
}
for
key
in
dictionary.keys:
code = code.replace(key, dictionary[key])
4、映射变量名称
最后一步就是更改预测标签。
# 修改预测标签
code = re.sub(
'Math.Exp'
,
'Exp'
, code)
code = re.sub(
'pred = .*n'
,
''
, code)
temp_var_list = re.findall(
r"var[0-9]+(d)"
, code)
for
var_idx
in
range(len(temp_var_list)):
code = re.sub(re.sub(
'('
,
'('
, re.sub(
')'
,
')'
, temp_var_list[var_idx])), iris.target_names[var_idx]+
'_prob'
, code)
然后保存sas模型文件。
#保存输出
vb = open(
'vb1.sas'
,
'w'
)
vb.write(code)
vb.close
最后,为了验证sas脚本是否正确,我们将sas模型的预测结果和Python的结果进行一下对比。
# python 预测
python_pred = pd.DataFrame(model.predict_proba(X_test))
python_pred.columns = [
'setosa_prob'
,
'versicolor_prob'
,
'virginica_prob'
]
python_pred
# sas 预测
sas_pred = pd.read_csv(
'pred_result.csv'
)
sas_pred = sas_pred.iloc[:,-3:]
sas_pred
(abs(python_pred - sas_pred) > 0.00001).sum
可以看到,两个预测的结果基本上一样,基本没问题,我们就可以在sas中跑xgboost模型了。
上面只是个最简单的示例,没有对特征处理。对于复杂的建模过程,比如很多特征工程,那就要对Python脚本进一步调整了。
觉得这个方法比较新颖,拿来分享一下,大家也可举一反三。
- END -
返回搜狐,查看更多
责任编辑:
声明:该文观点仅代表作者本人,搜狐号系信息发布平台,搜狐仅提供信息存储空间服务。