বিজ্ঞান-শিখার সিদ্ধান্ত-বৃক্ষ থেকে কীভাবে সিদ্ধান্তের বিধি নিষেধ করবেন?


156

আমি কি পাঠ্য তালিকায় প্রশিক্ষণপ্রাপ্ত গাছ থেকে অন্তর্নিহিত সিদ্ধান্ত-বিধিগুলি (বা 'সিদ্ধান্তের পথগুলি) আহরণ করতে পারি?

কিছুটা এইরকম:

if A>0.4 then if B<0.2 then if C>0.8 then class='X'

আপনার সাহায্যের জন্য ধন্যবাদ.



আপনি কি কখনও এই সমস্যার উত্তর খুঁজে পেয়েছেন? আমাকে সিদ্ধান্তের গাছের নিয়মগুলি এসএএস ডেটা স্টেপ ফর্ম্যাটে রফতানি করতে হবে যা আপনার তালিকাভুক্ত হিসাবে প্রায় ঠিক আছে।
জেলাজনি

1
আপনি সি, জাভা, জাভাস্ক্রিপ্ট এবং অন্যান্যগুলিতে সিদ্ধান্ত গাছগুলি (এলোমেলো বন এবং উত্সাহিত গাছগুলি) রফতানি এবং স্থানান্তর করতে প্যাকেজ স্কেলার্ন-পোর্টার ব্যবহার করতে পারেন ।
দারিয়াস

আপনি এই লিঙ্কটি চেক করতে পারেন- kdnuggets.com/2017/05/…
যোগেশ অগ্রবাল

উত্তর:


138

আমি বিশ্বাস করি যে এখানে উত্তরগুলির তুলনায় এই উত্তরটি আরও সঠিক:

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

এখানে কয়েকটি হোঁচট খাচ্ছি যা আমি অন্যান্য উত্তরে দেখছি:

  1. tree_.threshold == -2নোড একটি পাতা কিনা তা সিদ্ধান্ত নিতে ব্যবহার করা ভাল ধারণা নয়। যদি এটি -2 এর দ্বার সহ একটি বাস্তব সিদ্ধান্ত নোড হয়? পরিবর্তে, আপনি tree.featureবা তাকানো উচিত tree.children_*
  2. features = [feature_names[i] for i in tree_.feature]আমার স্কলারনের সংস্করণটির সাথে লাইনটি ক্র্যাশ করেছে, কারণ কিছু মান tree.tree_.feature-2 (বিশেষত পাতার নোডের জন্য)।
  3. পুনরাবৃত্তি ফাংশনে স্টেটমেন্ট থাকলে একাধিক থাকার দরকার নেই, কেবল একটি ঠিক আছে।

1
এই কোডটি আমার পক্ষে দুর্দান্ত কাজ করে। তবে, আমার কাছে 500+ বৈশিষ্ট্য_নাম রয়েছে তাই কোনও মানুষের পক্ষে আউটপুট কোডটি প্রায় অসম্ভব বুঝতে পারা যায়। ফাংশনটি সম্পর্কে আমি আগ্রহী এমন বৈশিষ্ট্য_নামগুলিকে কেবল ইনপুট করার কোনও উপায় আছে কি?
ব্যবহারকারী 3768495

1
আমি আগের মন্তব্যে একমত ক্লাস সূচকটি ফেরত print "{}return {}".format(indent, tree_.value[node])দেওয়ার print "{}return {}".format(indent, np.argmax(tree_.value[node][0]))জন্য ফাংশনটির জন্য আইআইইউসি-তে পরিবর্তন করা উচিত ।
স্যুপোল্ট

1
@ পলকর্নফিল্ড আহা হ্যাঁ, আমি দেখতে পাচ্ছি যে আপনি লুপ করতে পারেন RandomForestClassifier.estimators_তবে অনুমানকারীদের ফলাফলগুলি কীভাবে একত্রিত করবেন তা সম্পর্কে আমি কাজ করতে সক্ষম হইনি।
নাথান লয়েড

6
অজগর 3 এ আমি এই কাজটি পেতে পারি না, _ বিট বিটগুলি তারা কখনও কাজ করবে বলে মনে হয় না এবং TREE_UNDEFINED সংজ্ঞায়িত হয় না। এই লিঙ্কটি আমাকে সাহায্য করেছিল। যদিও রফতানীর কোডটি অজগরটিতে সরাসরি চালিত হয় না, এটি সি-লাইক এবং অন্যান্য ভাষায় অনুবাদ করা বেশ সহজ: ওয়েব.আরচিভ.আর.ইউবি
জোশিয়ার

1
@ জোসিয়াহ, অজগর 3 এ কাজ করতে মুদ্রণ বিবৃতিগুলিতে () যুক্ত করুন। যেমন print "bla"=>print("bla")
নীড়

48

স্কলার দ্বারা নির্মিত সিদ্ধান্ত গাছগুলি থেকে নিয়মগুলি বের করার জন্য আমি আমার নিজস্ব ফাংশন তৈরি করেছি:

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

নীচে টিপলসগুলির সেটগুলিতে আমার / তারপরে / অন্য বিবৃতিগুলি এসএএস তৈরি করার জন্য প্রয়োজনীয় সমস্ত কিছু ধারণ করে। আমি 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

উদাহরণস্বরূপ গাছের গ্রাফভিজ আউটপুট


এই ধরণের গাছটি সঠিক কারণ কোল 1 আবার আসছে আবার একটি কল 1 <= 0.50000 এবং একটি কোল 1 <= 2.5000 হ্যাঁ, লাইব্রেরিতে এই জাতীয় ধরণের পুনরাবৃত্তি হ'ল
জয়ন্ত সিংহ

ডান শাখার মধ্যে রেকর্ড থাকবে (0.5, 2.5]। গাছগুলি পুনরাবৃত্ত বিভাজন দিয়ে তৈরি করা হয়। কোনও পরিবর্তনশীল একাধিকবার নির্বাচিত হতে বাধা দেওয়ার কিছুই নেই nothing
জেলাজেনি 7

ঠিক আছে আপনি কি পুনরাবৃত্তির অংশটি ব্যাখ্যা করতে পারবেন যা ঘটেছিল কারণ আমার কোডটিতে এটি ব্যবহার করেছি এবং একই রকম ফলাফল দেখা যায়
জয়ন্ত সিংহ

38

আমি জেলাজনি by দ্বারা জমা দেওয়া কোডটি কিছু সিউডোকোড মুদ্রণের জন্য সংশোধন করেছি :

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.]]
}
}
}

