Advertisement
glavinova

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

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