Scikit learn 您能否从Scikit分类器中提取评分算法并将系数加载到Oracle中?

Scikit learn 您能否从Scikit分类器中提取评分算法并将系数加载到Oracle中?,scikit-learn,random-forest,scoring,Scikit Learn,Random Forest,Scoring,我使用sklearn模块在Python中运行了一个RandomForestClassifier模型。我将模型保存在pickle文件中。然后,我从Oracle提取数据,将其保存为.csv文件,将该.csv文件发送到一台机器,该机器可以用Python打开模型的pickle文件,并对数据进行评分。数据评分后,我将结果发送回Oracle 是否可以从RandomForestClassifier(.predict_proba)函数中提取评分系数,以便我可以将该数据加载到Oracle中,并仅在Oracle内部

我使用sklearn模块在Python中运行了一个RandomForestClassifier模型。我将模型保存在pickle文件中。然后,我从Oracle提取数据,将其保存为.csv文件,将该.csv文件发送到一台机器,该机器可以用Python打开模型的pickle文件,并对数据进行评分。数据评分后,我将结果发送回Oracle

是否可以从RandomForestClassifier(.predict_proba)函数中提取评分系数,以便我可以将该数据加载到Oracle中,并仅在Oracle内部对数据进行评分

阅读文档后,评分算法似乎过于复杂,无法执行上述建议,因为它必须将每个新记录推过每棵树,然后才能得出最终评分概率。这是正确的吗

我提前感谢你的帮助


Matt

AFAIK没有现成的工具可以这样做,但您可以阅读基本的Cython源代码,特别是通过决策树模型的拟合参数了解预测工作原理的方法。随机森林预测将单个树木预测视为二元概率(0或1),对其进行平均,并将其归一化为

不过,将其转换为PL/SQL可能并不简单。显然,Oracle数据挖掘在其他模型中有一些支持。不幸的是,我也不知道有任何针对scikit学习决策树的exporter实现(尽管以为例编写决策树可能更容易)


另一方面,请注意,在PostgreSQL下,您可以在使用编写的DB函数中直接使用scikit learn。

我的情况是,我必须在Oracle数据库上运行随机林模型。可以生成执行与Python Sk learn RF模型相同功能的PL/SQL包

一旦你有了Daniele的答案,这是非常琐碎的事情

首先,您有一个文件:rforest\u to\u 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]) + " ) then\n"
            depth += 1
            if left[node] != -1:
                code = recurse (left, right, threshold, features,left[node], depth, code)                 
            code += t(depth - 1) + "else\n"
            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 as\n"        
    #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 as\n    begin\n"
        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 as\n    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) + "begin\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 := " + 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
在数据库上创建该包后,可以执行以下操作:

select pkg_rforest_model.predict_proba(0.513889 , 0.511111 , 0.491667 ,  0)
from   dual;

这是纯PL/SQL,应该运行得非常快。如果你有一个非常大的射频,那么你可以编译本机的包,以获得更高的性能。警告-包装可能是1000秒LOC中的10秒

以下是使用库的方法:

当然,这可能不是评估RF分类器的最有效方法——对于大型林,生成的查询可能很容易达到MB大小

注意:如果您的林有100多个估计器,您可能还需要增加系统递归限制来编译它:

import sys
sys.setrecursionlimit(10000)

是的,随机森林通过并行运行一组决策树并让它们对最终结果进行投票来运行。我想,在Oracle DBMS中这样做是否太复杂取决于您的SQL fu;)
from skompiler import skompile
expr = skompile(gbr.predict)

skompile(rf.predict_proba).to('sqlalchemy/oracle')
import sys
sys.setrecursionlimit(10000)