1
আপনি কি বলতে পারেন, রিটার্ন স্টেটমেন্টের ঠিক [[1. 0.]] এর অর্থ উপরের আউটপুটটিতে কী বোঝায়। আমি পাইথন লোক নই, তবে একই ধরণের জিনিস নিয়ে কাজ করছি। সুতরাং দয়া করে কিছু বিবরণ প্রমাণ করলে আমার পক্ষে ভাল হবে যাতে এটি আমার পক্ষে সহজতর হয়।
সুব্রদীপ বোস

1
@ user3156186 এর অর্থ হ'ল ক্লাস '0' এর মধ্যে একটি বস্তু আছে এবং '1' শ্রেণিতে শূন্য বস্তু রয়েছে
ড্যানিয়েল

1
@ ড্যানিয়েল, আপনি কি জানেন যে ক্লাসগুলি অর্ডার করা হয় কীভাবে? আমি বর্ণানুক্রমিক অনুমান করব, কিন্তু আমি কোথাও নিশ্চিতকরণ পাইনি।
ইয়ানস

ধন্যবাদ! প্রান্ত কেস দৃশ্যকল্প যেখানে থ্রেশহোল্ড মান আসলে জন্য -2, আমরা পরিবর্তন করার প্রয়োজন হতে পারে (threshold[node] != -2)জন্য ( left[node] != -1)(শিশু নোড আইডি পাবার জন্য নিচের পদ্ধতি মতো)
tlingf

@ ড্যানিয়েল, কীভাবে আপনার ফাংশনটিকে "get_code" "রিটার্ন" করতে একটি মান তৈরি করতে হবে এবং এটি "মুদ্রণ" নয়, কারণ আমাকে এটি অন্য ফাংশনে প্রেরণ করা দরকার?
রায়উমআইএক্স

17

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

14

একটি নতুন নেই DecisionTreeClassifierপদ্ধতি, decision_pathএ, 0.18.0 মুক্তি। বিকাশকারীরা একটি বিস্তৃত (ভালভাবে ডকুমেন্টেড) ওয়াকথ্রু সরবরাহ করে

ওয়াকথ্রুতে কোডের প্রথম বিভাগ যা গাছের কাঠামো মুদ্রণ করে তা ঠিক আছে বলে মনে হচ্ছে। তবে আমি একটি নমুনা জিজ্ঞাসাবাদ করতে দ্বিতীয় বিভাগে কোডটি সংশোধন করেছি। আমার পরিবর্তনগুলি এর সাথে চিহ্নিত# <--

