Advertisement
glavinova

[СНЗ] Класификација со мнозинство на гласови

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