Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- """Дрво на одлучување Problem 1 (2 / 7)
- Да се промени класата за дрво на одлука за да чува и информација на кое ниво во дрвото се наоѓа јазолот. Потоа да се променат и функциите за градење и печатење на дрвото така што за секој јазол се додава информација за нивото и се печати и нивото. Коренот е на нулто ниво. Со функцијата print_tree треба да се испечати креираното дрво на одлука. Прочитана инстанца од стандарден влез да се додаде на тренинг множеството и потоа да се истренира и испечати дрвото на одлука со ова податочно множество."""
- from math import log
- def unique_counts(rows):
- """Креирај броење на можни резултати (последната колона
- во секоја редица е класата)
- :param rows: dataset
- :type rows: list
- :return: dictionary of possible classes as keys and count
- as values
- :rtype: dict
- """
- results = {}
- for row in rows:
- # Клацата е последната колона
- r = row[len(row) - 1]
- if r not in results:
- results[r] = 0
- results[r] += 1
- return results
- def gini_impurity(rows):
- """Probability that a randomly placed item will
- be in the wrong category
- :param rows: dataset
- :type rows: list
- :return: Gini impurity
- :rtype: float
- """
- total = len(rows)
- counts = unique_counts(rows)
- imp = 0
- for k1 in counts:
- p1 = float(counts[k1]) / total
- for k2 in counts:
- if k1 == k2:
- continue
- p2 = float(counts[k2]) / total
- imp += p1 * p2
- return imp
- def entropy(rows):
- """Ентропијата е сума од p(x)log(p(x)) за сите
- можни резултати
- :param rows: податочно множество
- :type rows: list
- :return: вредност за ентропијата
- :rtype: float
- """
- log2 = lambda x: log(x) / log(2)
- results = unique_counts(rows)
- # Пресметка на ентропијата
- ent = 0.0
- for r in results.keys():
- p = float(results[r]) / len(rows)
- ent = ent - p * log2(p)
- return ent
- class DecisionNode:
- def __init__(self, col=-1, value=None, results=None, tb=None, fb=None, level = None):
- """
- :param col: индексот на колоната (атрибутот) од тренинг множеството
- која се претставува со оваа инстанца т.е. со овој јазол
- :type col: int
- :param value: вредноста на јазолот според кој се дели дрвото
- :param results: резултати за тековната гранка, вредност (различна
- од None) само кај јазлите-листови во кои се донесува
- одлуката.
- :type results: dict
- :param tb: гранка која се дели од тековниот јазол кога вредноста е
- еднаква на value
- :type tb: DecisionNode
- :param fb: гранка која се дели од тековниот јазол кога вредноста е
- различна од value
- :type fb: DecisionNode
- """
- self.col = col
- self.value = value
- self.results = results
- self.tb = tb
- self.fb = fb
- self.level = level
- def compare_numerical(row, column, value):
- """Споредба на вредноста од редицата на посакуваната колона со
- зададена нумеричка вредност
- :param row: дадена редица во податочното множество
- :type row: list
- :param column: индекс на колоната (атрибутот) од тренирачкото множество
- :type column: int
- :param value: вредност на јазелот во согласност со кој се прави
- поделбата во дрвото
- :type value: int or float
- :return: True ако редицата >= value, инаку False
- :rtype: bool
- """
- return row[column] >= value
- def compare_nominal(row, column, value):
- """Споредба на вредноста од редицата на посакуваната колона со
- зададена номинална вредност
- :param row: дадена редица во податочното множество
- :type row: list
- :param column: индекс на колоната (атрибутот) од тренирачкото множество
- :type column: int
- :param value: вредност на јазелот во согласност со кој се прави
- поделбата во дрвото
- :type value: str
- :return: True ако редицата == value, инаку False
- :rtype: bool
- """
- return row[column] == value
- def divide_set(rows, column, value):
- """Поделба на множеството според одредена колона. Може да се справи
- со нумерички или номинални вредности.
- :param rows: тренирачко множество
- :type rows: list(list)
- :param column: индекс на колоната (атрибутот) од тренирачкото множество
- :type column: int
- :param value: вредност на јазелот во зависност со кој се прави поделбата
- во дрвото за конкретната гранка
- :type value: int or float or str
- :return: поделени подмножества
- :rtype: list, list
- """
- # Направи функција која ни кажува дали редицата е во
- # првата група (True) или втората група (False)
- if isinstance(value, int) or isinstance(value, float):
- # ако вредноста за споредба е од тип int или float
- split_function = compare_numerical
- else:
- # ако вредноста за споредба е од друг тип (string)
- split_function = compare_nominal
- # Подели ги редиците во две подмножества и врати ги
- # за секој ред за кој split_function враќа True
- set1 = [row for row in rows if
- split_function(row, column, value)]
- # set1 = []
- # for row in rows:
- # if not split_function(row, column, value):
- # set1.append(row)
- # за секој ред за кој split_function враќа False
- set2 = [row for row in rows if
- not split_function(row, column, value)]
- return set1, set2
- def build_tree(rows, scoref=entropy, level = 0):
- """Градење на дрво на одлука.
- :param rows: тренирачко множество
- :type rows: list(list)
- :param scoref: функција за одбирање на најдобар атрибут во даден чекор
- :type scoref: function
- :return: коренот на изграденото дрво на одлука
- :rtype: DecisionNode object
- """
- if len(rows) == 0:
- return DecisionNode()
- current_score = scoref(rows)
- # променливи со кои следиме кој критериум е најдобар
- best_gain = 0.0
- best_criteria = None
- best_sets = None
- column_count = len(rows[0]) - 1
- for col in range(0, column_count):
- # за секоја колона (col се движи во интервалот од 0 до
- # column_count - 1)
- # Следниов циклус е за генерирање на речник од различни
- # вредности во оваа колона
- column_values = {}
- for row in rows:
- column_values[row[col]] = 1
- # за секоја редица се зема вредноста во оваа колона и се
- # поставува како клуч во column_values
- for value in column_values.keys():
- (set1, set2) = divide_set(rows, col, value)
- # Информациона добивка
- p = float(len(set1)) / len(rows)
- gain = current_score - p * scoref(set1) - (1 - p) * scoref(set2)
- if gain > best_gain and len(set1) > 0 and len(set2) > 0:
- best_gain = gain
- best_criteria = (col, value)
- best_sets = (set1, set2)
- # Креирај ги подгранките
- if best_gain > 0:
- true_branch = build_tree(best_sets[0], scoref, level+1)
- false_branch = build_tree(best_sets[1], scoref, level+1)
- return DecisionNode(col=best_criteria[0], value=best_criteria[1],
- tb=true_branch, fb=false_branch, level=level)
- else:
- return DecisionNode(results=unique_counts(rows),level=0)
- def print_tree(tree, indent=''):
- """Принтање на дрво на одлука
- :param tree: коренот на дрвото на одлучување
- :type tree: DecisionNode object
- :param indent:
- :return: None
- """
- # Дали е ова лист јазел?
- if tree.results:
- print(str(tree.results))
- else:
- # Се печати условот
- print(str(tree.col) + ':' + str(tree.value) + '? ', 'Level=' +str(tree.level))
- # Се печатат True гранките, па False гранките
- print(indent + 'T->', end='')
- print_tree(tree.tb, indent + ' ')
- print(indent + 'F->', end='')
- print_tree(tree.fb, indent + ' ')
- def classify(observation, tree):
- """Класификација на нов податочен примерок со изградено дрво на одлука
- :param observation: еден ред од податочното множество за предвидување
- :type observation: list
- :param tree: коренот на дрвото на одлучување
- :type tree: DecisionNode object
- :return: речник со класите како клуч и бројот на појавување во листот на дрвото
- за класификација како вредност во речникот
- :rtype: dict
- """
- if tree.results:
- return tree.results
- else:
- value = observation[tree.col]
- if isinstance(value, int) or isinstance(value, float):
- compare = compare_numerical
- else:
- compare = compare_nominal
- if compare(observation, tree.col, tree.value):
- branch = tree.tb
- else:
- branch = tree.fb
- return classify(observation, branch)
- training_data = [['slashdot', 'USA', 'yes', 18, 'None'],
- ['google', 'France', 'yes', 23, 'Premium'],
- ['google', 'France', 'yes', 23, 'Basic'],
- ['google', 'France', 'yes', 23, 'Basic'],
- ['digg', 'USA', 'yes', 24, 'Basic'],
- ['kiwitobes', 'France', 'yes', 23, 'Basic'],
- ['google', 'UK', 'no', 21, 'Premium'],
- ['(direct)', 'New Zealand', 'no', 12, 'None'],
- ['(direct)', 'UK', 'no', 21, 'Basic'],
- ['google', 'USA', 'no', 24, 'Premium'],
- ['slashdot', 'France', 'yes', 19, 'None'],
- ['digg', 'USA', 'no', 18, 'None'],
- ['google', 'UK', 'no', 18, 'None'],
- ['kiwitobes', 'UK', 'no', 19, 'None'],
- ['digg', 'New Zealand', 'yes', 12, 'Basic'],
- ['slashdot', 'UK', 'no', 21, 'None'],
- ['google', 'UK', 'yes', 18, 'Basic'],
- ['kiwitobes', 'France', 'yes', 19, 'Basic']]
- if __name__ == "__main__":
- referrer = input()
- location = input()
- readFAQ = input()
- pagesVisited = int(input())
- serviceChosen = input()
- testCase = [referrer, location, readFAQ, pagesVisited, serviceChosen]
- training_data.append(testCase)
- t = build_tree(training_data,entropy)
- klasa = classify(testCase,t)
- print_tree(t)
- #print(sorted(list(klasa.items()),reverse=True,key=lambda x: x[1])[0][0])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement