我已经使用sklearn模块在Python中运行了一个RandomForestClassifier模型。我把模型保存在pickle文件中。然后,我从Oracle提取数据,将其保存为.csv文件,将该.csv文件发送到一台可以用Python打开模型pickle文件的机器,并对数据进行评分。一旦对数据进行了评分,我就会将结果发送回Oracle。
是否可以从RandomForestClassifier(.product_proba)函数中提取评分系数,以便我可以将数据加载到Oracle中,并仅在Oracle内部对数据进行评分?
在阅读了文档后,评分算法似乎太复杂了,无法执行上述建议,因为它必须将每个新记录推过每棵树,才能得出最终的评分概率。这是正确的吗?
我感谢你事先的帮助。
Matt
AFAIK没有现成的工具可以做到这一点,但您可以阅读基本决策树类的Cython源代码,特别是预测方法,以了解预测是如何根据决策树模型的拟合参数进行的。随机森林预测将单个树的预测视为二元概率(0或1),对其进行平均并归一化,如本文所述。
不过,将其转换为PL/SQL可能并非易事。显然,在其他模型中,Oracle数据挖掘对决策树模型的PMML导入/导出有一定的支持。不幸的是,我也不知道scikit学习决策树的PMML导出器的任何实现(尽管以graphviz树导出器的源代码为例,编写起来可能更容易)。
另一方面,请注意,在PostgreSQL下,您可以在使用PL/Python编写的DB函数中直接使用scikit-learn。
当时我不得不在Oracle数据库上运行一个随机林模型。可以生成一个PL/SQL包,该包执行与PythonSk-learn RF模型相同的功能。
一旦你从这个SO 中得到了类似Daniele的答案,这是非常琐碎的
首先,您有一个文件:rforest_to_plsql.py
def t(n):
return " " * 4 * n
def get_est_code(tree, feature_names):
left = tree.tree_.children_left
right = tree.tree_.children_right
threshold = tree.tree_.threshold
features = [feature_names[i] for i in tree.tree_.feature]
value = tree.tree_.value
def recurse(left, right, threshold, features, node, depth, code):
if (threshold[node] != -2):
code += t(depth) + "if ( " + features[node] + " <= " + str(threshold[node]) + " ) thenn"
depth += 1
if left[node] != -1:
code = recurse (left, right, threshold, features,left[node], depth, code)
code += t(depth - 1) + "elsen"
if right[node] != -1:
code = recurse (left, right, threshold, features,right[node], depth, code)
code += t(depth - 1) + "end if;n"
depth -= 1
else:
code += t(depth) + "return two_values(" + str(value[node][0][0]) + ", " + str(value[node][0][1]) + ");n"
return code
return recurse(left, right, threshold, features, 0, 2, "")
def get_pkg_header_code(clf, feature_names):
pkg_h_code = """create or replace package pkg_rforest_model as
function predict_proba (n"""
for feat in feature_names:
pkg_h_code += t(2) + feat + " number,n"
pkg_h_code = pkg_h_code[:-2] + ") return number;n"
pkg_h_code += "end pkg_rforest_model;"
return pkg_h_code
def get_pkg_body_code(clf, feature_names):
pkg_b_code = "create or replace package body pkg_rforest_model asn"
#code for each estimator
for index, estimator in enumerate(clf.estimators_):
func_name = "f_est_" + str(index).zfill(3)
pkg_b_code += t(1) + "function " + func_name + " (n"
for feat in feature_names:
pkg_b_code += t(2) + feat + " number,n"
pkg_b_code = pkg_b_code[:-2] + ") return two_values asn beginn"
pkg_b_code += get_est_code(clf.estimators_[index], ["f" + str(i) for i in range(7)])
pkg_b_code += " end " + func_name + ";n"
#this function calls all each estimator function and returns a weighted probability
pkg_b_code += " function predict_proba (n"
for feat in feature_names:
pkg_b_code += t(2) + feat + " number,n"
pkg_b_code = pkg_b_code[:-2] + ") return number asn v_prob number;n"
for index, estimator in enumerate(clf.estimators_):
func_name = "f_est_" + str(index).zfill(3)
pkg_b_code += t(2) + "v_" + func_name + "_a number;n"
pkg_b_code += t(2) + "v_" + func_name + "_b number;n"
pkg_b_code += t(2) + "pr_est_" + str(index).zfill(3) + " number;n"
pkg_b_code += t(1) + "beginn"
for index, estimator in enumerate(clf.estimators_):
func_name = "f_est_" + str(index).zfill(3)
pkg_b_code += t(2) + "v_" + func_name + "_a := " + func_name+ "(" + ", ".join(feature_names) + ").a;n"
pkg_b_code += t(2) + "v_" + func_name + "_b := " + func_name+ "(" + ", ".join(feature_names) + ").b;n"
pkg_b_code += t(2) + "pr_est_" + str(index).zfill(3) + " := v_" + func_name + "_a / ( v_" +
func_name + "_a + v_" + func_name + "_b);n"
pkg_b_code += t(2) + "return ("
for index, estimator in enumerate(clf.estimators_):
pkg_b_code += "pr_est_" + str(index).zfill(3) + " + "
pkg_b_code = pkg_b_code[:-2] + ") / " + str(len(clf.estimators_)) + ";n"
pkg_b_code += t(1) + "end predict_proba;n"
pkg_b_code += "end pkg_rforest_model;"
return pkg_b_code
然后训练您的模型,并将PL/SQL代码带回文件的函数:
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
import rforest_to_plsql
n_features = 4
X, y = make_classification(n_samples=1000, n_features=n_features,
n_informative=2, n_redundant=0,
random_state=0, shuffle=False)
clf = RandomForestClassifier(max_depth=2, random_state=0)
clf.fit(X, y)
features = ["f" + str(i) for i in range(n_features)]
pkg_h_code = rforest_to_plsql.get_pkg_header_code(clf, features)
pkg_b_code = rforest_to_plsql.get_pkg_body_code(clf, features)
print pkg_h_code
print pkg_b_code
一旦你在数据库上创建了这个包,你就可以做一些类似的事情:
select pkg_rforest_model.predict_proba(0.513889 , 0.511111 , 0.491667 , 0)
from dual;
这是纯PL/SQL,运行速度应该非常快。如果你有一个非常大的RF,那么你可以原生地编译包以获得更高的性能。请注意,包裹可能是1000秒LOC中的10秒。
以下是使用SKompiler库的方法:
from skompiler import skompile
expr = skompile(gbr.predict)
skompile(rf.predict_proba).to('sqlalchemy/oracle')
当然,这可能不是评估RF分类器的最有效方法——对于大型森林,生成的查询可能很容易达到兆字节大小。
注意:如果你的森林有超过一百个估计量,你可能还需要增加系统递归限制来编译它:
import sys
sys.setrecursionlimit(10000)