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

45 statements  

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 

12 

13 

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). 

20 

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 

26 

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'``. 

31 

32 Additional parameters: 

33 - *with_loop*: False by default, *True* not implemented. 

34 

35 .. note:: 

36 

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>`_: 

40 

41 :: 

42 

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] 

53 

54 out_ptr[i] = <SIZE_t>(node - self.nodes) # node offset 

55 

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' 

66 

67 from sklearn.tree import DecisionTreeRegressor 

68 check_type(model, DecisionTreeRegressor) 

69 

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") 

82 

83 ex = numpy.zeros(model.n_features_, numpy.float32) 

84 lvar = MLActionVar(ex, input_names) 

85 

86 lind = MLActionCst(numpy.int32(0), comment="lind") 

87 th = MLActionTensorTake(lthres, lind) 

88 m1 = MLActionCst(numpy.int32(-1), comment="m1") 

89 

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 

97 

98 le = MLActionTensorTake(lleft, lind) 

99 lr = MLActionTensorTake(lright, lind) 

100 

101 di = MLActionTensorTake(lfeat, lind) 

102 df = MLActionTensorTake(lfeat, di) 

103 xx = MLActionTensorTake(lvar, df) 

104 te = MLActionTestInf(xx, th) 

105 

106 new_lind = MLActionIfElse(te, le, lr, comment="lind{0}".format(i)) 

107 le = MLActionTensorTake(lleft, new_lind) 

108 th = MLActionTensorTake(lthres, new_lind) 

109 

110 eq = MLActionTestEqual(m1, le) 

111 va = MLActionTensorTake(lvalue, new_lind) 

112 cont = MLActionIfElse(eq, va, th, comment="cont{0}".format(i)) 

113 

114 ret = MLActionReturn(cont) 

115 return MLModel(ret, output_names, name=DecisionTreeRegressor.__name__)