Coverage for mlprodict/grammar/grammar_sklearn/g_sklearn_tree.py: 100%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2"""
3@file
4@brief List of converters from scikit-learn model.
5"""
6import numpy
7from .g_sklearn_type_helpers import check_type
8from .grammar.gactions import MLActionVar, MLActionCst, MLActionIfElse, MLActionReturn
9from .grammar.gactions_tensor import MLActionTensorTake
10from .grammar.gactions_num import MLActionTestInf, MLActionTestEqual
11from .grammar.gmlactions import MLModel
14def sklearn_decision_tree_regressor(model, input_names=None, output_names=None, **kwargs):
15 """
16 Converts a `DecisionTreeRegressor
17 <http://scikit-learn.org/stable/modules/generated/
18 sklearn.tree.DecisionTreeRegressor.html>`_
19 model into a *grammar* model (semantic graph representation).
21 @param model scikit-learn model
22 @param input_names name of the input features
23 @param output_names name of the output predictions
24 @param kwargs addition parameter (*with_loop*)
25 @return graph model
27 If *input* is None or *output* is None, default values
28 will be given to the outputs
29 ``['Prediction', 'Score']`` for the outputs.
30 If *input_names* is None, it wil be ``'Features'``.
32 Additional parameters:
33 - *with_loop*: False by default, *True* not implemented.
35 .. note::
37 The code to compute on output is
38 `here <https://github.com/scikit-learn/scikit-learn/blob/
39 ef5cb84a805efbe4bb06516670a9b8c690992bd7/sklearn/tree/_tree.pyx#L806>`_:
41 ::
43 for i in range(n_samples):
44 node = self.nodes
45 # While node not a leaf
46 while node.left_child != _TREE_LEAF:
47 # ... and node.right_child != _TREE_LEAF:
48 if X_ptr[X_sample_stride * i +
49 X_fx_stride * node.feature] <= node.threshold:
50 node = &self.nodes[node.left_child]
51 else:
52 node = &self.nodes[node.right_child]
54 out_ptr[i] = <SIZE_t>(node - self.nodes) # node offset
56 TODO: improve C code (all leaves are computed and this is unnecessary).
57 TODO: create a function tree and an intermediate node and use it here.
58 """
59 if kwargs.get('with_loop', False):
60 raise NotImplementedError( # pragma: no cover
61 "Loop version is not implemented.")
62 if output_names is None:
63 output_names = ['Prediction', 'Score']
64 if input_names is None:
65 input_names = 'Features'
67 from sklearn.tree import DecisionTreeRegressor
68 check_type(model, DecisionTreeRegressor)
70 # We convert the tree into arrays.
71 # run help(model.tree_).
72 lthres = MLActionCst(model.tree_.threshold.ravel().astype(
73 numpy.float32), comment="threshold")
74 lleft = MLActionCst(model.tree_.children_left.ravel().astype(
75 numpy.int32), comment="left")
76 lright = MLActionCst(model.tree_.children_right.ravel().astype(
77 numpy.int32), comment="right")
78 lfeat = MLActionCst(model.tree_.feature.ravel().astype(
79 numpy.int32), comment="indfeat")
80 lvalue = MLActionCst(model.tree_.value.ravel().astype(
81 numpy.float32), comment="value")
83 ex = numpy.zeros(model.n_features_, numpy.float32)
84 lvar = MLActionVar(ex, input_names)
86 lind = MLActionCst(numpy.int32(0), comment="lind")
87 th = MLActionTensorTake(lthres, lind)
88 m1 = MLActionCst(numpy.int32(-1), comment="m1")
90 max_depth = model.tree_.max_depth
91 cont = None
92 new_lind = None
93 for i in range(0, max_depth):
94 # Leave ?
95 if new_lind is not None:
96 lind = new_lind
98 le = MLActionTensorTake(lleft, lind)
99 lr = MLActionTensorTake(lright, lind)
101 di = MLActionTensorTake(lfeat, lind)
102 df = MLActionTensorTake(lfeat, di)
103 xx = MLActionTensorTake(lvar, df)
104 te = MLActionTestInf(xx, th)
106 new_lind = MLActionIfElse(te, le, lr, comment="lind{0}".format(i))
107 le = MLActionTensorTake(lleft, new_lind)
108 th = MLActionTensorTake(lthres, new_lind)
110 eq = MLActionTestEqual(m1, le)
111 va = MLActionTensorTake(lvalue, new_lind)
112 cont = MLActionIfElse(eq, va, th, comment="cont{0}".format(i))
114 ret = MLActionReturn(cont)
115 return MLModel(ret, output_names, name=DecisionTreeRegressor.__name__)