Magia de las matrices
Originalmente pensaba llamar a este post «Volviendo a la base», ya que me estoy moviendo fuera del tidyverse y en el mundo de las matrices, pero realmente no hay nada básico en esto. Vamos a recorrerlo paso a paso.
Primero, vamos a coger nuestra tabla y convertirla en una matriz. No podemos hacer as.matrix()
directamente, ya que hará que la columna Ataque sea la primera columna, mientras que nosotros queremos que sean los rownames, así que lo haremos en dos pasos.
m <- as.matrix(type_comparisons)rownames(m) <- type_comparisons$Attacking
A continuación, como sólo nos importa si la entrada es 2 o no, cambiaremos cada entrada que sea un 2 para que sea 1 y cada entrada que no lo sea para que sea 0 (el 1L *
hace que sea 1 o 0 en lugar de TRUE o 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
La matriz all_combinations
que hemos creado antes es esencialmente un conjunto de índices para la matriz super_effective_m
. Por ejemplo, la columna 1 de all_combinations
son los números del 1 al 6, lo que significa que queremos obtener las filas del 1 al 6 de super_effective_m
. Recuerda que cada fila de super_effective_m
es un tipo de ataque en nuestro equipo, y cada columna es un tipo de defensa. A continuación, queremos obtener la suma de cada columna y saber cuántas columnas tienen una suma superior a 0, lo que significa que al menos uno de nuestros tipos de ataque fue súper efectivo contra él. Haremos una función, super_effective_nb
:
super_effective_nb <- function(indices) { sum(colSums(super_effective_m) > 0)}
Ahora podemos usar apply()
para obtener un vector, para todos los equipos de 18k+, de cuántos tipos son súper efectivos contra. Si no estás familiarizado con apply()
, el primer argumento es a lo que estamos aplicando nuestra función, el segundo es si debe aplicarse a las filas o a las columnas (elegimos 2 para la columna, ya que cada columna es el equipo), y el tercero es la función.
super_effective_results <- apply(all_combinations, 2, super_effective_nb)
¿Cuáles son las combinaciones que son súper efectivas contra el máximo número de tipos posibles?
which(super_effective_results == max(super_effective_results))
## 14323 14325 15610 15612 16454 16459 16852 16854 16989 16994
Vemos que hay 10 combinaciones posibles de seis tipos. Vamos a verlas sacando esas columnas de 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
Ahora tenemos una matriz, best_combo
, donde cada columna es un equipo. Por ejemplo, vemos que un equipo de los tipos 4, 6, 7, 9, 10 y 14 cubren el máximo número de tipos de defensa. Pero, ¿qué es el tipo 4? Para responder a eso, cogemos los nombres de las filas de super_effective_m
y lo indexamos por 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"
Sin embargo, esto nos da un vector de caracteres. Está en orden, por lo que sabemos que los seis primeros son del equipo 1, los segundos del equipo 2, etc, pero no se visualiza muy bien. Podemos usar matrix
para convertir esto en una matriz en su lugar, especificando que queremos 6 filas.
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"
Para nuestro paso final, vamos a convertir esto en un tibble, para poder ver qué tipos aparecen con más frecuencia en las diferentes posibilidades de equipo.
strongest_teams %>% as_tibble() %>% gather(team, type) %>% count(type, sort = TRUE) %>% knitr::kable()
tipo | n | ||
---|---|---|---|
Terreno | 10 | Lucha | 8 | Vuelo | 8 | 8 | Oscuridad | 5 |
Fantasma | 5 | ||
Hierba | 4 | Veneno | 4 | Eléctrico | 2 | Hada | 2 |
Roca | 2 | ||
Acero | 2 |
Vemos que los 10 equipos necesitan un tipo de suelo, donde 8 tienen un tipo Fighting, Flying, o Ice. Por otro lado, Eléctrico, Hada, Roca y Acero sólo son utilizados por dos equipos cada uno.