Python模型完美切换SAS,还能这么玩。。

大家都知道,Python 和 SAS 是两个很常用的数据挖掘工具。Python 开源、免费、有丰富的三方库,一般在互联网公司广泛使用。而SAS需付费,且费用较高,一般互联网公司无法承担,更多的是在银行等传统金融机构中使用,不过这两年由于Python太火,原本使用SAS的也开始逐渐转向Python了。

拥抱开源,越来越多的爱好者造出优秀的Python轮子,比如当下比较流行的万金油模型XgboostLightGBM,在各种竞赛的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,链接如下:

The Iris Dataset — scikit-learn 1.1.1 documentation

下面,演示一下如何将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。使用m2cgenexport_to_visual_basic方法就可以直接转成VBA了。转换成其他语言脚本也是同理,非常简单。

code = m2c.export_to_visual_basic(model, function_name = 'pred')

核心的骚操作来了!

m2cgen不支持SAS,但我们可以把VBA代码稍加改动,就能变成符合SAS标准的代码了。而这个改动也无需手动一个个改,写一段Python脚本即可实现VBA脚本转换为SAS脚本。

改动的地方不多,主要包括:删除在SAS环境中不能使用的代码,像上面结果中的Module xxxFunction 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 Model\nFunction pred(ByRef inputVector() As Double) As Double()\n', 
                'DATA pred_result;\nSET dataset_name;', code)
# 3、修改结尾
code = re.sub('End Function\nEnd Module\n', '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 Model\nFunction pred(ByRef inputVector() As Double) As Double()\n', 
                'DATA pred_result;\nSET dataset_name;', code)
# 修改结尾
code = re.sub('End Function\nEnd Module\n', '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脚本进一步调整了。

以上就是本次分享的所有内容,如果你觉得文章还不错,欢迎关注公众号:Python编程学习圈,每日干货分享,发送“J”还可领取大量学习资料,内容覆盖Python电子书、教程、数据库编程、Django,爬虫,云计算等等。或是前往编程学习网,了解更多编程技术知识。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值