127 lines
4.9 KiB
Markdown
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)
|
|
```
|
|
|
|
|