Tabla de contingencia
Introducción
Una tabla de contingencia es una tabla en la que se resume la distribución de frecuencias conjuntas de dos variables. En esta tabla, cada fila representa una categoría de la variable \(X\) y cada columna representa una ctegoría de la variable \(Y\).
Cada celda de la tabla representa la frecuencia con la que aparecen conjuntamente las categorías de la fila y la columna en la que está ubicada. Por ejemplo, la celda en la fila 2 con columna 3, es la frecuencia de la categoría 2 de las filas, y la categoría 3 de las columnas.
Las tablas de contingencia también son conocidas como tablas cruzadas, tablas de frecuencias de doble entrada o tablas de frecuencias bidimensionales.
Estuve buscando en internet si existía alguna notación estándar para las tablas de contingencia y no conseguí nada. Sin embargo, utilicé una notación que me pareció lógica y bastante parecida a la que me enseñaron en la universidad.
Datos
Vamos a cargar el conjunto de datos Cars93
del paquete MASS
. Al igual que como hemos hecho con iris
, vamos a limpiar los nombres y además le ponemos un nombre más alineado con la guía de estilos del tidyverse.
library(dplyr)
library(janitor)
data("Cars93", package = "MASS")
(cars <- Cars93 %>% as_tibble() %>% clean_names())
## # A tibble: 93 x 27
## manufacturer model type min_price price max_price mpg_city mpg_highway
## <fct> <fct> <fct> <dbl> <dbl> <dbl> <int> <int>
## 1 Acura Inte… Small 12.9 15.9 18.8 25 31
## 2 Acura Lege… Mids… 29.2 33.9 38.7 18 25
## 3 Audi 90 Comp… 25.9 29.1 32.3 20 26
## 4 Audi 100 Mids… 30.8 37.7 44.6 19 26
## 5 BMW 535i Mids… 23.7 30 36.2 22 30
## 6 Buick Cent… Mids… 14.2 15.7 17.3 22 31
## 7 Buick LeSa… Large 19.9 20.8 21.7 19 28
## 8 Buick Road… Large 22.6 23.7 24.9 16 25
## 9 Buick Rivi… Mids… 26.3 26.3 26.3 19 27
## 10 Cadillac DeVi… Large 33 34.7 36.3 16 25
## # … with 83 more rows, and 19 more variables: air_bags <fct>,
## # drive_train <fct>, cylinders <fct>, engine_size <dbl>, horsepower <int>,
## # rpm <int>, rev_per_mile <int>, man_trans_avail <fct>,
## # fuel_tank_capacity <dbl>, passengers <int>, length <int>, wheelbase <int>,
## # width <int>, turn_circle <int>, rear_seat_room <dbl>, luggage_room <int>,
## # weight <int>, origin <fct>, make <fct>
Ejemplo
Podemos utilizar la función table
para obtener una tabla de contingencia:
cars %>%
select(type, air_bags) %>%
table()
## air_bags
## type Driver & Passenger Driver only None
## Compact 2 9 5
## Large 4 7 0
## Midsize 7 11 4
## Small 0 5 16
## Sporty 3 8 3
## Van 0 3 6
Según este resultado, 11 de los automóviles son de tipo Midsize y a su vez tienen bolsa de aire (air bag) en el asiento del conductor sólamente (Driver only), mientras que ningún auto tipo Small tiene air bag en los asientos del conductor y del pasajero.
El resultado de la función table
es un objeto de tipo matrix
, una matriz. Aunque estos objetos tienen algunas cosas en común con los data.frame
, tienen ciertas diferencias que te pueden causar problemas si no sabes bien lo que estás haciendo.
Pregunta
La frecuencia de la fila \(i\) fila y la columna \(j\) se denota por \(f_{ij}\) y se lee “efe sub i, jota”, similar a la notación de las tablas de frecuencia unidimensionales, sólo que con dos índices, uno para las filas y uno para las columnas. Cuando substituímos \(ij\) por números, podemos agregar una coma para separar los índices y evitar confusiones. En el ejemplo anterior diríamos que \(f_{3,2}=11\).
Si sumamos todas las frecuencias conjuntas obtenemos el tamaño de la muestra:
\[ \sum_{i=1}^{c}\sum_{j=1}^{r}{f_{ij}} = n \]
Lo comprobamos en R
:
cars %>%
select(type, air_bags) %>%
table() %>%
sum()
## [1] 93
nrow(cars)
## [1] 93
Tabla de frecuencias relativas
Nos preguntamos ahora ¿qué proporción de estos autos tienen bolsa de aire en ambos asientos (Driver & Passenger) y son grandes (Large)?. Tendríamos entonces que dividir esa frecuencia conjunta entre el total de datos: \(4/93=0.043\). En otras palabras, \(4.3\)% de los autos tienen simultáneamente las dos características que nos interesan.
En una tabla de frecuencias relativas, cada celda representa la proporción de elementos que pertenecen a la fila y columna en la que está. La frecuencia relativa de la fila \(i\) y la columna \(j\) se denota por \(h_{ij}\) y se calcula de la siguiente manera:
\[ h_{ij}=\frac{f_{ij}}{n} \]
Para enfatizar la diferencia entre \(f_{ij}\) y \(h_{ij}\), diremos que \(f_{ij}\) es la frecuencia absoluta de la fila \(i\) y la columna \(j\).
Podemos obtener una tabla de frecuencias relativas calculando la tabla de frecuencias absolutas y usando la función prop.table
:
abs_table <- cars %>%
select(type, air_bags) %>%
table()
(rel_table <- prop.table(abs_table))
## air_bags
## type Driver & Passenger Driver only None
## Compact 0.02150538 0.09677419 0.05376344
## Large 0.04301075 0.07526882 0.00000000
## Midsize 0.07526882 0.11827957 0.04301075
## Small 0.00000000 0.05376344 0.17204301
## Sporty 0.03225806 0.08602151 0.03225806
## Van 0.00000000 0.03225806 0.06451613
Propiedad
La suma de todas las frecuencias relativas es igual a 1
\[ \sum_{i=1}^{c}\sum_{j=1}^{r}{h_{ij}} = 1 \]
Lo comprobamos en R
:
sum(rel_table)
## [1] 1
Frecuencias marginales
En una tabla de frecuencias, llamamos frecuencias a la suma de las frecuencias de cada fila o columna.
- La frecuencia marginal de la fila \(i\) se denota por \(f_{i.}\) y se lee efe sub i, punto
- La frecuencia marginal de la columna \(j\) se denota por \(f_{.j}\) y se lee efe sub punto, jota
Para calcular la frecuencia marginal de la fila \(i\), sumamos en esa fila todas las columnas \[ f_{i.} = \sum_{j=1}^{c}{f_{ij}} \]
Para calcular la frecuencia marginal de la columna \(j\), sumamos en esa columna todas las filas \[ f_{.j} = \sum_{i=1}^{r}{f_{ij}} \]
Recordemos que la tabla de frecuencias absolutas se ve así:
abs_table
## air_bags
## type Driver & Passenger Driver only None
## Compact 2 9 5
## Large 4 7 0
## Midsize 7 11 4
## Small 0 5 16
## Sporty 3 8 3
## Van 0 3 6
Ahora podemos usar la función margin.table
con 1
para las filas y 2
para las columnas:
(row_marginals <- margin.table(abs_table, 1))
## type
## Compact Large Midsize Small Sporty Van
## 16 11 22 21 14 9
Si sumamos las frecuencias en la fila Compact obtenemos el resultado \(16 = 2 + 9 + 5\).
(col_marginals <- margin.table(abs_table, 2))
## air_bags
## Driver & Passenger Driver only None
## 16 43 34
Si sumamos las frecuencias de la columna Driver only obtenemos el resultado \(43 = 9 + 7 + 11 + 5 + 8 + 3\).
Frecuencias relativas marginales
También podemos calcular Frecuencias relativas marginales, dividiendo las frecuencias marginales entre el tamaño de la muestra o sumando las frecuencias relativas por filas o columnas:
\[ h_{i.}=\frac{f_{i.}}{n}=\sum_{j=1}^{c}{h_{ij}} \]
\[ h_{.j}=\frac{f_{.j}}{n}=\sum_{i=1}^{r}{h_{ij}} \]
Y ahora en R
podemos usar la función margin.table
esta vez con la tabla de frecuencias relativas:
(row_rel_marginals <- margin.table(rel_table, 1))
## type
## Compact Large Midsize Small Sporty Van
## 0.17204301 0.11827957 0.23655914 0.22580645 0.15053763 0.09677419
(col_rel_marginals <- margin.table(rel_table, 2))
## air_bags
## Driver & Passenger Driver only None
## 0.1720430 0.4623656 0.3655914
Si tenemos la data desagregada, podemos usar count
o una combinación de group_by
y summarise
, como hicimos en el artículo de tablas de frecuencia. La ventaja es que el resultado es un tibble
o data.frame
en lugar de un matrix
.
cars %>% count(type)
## # A tibble: 6 x 2
## type n
## <fct> <int>
## 1 Compact 16
## 2 Large 11
## 3 Midsize 22
## 4 Small 21
## 5 Sporty 14
## 6 Van 9
cars %>% count(air_bags)
## # A tibble: 3 x 2
## air_bags n
## <fct> <int>
## 1 Driver & Passenger 16
## 2 Driver only 43
## 3 None 34
Frecuencias condicionales
Si nos interesa saber qué proporción de una fila o una columna representa una frecuencia conjunta, debemos calcular una Frecuencia condicional.
La frecuencia condicional de la fila \(i\) dada la columna \(j\) se denota por \(f_{i|c=j}\) y se lee efe sub i dado jota \[ f_{i|c=j}=\frac{f_{ij}}{f_{.j}}=\frac{h_{ij}}{h_{.j}} \]
La frecuencia condicional de la columna \(j\) dada la fila \(i\) se denota por \(f_{j|r=i}\) y se lee efe sub i dado jota \[ f_{j|r=i}=\frac{f_{ij}}{f_{i.}}=\frac{h_{ij}}{h_{i.}} \]
Podemos calcular tablas de frecuencias condicionales con la función prop.table
con 1
para condicionar por filas y 2
para condicionar las columnas:
Por filas:
prop.table(abs_table, 1)
## air_bags
## type Driver & Passenger Driver only None
## Compact 0.1250000 0.5625000 0.3125000
## Large 0.3636364 0.6363636 0.0000000
## Midsize 0.3181818 0.5000000 0.1818182
## Small 0.0000000 0.2380952 0.7619048
## Sporty 0.2142857 0.5714286 0.2142857
## Van 0.0000000 0.3333333 0.6666667
Por columnas:
prop.table(abs_table, 2)
## air_bags
## type Driver & Passenger Driver only None
## Compact 0.12500000 0.20930233 0.14705882
## Large 0.25000000 0.16279070 0.00000000
## Midsize 0.43750000 0.25581395 0.11764706
## Small 0.00000000 0.11627907 0.47058824
## Sporty 0.18750000 0.18604651 0.08823529
## Van 0.00000000 0.06976744 0.17647059
También obtenemos el mismo resultado si hacemos los cálculos con las frecuencias relativas:
Por filas:
prop.table(rel_table, 1)
## air_bags
## type Driver & Passenger Driver only None
## Compact 0.1250000 0.5625000 0.3125000
## Large 0.3636364 0.6363636 0.0000000
## Midsize 0.3181818 0.5000000 0.1818182
## Small 0.0000000 0.2380952 0.7619048
## Sporty 0.2142857 0.5714286 0.2142857
## Van 0.0000000 0.3333333 0.6666667
Por columnas:
prop.table(rel_table, 2)
## air_bags
## type Driver & Passenger Driver only None
## Compact 0.12500000 0.20930233 0.14705882
## Large 0.25000000 0.16279070 0.00000000
## Midsize 0.43750000 0.25581395 0.11764706
## Small 0.00000000 0.11627907 0.47058824
## Sporty 0.18750000 0.18604651 0.08823529
## Van 0.00000000 0.06976744 0.17647059
Pregunta
Propiedad
Cada fila de la tabla de frecuencias relativas por fila suma 1, y cada columna de la tabla de frecuencias relativas por columnas suma 1.
rowSums(prop.table(abs_table, 1))
## Compact Large Midsize Small Sporty Van
## 1 1 1 1 1 1
colSums(prop.table(abs_table, 2))
## Driver & Passenger Driver only None
## 1 1 1