首頁>技術>

大家都知道,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 pdimport numpy as npimport os import refrom sklearn import datasetsfrom xgboost import XGBClassifierfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import accuracy_scoreimport m2cgen as m2c# 匯入資料iris = datasets.load_iris()X = iris.dataY = iris.target

然後,我們劃分資料集,直接扔進XGBoost裡面,建立base模型。

# 劃分資料為訓練集和測試集seed = 2020test_size = 0.3X_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 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來替代inputVectordictionary = {'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、開頭、結尾、輸出名稱

使用過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來替代inputVectordictionary = {'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指令碼進一步調整了。

參考連結:https://towardsdatascience.com/converting-machine-learning-models-to-sas-using-m2cgen-python-190d846090dc

15
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 資料庫系統