क्या मैं एक निर्णय वृक्ष में एक प्रशिक्षित पेड़ से एक पाठ सूची के रूप में अंतर्निहित निर्णय-नियम (या 'निर्णय पथ') निकाल सकता हूं?
कुछ इस तरह:
if A>0.4 then if B<0.2 then if C>0.8 then class='X'
आपकी सहायता के लिए धन्यवाद।
क्या मैं एक निर्णय वृक्ष में एक प्रशिक्षित पेड़ से एक पाठ सूची के रूप में अंतर्निहित निर्णय-नियम (या 'निर्णय पथ') निकाल सकता हूं?
कुछ इस तरह:
if A>0.4 then if B<0.2 then if C>0.8 then class='X'
आपकी सहायता के लिए धन्यवाद।
जवाबों:
मेरा मानना है कि यह उत्तर अन्य उत्तरों की तुलना में अधिक सही है:
from sklearn.tree import _tree
def tree_to_code(tree, feature_names):
tree_ = tree.tree_
feature_name = [
feature_names[i] if i != _tree.TREE_UNDEFINED else "undefined!"
for i in tree_.feature
]
print "def tree({}):".format(", ".join(feature_names))
def recurse(node, depth):
indent = " " * depth
if tree_.feature[node] != _tree.TREE_UNDEFINED:
name = feature_name[node]
threshold = tree_.threshold[node]
print "{}if {} <= {}:".format(indent, name, threshold)
recurse(tree_.children_left[node], depth + 1)
print "{}else: # if {} > {}".format(indent, name, threshold)
recurse(tree_.children_right[node], depth + 1)
else:
print "{}return {}".format(indent, tree_.value[node])
recurse(0, 1)
यह एक मान्य पायथन फ़ंक्शन को प्रिंट करता है। यहां एक पेड़ के लिए एक उदाहरण आउटपुट है जो अपने इनपुट को वापस करने की कोशिश कर रहा है, 0 और 10 के बीच की संख्या।
def tree(f0):
if f0 <= 6.0:
if f0 <= 1.5:
return [[ 0.]]
else: # if f0 > 1.5
if f0 <= 4.5:
if f0 <= 3.5:
return [[ 3.]]
else: # if f0 > 3.5
return [[ 4.]]
else: # if f0 > 4.5
return [[ 5.]]
else: # if f0 > 6.0
if f0 <= 8.5:
if f0 <= 7.5:
return [[ 7.]]
else: # if f0 > 7.5
return [[ 8.]]
else: # if f0 > 8.5
return [[ 9.]]
यहाँ कुछ ठोकरें हैं जो मैं अन्य उत्तरों में देखता हूं:
tree_.threshold == -2
तय करने के लिए एक नोड एक पत्ता है कि क्या एक अच्छा विचार नहीं है। क्या होगा अगर यह -2 की सीमा के साथ एक वास्तविक निर्णय नोड है? इसके बजाय, आपको देखना चाहिए tree.feature
या tree.children_*
।features = [feature_names[i] for i in tree_.feature]
मेरे स्केलेर के संस्करण के साथ दुर्घटनाग्रस्त हो जाती है, क्योंकि tree.tree_.feature
-2 के कुछ मूल्य (विशेष रूप से पत्ती नोड्स के लिए) हैं।print "{}return {}".format(indent, tree_.value[node])
करने print "{}return {}".format(indent, np.argmax(tree_.value[node][0]))
के लिए फ़ंक्शन के लिए बदला जाना चाहिए ।
RandomForestClassifier.estimators_
, लेकिन मैं अनुमान लगाने वालों के परिणामों को संयोजित करने के लिए काम नहीं कर पा रहा था।
print "bla"
=>print("bla")
मैंने स्केलेर द्वारा बनाए गए निर्णय पेड़ों से नियमों को निकालने के लिए अपना स्वयं का फ़ंक्शन बनाया:
import pandas as pd
import numpy as np
from sklearn.tree import DecisionTreeClassifier
# dummy data:
df = pd.DataFrame({'col1':[0,1,2,3],'col2':[3,4,5,6],'dv':[0,1,0,1]})
# create decision tree
dt = DecisionTreeClassifier(max_depth=5, min_samples_leaf=1)
dt.fit(df.ix[:,:2], df.dv)
यह फ़ंक्शन पहले नोड्स से शुरू होता है (बच्चे के सरणियों में -1 द्वारा पहचाना जाता है) और फिर माता-पिता को पुन: खोजता है। मैं इसे नोड का 'वंश' कहता हूं। रास्ते के साथ, मैं उन मूल्यों को हड़पता हूं जो मुझे बनाने की आवश्यकता है अगर / फिर / अन्यथा एसएएस तर्क:
def get_lineage(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]
# get ids of child nodes
idx = np.argwhere(left == -1)[:,0]
def recurse(left, right, child, lineage=None):
if lineage is None:
lineage = [child]
if child in left:
parent = np.where(left == child)[0].item()
split = 'l'
else:
parent = np.where(right == child)[0].item()
split = 'r'
lineage.append((parent, split, threshold[parent], features[parent]))
if parent == 0:
lineage.reverse()
return lineage
else:
return recurse(left, right, parent, lineage)
for child in idx:
for node in recurse(left, right, child):
print node
नीचे tuples के सेट में सब कुछ है जो मुझे SAS बनाने की ज़रूरत है अगर / फिर / फिर अन्य कथन। मुझे do
एसएएस में ब्लॉक का उपयोग करना पसंद नहीं है यही कारण है कि मैं एक नोड के पूरे पथ का वर्णन करने वाले तर्क बनाता हूं। ट्यूपल्स के बाद एकल पूर्णांक एक पथ में टर्मिनल नोड की आईडी है। पूर्ववर्ती ट्यूपल्स उस नोड को बनाने के लिए गठबंधन करते हैं।
In [1]: get_lineage(dt, df.columns)
(0, 'l', 0.5, 'col1')
1
(0, 'r', 0.5, 'col1')
(2, 'l', 4.5, 'col2')
3
(0, 'r', 0.5, 'col1')
(2, 'r', 4.5, 'col2')
(4, 'l', 2.5, 'col1')
5
(0, 'r', 0.5, 'col1')
(2, 'r', 4.5, 'col2')
(4, 'r', 2.5, 'col1')
6
(0.5, 2.5]
। पेड़ों को पुनरावर्ती विभाजन के साथ बनाया गया है। एक चर को कई बार चयनित होने से रोकने के लिए कुछ भी नहीं है।
मैंने कुछ छद्मकोड मुद्रित करने के लिए ज़ेलज़नी 7 द्वारा प्रस्तुत कोड को संशोधित किया :
def get_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):
if (threshold[node] != -2):
print "if ( " + features[node] + " <= " + str(threshold[node]) + " ) {"
if left[node] != -1:
recurse (left, right, threshold, features,left[node])
print "} else {"
if right[node] != -1:
recurse (left, right, threshold, features,right[node])
print "}"
else:
print "return " + str(value[node])
recurse(left, right, threshold, features, 0)
यदि आप get_code(dt, df.columns)
उसी उदाहरण पर कॉल करते हैं जो आपको प्राप्त होगा:
if ( col1 <= 0.5 ) {
return [[ 1. 0.]]
} else {
if ( col2 <= 4.5 ) {
return [[ 0. 1.]]
} else {
if ( col1 <= 2.5 ) {
return [[ 1. 0.]]
} else {
return [[ 0. 1.]]
}
}
}
(threshold[node] != -2)
है ( left[node] != -1)
(बच्चे के नोड्स की आईडी प्राप्त करने के लिए नीचे दी गई विधि के समान)
स्किकिट सीख ने export_text
एक पेड़ से नियमों को निकालने के लिए संस्करण 0.21 (मई 2019) में एक स्वादिष्ट नई विधि पेश की । यहाँ प्रलेखन । कस्टम फ़ंक्शन बनाने के लिए यह आवश्यक नहीं है।
एक बार जब आप अपना मॉडल फिट कर लेते हैं, तो आपको कोड की दो लाइनें चाहिए। सबसे पहले, आयात export_text
:
from sklearn.tree.export import export_text
दूसरा, एक ऑब्जेक्ट बनाएं जिसमें आपके नियम होंगे। नियमों को अधिक पठनीय बनाने के लिए, feature_names
तर्क का उपयोग करें और अपने फीचर नामों की सूची पास करें। उदाहरण के लिए, यदि आपके मॉडल को कॉल किया जाता है model
और आपकी विशेषताओं को एक डेटाफ़्रेम में नामित किया जाता है X_train
, तो आप नामक एक ऑब्जेक्ट बना सकते हैं tree_rules
:
tree_rules = export_text(model, feature_names=list(X_train))
फिर सिर्फ प्रिंट करें या सेव करें tree_rules
। आपका आउटपुट इस तरह दिखेगा:
|--- Age <= 0.63
| |--- EstimatedSalary <= 0.61
| | |--- Age <= -0.16
| | | |--- class: 0
| | |--- Age > -0.16
| | | |--- EstimatedSalary <= -0.06
| | | | |--- class: 0
| | | |--- EstimatedSalary > -0.06
| | | | |--- EstimatedSalary <= 0.40
| | | | | |--- EstimatedSalary <= 0.03
| | | | | | |--- class: 1
0.18.0 रिलीज में DecisionTreeClassifier
, एक नया तरीका है । डेवलपर्स एक व्यापक (अच्छी तरह से प्रलेखित) वॉकथ्रू प्रदान करते हैं ।decision_path
वॉकथ्रू में कोड का पहला खंड जो पेड़ की संरचना को प्रिंट करता है, ठीक लगता है। हालांकि, मैंने एक नमूने को पूछताछ करने के लिए दूसरे खंड में कोड को संशोधित किया। मेरे परिवर्तन के साथ निरूपित# <--
संपादित करें# <--
नीचे दिए गए कोड में चिह्नित परिवर्तन तब से चलना लिंक में अपडेट किए गए हैं जब त्रुटियों को पुल अनुरोधों # 8653 और # 10951 में इंगित किया गया था । अब साथ चलना बहुत आसान है।
sample_id = 0
node_index = node_indicator.indices[node_indicator.indptr[sample_id]:
node_indicator.indptr[sample_id + 1]]
print('Rules used to predict sample %s: ' % sample_id)
for node_id in node_index:
if leave_id[sample_id] == node_id: # <-- changed != to ==
#continue # <-- comment out
print("leaf node {} reached, no decision here".format(leave_id[sample_id])) # <--
else: # < -- added else to iterate through decision nodes
if (X_test[sample_id, feature[node_id]] <= threshold[node_id]):
threshold_sign = "<="
else:
threshold_sign = ">"
print("decision id node %s : (X[%s, %s] (= %s) %s %s)"
% (node_id,
sample_id,
feature[node_id],
X_test[sample_id, feature[node_id]], # <-- changed i to sample_id
threshold_sign,
threshold[node_id]))
Rules used to predict sample 0:
decision id node 0 : (X[0, 3] (= 2.4) > 0.800000011921)
decision id node 2 : (X[0, 2] (= 5.1) > 4.94999980927)
leaf node 4 reached, no decision here
sample_id
अन्य नमूनों के लिए निर्णय पथ देखने के लिए बदलें । मैंने डेवलपर्स से इन परिवर्तनों के बारे में नहीं पूछा है, उदाहरण के माध्यम से काम करते समय बस अधिक सहज लग रहा था।
from StringIO import StringIO
out = StringIO()
out = tree.export_graphviz(clf, out_file=out)
print out.getvalue()
आप एक डिग ट्री देख सकते हैं। फिर,clf.tree_.feature
और clf.tree_.value
नोड्स विभाजन सुविधा के सरणी और क्रमशः नोड्स मानों के सरणी हैं। आप इस github स्रोत से अधिक विवरणों को संदर्भित कर सकते हैं ।
सिर्फ इसलिए कि हर कोई इतना मददगार था कि मैं सिर्फ ज़ेलज़नी 7 और डेनियल के सुंदर समाधानों में संशोधन करूँगा। यह अजगर 2.7 के लिए है, इसे और अधिक पठनीय बनाने के लिए टैब के साथ:
def get_code(tree, feature_names, tabdepth=0):
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, tabdepth=0):
if (threshold[node] != -2):
print '\t' * tabdepth,
print "if ( " + features[node] + " <= " + str(threshold[node]) + " ) {"
if left[node] != -1:
recurse (left, right, threshold, features,left[node], tabdepth+1)
print '\t' * tabdepth,
print "} else {"
if right[node] != -1:
recurse (left, right, threshold, features,right[node], tabdepth+1)
print '\t' * tabdepth,
print "}"
else:
print '\t' * tabdepth,
print "return " + str(value[node])
recurse(left, right, threshold, features, 0)
नीचे दिए गए कोड एनाकोंडा पायथन 2.7 के तहत मेरा दृष्टिकोण है और निर्णय नियमों के अनुसार एक पीडीएफ फाइल बनाने के लिए एक पैकेज नाम "पीडोट-एनजी" है। मुझे आशा है कि यह उपयोगी है।
from sklearn import tree
clf = tree.DecisionTreeClassifier(max_leaf_nodes=n)
clf_ = clf.fit(X, data_y)
feature_names = X.columns
class_name = clf_.classes_.astype(int).astype(str)
def output_pdf(clf_, name):
from sklearn import tree
from sklearn.externals.six import StringIO
import pydot_ng as pydot
dot_data = StringIO()
tree.export_graphviz(clf_, out_file=dot_data,
feature_names=feature_names,
class_names=class_name,
filled=True, rounded=True,
special_characters=True,
node_ids=1,)
graph = pydot.graph_from_dot_data(dot_data.getvalue())
graph.write_pdf("%s.pdf"%name)
output_pdf(clf_, name='filename%s'%n)
मैं इसके माध्यम से जा रहा हूं, लेकिन मुझे इस प्रारूप में लिखे जाने वाले नियमों की आवश्यकता है
if A>0.4 then if B<0.2 then if C>0.8 then class='X'
इसलिए मैंने @paulkernfeld (धन्यवाद) के उत्तर को अनुकूलित किया, जिसे आप अपनी आवश्यकता के अनुसार अनुकूलित कर सकते हैं
def tree_to_code(tree, feature_names, Y):
tree_ = tree.tree_
feature_name = [
feature_names[i] if i != _tree.TREE_UNDEFINED else "undefined!"
for i in tree_.feature
]
pathto=dict()
global k
k = 0
def recurse(node, depth, parent):
global k
indent = " " * depth
if tree_.feature[node] != _tree.TREE_UNDEFINED:
name = feature_name[node]
threshold = tree_.threshold[node]
s= "{} <= {} ".format( name, threshold, node )
if node == 0:
pathto[node]=s
else:
pathto[node]=pathto[parent]+' & ' +s
recurse(tree_.children_left[node], depth + 1, node)
s="{} > {}".format( name, threshold)
if node == 0:
pathto[node]=s
else:
pathto[node]=pathto[parent]+' & ' +s
recurse(tree_.children_right[node], depth + 1, node)
else:
k=k+1
print(k,')',pathto[parent], tree_.value[node])
recurse(0, 1, 0)
यह @paulkernfeld के उत्तर पर बनाता है। यदि आपके पास अपनी विशेषताओं के साथ एक डेटाफ़्रेम एक्स है और आपके प्रतिसाद के साथ एक लक्ष्य डेटाफ़्रेम वाई है और आप एक विचार प्राप्त करना चाहते हैं कि कौन सा y मान किस नोड में समाप्त हुआ (और तदनुसार इसे प्लॉट करने के लिए चींटी भी) आप निम्नलिखित कर सकते हैं:
def tree_to_code(tree, feature_names):
from sklearn.tree import _tree
codelines = []
codelines.append('def get_cat(X_tmp):\n')
codelines.append(' catout = []\n')
codelines.append(' for codelines in range(0,X_tmp.shape[0]):\n')
codelines.append(' Xin = X_tmp.iloc[codelines]\n')
tree_ = tree.tree_
feature_name = [
feature_names[i] if i != _tree.TREE_UNDEFINED else "undefined!"
for i in tree_.feature
]
#print "def tree({}):".format(", ".join(feature_names))
def recurse(node, depth):
indent = " " * depth
if tree_.feature[node] != _tree.TREE_UNDEFINED:
name = feature_name[node]
threshold = tree_.threshold[node]
codelines.append ('{}if Xin["{}"] <= {}:\n'.format(indent, name, threshold))
recurse(tree_.children_left[node], depth + 1)
codelines.append( '{}else: # if Xin["{}"] > {}\n'.format(indent, name, threshold))
recurse(tree_.children_right[node], depth + 1)
else:
codelines.append( '{}mycat = {}\n'.format(indent, node))
recurse(0, 1)
codelines.append(' catout.append(mycat)\n')
codelines.append(' return pd.DataFrame(catout,index=X_tmp.index,columns=["category"])\n')
codelines.append('node_ids = get_cat(X)\n')
return codelines
mycode = tree_to_code(clf,X.columns.values)
# now execute the function and obtain the dataframe with all nodes
exec(''.join(mycode))
node_ids = [int(x[0]) for x in node_ids.values]
node_ids2 = pd.DataFrame(node_ids)
print('make plot')
import matplotlib.cm as cm
colors = cm.rainbow(np.linspace(0, 1, 1+max( list(set(node_ids)))))
#plt.figure(figsize=cm2inch(24, 21))
for i in list(set(node_ids)):
plt.plot(y[node_ids2.values==i],'o',color=colors[i], label=str(i))
mytitle = ['y colored by node']
plt.title(mytitle ,fontsize=14)
plt.xlabel('my xlabel')
plt.ylabel(tagname)
plt.xticks(rotation=70)
plt.legend(loc='upper center', bbox_to_anchor=(0.5, 1.00), shadow=True, ncol=9)
plt.tight_layout()
plt.show()
plt.close
सबसे सुंदर संस्करण नहीं है, लेकिन यह काम करता है ...
मैंने ज्यूपिटर नोटबुक अजगर 3 में सही ढंग से इंडेंट करने के लिए शीर्ष पसंद किए गए कोड को संशोधित किया है
import numpy as np
from sklearn.tree import _tree
def tree_to_code(tree, feature_names):
tree_ = tree.tree_
feature_name = [feature_names[i]
if i != _tree.TREE_UNDEFINED else "undefined!"
for i in tree_.feature]
print("def tree({}):".format(", ".join(feature_names)))
def recurse(node, depth):
indent = " " * depth
if tree_.feature[node] != _tree.TREE_UNDEFINED:
name = feature_name[node]
threshold = tree_.threshold[node]
print("{}if {} <= {}:".format(indent, name, threshold))
recurse(tree_.children_left[node], depth + 1)
print("{}else: # if {} > {}".format(indent, name, threshold))
recurse(tree_.children_right[node], depth + 1)
else:
print("{}return {}".format(indent, np.argmax(tree_.value[node])))
recurse(0, 1)
यहाँ एक कार्य है, अजगर 3 के तहत एक शिकिट-लर्न डिसीजन ट्री के मुद्रण नियम और संरचना को अधिक पठनीय बनाने के लिए सशर्त ब्लॉकों के लिए ऑफसेट के साथ:
def print_decision_tree(tree, feature_names=None, offset_unit=' '):
'''Plots textual representation of rules of a decision tree
tree: scikit-learn representation of tree
feature_names: list of feature names. They are set to f1,f2,f3,... if not specified
offset_unit: a string of offset of the conditional block'''
left = tree.tree_.children_left
right = tree.tree_.children_right
threshold = tree.tree_.threshold
value = tree.tree_.value
if feature_names is None:
features = ['f%d'%i for i in tree.tree_.feature]
else:
features = [feature_names[i] for i in tree.tree_.feature]
def recurse(left, right, threshold, features, node, depth=0):
offset = offset_unit*depth
if (threshold[node] != -2):
print(offset+"if ( " + features[node] + " <= " + str(threshold[node]) + " ) {")
if left[node] != -1:
recurse (left, right, threshold, features,left[node],depth+1)
print(offset+"} else {")
if right[node] != -1:
recurse (left, right, threshold, features,right[node],depth+1)
print(offset+"}")
else:
print(offset+"return " + str(value[node]))
recurse(left, right, threshold, features, 0,0)
आप इसे और अधिक जानकारीपूर्ण बना सकते हैं ताकि यह पता चले कि यह किस वर्ग का है या इसके उत्पादन मूल्य का उल्लेख करके भी।
def print_decision_tree(tree, feature_names, offset_unit=' '):
left = tree.tree_.children_left
right = tree.tree_.children_right
threshold = tree.tree_.threshold
value = tree.tree_.value
if feature_names is None:
features = ['f%d'%i for i in tree.tree_.feature]
else:
features = [feature_names[i] for i in tree.tree_.feature]
def recurse(left, right, threshold, features, node, depth=0):
offset = offset_unit*depth
if (threshold[node] != -2):
print(offset+"if ( " + features[node] + " <= " + str(threshold[node]) + " ) {")
if left[node] != -1:
recurse (left, right, threshold, features,left[node],depth+1)
print(offset+"} else {")
if right[node] != -1:
recurse (left, right, threshold, features,right[node],depth+1)
print(offset+"}")
else:
#print(offset,value[node])
#To remove values from node
temp=str(value[node])
mid=len(temp)//2
tempx=[]
tempy=[]
cnt=0
for i in temp:
if cnt<=mid:
tempx.append(i)
cnt+=1
else:
tempy.append(i)
cnt+=1
val_yes=[]
val_no=[]
res=[]
for j in tempx:
if j=="[" or j=="]" or j=="." or j==" ":
res.append(j)
else:
val_no.append(j)
for j in tempy:
if j=="[" or j=="]" or j=="." or j==" ":
res.append(j)
else:
val_yes.append(j)
val_yes = int("".join(map(str, val_yes)))
val_no = int("".join(map(str, val_no)))
if val_yes>val_no:
print(offset,'\033[1m',"YES")
print('\033[0m')
elif val_no>val_yes:
print(offset,'\033[1m',"NO")
print('\033[0m')
else:
print(offset,'\033[1m',"Tie")
print('\033[0m')
recurse(left, right, threshold, features, 0,0)
यहां निर्णय नियमों को एक ऐसे रूप में निकालने का मेरा तरीका है जो सीधे sql में उपयोग किया जा सकता है, इसलिए डेटा को नोड द्वारा समूहीकृत किया जा सकता है। (पिछले पोस्टर के दृष्टिकोण के आधार पर।)
इसका परिणाम बाद के CASE
क्लॉज़ होंगे जिन्हें एक sql स्टेटमेंट में कॉपी किया जा सकता है, उदा।
SELECT COALESCE(*CASE WHEN <conditions> THEN > <NodeA>*, > *CASE WHEN
<conditions> THEN <NodeB>*, > ....)NodeName,* > FROM <table or view>
import numpy as np
import pickle
feature_names=.............
features = [feature_names[i] for i in range(len(feature_names))]
clf= pickle.loads(trained_model)
impurity=clf.tree_.impurity
importances = clf.feature_importances_
SqlOut=""
#global Conts
global ContsNode
global Path
#Conts=[]#
ContsNode=[]
Path=[]
global Results
Results=[]
def print_decision_tree(tree, feature_names, offset_unit='' ''):
left = tree.tree_.children_left
right = tree.tree_.children_right
threshold = tree.tree_.threshold
value = tree.tree_.value
if feature_names is None:
features = [''f%d''%i for i in tree.tree_.feature]
else:
features = [feature_names[i] for i in tree.tree_.feature]
def recurse(left, right, threshold, features, node, depth=0,ParentNode=0,IsElse=0):
global Conts
global ContsNode
global Path
global Results
global LeftParents
LeftParents=[]
global RightParents
RightParents=[]
for i in range(len(left)): # This is just to tell you how to create a list.
LeftParents.append(-1)
RightParents.append(-1)
ContsNode.append("")
Path.append("")
for i in range(len(left)): # i is node
if (left[i]==-1 and right[i]==-1):
if LeftParents[i]>=0:
if Path[LeftParents[i]]>" ":
Path[i]=Path[LeftParents[i]]+" AND " +ContsNode[LeftParents[i]]
else:
Path[i]=ContsNode[LeftParents[i]]
if RightParents[i]>=0:
if Path[RightParents[i]]>" ":
Path[i]=Path[RightParents[i]]+" AND not " +ContsNode[RightParents[i]]
else:
Path[i]=" not " +ContsNode[RightParents[i]]
Results.append(" case when " +Path[i]+" then ''" +"{:4d}".format(i)+ " "+"{:2.2f}".format(impurity[i])+" "+Path[i][0:180]+"''")
else:
if LeftParents[i]>=0:
if Path[LeftParents[i]]>" ":
Path[i]=Path[LeftParents[i]]+" AND " +ContsNode[LeftParents[i]]
else:
Path[i]=ContsNode[LeftParents[i]]
if RightParents[i]>=0:
if Path[RightParents[i]]>" ":
Path[i]=Path[RightParents[i]]+" AND not " +ContsNode[RightParents[i]]
else:
Path[i]=" not "+ContsNode[RightParents[i]]
if (left[i]!=-1):
LeftParents[left[i]]=i
if (right[i]!=-1):
RightParents[right[i]]=i
ContsNode[i]= "( "+ features[i] + " <= " + str(threshold[i]) + " ) "
recurse(left, right, threshold, features, 0,0,0,0)
print_decision_tree(clf,features)
SqlOut=""
for i in range(len(Results)):
SqlOut=SqlOut+Results[i]+ " end,"+chr(13)+chr(10)
अब आप export_text का उपयोग कर सकते हैं।
from sklearn.tree import export_text
r = export_text(loan_tree, feature_names=(list(X_train.columns)))
print(r)
[Sklearn] [1] से एक पूर्ण उदाहरण
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_text
iris = load_iris()
X = iris['data']
y = iris['target']
decision_tree = DecisionTreeClassifier(random_state=0, max_depth=2)
decision_tree = decision_tree.fit(X, y)
r = export_text(decision_tree, feature_names=iris['feature_names'])
print(r)
निर्णय पेड़ से एसक्यूएल लाने के लिए संशोधित ज़ेलज़नी 7 का कोड।
# SQL from decision tree
def get_lineage(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]
le='<='
g ='>'
# get ids of child nodes
idx = np.argwhere(left == -1)[:,0]
def recurse(left, right, child, lineage=None):
if lineage is None:
lineage = [child]
if child in left:
parent = np.where(left == child)[0].item()
split = 'l'
else:
parent = np.where(right == child)[0].item()
split = 'r'
lineage.append((parent, split, threshold[parent], features[parent]))
if parent == 0:
lineage.reverse()
return lineage
else:
return recurse(left, right, parent, lineage)
print 'case '
for j,child in enumerate(idx):
clause=' when '
for node in recurse(left, right, child):
if len(str(node))<3:
continue
i=node
if i[1]=='l': sign=le
else: sign=g
clause=clause+i[3]+sign+str(i[2])+' and '
clause=clause[:-4]+' then '+str(j)
print clause
print 'else 99 end as clusters'
जाहिरा तौर पर एक लंबे समय से पहले ही किसी ने आधिकारिक स्किकट के पेड़ निर्यात कार्यों के लिए निम्नलिखित फ़ंक्शन को जोड़ने का प्रयास करने का फैसला किया (जो मूल रूप से केवल export_graphviz का समर्थन करता है)
def export_dict(tree, feature_names=None, max_depth=None) :
"""Export a decision tree in dict format.
यहाँ उसकी पूरी प्रतिबद्धता है:
निश्चित रूप से निश्चित नहीं है कि इस टिप्पणी का क्या हुआ। लेकिन आप उस फ़ंक्शन का उपयोग करने का प्रयास भी कर सकते हैं।
मुझे लगता है कि यह वारंट scikit के अच्छे लोगों के लिए एक गंभीर दस्तावेजीकरण का अनुरोध- sklearn.tree.Tree
एपीआई को ठीक से दस्तावेज करने के लिए सीखता है जो कि अंतर्निहित पेड़ संरचना है जो DecisionTreeClassifier
इसकी विशेषता के रूप में उजागर करता है tree_
।
बस इस तरह से sklearn.tree से फ़ंक्शन का उपयोग करें
from sklearn.tree import export_graphviz
export_graphviz(tree,
out_file = "tree.dot",
feature_names = tree.columns) //or just ["petal length", "petal width"]
और फिर फ़ाइल ट्री.डॉट के लिए अपने प्रोजेक्ट फ़ोल्डर में देखें , सभी सामग्री को कॉपी करें और इसे यहां पेस्ट करें http://www.webgraphviz.com/ और अपना ग्राफ बनाएं :)
@Paulkerfeld के अद्भुत समाधान के लिए धन्यवाद। उनके समाधान के शीर्ष पर, के लिए उन सभी जो पेड़ों की एक धारावाहिक संस्करण करना चाहते हैं, तो बस का उपयोग tree.threshold
, tree.children_left
, tree.children_right
, tree.feature
और tree.value
। के बाद से पत्ते विभाजन की जरूरत नहीं है और इसलिए कोई नाम और बच्चों में अपने प्लेसहोल्डर सुविधा tree.feature
और tree.children_***
कर रहे हैं _tree.TREE_UNDEFINED
और _tree.TREE_LEAF
। हर विभाजन को एक अद्वितीय सूचकांक द्वारा निर्दिष्ट किया जाता है depth first search
।
ध्यान दें कि tree.value
आकार का है[n, 1, 1]
यहाँ एक फ़ंक्शन है जो एक आउटपुट ट्री से पायथन कोड उत्पन्न करता है export_text
:
import string
from sklearn.tree import export_text
def export_py_code(tree, feature_names, max_depth=100, spacing=4):
if spacing < 2:
raise ValueError('spacing must be > 1')
# Clean up feature names (for correctness)
nums = string.digits
alnums = string.ascii_letters + nums
clean = lambda s: ''.join(c if c in alnums else '_' for c in s)
features = [clean(x) for x in feature_names]
features = ['_'+x if x[0] in nums else x for x in features if x]
if len(set(features)) != len(feature_names):
raise ValueError('invalid feature names')
# First: export tree to text
res = export_text(tree, feature_names=features,
max_depth=max_depth,
decimals=6,
spacing=spacing-1)
# Second: generate Python code from the text
skip, dash = ' '*spacing, '-'*(spacing-1)
code = 'def decision_tree({}):\n'.format(', '.join(features))
for line in repr(tree).split('\n'):
code += skip + "# " + line + '\n'
for line in res.split('\n'):
line = line.rstrip().replace('|',' ')
if '<' in line or '>' in line:
line, val = line.rsplit(maxsplit=1)
line = line.replace(' ' + dash, 'if')
line = '{} {:g}:'.format(line, float(val))
else:
line = line.replace(' {} class:'.format(dash), 'return')
code += skip + line + '\n'
return code
नमूना उपयोग:
res = export_py_code(tree, feature_names=names, spacing=4)
print (res)
नमूना उत्पादन:
def decision_tree(f1, f2, f3):
# DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=3,
# max_features=None, max_leaf_nodes=None,
# min_impurity_decrease=0.0, min_impurity_split=None,
# min_samples_leaf=1, min_samples_split=2,
# min_weight_fraction_leaf=0.0, presort=False,
# random_state=42, splitter='best')
if f1 <= 12.5:
if f2 <= 17.5:
if f1 <= 10.5:
return 2
if f1 > 10.5:
return 3
if f2 > 17.5:
if f2 <= 22.5:
return 1
if f2 > 22.5:
return 1
if f1 > 12.5:
if f1 <= 17.5:
if f3 <= 23.5:
return 2
if f3 > 23.5:
return 3
if f1 > 17.5:
if f1 <= 25:
return 1
if f1 > 25:
return 2
उपरोक्त उदाहरण के साथ उत्पन्न होता है names = ['f'+str(j+1) for j in range(NUM_FEATURES)]
।
एक उपयोगी विशेषता यह है कि यह कम रिक्ति के साथ छोटे फ़ाइल आकार उत्पन्न कर सकता है। बस सेट spacing=2
।