Matrixmagie
Ik dacht er oorspronkelijk aan om deze post “Terug naar de basis” te noemen, omdat ik uit de tidyverse stap en in de wereld van matrices, maar er is echt niets basaals aan dit onderwerp. Laten we er stap voor stap doorheen lopen.
Eerst gaan we onze tabel nemen en er een matrix van maken. We kunnen niet gewoon direct as.matrix()
doen, want dan wordt de kolom Aanvallen de eerste kolom, terwijl we willen dat dat de rownamen zijn, dus doen we het in twee stappen.
m <- as.matrix(type_comparisons)rownames(m) <- type_comparisons$Attacking
Volgende, omdat we alleen maar willen weten of de entry 2 is of niet, veranderen we elke entry die een 2 is in 1 en elke entry die dat niet is in 0 (de 1L *
maakt het 1 of 0 in plaats van TRUE of FALSE).
super_effective_m <- (m == 2) * 1L
super_effective_m
## Normal Fire Water Electric Grass Ice Fighting Poison Ground Flying## Normal 0 0 0 0 0 0 0 0 0 0## Fire 0 0 0 0 1 1 0 0 0 0## Water 0 1 0 0 0 0 0 0 1 0## Electric 0 0 1 0 0 0 0 0 0 1## Grass 0 0 1 0 0 0 0 0 1 0## Ice 0 0 0 0 1 0 0 0 1 1## Fighting 1 0 0 0 0 1 0 0 0 0## Poison 0 0 0 0 1 0 0 0 0 0## Ground 0 1 0 1 0 0 0 1 0 0## Flying 0 0 0 0 1 0 1 0 0 0## Psychic 0 0 0 0 0 0 1 1 0 0## Bug 0 0 0 0 1 0 0 0 0 0## Rock 0 1 0 0 0 1 0 0 0 1## Ghost 0 0 0 0 0 0 0 0 0 0## Dragon 0 0 0 0 0 0 0 0 0 0## Dark 0 0 0 0 0 0 0 0 0 0## Steel 0 0 0 0 0 1 0 0 0 0## Fairy 0 0 0 0 0 0 1 0 0 0## Psychic Bug Rock Ghost Dragon Dark Steel Fairy## Normal 0 0 0 0 0 0 0 0## Fire 0 1 0 0 0 0 1 0## Water 0 0 1 0 0 0 0 0## Electric 0 0 0 0 0 0 0 0## Grass 0 0 1 0 0 0 0 0## Ice 0 0 0 0 1 0 0 0## Fighting 0 0 1 0 0 1 1 0## Poison 0 0 0 0 0 0 0 1## Ground 0 0 1 0 0 0 1 0## Flying 0 1 0 0 0 0 0 0## Psychic 0 0 0 0 0 0 0 0## Bug 1 0 0 0 0 1 0 0## Rock 0 1 0 0 0 0 0 0## Ghost 1 0 0 1 0 0 0 0## Dragon 0 0 0 0 1 0 0 0## Dark 1 0 0 1 0 0 0 0## Steel 0 0 1 0 0 0 0 1## Fairy 0 0 0 0 1 1 0 0
De all_combinations
matrix die we eerder hebben gemaakt is in wezen een verzameling indices voor de super_effective_m
matrix. Bijvoorbeeld, kolom 1 van all_combinations
zijn de nummers 1 tot en met 6, wat betekent dat we de rijen 1 tot en met 6 van super_effective_m
willen hebben. Onthoud, elke rij van super_effective_m
is een aanvallend type in ons team, en elke kolom is een verdedigend type. We willen dan de som van elke kolom krijgen en weten hoeveel kolommen een som van meer dan 0 hebben, wat betekent dat ten minste een van onze aanvallende types er super effectief tegen was. We maken een functie, super_effective_nb
:
super_effective_nb <- function(indices) { sum(colSums(super_effective_m) > 0)}
Nu kunnen we apply()
gebruiken om een vector te krijgen, voor alle 18k+ teams, van hoeveel types ze super effectief zijn tegen. Als je niet bekend bent met apply()
, het eerste argument is waar we onze functie op toepassen, het tweede is of het moet gelden voor de rijen of kolommen (we kiezen 2 voor kolom, omdat elke kolom een team is), en het derde is de functie.
super_effective_results <- apply(all_combinations, 2, super_effective_nb)
Wat zijn de combinaties die super effectief zijn tegen het maximaal aantal mogelijke types?
which(super_effective_results == max(super_effective_results))
## 14323 14325 15610 15612 16454 16459 16852 16854 16989 16994
We zien dat er 10 mogelijke combinaties van zes types zijn. Laten we ze eens bekijken door die kolommen uit all_combinations
te halen.
best_combos <- all_combinationsbest_combos
## ## 4 4 5 5 5 5 6 6 6 6## 6 6 6 6 8 8 7 7 7 7## 7 7 7 7 9 9 8 8 9 9## 9 9 9 9 13 13 9 9 10 10## 10 10 10 10 14 16 10 10 14 16## 14 16 14 16 18 18 14 16 17 17
We hebben nu een matrix, best_combo
, waarin elke kolom een team is. We zien bijvoorbeeld dat een team van type 4, 6, 7, 9, 10, en 14 het maximum aantal verdedigende types dekt. Maar wat is type 4? Om dat te beantwoorden, nemen we de rijnamen uit super_effective_m
en indexeren die met best_combos
.
rownames(super_effective_m)
## "Electric" "Ice" "Fighting" "Ground" "Flying" "Ghost" ## "Electric" "Ice" "Fighting" "Ground" "Flying" "Dark" ## "Grass" "Ice" "Fighting" "Ground" "Flying" "Ghost" ## "Grass" "Ice" "Fighting" "Ground" "Flying" "Dark" ## "Grass" "Poison" "Ground" "Rock" "Ghost" "Fairy" ## "Grass" "Poison" "Ground" "Rock" "Dark" "Fairy" ## "Ice" "Fighting" "Poison" "Ground" "Flying" "Ghost" ## "Ice" "Fighting" "Poison" "Ground" "Flying" "Dark" ## "Ice" "Fighting" "Ground" "Flying" "Ghost" "Steel" ## "Ice" "Fighting" "Ground" "Flying" "Dark" "Steel"
Dit levert ons echter een tekenvector op. Het is in volgorde, dus we weten dat de eerste zes team 1 is, de tweede zes team 2, etc., maar het wordt niet erg goed weergegeven. We kunnen matrix
gebruiken om er een matrix van te maken, waarbij we aangeven dat we 6 rijen willen.
strongest_teams <- matrix(rownames(super_effective_m), nrow = 6)
strongest_teams
## ## "Electric" "Electric" "Grass" "Grass" "Grass" "Grass" "Ice" ## "Ice" "Ice" "Ice" "Ice" "Poison" "Poison" "Fighting"## "Fighting" "Fighting" "Fighting" "Fighting" "Ground" "Ground" "Poison" ## "Ground" "Ground" "Ground" "Ground" "Rock" "Rock" "Ground" ## "Flying" "Flying" "Flying" "Flying" "Ghost" "Dark" "Flying" ## "Ghost" "Dark" "Ghost" "Dark" "Fairy" "Fairy" "Ghost" ## ## "Ice" "Ice" "Ice" ## "Fighting" "Fighting" "Fighting"## "Poison" "Ground" "Ground" ## "Ground" "Flying" "Flying" ## "Flying" "Ghost" "Dark" ## "Dark" "Steel" "Steel"
Voor onze laatste stap gaan we hier een tabel van maken, zodat ik kan zien welke types het vaakst voorkomen bij de verschillende teammogelijkheden.
strongest_teams %>% as_tibble() %>% gather(team, type) %>% count(type, sort = TRUE) %>% knitr::kable()
type | n |
---|---|
Grond | 10 |
Vliegen | 8 |
Vliegen | 8 |
Is | 8 |
Donker | 5 |
Ghost | 5 |
4 | |
4 | |
Electric | 2 |
Fairy | 2 |
Rock | 2 |
Steel | 2 |
We zien dat alle 10 de teams een grondtype nodig hebben, waar 8 een Fighting, Flying, of Ice type hebben. Electric, Fairy, Rock, en Steel worden daarentegen elk maar door twee teams gebruikt.