SI_Traktor/decisiontree.md

127 lines
4.9 KiB
Markdown

# Sztuczna Inteligencja - Raport
**Członkowie zespołu:** Marcin Kwapisz, Kamila Matysiak, Piotr Rychlicki, Justyna Zarzycka
**Autor podprojektu:** Kamila Matysiak
### Drzewo Decyzyjne
Projekt wykorzystuje drzewo decyzyjne do wybrania czynności dla każdego pola, a następnie wysłania traktora do pól zgodnych z obecnie wybranym trybem.
Projekt używa metody CART (Classification and Regression Tree). Tworzy on drzewo binarne, w którym rozpatruje wszystkie możliwe podziały zbioru wartości cech na dwa rozłączne i uzupełniające się podzbiory dla cech dyskretnych.
Uruchamia się go za pomocą klawisza **F6**.
#### Zbiór uczący:
Zbiorem uczącym jest zestaw danych informujących drzewo jak postępować z polem o danych parametrach.
Kolejne cyfry odpowiadają za: nawodnienie pola, obecność chwastów, czy pole jest puste, czy jest do zbioru.
```
training_data = [[0, 0, 1, 0, "Zasadzic"],
[0, 1, 1, 0, "Odchwascic"],
[0, 0, 0, 0, "Podlac"],
[0, 1, 0, 0, "Odchwascic"],
[1, 0, 1, 0, "Zasadzic"],
[1, 1, 1, 0, "Odchwascic"],
[1, 0, 0, 0, "Czekac"],
[1, 1, 0, 0, "Odchwascic"],
[0, 0, 0, 1, "Zebrac"]]
self.tree = build_tree(training_data)
print_tree(self.tree)
```
#### Algotytm tworzenia drzewa:
Budowanie drzewa zaczynamy od stworzenia klasy **Question**, w której będziemy tworzyć zapytanie, na podstawie którego będziemy dzielić nasze dane. Następnie tworzymy funkcję **partition**, która na podstawie zapytania dzieli nam dane na spełnione i niespełnione wiersze:
```
# podział danych na spełnione i niespełnione wiersze
def partition(rows, question):
true_rows, false_rows = [], []
for row in rows:
if question.match(row):
true_rows.append(row)
else:
false_rows.append(row)
return true_rows, false_rows
```
Następnie wyokrzystujemy **Index Gini**, który mierzy jak często losowo wybrany element będzie źle zindentyfikowany. Gdy jest równy 0, oznacza to, że element zostanie właściwie oznaczony.
```
# funkcja implementująca indeks gini
def gini(rows):
counts = class_counts(rows)
impurity = 1
for lbl in counts:
prob_of_lbl = counts[lbl] / float(len(rows))
impurity -= prob_of_lbl ** 2
return impurity
def info_gain(left, right, current_uncertainty):
p = float(len(left)) / (len(left) + len(right))
return current_uncertainty - p * gini(left) - (1 - p) * gini(right)
```
Następnie na podstawie uzykanych informacji, znajdujemy najlepsze miejsce na podział danych:
```
# znalezienie najlepszego "miejsca" na podział danych
def find_best_split(rows):
best_gain = 0
best_question = None
current_uncertainty = gini(rows)
n_features = len(rows[0]) - 1
for col in range(n_features):
values = set([row[col] for row in rows])
for val in values:
question = Question(col, val)
true_rows, false_rows = partition(rows, question)
if len(true_rows) == 0 or len(false_rows) == 0:
continue
gain = info_gain(true_rows, false_rows, current_uncertainty)
if gain >= best_gain:
best_gain, best_question = gain, question
return best_gain, best_question
```
Po stworzeniu klas definiujących liść i węzęł deycyzyjny przechodzimy do właściwej funkcji **build_tree*:
```
# funkcja budująca drzewo
def build_tree(rows):
gain, question = find_best_split(rows) # znalezienie najlepszego podziału
if gain == 0:
return Leaf(rows)
true_rows, false_rows = partition(rows, question) # podział danych
true_branch = build_tree(true_rows)
false_branch = build_tree(false_rows) #stworzenie gałęzi prawdy i fałszu
return DecisionNode(question, true_branch, false_branch)
```
#### Integracja:
Program sczytuje dane z głównego projektu, następnie interpretuje je za pomocą prostej funkcji **translate**, która zwraca informacje o stanie pola. Następnie za pomocą drzewa określamy czynność, jaka powinna zostać wykonana na tym polu. Wykonanie pracy zlecamy klasie **pathfinding**, która za pomocą algorytmu A* wysyła traktor na pola odpowiadające wybranemu trybowi.
```
def search_field(self):
matrix = self.field.get_matrix()
for i in range(len(matrix)):
for j in range(len(matrix[i])):
print("Pole (%d,%d) Przewidziania czynnosc: %s"
% (i, j, print_leaf(classify(translate(matrix[i][j]), self.tree))))
if work[self.traktor.get_mode()] in self.work_field(classify(translate(matrix[i][j]), self.tree)):
print("Zgodna z aktualnym trybem, czynnosc wykonywana")
self.path.find_path(self.traktor, self.field, self.ui, [j, i])
self.ui.update()
time.sleep(0.5)
```