Magia delle matrici
In origine pensavo di chiamare questo post “Tornare alla base”, dato che sto uscendo dal tidyverse per entrare nel mondo delle matrici, ma non c’è davvero nulla di basilare in questo. Procediamo passo dopo passo.
Prima di tutto, prendiamo la nostra tabella e la trasformiamo in una matrice. Non possiamo semplicemente fare as.matrix()
direttamente, perché renderebbe la colonna Attacking la prima colonna, mentre noi vogliamo che siano i rownames, quindi lo faremo in due passi.
m <- as.matrix(type_comparisons)rownames(m) <- type_comparisons$Attacking
In seguito, poiché ci interessa solo sapere se la voce è 2 o no, cambieremo ogni voce che è un 2 in 1 e ogni voce che non lo è in 0 (il 1L *
la rende 1 o 0 invece di VERO o FALSO).
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
La matrice all_combinations
che abbiamo creato prima è essenzialmente un insieme di indici per la matrice super_effective_m
. Per esempio, la colonna 1 di all_combinations
sono i numeri da 1 a 6, il che significa che vogliamo ottenere le righe da 1 a 6 di super_effective_m
. Ricordate, ogni riga di super_effective_m
è un tipo di attacco della nostra squadra, e ogni colonna è un tipo di difesa. Vogliamo quindi ottenere la somma di ogni colonna e sapere quante colonne hanno una somma superiore a 0, il che significa che almeno uno dei nostri tipi di attacco è stato super efficace contro di esso. Faremo una funzione, super_effective_nb
:
super_effective_nb <- function(indices) { sum(colSums(super_effective_m) > 0)}
Ora possiamo usare apply()
per ottenere un vettore, per tutte le 18k+ squadre, di quanti tipi sono super efficaci contro. Se non avete familiarità con apply()
, il primo argomento è ciò a cui stiamo applicando la nostra funzione, il secondo è se si deve applicare alle righe o alle colonne (scegliamo 2 per colonna, poiché ogni colonna è la squadra), e il terzo è la funzione.
super_effective_results <- apply(all_combinations, 2, super_effective_nb)
Quali sono le combinazioni super efficaci contro il massimo numero di tipi possibili?
which(super_effective_results == max(super_effective_results))
## 14323 14325 15610 15612 16454 16459 16852 16854 16989 16994
Vediamo che ci sono 10 possibili combinazioni di sei tipi. Diamo un’occhiata prendendo le colonne da 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
Abbiamo ora una matrice, best_combo
, dove ogni colonna è una squadra. Per esempio, vediamo che una squadra di tipo 4, 6, 7, 9, 10 e 14 copre il numero massimo di tipi di difesa. Ma qual è il tipo 4? Per rispondere, prendiamo i nomi delle righe da super_effective_m
e li indicizziamo per 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"
Questo ci dà un vettore di caratteri. È in ordine, quindi sappiamo che i primi sei sono la squadra 1, i secondi sei la squadra 2, ecc, ma non è visualizzato molto bene. Possiamo usare matrix
per trasformarlo invece in una matrice, specificando che vogliamo 6 righe.
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"
Per il nostro passo finale, faremo una tibbia, così posso vedere quali tipi appaiono più spesso nelle diverse possibilità di squadra.
strongest_teams %>% as_tibble() %>% gather(team, type) %>% count(type, sort = TRUE) %>% knitr::kable()
tipo | n | |
---|---|---|
Terra | 10 | |
Combattimento | 8 | |
Volare | 8 | |
Ghiaccio | 8 | |
Oscuro | 5 | |
Ghost | 5 | |
Grass | 4 | |
Poison | 4 | |
Electric | 2 | |
Fairy | 2 | |
Rock | 2 | |
Steel | 2 |
Vediamo tutte e 10 le squadre hanno bisogno di un tipo di terreno, dove 8 hanno un tipo Lotta, Volante o Ghiaccio. D’altra parte, Electric, Fairy, Rock e Steel sono usati solo da due squadre ciascuno.