সম্পাদনা# <-- নীচের কোডে চিহ্নিত চিহ্নিত পরিবর্তনগুলি ওয়াকথ্রু লিঙ্কে আপডেট হয়েছে ততক্ষণে ভুলগুলি টানতে অনুরোধ করার পরে # 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অন্যান্য নমুনাগুলির সিদ্ধান্তের পথগুলি দেখতে পরিবর্তন করুন । আমি এই পরিবর্তনগুলি সম্পর্কে বিকাশকারীদের জিজ্ঞাসা করি নি, উদাহরণের মাধ্যমে কাজ করার সময় আরও স্বজ্ঞাত বলে মনে হয়েছিল।


আপনি আমার বন্ধু একটি কিংবদন্তি! কোনও নির্দিষ্ট ধারণা কীভাবে সেই নির্দিষ্ট নমুনার জন্য সিদ্ধান্ত গাছকে প্লট করবেন? অনেক সাহায্যের প্রশংসা করা হয়েছে

1
ধন্যবাদ ভিক্টর, এটিকে পৃথক প্রশ্ন হিসাবে জিজ্ঞাসা করা ভাল, যেহেতু চক্রান্তের প্রয়োজনীয়তা কোনও ব্যবহারকারীর প্রয়োজনের সাথে নির্দিষ্ট হতে পারে। আপনি যদি আউটপুটটি দেখতে চান এমন ধারণা সরবরাহ করেন তবে আপনি সম্ভবত একটি ভাল প্রতিক্রিয়া পাবেন।
কেভিন

হেই কেভিন, আমি প্রশ্ন নির্মিত stackoverflow.com/questions/48888893/...

: আপনি এখন কটাক্ষপাত করা প্রতি সদয় হবে stackoverflow.com/questions/52654280/...
আলেকজান্ডার Chervov

আপনি দয়া করে নোড_ইনডেক্স নামক অংশটি ব্যাখ্যা করতে পারেন, সেই অংশটি পাচ্ছেন না। এটার কাজ কি?
অনিন্দ্য শঙ্কর দে

12
from StringIO import StringIO
out = StringIO()
out = tree.export_graphviz(clf, out_file=out)
print out.getvalue()

আপনি একটি ডিগ্রাফ গাছ দেখতে পাবেন। তারপরে clf.tree_.featureএবং clf.tree_.valueনোডগুলির বিভাজনকারী বৈশিষ্ট্য এবং যথাক্রমে নোডের মানগুলির অ্যারে হয়। আপনি এই গিথুব উত্স থেকে আরও বিশদ উল্লেখ করতে পারেন ।


1
হ্যাঁ, আমি কীভাবে গাছ আঁকতে জানি - তবে আমার আরও পাঠ্য সংস্করণ প্রয়োজন - নিয়ম। এর মতো কিছু: কমলা.বিওল্যাব.সি
হিলম্যান

4

সবাই এতটা সহায়ক ছিল বলেই আমি কেবল জেলাজনি 7 এবং ড্যানিয়েলের সুন্দর সমাধানগুলিতে একটি পরিবর্তন যুক্ত করব। এটি আরও অধ্যয়নযোগ্য করার জন্য ট্যাবগুলি সহ পাইথন ২.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)

3

নীচের কোডগুলি অ্যানাকোন্ডা পাইথন ২.7 এর অধীনে সিদ্ধান্তের বিধিগুলির সাথে পিডিএফ ফাইল তৈরির জন্য একটি প্যাকেজ নাম "পাইডোট-এনজি" এর অধীনে approach আমি এটা সহায়ক আশা করি।

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)

একটি গাছের গ্রাফি শো এখানে


3

আমি এর মধ্যে দিয়ে যাচ্ছি, তবে এই ফর্ম্যাটটিতে আমার নিয়মগুলি লেখার দরকার ছিল

if A>0.4 then if B<0.2 then if C>0.8 then class='X' 

সুতরাং আমি @ পলকর্নফিল্ডের উত্তরটিকে (অভিবাদন) অভিযোজিত করেছি যা আপনি নিজের প্রয়োজন অনুসারে কাস্টমাইজ করতে পারেন

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)

3

এসকেম্পাইলার লাইব্রেরি ব্যবহার করে পুরো গাছটিকে একটি একক (অগত্যা খুব বেশি মানব-পঠনযোগ্য নয়) পাইথন এক্সপ্রেশনটিতে অনুবাদ করার একটি উপায় এখানে রয়েছে :

from skompiler import skompile
skompile(dtree.predict).to('python/code')

3

এটি @ পলকর্নফিল্ডের উত্তরে তৈরি হয়েছে। আপনার বৈশিষ্ট্যগুলির সাথে ডেটাফ্রেম এক্স এবং আপনার অনুরণনগুলির সাথে একটি টার্গেট ডেটাফ্রেম 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 

সবচেয়ে মার্জিত সংস্করণ নয় তবে এটি কাজটি করে ...


1
আপনি যখন লাইনগুলি কেবল মুদ্রণের পরিবর্তে ফিরিয়ে দিতে চান তখন এটি ভাল পদ্ধতির।
হাজার হোমায়ৌনি

3

এটি আপনার প্রয়োজন কোড

আমি একটি বৃহত্তর নোটবুক পাইথন 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)

2

অজগর 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)

2

আপনি এটি কোন শ্রেণীর অন্তর্ভুক্ত বা এটির আউটপুট মান উল্লেখ করে এটি আলাদা করেও এটিকে আরও তথ্যপূর্ণ করতে পারেন।

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)

এখানে চিত্র বর্ণনা লিখুন


2

সিদ্ধান্তের নিয়মগুলি এমন ফর্মটিতে প্রত্যক্ষ করার জন্য আমার পদ্ধতির জন্য যা সরাসরি স্কুএলে ব্যবহার করা যেতে পারে, সুতরাং নোড দ্বারা ডেটাগুলি গোষ্ঠীভুক্ত করা যেতে পারে। (পূর্ববর্তী পোস্টারগুলির পদ্ধতির উপর ভিত্তি করে))

ফলস্বরূপ পরবর্তী CASEক্লজগুলি হবে যা একটি স্কিল বিবৃতিতে অনুলিপি করা যেতে পারে, প্রাক্তন।

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)

1

এখন আপনি এক্সপোর্ট_টেক্সট ব্যবহার করতে পারেন।

from sklearn.tree import export_text

r = export_text(loan_tree, feature_names=(list(X_train.columns)))
print(r)

[স্কলারন] [১] এর সম্পূর্ণ উদাহরণ

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)

0

সিদ্ধান্ত গাছ থেকে এসকিউএল আনার জন্য জেলাজেনি 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'

0

স্পষ্টতই দীর্ঘদিন আগে কেউ সরকারী বিজ্ঞানের গাছের রফতানি কার্যক্রমে (যা মূলত কেবল এক্সপোর্ট_গ্রাভিজকে সমর্থন করে) নিম্নলিখিত ফাংশনটি যুক্ত করার চেষ্টা করার সিদ্ধান্ত নিয়েছে decided

def export_dict(tree, feature_names=None, max_depth=None) :
    """Export a decision tree in dict format.

এখানে তাঁর পূর্ণ প্রতিশ্রুতি রইল:

https://github.com/scikit-learn/scikit-learn/blob/79bdc8f711d0af225ed6be9fdb708cea9f98a910/sklearn/tree/export.py

এই মন্তব্যে কী ঘটেছিল তা ঠিক নিশ্চিত নয়। তবে আপনি এই ফাংশনটি ব্যবহার করার চেষ্টাও করতে পারেন।

আমি মনে করি এই বিজ্ঞান বিজ্ঞানের পক্ষে ভাল লোকদের কাছে গুরুতর ডকুমেন্টেশন অনুরোধের অনুরোধ জানায় - sklearn.tree.Treeএপিআই সঠিকভাবে ডকুমেন্ট করতে শিখায় যা অন্তর্নিহিত গাছ কাঠামো যা DecisionTreeClassifierএর বৈশিষ্ট্য হিসাবে প্রকাশ করে tree_


0

এই জাতীয় 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.webographicviz.com/ পেস্ট করুন এবং আপনার গ্রাফ তৈরি করুন :)


0

@ পলকারফিল্ডের দুর্দান্ত সমাধানের জন্য ধন্যবাদ। তার সমাধান উপরে, সমস্ত যারা গাছ একটি ধারাবাহিকভাবে সংস্করণ আছে করতে চাই, শুধু ব্যবহার 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]


0

এখানে একটি ফাংশন যা এর ফলাফলকে রূপান্তর করে সিদ্ধান্ত গাছ থেকে পাইথন কোড উত্পন্ন করে 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

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.