Macierzowa magia
Początkowo myślałem o nazwaniu tego postu „Powrót do bazy”, ponieważ wychodzę z tidyverse i wkraczam w świat macierzy, ale tak naprawdę nie ma w tym nic podstawowego. Przejdźmy przez to krok po kroku.
Po pierwsze, weźmiemy naszą tabelę i zrobimy z niej macierz. Nie możemy po prostu zrobić tego bezpośrednio as.matrix()
, ponieważ spowoduje to, że kolumna Atakowanie będzie pierwszą kolumną, podczas gdy my chcemy, aby to były nazwy własne, więc zrobimy to w dwóch krokach.
m <- as.matrix(type_comparisons)rownames(m) <- type_comparisons$Attacking
Następnie, ponieważ zależy nam tylko na tym, czy wpis jest 2, czy nie, zmienimy każdy wpis, który jest 2, na 1 i każdy wpis, który nie jest, na 0 (1L *
sprawia, że jest to 1 lub 0 zamiast TRUE lub 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
Macierz all_combinations
, którą stworzyliśmy wcześniej, jest w zasadzie zbiorem indeksów dla macierzy super_effective_m
. Na przykład, kolumna 1 all_combinations
to liczby od 1 do 6, co oznacza, że chcemy uzyskać wiersze od 1 do 6 super_effective_m
. Pamiętaj, że każdy rząd super_effective_m
to typ atakujący w naszej drużynie, a każda kolumna to typ broniący. Następnie chcemy uzyskać sumę każdej kolumny i wiedzieć, ile kolumn ma sumę większą niż 0, co oznacza, że przynajmniej jeden z naszych typów atakujących był super skuteczny przeciwko niemu. Stworzymy funkcję, super_effective_nb
:
super_effective_nb <- function(indices) { sum(colSums(super_effective_m) > 0)}
Teraz możemy użyć apply()
aby uzyskać wektor, dla wszystkich 18k+ drużyn, ile typów jest super skutecznych przeciwko nim. Jeśli nie jesteś zaznajomiony z apply()
, pierwszym argumentem jest to, do czego stosujemy naszą funkcję, drugim jest to, czy ma ona być stosowana do wierszy czy kolumn (wybieramy 2 dla kolumn, ponieważ każda kolumna to drużyna), a trzecim jest funkcja.
super_effective_results <- apply(all_combinations, 2, super_effective_nb)
Jakie są kombinacje, które są super skuteczne przeciwko maksymalnej liczbie możliwych typów?
which(super_effective_results == max(super_effective_results))
## 14323 14325 15610 15612 16454 16459 16852 16854 16989 16994
Widzimy, że istnieje 10 możliwych kombinacji sześciu typów. Przyjrzyjmy się im, pobierając te kolumny z all_combinations
.
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
Mamy teraz macierz, best_combo
, gdzie każda kolumna to zespół. Na przykład widzimy, że zespół typów 4, 6, 7, 9, 10 i 14 obejmuje maksymalną liczbę typów obrońców. Ale co to jest typ 4? Aby odpowiedzieć na to pytanie, weźmiemy nazwy wierszy z super_effective_m
i zindeksujemy je przez 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"
W ten sposób otrzymamy wektor postaci. Jest w porządku, więc wiemy, że pierwsza szóstka to drużyna 1, druga szóstka to drużyna 2 itd, ale nie jest to wyświetlane zbyt dobrze. Możemy użyć matrix
aby zamienić to w matrycę, określając, że chcemy 6 rzędów.
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"
Dla naszego ostatniego kroku, faktycznie zamierzamy zrobić z tego tibble, więc mogę spojrzeć na to, które typy pojawiają się najczęściej w różnych możliwościach zespołu.
strongest_teams %>% as_tibble() %>% gather(team, type) %>% count(type, sort = TRUE) %>% knitr::kable()
typ | n |
---|---|
Ground | 10 |
Fighting | 8 |
Flying | 8 |
Ice | 8 |
Dark | 5 |
Ghost | 5 |
Grass | 4 |
Poison | 4 |
Electric | 2 |
Fairy | 2 |
Rock | 2 |
Steel | 2 |
Widzimy, że wszystkie 10 drużyn potrzebuje typu podłoża, gdzie 8 ma typ Fighting, Flying, lub Ice. Z drugiej strony, Electric, Fairy, Rock i Steel są używane tylko przez dwie drużyny.