forked from s444420/AL-2020
Merge branch 'master' of s444428/AL-2020 into master
This commit is contained in:
commit
b02e90ebcf
@ -3,5 +3,5 @@
|
|||||||
<component name="JavaScriptSettings">
|
<component name="JavaScriptSettings">
|
||||||
<option name="languageLevel" value="ES6" />
|
<option name="languageLevel" value="ES6" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (Projekt)" project-jdk-type="Python SDK" />
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.7 (AL-2020)" project-jdk-type="Python SDK" />
|
||||||
</project>
|
</project>
|
@ -4,7 +4,7 @@
|
|||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
<excludeFolder url="file://$MODULE_DIR$/venv" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="Python 3.8 (Projekt)" jdkType="Python SDK" />
|
<orderEntry type="jdk" jdkName="Python 3.7 (AL-2020)" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
<component name="TestRunnerService">
|
<component name="TestRunnerService">
|
||||||
|
132
Raporty/raport_444428.md
Normal file
132
Raporty/raport_444428.md
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
# Wojciech Lukasik - drzewa decyzyjne, algorytm CART
|
||||||
|
|
||||||
|
### Opis podprojektu
|
||||||
|
Podprojekt implementuje tworzenie drzewa decyzyjnego w oparciu o algorytm CART
|
||||||
|
(Classification And Regression Tree), które pomaga Agentowi w rozpoznaniu słodyczy na podstawie
|
||||||
|
ich cech fizycznych (kolor, kształt, masa, rozmiar).
|
||||||
|
|
||||||
|
Wszystkie funkcje oraz klasy wykorzystywane w tym podprojekcie znajdują się w pliku decision_tree.py,
|
||||||
|
dane uczące znajdują się w pliku data.py w liście learning_data
|
||||||
|
|
||||||
|
### Tworzenie drzewa decyzyjnego
|
||||||
|
|
||||||
|
Główną funkcją jest build_tree(rows), która jak wskazuje nazwa tworzy drzewo. Funkcja przyjmuje
|
||||||
|
jako argument listę zawierającą zestaw danych, w tym przypadku będą to słodycze o różnych właściwościach.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def build_tree(rows):
|
||||||
|
gain, question = find_best_split(rows)
|
||||||
|
|
||||||
|
if gain == 0:
|
||||||
|
return Leaf(rows)
|
||||||
|
|
||||||
|
true_rows, false_rows = partition(rows, question)
|
||||||
|
|
||||||
|
true_branch = build_tree(true_rows)
|
||||||
|
|
||||||
|
false_branch = build_tree(false_rows)
|
||||||
|
|
||||||
|
return DecisionNode(question, true_branch, false_branch)
|
||||||
|
```
|
||||||
|
|
||||||
|
Drzewo jest budowane w oparciu o najlepsze możlwe podziały (najbardziej korzystne 'pytanie', które można zadać).
|
||||||
|
Zajmuje się tym funkcja
|
||||||
|
|
||||||
|
`find_best_split(rows)` która dla wszystkich właściwości przekazanego zestawu informacji
|
||||||
|
wylicza dla nich 'zysk informacji'.
|
||||||
|
|
||||||
|
Jeżeli nie otrzymujemy żadnych informacji (gain == 0) to znaczy, że znajdujemy
|
||||||
|
się w liściu drzewa.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def find_best_split(rows):
|
||||||
|
""" znajdź najlepsze możliwe pytanie do zadania, sprawdzając wszystkie
|
||||||
|
właściwośći oraz licząc dla nich 'info_gain' """
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
Zysk informacji z danego podziału otrzymujemy obliczając wartość 'Gini Impurity'. Jest to miara tego jak często losowo
|
||||||
|
wybrany element zbioru byłby źle skategoryzowany, gdyby przypisać mu losową kategorię spośród wszystkich kategorii
|
||||||
|
znajdujących się w danym zbiorze.
|
||||||
|
|
||||||
|
```python
|
||||||
|
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
|
||||||
|
```
|
||||||
|
`class_counts(rows)` to funkcja, która dla danego zestawu danych zwraca wszystkie unikalne klasy oraz liczbę ich wystąpień.
|
||||||
|
|
||||||
|
Dla przykładu, dla zestawu w którym wszystkie elementy podchodzą pod tę samą kategorię wartość Gini będzie równa zero,
|
||||||
|
natomiast dla zbioru w którym znajdują się dwie kategorie wartość ta wyniesie 0,5.
|
||||||
|
|
||||||
|
Po znalezieniu najbardziej optymalnego pytania, algorytm dzieli zestaw na elementy, dla których pytanie jest prawdziwe
|
||||||
|
(true_rows), oraz te dla których jest fałszywe (false_rows). Następnie wykonuje rekurencyjnie procedurę build_tree dla
|
||||||
|
obu poddrzew tak długo aż nie dojdzie do liści.
|
||||||
|
|
||||||
|
Element o zadanym zestawie cech, zostaje odnaleziony w drzewie dzięki prostej procedurze
|
||||||
|
|
||||||
|
`classify(row, node)` 'row' to lista cech elementu, natomiast 'node' na początu jest korzeniem już zbudowanego drzewa.
|
||||||
|
|
||||||
|
Element jest odnaleziony dzięki
|
||||||
|
rekurencyjnym porównaniom atrybutów elementu z pytaniami w kolejnych węzłach drzewa.
|
||||||
|
|
||||||
|
```python
|
||||||
|
def classify(row, node):
|
||||||
|
if isinstance(node, Leaf):
|
||||||
|
return node.predicions
|
||||||
|
|
||||||
|
if node.question.match(row):
|
||||||
|
return classify(row, node.true_branch)
|
||||||
|
else:
|
||||||
|
return classify(row, node.false_branch)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Zestaw uczący
|
||||||
|
|
||||||
|
Zestaw budujący drzewo to lista zawierająca 27 przykładowych słodyczy. Ich atrybuty zapisane są w formacie ['kolor',
|
||||||
|
'kształt', 'masa', 'wielkość', 'nazwa']. Oczywiście przy wyszukiwaniu elementu w drzewie jego nazwa nie jest potrzebna
|
||||||
|
ponieważ to jej szukamy. Przykładowe elementy z zestawu uczącego:
|
||||||
|
|
||||||
|
```python
|
||||||
|
['black', 'rectangle', 51, 'small', 'Mars'],
|
||||||
|
['gold', 'pack', 100, 'big', 'Haribo'],
|
||||||
|
['purple', 'rectangle', 100, 'big', 'Milka'],
|
||||||
|
['brown', 'pack', 45, 'small', 'M&M'],
|
||||||
|
```
|
||||||
|
|
||||||
|
### Implementacja w projekcie
|
||||||
|
|
||||||
|
Przy rozpoczęciu głównej pętli programu w pliku `main.py` drzewo `my_tree` zostaje zbudowane w oparciu o dane
|
||||||
|
`data.learning_data`.
|
||||||
|
|
||||||
|
Gdy program już działa, po wciśnięciu `spacji` jeden ze słodyczy zostanie losowo wybrany z zestawu `data.learning_data`
|
||||||
|
oraz umieszczony na polu `board[9][0]`, a jego nazwa zostanie wypisana w konsoli. Następnie Agent przemieszcza się do
|
||||||
|
punktu `board[9][0]` i rozpoczne procedurę wyszukiwania elementu w zbudowanym drzewie. Na końcu wypisze w
|
||||||
|
konsoli nazwę produktu.
|
||||||
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
BIN
__pycache__/mcda.cpython-37.pyc
Normal file
BIN
__pycache__/mcda.cpython-37.pyc
Normal file
Binary file not shown.
BIN
__pycache__/product.cpython-37.pyc
Normal file
BIN
__pycache__/product.cpython-37.pyc
Normal file
Binary file not shown.
BIN
__pycache__/supply.cpython-37.pyc
Normal file
BIN
__pycache__/supply.cpython-37.pyc
Normal file
Binary file not shown.
2
data.py
2
data.py
@ -40,7 +40,7 @@ learning_data = [
|
|||||||
['gold', 'rectangle', 40, 'medium', 'Twix'],
|
['gold', 'rectangle', 40, 'medium', 'Twix'],
|
||||||
['gold', 'rectangle', 50, 'medium', 'Prince-polo'],
|
['gold', 'rectangle', 50, 'medium', 'Prince-polo'],
|
||||||
['brown', 'rectangle', 55, 'medium', 'Snickers'],
|
['brown', 'rectangle', 55, 'medium', 'Snickers'],
|
||||||
['brown', 'rectangle', 45, 'medium', 'Lion'],
|
['brown', 'rectangle', 45, 'medium', 'Lion'],
|
||||||
['white', 'rectangle', 40, 'medium', 'Kinder-bueno'],
|
['white', 'rectangle', 40, 'medium', 'Kinder-bueno'],
|
||||||
['red', 'rectangle', 50, 'medium', 'Kit-kat'],
|
['red', 'rectangle', 50, 'medium', 'Kit-kat'],
|
||||||
['blue', 'rectangle', 115, 'big', 'Wedel'],
|
['blue', 'rectangle', 115, 'big', 'Wedel'],
|
||||||
|
5
field.py
5
field.py
@ -33,7 +33,6 @@ class Field:
|
|||||||
|
|
||||||
self.rect.center = (center_x, center_y)
|
self.rect.center = (center_x, center_y)
|
||||||
|
|
||||||
|
|
||||||
# Metoda do wyświetlania pola na ekranie
|
# Metoda do wyświetlania pola na ekranie
|
||||||
def blitme(self):
|
def blitme(self):
|
||||||
self.screen.blit(self.image, self.rect)
|
self.screen.blit(self.image, self.rect)
|
||||||
@ -49,5 +48,5 @@ class Field:
|
|||||||
self.neighbors.append(board[self.y + 1][self.x])
|
self.neighbors.append(board[self.y + 1][self.x])
|
||||||
|
|
||||||
def addShelf(self):
|
def addShelf(self):
|
||||||
shelf = Shelf(len(self.shelves)+1)
|
shelf = Shelf(len(self.shelves) + 1)
|
||||||
self.shelves.append(shelf)
|
self.shelves.append(shelf)
|
||||||
|
1
main.py
1
main.py
@ -48,7 +48,6 @@ def run():
|
|||||||
elif event.key == pygame.K_SPACE:
|
elif event.key == pygame.K_SPACE:
|
||||||
board[9][0].item = choice(data.learning_data)
|
board[9][0].item = choice(data.learning_data)
|
||||||
print("Wybrano: " + board[9][0].item[-1])
|
print("Wybrano: " + board[9][0].item[-1])
|
||||||
board[9][0].item[-1] = 'Something'
|
|
||||||
field = board[9][0]
|
field = board[9][0]
|
||||||
if not field.is_shelf:
|
if not field.is_shelf:
|
||||||
path = functions.a_star(board[agent.y][agent.x], field, board)
|
path = functions.a_star(board[agent.y][agent.x], field, board)
|
||||||
|
Loading…
Reference in New Issue
Block a user