DT Report alpha version
This commit is contained in:
parent
3229d9405a
commit
d9d67388e5
182
DecisionTree.md
182
DecisionTree.md
@ -21,6 +21,186 @@ Czy:
|
||||
|
||||
## Metoda uczenia - Algorytm ID3
|
||||
|
||||
Metoda użyta do uczenia drzewa decyzyjnego to metoda **indukcyjnego uczenia drzewa decyzyjnego**.
|
||||
|
||||
### Działanie ID3
|
||||
* Definiujemy atrybuty, które będą posiadały przykłady służące do uczenia drzewa (**atrybuty**)
|
||||
```python
|
||||
class AttributeDefinition:
|
||||
def __init__(self, id, name: str, values: List):
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.values = values
|
||||
|
||||
class Attribute:
|
||||
def __init__(self, attributeDefinition: AttributeDefinition, value):
|
||||
self.attributeDefinition = attributeDefinition
|
||||
self.value = value
|
||||
```
|
||||
* Tworzymy przykłady z wykorzystaniem atrybutów (**przykłady**)
|
||||
```python
|
||||
class DecisionTreeExample:
|
||||
def __init__(self, classification, attributes: List[Attribute]):
|
||||
self.attributes = attributes
|
||||
self.classification = classification
|
||||
```
|
||||
* Ustalamy domyślną wartość do zwrócenia przez drzewo - **klasa domyślna**
|
||||
* Następnie postępujemy indukcyjnie:
|
||||
* Jeżeli liczba przykładów == 0: zwracamy wierzchołek oznaczony klasą domyślną
|
||||
* Jeżeli wszystkie przykłady są tak samo sklasyfikowane: zwracamy wierzchołek oznacz. tą klasą
|
||||
* Jeżeli liczba atrybutów == 0: zwracamy wierzchołek oznacz. klasą, którą posiada większość przykładów
|
||||
* W przeciwnym wypadku **wybieramy atrybut** A (o wyborze atrybutu poniżej) i czynimy go korzeniem drzewa T
|
||||
* **nowa_klasa_domyślna** = wierzchołek oznaczony klasą, która jest przypisana największej liczbie przykładów
|
||||
* Dla każdej wartości W atrybutu A:
|
||||
* nowe_przykłady = przykłady, dla których atrybut A przyjmuje wartość W
|
||||
* Dodajemy do T krawędź oznaczoną przez wartość W, która prowadzi do wierzchołka zwróconego przez wywołanie indukcyjne:
|
||||
*treelearn(nowe_przykłady, atrybuty−A, nowa_klasa_domyślna)*
|
||||
* Zwróć drzewo T
|
||||
```python
|
||||
class DecisionTree(object):
|
||||
def __init__(self, root):
|
||||
self.root = root
|
||||
self.branches = []
|
||||
self.branchesNum = 0
|
||||
```
|
||||
|
||||
### Wybór atrybutu
|
||||
W trakcie uczenia drzewa decyzyjnego chcemy wybrać jak najlepszy atrybut, dzięki któremu możliwie jak najszybciej będziemy mogli sklasyfikować podane przykłady.
|
||||
|
||||
Miarą porównawczą atrybutów będzie **zysk informacji** dla danego atrybutu (**information gain**).
|
||||
|
||||
Atrybut o największym zysku zostanie wybrany.
|
||||
|
||||
**Implementacja**
|
||||
|
||||
```python
|
||||
def chooseAttribute(attributes: List[AttributeDefinition], examples: List[DecisionTreeExample], classifications):
|
||||
bestAttribute = None
|
||||
bestAttributeGain = -1
|
||||
|
||||
for attribute in attributes:
|
||||
attrInformationGain = calculateInformationGain(attribute, classifications, examples)
|
||||
if attrInformationGain > bestAttributeGain:
|
||||
bestAttribute = attribute
|
||||
bestAttributeGain = attrInformationGain
|
||||
|
||||
return bestAttribute
|
||||
```
|
||||
|
||||
|
||||
#### Obliczanie zysku informacji
|
||||
(Wszelkie obliczenia wedle wzorów podanych na zajęciach)
|
||||
* I(C) - Obliczamy zawartość informacji dla zbioru możliwych klasyfikacji
|
||||
* E(A) - Obliczamy ilość informacji potrzebną do zakończenia klasyfikacji po sprawdzeniu atrybutu
|
||||
* **G(A)** - **Przyrost informacji dla atrybutu A** = I(C) - E(A)
|
||||
|
||||
**Implementacja**
|
||||
|
||||
```python
|
||||
def calculateInformationGain(attribute: AttributeDefinition, classifications, examples: List[DecisionTreeExample]):
|
||||
return calculateEntropy(classifications, examples) - calculateRemainder(attribute, examples, classifications)
|
||||
```
|
||||
|
||||
## Opis implementacji
|
||||
### Definicje atrybutów:
|
||||
* Głód: **[0, 1/4); [1/4, 1/2); [1/2, 3/4); [3/4, 1]**
|
||||
* Pragnienie: **[0, 1/4); [1/4, 1/2); [1/2, 3/4); [3/4, 1]**
|
||||
* Energia: **[0, 1/4); [1/4, 1/2); [1/2, 3/4); [3/4, 1]**
|
||||
* Odległość od jedzenia: **[0, 3); [3, 8); [8, 15); [15, max)**
|
||||
* Odległość od źródła wody: **[0, 3); [3, 8); [8, 15); [15, max)**
|
||||
* Odległość od miejsca spoczynku: **[0, 3); [3, 8); [8, 15); [15, max)**
|
||||
* Odległość pomiędzy wodą a jedzeniem: **[0, 3); [3, 8); [8, 15); [15, max)**
|
||||
|
||||
```python
|
||||
class PlayerStatsValue(Enum):
|
||||
ZERO_TO_QUARTER = 0
|
||||
QUARTER_TO_HALF = 1
|
||||
HALF_TO_THREE_QUARTERS = 2
|
||||
THREE_QUARTERS_TO_FULL = 3
|
||||
|
||||
class DistFromObject(Enum):
|
||||
LT_3 = 0
|
||||
GE_3_LT_8 = 1
|
||||
GE_8_LT_15 = 2
|
||||
GE_15 = 3
|
||||
```
|
||||
### Uczenie drzewa
|
||||
|
||||
```python
|
||||
def inductiveDecisionTreeLearning(examples: List[DecisionTreeExample], attributes: List[AttributeDefinition], default,
|
||||
classifications)
|
||||
```
|
||||
|
||||
### Zwracanie decyzji przez drzewo
|
||||
```python
|
||||
def giveAnswer(self, example: DecisionTreeExample):
|
||||
if self.branchesNum == 0:
|
||||
return self.root
|
||||
|
||||
for attr in example.attributes:
|
||||
if attr.attributeDefinition.id == self.root.id:
|
||||
for branch in self.branches:
|
||||
if branch.label == attr.value:
|
||||
return branch.subtree.giveAnswer(example)
|
||||
```
|
||||
|
||||
### Wybór celu dla agenta
|
||||
```python
|
||||
def pickEntity(self, player, map, pickForGa=False):
|
||||
foods = map.getInteractablesByClassifier(Classifiers.FOOD)
|
||||
waters = map.getInteractablesByClassifier(Classifiers.WATER)
|
||||
rests = map.getInteractablesByClassifier(Classifiers.REST)
|
||||
|
||||
playerStats = DTPlayerStats.dtStatsFromPlayerStats(player.statistics)
|
||||
|
||||
# Get waters sorted by distance from player
|
||||
dtWaters: List[DTSurvivalInteractable] = []
|
||||
for water in waters:
|
||||
dtWater = DTSurvivalInteractable.dtInteractableFromInteractable(water, player.x, player.y)
|
||||
dtWaters.append(dtWater)
|
||||
dtWaters.sort(key=lambda x: x.accurateDistanceFromPlayer)
|
||||
nearestDtWater = dtWaters[0]
|
||||
|
||||
# Get foods sorted by distance from player
|
||||
dtFoods: List[DTSurvivalInteractable] = []
|
||||
for food in foods:
|
||||
dtFood = DTSurvivalInteractable.dtInteractableFromInteractable(food, player.x, player.y)
|
||||
dtFoods.append(dtFood)
|
||||
|
||||
dtFoods.sort(key=lambda x: x.accurateDistanceFromPlayer)
|
||||
# If there is no food on map return nearest water.
|
||||
try:
|
||||
nearestDtFood = dtFoods[0]
|
||||
except IndexError:
|
||||
return nearestDtWater.interactable
|
||||
|
||||
# Get rest places sorted by distance from player
|
||||
dtRestPlaces: List[DTSurvivalInteractable] = []
|
||||
for rest in rests:
|
||||
dtRest = DTSurvivalInteractable.dtInteractableFromInteractable(rest, player.x, player.y)
|
||||
dtRestPlaces.append(dtRest)
|
||||
dtRestPlaces.sort(key=lambda x: x.accurateDistanceFromPlayer)
|
||||
nearestDtRest = dtRestPlaces[0]
|
||||
|
||||
currentSituation = SurvivalDTExample(None, playerStats.hungerAmount, playerStats.thirstAmount,
|
||||
playerStats.staminaAmount,
|
||||
nearestDtFood.dtDistanceFromPlayer, nearestDtWater.dtDistanceFromPlayer,
|
||||
nearestDtRest.dtDistanceFromPlayer,
|
||||
nearestDtFood.getDtDistanceFromOtherInteractable(nearestDtWater.interactable))
|
||||
|
||||
treeDecision, choice = self.__pickEntityAfterTreeDecision__(currentSituation,
|
||||
dtFoods,
|
||||
dtRestPlaces,
|
||||
dtWaters)
|
||||
return choice.interactable
|
||||
```
|
||||
|
||||
## Zestaw uczący, zestaw testowy
|
||||
|
||||
## Zastosowanie w projekcie
|
||||
### Zestaw uczący
|
||||
|
||||
Zestaw uczący był generowany poprzez tworzenie losowych przykładów i zapytanie użytkownika o klasyfikację, a następnie zapisywany do pliku.
|
||||
|
||||
### Zestaw testowy
|
||||
|
||||
Przy testowaniu drzewa podajemy ile procent wszystkich, wcześniej wygenerowanych przykładów mają być przykłady testowe.
|
Loading…
Reference in New Issue
Block a user