Podprojekt update
This commit is contained in:
parent
ecc954719d
commit
16d45a7d51
77
Justyna.md
77
Justyna.md
@ -10,51 +10,66 @@ Projekt implementuje tworzenie drzewa decyzyjnego wykorzystującego algorytm ID3
|
||||
funkcja budująca drzewo za pomocą algorymu ID3:
|
||||
|
||||
```py
|
||||
def ID3(data, original_data, features, target_attribute_name, parent_node_class=None):
|
||||
def ID3(data, original_data, attributes, target, parent_node_class=None):
|
||||
|
||||
if len(np.unique(data[target])) <= 1:
|
||||
return np.unique(data[target])[0]
|
||||
elif len(data) == 0:
|
||||
return np.unique(original_data[target])[
|
||||
np.argmax(np.unique(original_data[target], return_counts=True)[1])]
|
||||
elif len(attributes) == 0:
|
||||
return parent_node_class
|
||||
else:
|
||||
parent_node_class = np.unique(data[target])[
|
||||
np.argmax(np.unique(data[target], return_counts=True)[1])]
|
||||
|
||||
item_values = [info_gain(data, i, target) for i in
|
||||
attributes]
|
||||
|
||||
best_attribute_index = np.argmax(item_values)
|
||||
best_attribute = attributes[best_attribute_index]
|
||||
|
||||
tree = {best_attribute: {}}
|
||||
|
||||
item_values = [info_gain(data, feature, target_attribute_name) for feature in
|
||||
features]
|
||||
best_feature_index = np.argmax(item_values)
|
||||
best_feature = features[best_feature_index]
|
||||
tree = {best_feature: {}}
|
||||
features = [i for i in features if i != best_feature]
|
||||
for value in np.unique(data[best_feature]):
|
||||
|
||||
sub_data = data.where(data[best_feature] == value).dropna()
|
||||
subtree = ID3(sub_data, data, features, target_attribute_name, parent_node_class)
|
||||
|
||||
tree[best_feature][value] = subtree
|
||||
attributes = [i for i in attributes if i != best_attribute]
|
||||
for value in np.unique(data[best_attribute]):
|
||||
sub_data = data.where(data[best_attribute] == value).dropna()
|
||||
subtree = ID3(sub_data, data, attributes, target, parent_node_class)
|
||||
tree[best_attribute][value] = subtree
|
||||
|
||||
return (tree)
|
||||
```
|
||||
Cechą charakterystyczną algorytmu jest wybór atrybutów dla których kolejno przeprowadzane są testy taki, aby końcowe drzewo było jak najprostsze i jak najefektywniejsze. Wybór atrybutów opiera się na liczeniu entropii, co pozwala obliczyć, wybór którego z atrybutów da największy przyrost informacji.
|
||||
|
||||
Drzewo budowane jest w oparciu o najlepsze możliwe podziały:
|
||||
#obliczanie wartości przyrostu informacji
|
||||
|
||||
Funkcja oblicza który atrybut najlepiej rozdziela zbiór danych (dzieli zbiór przykładów na jak najbardziej równe podzbiory).
|
||||
|
||||
```py
|
||||
#obliczanie wartości przyrostu informacji
|
||||
def info_gain(data, split_attribute_name, target_name):
|
||||
|
||||
# Wartość entropii zbioru
|
||||
total_entropy = entropy(data[target_name])
|
||||
|
||||
# Wyodrębnienie poszczególnych "podzbiorów"
|
||||
vals, counts = np.unique(data[split_attribute_name], return_counts=True)
|
||||
|
||||
# Średnia ważona entropii każdego podzbioru
|
||||
def info_gain(data, split_attribute, target):
|
||||
|
||||
_entropy = entropy(data[target])
|
||||
vals, counts = np.unique(data[split_attribute], return_counts=True)
|
||||
weighted_entropy = np.sum(
|
||||
[(counts[i] / np.sum(counts)) * entropy(data.where(data[split_attribute_name] == vals[i]).dropna()[target_name])
|
||||
[(counts[i] / np.sum(counts)) * entropy(data.where(data[split_attribute] == vals[i]).dropna()[target])
|
||||
for i in range(len(vals))])
|
||||
|
||||
# Przyrost informacji
|
||||
information_gain = total_entropy - weighted_entropy
|
||||
information_gain = _entropy - weighted_entropy
|
||||
|
||||
return information_gain
|
||||
```
|
||||
|
||||
Entropia:
|
||||
|
||||
Entropia jest miarą ilości informacji - im mniejsza entropia, tym więcej informacji. W przypadku problemu klasyfikacji przykładów do dwóch odrębnych klas, wzór na entropię przedstawia się następująco:
|
||||
|
||||
Entropy(S) = - ∑ pᵢ * log₂(pᵢ) ; i = 1 to n
|
||||
gdzie:
|
||||
Z - źródło informacji
|
||||
p - prawdopodobieństwo wystąpienia przykładu pozytywnego w zbiorze trenującym
|
||||
(1-p) - prawdopodobieństwo wystąpienia przykładu negatywnego w zbiorze trenującym
|
||||
|
||||
```py
|
||||
def entropy(target_col):
|
||||
def entropy(attribute):
|
||||
values, counts = np.unique(target_col, return_counts=True)
|
||||
entropy = np.sum(
|
||||
[(-counts[i] / np.sum(counts)) * np.log2(counts[i] / np.sum(counts)) for i in range(len(values))])
|
||||
@ -63,7 +78,7 @@ def entropy(target_col):
|
||||
|
||||
### Zestaw uczący
|
||||
|
||||
Zestaw budujący drzewo to lista zawierająca 20 przykładów waruków panujących na polu. Atrybyty zapisane są w formacie ['pogoda', 'ile_chwastow', 'ile_burakow', 'czy_chce_pracowac'].
|
||||
Zestaw budujący drzewo to lista zawierająca 24 przykładów waruków panujących na polu. Atrybyty zapisane są w formacie ['pogoda', 'ile_chwastow', 'ile_burakow', 'czy_chce_pracowac']. Przykłady ze zbioru:
|
||||
|
||||
```py
|
||||
['slonecznie', 'duzo', 'bardzo_malo', 'srednio'],
|
||||
@ -73,5 +88,5 @@ Zestaw budujący drzewo to lista zawierająca 20 przykładów waruków panujący
|
||||
```
|
||||
|
||||
### Implementacja w projekcie
|
||||
Podprojet uruchamiany jest za pomocą klawisza *F5*.
|
||||
Podprojet uruchamiany jest za pomocą klawisza *F5*. Pobierane są inforamcje o warunkach panujących na polu, na podstawie których oceniana jest chęć do pracy.
|
||||
|
||||
|
87
Justyna.py
87
Justyna.py
@ -1,80 +1,78 @@
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from pprint import pprint
|
||||
import time
|
||||
import dataset
|
||||
import random
|
||||
|
||||
# obliczenie entropii dla wskazanej kolumny
|
||||
def entropy(target_col):
|
||||
values, counts = np.unique(target_col, return_counts=True)
|
||||
def entropy(attribute):
|
||||
values, counts = np.unique(attribute, return_counts=True)
|
||||
entropy = np.sum(
|
||||
[(-counts[i] / np.sum(counts)) * np.log2(counts[i] / np.sum(counts)) for i in range(len(values))])
|
||||
return entropy
|
||||
|
||||
#obliczanie wartości przyrostu informacji
|
||||
def info_gain(data, split_attribute_name, target_name):
|
||||
def info_gain(data, split_attribute, target):
|
||||
|
||||
# Wartość entropii zbioru
|
||||
total_entropy = entropy(data[target_name])
|
||||
_entropy = entropy(data[target])
|
||||
|
||||
# Wyodrębnienie poszczególnych "podzbiorów"
|
||||
vals, counts = np.unique(data[split_attribute_name], return_counts=True)
|
||||
# Wyodrębnienie poszczególnych podzbiorów
|
||||
vals, counts = np.unique(data[split_attribute], return_counts=True)
|
||||
|
||||
# Średnia ważona entropii każdego podzbioru
|
||||
weighted_entropy = np.sum(
|
||||
[(counts[i] / np.sum(counts)) * entropy(data.where(data[split_attribute_name] == vals[i]).dropna()[target_name])
|
||||
[(counts[i] / np.sum(counts)) * entropy(data.where(data[split_attribute] == vals[i]).dropna()[target])
|
||||
for i in range(len(vals))])
|
||||
|
||||
# Przyrost informacji
|
||||
information_gain = total_entropy - weighted_entropy
|
||||
information_gain = _entropy - weighted_entropy
|
||||
|
||||
return information_gain
|
||||
|
||||
|
||||
def ID3(data, original_data, features, target_attribute_name, parent_node_class=None):
|
||||
|
||||
def ID3(data, original_data, attributes, target, parent_node_class=None):
|
||||
|
||||
|
||||
# Jeżeli wszystkie atrybuty są takie same, zwracamy liść z pierwszą napotkaną wartością
|
||||
|
||||
if len(np.unique(data[target_attribute_name])) <= 1:
|
||||
return np.unique(data[target_attribute_name])[0]
|
||||
if len(np.unique(data[target])) <= 1:
|
||||
return np.unique(data[target])[0]
|
||||
|
||||
elif len(data) == 0:
|
||||
return np.unique(original_data[target_attribute_name])[
|
||||
np.argmax(np.unique(original_data[target_attribute_name], return_counts=True)[1])]
|
||||
return np.unique(original_data[target])[
|
||||
np.argmax(np.unique(original_data[target], return_counts=True)[1])]
|
||||
|
||||
elif len(features) == 0:
|
||||
elif len(attributes) == 0:
|
||||
return parent_node_class
|
||||
|
||||
else:
|
||||
|
||||
# Aktualizacja nadrzędnej wartości
|
||||
parent_node_class = np.unique(data[target_attribute_name])[
|
||||
np.argmax(np.unique(data[target_attribute_name], return_counts=True)[1])]
|
||||
# nadrzędna wartość
|
||||
parent_node_class = np.unique(data[target])[
|
||||
np.argmax(np.unique(data[target], return_counts=True)[1])]
|
||||
|
||||
# Obliczenie przyrostu informacji dla każdego potencjalnego atrybutu,
|
||||
# według którego nastąpi podział zbioru
|
||||
item_values = [info_gain(data, feature, target_attribute_name) for feature in
|
||||
features]
|
||||
# obliczenie przyrostu informacji dla każdego atrybutu
|
||||
item_values = [info_gain(data, i, target) for i in
|
||||
attributes]
|
||||
|
||||
# Najlepszym atrybutem jest ten o największym przyroście informacji
|
||||
best_feature_index = np.argmax(item_values)
|
||||
best_feature = features[best_feature_index]
|
||||
# Wybór najlepszego atrybutu
|
||||
best_attribute_index = np.argmax(item_values)
|
||||
best_attribute = attributes[best_attribute_index]
|
||||
|
||||
# Struktura drzewa
|
||||
tree = {best_feature: {}}
|
||||
tree = {best_attribute: {}}
|
||||
|
||||
# Aktualizacja zbioru atrybutów
|
||||
features = [i for i in features if i != best_feature]
|
||||
attributes = [i for i in attributes if i != best_attribute]
|
||||
|
||||
# Dla każdej wartości wybranego atrybutu budujemy kolejne poddrzewo
|
||||
for value in np.unique(data[best_feature]):
|
||||
# Budowa poddrzewa dla każdej wartości wybranego atrybutu
|
||||
for value in np.unique(data[best_attribute]):
|
||||
|
||||
sub_data = data.where(data[best_feature] == value).dropna()
|
||||
subtree = ID3(sub_data, data, features, target_attribute_name, parent_node_class)
|
||||
sub_data = data.where(data[best_attribute] == value).dropna()
|
||||
subtree = ID3(sub_data, data, attributes, target, parent_node_class)
|
||||
|
||||
tree[best_feature][value] = subtree
|
||||
tree[best_attribute][value] = subtree
|
||||
|
||||
return (tree)
|
||||
|
||||
@ -88,8 +86,8 @@ def test(data, tree):
|
||||
predicted.loc[i, "predicted"] = search(queries[i], tree, 'nie')
|
||||
print('Precyzja przewidywań: ', (np.sum(predicted["predicted"] == data['czy_chce_pracowac']) / len(data)) * 100, '%')
|
||||
|
||||
#dostowanie danych (lista na słownik) i wywolanie na nich funkcji serach
|
||||
def predict_data(data, tree):
|
||||
#dostowanie danych (lista na słownik) i wywolanie na nich funkcji serach
|
||||
def data_to_dict(data, tree):
|
||||
|
||||
queries = pd.DataFrame(data=data, columns=dataset.header)
|
||||
predicted = pd.DataFrame(columns=["predicted"])
|
||||
@ -128,11 +126,14 @@ class main():
|
||||
training_data = pd.DataFrame(data=dataset.training_data, columns=dataset.header)
|
||||
testing_data = pd.DataFrame(data=dataset.testing_data, columns=dataset.header)
|
||||
|
||||
#utworzenie drzewa
|
||||
# Utworzenie drzewa
|
||||
tree = ID3(training_data, training_data, training_data.columns[:-1], 'czy_chce_pracowac')
|
||||
pprint(tree)
|
||||
|
||||
#uzyskanie danych od agenta
|
||||
|
||||
# Testowanie drzewa
|
||||
print(test(testing_data, tree))
|
||||
|
||||
# Uzyskanie danych od agenta
|
||||
ocena_burakow = self.ocen_ile_burakow()
|
||||
ocena_chwastow = self.ocen_ile_chwastow()
|
||||
pogoda = self.pogoda()
|
||||
@ -142,13 +143,13 @@ class main():
|
||||
data = [[pogoda, ocena_chwastow, ocena_burakow, '']]
|
||||
|
||||
#podjecie decyzji
|
||||
result = predict_data(data, tree)
|
||||
result = data_to_dict(data, tree)
|
||||
print('czy traktor chce pracowac: ' + result)
|
||||
|
||||
|
||||
|
||||
def licz_chwasty_buraki(self):
|
||||
chwasty = 0
|
||||
buraki = 0
|
||||
buraki = 0
|
||||
|
||||
for i in self.field.field_matrix:
|
||||
for j in i:
|
||||
@ -157,7 +158,7 @@ class main():
|
||||
elif(j%2==1):
|
||||
chwasty = chwasty + 1
|
||||
return chwasty, buraki
|
||||
|
||||
|
||||
def ocen_ile_burakow(self):
|
||||
chwasty, buraki = self.licz_chwasty_buraki()
|
||||
if buraki < 5:
|
||||
@ -183,7 +184,7 @@ class main():
|
||||
return 'duzo'
|
||||
elif chwasty >=48:
|
||||
return 'bardzo_duzo'
|
||||
|
||||
|
||||
def pogoda(self):
|
||||
number = random.randrange(0, 4)
|
||||
if number==0:
|
||||
|
@ -7,21 +7,25 @@ training_data = [
|
||||
['slonecznie', 'bardzo_duzo', 'malo', 'srednio'],
|
||||
['slonecznie', 'malo', 'bardzo_duzo', 'tak'],
|
||||
['slonecznie', 'duzo', 'bardzo_malo', 'srednio'],
|
||||
['slonecznie', 'malo', 'bardzo_malo', 'srednio'],
|
||||
['deszcz', 'bardzo_duzo', 'malo', 'nie'],
|
||||
['deszcz', 'srednio', 'srednio', 'srednio'],
|
||||
['deszcz', 'malo', 'bardzo_duzo', 'tak'],
|
||||
['deszcz', 'duzo', 'duzo', 'srednio'],
|
||||
['deszcz', 'malo', 'malo', 'tak'],
|
||||
['deszcz', 'srednio', 'bardzo_duzo', 'tak'],
|
||||
['grad', 'srednio', 'malo', 'nie'],
|
||||
['grad', 'bradzo_malo', 'bardzo_duzo', 'srednio'],
|
||||
['grad', 'duzo', 'srednio', 'nie'],
|
||||
['grad', 'malo', 'bardzo_malo', 'srednio'],
|
||||
['grad', 'bardzo_duzo', 'bardzo_malo', 'nie'],
|
||||
['grad', 'srednio', 'bardzo_malo', 'nie'],
|
||||
['zachmurzenie', 'srednio', 'srednio', 'tak'],
|
||||
['zachmurzenie', 'bardzo_duzo', 'duzo', 'nie'],
|
||||
['zachmurzenie', 'malo', 'srednio', 'tak'],
|
||||
['zachmurzenie', 'duzo', 'malo', 'srednio'],
|
||||
['zachmurzenie', 'malo', 'bardzo_malo', 'tak']
|
||||
['zachmurzenie', 'malo', 'bardzo_malo', 'tak'],
|
||||
['zachmurzenie', 'malo', 'srednio', 'tak']
|
||||
]
|
||||
|
||||
testing_data = [
|
||||
|
Loading…
Reference in New Issue
Block a user