Advertisement
glavinova

[СНЗ] Дрва на одлука

Jul 5th, 2020
1,052
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 18.17 KB | None | 0 0
  1. """Дрва на одлука Problem 1 (2 / 2)
  2. Изградете 2 дрва на одлука. Едното дрво на одлука ќе ја користи првата половина од податочното множество, а другото дрво, втората половина. Доколку двете дрва на одлука на тест примерот го дадат истиот резултат, да се испечати тој резултат. Доколку дадат различен резултат, да се испечати KONTRADIKCIJA. Доколку некое од дрвата има само една класа тогаш се предвидува истата, но ако има повеќе од една треба да се избере таа со најголем број на инстанци. Ако во листот има неколку класи со ист број на инстанци да се предвиде првата класа по азбучен ред."""
  3.  
  4.  
  5.  
  6. from math import log
  7. trainingData = [
  8.     [6.3, 2.9, 5.6, 1.8, 'I. virginica'],
  9.     [6.5, 3.0, 5.8, 2.2, 'I. virginica'],
  10.     [7.6, 3.0, 6.6, 2.1, 'I. virginica'],
  11.     [4.9, 2.5, 4.5, 1.7, 'I. virginica'],
  12.     [7.3, 2.9, 6.3, 1.8, 'I. virginica'],
  13.     [6.7, 2.5, 5.8, 1.8, 'I. virginica'],
  14.     [7.2, 3.6, 6.1, 2.5, 'I. virginica'],
  15.     [6.5, 3.2, 5.1, 2.0, 'I. virginica'],
  16.     [6.4, 2.7, 5.3, 1.9, 'I. virginica'],
  17.     [6.8, 3.0, 5.5, 2.1, 'I. virginica'],
  18.     [5.7, 2.5, 5.0, 2.0, 'I. virginica'],
  19.     [5.8, 2.8, 5.1, 2.4, 'I. virginica'],
  20.     [6.4, 3.2, 5.3, 2.3, 'I. virginica'],
  21.     [6.5, 3.0, 5.5, 1.8, 'I. virginica'],
  22.     [7.7, 3.8, 6.7, 2.2, 'I. virginica'],
  23.     [7.7, 2.6, 6.9, 2.3, 'I. virginica'],
  24.     [6.0, 2.2, 5.0, 1.5, 'I. virginica'],
  25.     [6.9, 3.2, 5.7, 2.3, 'I. virginica'],
  26.     [5.6, 2.8, 4.9, 2.0, 'I. virginica'],
  27.     [7.7, 2.8, 6.7, 2.0, 'I. virginica'],
  28.     [6.3, 2.7, 4.9, 1.8, 'I. virginica'],
  29.     [6.7, 3.3, 5.7, 2.1, 'I. virginica'],
  30.     [7.2, 3.2, 6.0, 1.8, 'I. virginica'],
  31.     [6.2, 2.8, 4.8, 1.8, 'I. virginica'],
  32.     [6.1, 3.0, 4.9, 1.8, 'I. virginica'],
  33.     [6.4, 2.8, 5.6, 2.1, 'I. virginica'],
  34.     [7.2, 3.0, 5.8, 1.6, 'I. virginica'],
  35.     [7.4, 2.8, 6.1, 1.9, 'I. virginica'],
  36.     [7.9, 3.8, 6.4, 2.0, 'I. virginica'],
  37.     [6.4, 2.8, 5.6, 2.2, 'I. virginica'],
  38.     [6.3, 2.8, 5.1, 1.5, 'I. virginica'],
  39.     [6.1, 2.6, 5.6, 1.4, 'I. virginica'],
  40.     [7.7, 3.0, 6.1, 2.3, 'I. virginica'],
  41.     [6.3, 3.4, 5.6, 2.4, 'I. virginica'],
  42.     [5.1, 3.5, 1.4, 0.2, 'I. setosa'],
  43.     [4.9, 3.0, 1.4, 0.2, 'I. setosa'],
  44.     [4.7, 3.2, 1.3, 0.2, 'I. setosa'],
  45.     [4.6, 3.1, 1.5, 0.2, 'I. setosa'],
  46.     [5.0, 3.6, 1.4, 0.2, 'I. setosa'],
  47.     [5.4, 3.9, 1.7, 0.4, 'I. setosa'],
  48.     [4.6, 3.4, 1.4, 0.3, 'I. setosa'],
  49.     [5.0, 3.4, 1.5, 0.2, 'I. setosa'],
  50.     [4.4, 2.9, 1.4, 0.2, 'I. setosa'],
  51.     [4.9, 3.1, 1.5, 0.1, 'I. setosa'],
  52.     [5.4, 3.7, 1.5, 0.2, 'I. setosa'],
  53.     [4.8, 3.4, 1.6, 0.2, 'I. setosa'],
  54.     [4.8, 3.0, 1.4, 0.1, 'I. setosa'],
  55.     [4.3, 3.0, 1.1, 0.1, 'I. setosa'],
  56.     [5.8, 4.0, 1.2, 0.2, 'I. setosa'],
  57.     [5.7, 4.4, 1.5, 0.4, 'I. setosa'],
  58.     [5.4, 3.9, 1.3, 0.4, 'I. setosa'],
  59.     [5.1, 3.5, 1.4, 0.3, 'I. setosa'],
  60.     [5.7, 3.8, 1.7, 0.3, 'I. setosa'],
  61.     [5.1, 3.8, 1.5, 0.3, 'I. setosa'],
  62.     [5.4, 3.4, 1.7, 0.2, 'I. setosa'],
  63.     [5.1, 3.7, 1.5, 0.4, 'I. setosa'],
  64.     [4.6, 3.6, 1.0, 0.2, 'I. setosa'],
  65.     [5.1, 3.3, 1.7, 0.5, 'I. setosa'],
  66.     [4.8, 3.4, 1.9, 0.2, 'I. setosa'],
  67.     [5.0, 3.0, 1.6, 0.2, 'I. setosa'],
  68.     [5.0, 3.4, 1.6, 0.4, 'I. setosa'],
  69.     [5.2, 3.5, 1.5, 0.2, 'I. setosa'],
  70.     [5.2, 3.4, 1.4, 0.2, 'I. setosa'],
  71.     [5.5, 2.3, 4.0, 1.3, 'I. versicolor'],
  72.     [6.5, 2.8, 4.6, 1.5, 'I. versicolor'],
  73.     [5.7, 2.8, 4.5, 1.3, 'I. versicolor'],
  74.     [6.3, 3.3, 4.7, 1.6, 'I. versicolor'],
  75.     [4.9, 2.4, 3.3, 1.0, 'I. versicolor'],
  76.     [6.6, 2.9, 4.6, 1.3, 'I. versicolor'],
  77.     [5.2, 2.7, 3.9, 1.4, 'I. versicolor'],
  78.     [5.0, 2.0, 3.5, 1.0, 'I. versicolor'],
  79.     [5.9, 3.0, 4.2, 1.5, 'I. versicolor'],
  80.     [6.0, 2.2, 4.0, 1.0, 'I. versicolor'],
  81.     [6.1, 2.9, 4.7, 1.4, 'I. versicolor'],
  82.     [5.6, 2.9, 3.6, 1.3, 'I. versicolor'],
  83.     [6.7, 3.1, 4.4, 1.4, 'I. versicolor'],
  84.     [5.6, 3.0, 4.5, 1.5, 'I. versicolor'],
  85.     [5.8, 2.7, 4.1, 1.0, 'I. versicolor'],
  86.     [6.2, 2.2, 4.5, 1.5, 'I. versicolor'],
  87.     [5.6, 2.5, 3.9, 1.1, 'I. versicolor'],
  88.     [5.9, 3.2, 4.8, 1.8, 'I. versicolor'],
  89.     [6.1, 2.8, 4.0, 1.3, 'I. versicolor'],
  90.     [6.3, 2.5, 4.9, 1.5, 'I. versicolor'],
  91.     [6.1, 2.8, 4.7, 1.2, 'I. versicolor'],
  92.     [6.4, 2.9, 4.3, 1.3, 'I. versicolor'],
  93.     [6.6, 3.0, 4.4, 1.4, 'I. versicolor'],
  94.     [6.8, 2.8, 4.8, 1.4, 'I. versicolor'],
  95.     [6.7, 3.0, 5.0, 1.7, 'I. versicolor'],
  96.     [6.0, 2.9, 4.5, 1.5, 'I. versicolor'],
  97.     [5.7, 2.6, 3.5, 1.0, 'I. versicolor'],
  98.     [5.5, 2.4, 3.8, 1.1, 'I. versicolor'],
  99.     [5.5, 2.4, 3.7, 1.0, 'I. versicolor'],
  100.     [5.8, 2.7, 3.9, 1.2, 'I. versicolor'],
  101.     [6.0, 2.7, 5.1, 1.6, 'I. versicolor'],
  102.     [5.4, 3.0, 4.5, 1.5, 'I. versicolor'],
  103.     [6.0, 3.4, 4.5, 1.6, 'I. versicolor'],
  104.     [6.7, 3.1, 4.7, 1.5, 'I. versicolor'],
  105.     [6.3, 2.3, 4.4, 1.3, 'I. versicolor'],
  106.     [5.6, 3.0, 4.1, 1.3, 'I. versicolor'],
  107.     [5.5, 2.5, 4.0, 1.3, 'I. versicolor'],
  108.     [5.5, 2.6, 4.4, 1.2, 'I. versicolor'],
  109.     [6.1, 3.0, 4.6, 1.4, 'I. versicolor'],
  110.     [5.8, 2.6, 4.0, 1.2, 'I. versicolor'],
  111.     [5.0, 2.3, 3.3, 1.0, 'I. versicolor'],
  112.     [5.6, 2.7, 4.2, 1.3, 'I. versicolor'],
  113.     [5.7, 3.0, 4.2, 1.2, 'I. versicolor'],
  114.     [5.7, 2.9, 4.2, 1.3, 'I. versicolor'],
  115.     [6.2, 2.9, 4.3, 1.3, 'I. versicolor'],
  116.     [5.1, 2.5, 3.0, 1.1, 'I. versicolor'],
  117.     [5.7, 2.8, 4.1, 1.3, 'I. versicolor'],
  118.     [6.4, 3.1, 5.5, 1.8, 'I. virginica'],
  119.     [6.0, 3.0, 4.8, 1.8, 'I. virginica'],
  120.     [6.9, 3.1, 5.4, 2.1, 'I. virginica'],
  121.     [6.7, 3.1, 5.6, 2.4, 'I. virginica'],
  122.     [6.9, 3.1, 5.1, 2.3, 'I. virginica'],
  123.     [5.8, 2.7, 5.1, 1.9, 'I. virginica'],
  124.     [6.8, 3.2, 5.9, 2.3, 'I. virginica'],
  125.     [6.7, 3.3, 5.7, 2.5, 'I. virginica'],
  126.     [6.7, 3.0, 5.2, 2.3, 'I. virginica'],
  127.     [6.3, 2.5, 5.0, 1.9, 'I. virginica'],
  128.     [6.5, 3.0, 5.2, 2.0, 'I. virginica'],
  129.     [6.2, 3.4, 5.4, 2.3, 'I. virginica'],
  130.     [4.7, 3.2, 1.6, 0.2, 'I. setosa'],
  131.     [4.8, 3.1, 1.6, 0.2, 'I. setosa'],
  132.     [5.4, 3.4, 1.5, 0.4, 'I. setosa'],
  133.     [5.2, 4.1, 1.5, 0.1, 'I. setosa'],
  134.     [5.5, 4.2, 1.4, 0.2, 'I. setosa'],
  135.     [4.9, 3.1, 1.5, 0.2, 'I. setosa'],
  136.     [5.0, 3.2, 1.2, 0.2, 'I. setosa'],
  137.     [5.5, 3.5, 1.3, 0.2, 'I. setosa'],
  138.     [4.9, 3.6, 1.4, 0.1, 'I. setosa'],
  139.     [4.4, 3.0, 1.3, 0.2, 'I. setosa'],
  140.     [5.1, 3.4, 1.5, 0.2, 'I. setosa'],
  141.     [5.0, 3.5, 1.3, 0.3, 'I. setosa'],
  142.     [4.5, 2.3, 1.3, 0.3, 'I. setosa'],
  143.     [4.4, 3.2, 1.3, 0.2, 'I. setosa'],
  144.     [5.0, 3.5, 1.6, 0.6, 'I. setosa'],
  145.     [5.1, 3.8, 1.9, 0.4, 'I. setosa'],
  146.     [4.8, 3.0, 1.4, 0.3, 'I. setosa'],
  147.     [5.1, 3.8, 1.6, 0.2, 'I. setosa'],
  148.     [5.9, 3.0, 5.1, 1.8, 'I. virginica']
  149. ]
  150.  
  151.  
  152. from math import log
  153.  
  154.  
  155. def unique_counts(rows):
  156.     """Креирај броење на можни резултати (последната колона
  157.    во секоја редица е класата)
  158.  
  159.    :param rows: dataset
  160.    :type rows: list
  161.    :return: dictionary of possible classes as keys and count
  162.             as values
  163.    :rtype: dict
  164.    """
  165.     results = {}
  166.     for row in rows:
  167.         # Клацата е последната колона
  168.         r = row[len(row) - 1]
  169.         if r not in results:
  170.             results[r] = 0
  171.         results[r] += 1
  172.     return results
  173.  
  174.  
  175. def gini_impurity(rows):
  176.     """Probability that a randomly placed item will
  177.    be in the wrong category
  178.  
  179.    :param rows: dataset
  180.    :type rows: list
  181.    :return: Gini impurity
  182.    :rtype: float
  183.    """
  184.     total = len(rows)
  185.     counts = unique_counts(rows)
  186.     imp = 0
  187.     for k1 in counts:
  188.         p1 = float(counts[k1]) / total
  189.         for k2 in counts:
  190.             if k1 == k2:
  191.                 continue
  192.             p2 = float(counts[k2]) / total
  193.             imp += p1 * p2
  194.     return imp
  195.  
  196.  
  197. def entropy(rows):
  198.     """Ентропијата е сума од p(x)log(p(x)) за сите
  199.    можни резултати
  200.  
  201.    :param rows: податочно множество
  202.    :type rows: list
  203.    :return: вредност за ентропијата
  204.    :rtype: float
  205.    """
  206.     log2 = lambda x: log(x) / log(2)
  207.     results = unique_counts(rows)
  208.     # Пресметка на ентропијата
  209.     ent = 0.0
  210.     for r in results.keys():
  211.         p = float(results[r]) / len(rows)
  212.         ent = ent - p * log2(p)
  213.     return ent
  214.  
  215.  
  216. class DecisionNode:
  217.     def __init__(self, col=-1, value=None, results=None, tb=None, fb=None):
  218.         """
  219.        :param col: индексот на колоната (атрибутот) од тренинг множеството
  220.                    која се претставува со оваа инстанца т.е. со овој јазол
  221.        :type col: int
  222.        :param value: вредноста на јазолот според кој се дели дрвото
  223.        :param results: резултати за тековната гранка, вредност (различна
  224.                        од None) само кај јазлите-листови во кои се донесува
  225.                        одлуката.
  226.        :type results: dict
  227.        :param tb: гранка која се дели од тековниот јазол кога вредноста е
  228.                   еднаква на value
  229.        :type tb: DecisionNode
  230.        :param fb: гранка која се дели од тековниот јазол кога вредноста е
  231.                   различна од value
  232.        :type fb: DecisionNode
  233.        """
  234.         self.col = col
  235.         self.value = value
  236.         self.results = results
  237.         self.tb = tb
  238.         self.fb = fb
  239.  
  240.  
  241. def compare_numerical(row, column, value):
  242.     """Споредба на вредноста од редицата на посакуваната колона со
  243.    зададена нумеричка вредност
  244.  
  245.    :param row: дадена редица во податочното множество
  246.    :type row: list
  247.    :param column: индекс на колоната (атрибутот) од тренирачкото множество
  248.    :type column: int
  249.    :param value: вредност на јазелот во согласност со кој се прави
  250.                  поделбата во дрвото
  251.    :type value: int or float
  252.    :return: True ако редицата >= value, инаку False
  253.    :rtype: bool
  254.    """
  255.     return row[column] >= value
  256.  
  257.  
  258. def compare_nominal(row, column, value):
  259.     """Споредба на вредноста од редицата на посакуваната колона со
  260.    зададена номинална вредност
  261.  
  262.    :param row: дадена редица во податочното множество
  263.    :type row: list
  264.    :param column: индекс на колоната (атрибутот) од тренирачкото множество
  265.    :type column: int
  266.    :param value: вредност на јазелот во согласност со кој се прави
  267.                  поделбата во дрвото
  268.    :type value: str
  269.    :return: True ако редицата == value, инаку False
  270.    :rtype: bool
  271.    """
  272.     return row[column] == value
  273.  
  274.  
  275. def divide_set(rows, column, value):
  276.     """Поделба на множеството според одредена колона. Може да се справи
  277.    со нумерички или номинални вредности.
  278.  
  279.    :param rows: тренирачко множество
  280.    :type rows: list(list)
  281.    :param column: индекс на колоната (атрибутот) од тренирачкото множество
  282.    :type column: int
  283.    :param value: вредност на јазелот во зависност со кој се прави поделбата
  284.                  во дрвото за конкретната гранка
  285.    :type value: int or float or str
  286.    :return: поделени подмножества
  287.    :rtype: list, list
  288.    """
  289.     # Направи функција која ни кажува дали редицата е во
  290.     # првата група (True) или втората група (False)
  291.     if isinstance(value, int) or isinstance(value, float):
  292.         # ако вредноста за споредба е од тип int или float
  293.         split_function = compare_numerical
  294.     else:
  295.         # ако вредноста за споредба е од друг тип (string)
  296.         split_function = compare_nominal
  297.  
  298.     # Подели ги редиците во две подмножества и врати ги
  299.     # за секој ред за кој split_function враќа True
  300.     set1 = [row for row in rows if
  301.             split_function(row, column, value)]
  302.     # set1 = []
  303.     # for row in rows:
  304.     #     if not split_function(row, column, value):
  305.     #         set1.append(row)
  306.     # за секој ред за кој split_function враќа False
  307.     set2 = [row for row in rows if
  308.             not split_function(row, column, value)]
  309.     return set1, set2
  310.  
  311.  
  312. def build_tree(rows, scoref=entropy):
  313.     """Градење на дрво на одлука.
  314.  
  315.    :param rows: тренирачко множество
  316.    :type rows: list(list)
  317.    :param scoref: функција за одбирање на најдобар атрибут во даден чекор
  318.    :type scoref: function
  319.    :return: коренот на изграденото дрво на одлука
  320.    :rtype: DecisionNode object
  321.    """
  322.     if len(rows) == 0:
  323.         return DecisionNode()
  324.     current_score = scoref(rows)
  325.  
  326.     # променливи со кои следиме кој критериум е најдобар
  327.     best_gain = 0.0
  328.     best_criteria = None
  329.     best_sets = None
  330.  
  331.     column_count = len(rows[0]) - 1
  332.     for col in range(0, column_count):
  333.         # за секоја колона (col се движи во интервалот од 0 до
  334.         # column_count - 1)
  335.         # Следниов циклус е за генерирање на речник од различни
  336.         # вредности во оваа колона
  337.         column_values = {}
  338.         for row in rows:
  339.             column_values[row[col]] = 1
  340.         # за секоја редица се зема вредноста во оваа колона и се
  341.         # поставува како клуч во column_values
  342.         for value in column_values.keys():
  343.             (set1, set2) = divide_set(rows, col, value)
  344.  
  345.             # Информациона добивка
  346.             p = float(len(set1)) / len(rows)
  347.             gain = current_score - p * scoref(set1) - (1 - p) * scoref(set2)
  348.             if gain > best_gain and len(set1) > 0 and len(set2) > 0:
  349.                 best_gain = gain
  350.                 best_criteria = (col, value)
  351.                 best_sets = (set1, set2)
  352.  
  353.     # Креирај ги подгранките
  354.     if best_gain > 0:
  355.         true_branch = build_tree(best_sets[0], scoref)
  356.         false_branch = build_tree(best_sets[1], scoref)
  357.         return DecisionNode(col=best_criteria[0], value=best_criteria[1],
  358.                             tb=true_branch, fb=false_branch)
  359.     else:
  360.         return DecisionNode(results=unique_counts(rows))
  361.  
  362.  
  363. def print_tree(tree, indent=''):
  364.     """Принтање на дрво на одлука
  365.  
  366.    :param tree: коренот на дрвото на одлучување
  367.    :type tree: DecisionNode object
  368.    :param indent:
  369.    :return: None
  370.    """
  371.     # Дали е ова лист јазел?
  372.     if tree.results:
  373.         print(str(tree.results))
  374.     else:
  375.         # Се печати условот
  376.         print(str(tree.col) + ':' + str(tree.value) + '? ')
  377.         # Се печатат True гранките, па False гранките
  378.         print(indent + 'T->', end='')
  379.         print_tree(tree.tb, indent + '  ')
  380.         print(indent + 'F->', end='')
  381.         print_tree(tree.fb, indent + '  ')
  382.  
  383.  
  384. def classify(observation, tree):
  385.     """Класификација на нов податочен примерок со изградено дрво на одлука
  386.  
  387.    :param observation: еден ред од податочното множество за предвидување
  388.    :type observation: list
  389.    :param tree: коренот на дрвото на одлучување
  390.    :type tree: DecisionNode object
  391.    :return: речник со класите како клуч и бројот на појавување во листот на дрвото
  392.    за класификација како вредност во речникот
  393.    :rtype: dict
  394.    """
  395.     if tree.results:
  396.         return tree.results
  397.     else:
  398.         value = observation[tree.col]
  399.         if isinstance(value, int) or isinstance(value, float):
  400.             compare = compare_numerical
  401.         else:
  402.             compare = compare_nominal
  403.  
  404.         if compare(observation, tree.col, tree.value):
  405.             branch = tree.tb
  406.         else:
  407.             branch = tree.fb
  408.  
  409.         return classify(observation, branch)
  410.  
  411. if __name__ == "__main__":
  412.     att1 = float(input())
  413.     att2 = float(input())
  414.     att3 = float(input())
  415.     att4 = float(input())
  416.     planttype = input()
  417.  
  418.     test_case = [att1, att2, att3, att4, planttype]
  419.  
  420.     train_data1 = trainingData[:int(len(trainingData)*0.5)]
  421.     train_data2 = trainingData[int(len(trainingData) * 0.5):]
  422.  
  423.     t1= build_tree(train_data1,entropy)
  424.     t2 = build_tree(train_data2,entropy)
  425.  
  426.     klasa1 = classify(test_case,t1)
  427.     klasa2 = classify(test_case, t2)
  428.  
  429.  
  430.     c1 = ''
  431.     for i in klasa1.items():
  432.         maxValue = 0
  433.         if i[1] > maxValue:
  434.             maxValue=i[1]
  435.             c1 = i[0]
  436.  
  437.     c2 = ''
  438.     for i in klasa2.items():
  439.         maxValue = 0
  440.         if i[1] > maxValue:
  441.             maxValue = i[1]
  442.             c2 = i[0]
  443.  
  444.     if c1==c2:
  445.         print(c1)
  446.     else:
  447.         print("KONTRADIKCIJA")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement