6.7 Simulación de distribuciones multivariantes discretas
En el caso de una distribución \(d\)-dimensional discreta el procedimiento habitual es simular una variable aleatoria discreta unidimensional equivalente. Este tipo de procedimientos son conocidos como métodos de etiquetado o codificación y la idea básica consistiría en construir un indice unidimensional equivalente al indice multidimensional, mediante una función de etiquetado \(l(\mathbf{i}) = l\left(i_1, i_2, \ldots,i_d \right) \in \mathbb{N}\).
Si la variable discreta multidimensional tiene soporte finito, este tipo de recodificación se puede hacer de forma automática en R cambiando simplemente el indexado26 (empleando la función as.vector()
para cambiar a un indexado unidimensional y posteriormente las funciones as.matrix()
, o as.array()
, para reconstruir el indexado multidimensional).
Como ejemplo ilustrativo, en el caso bidimensional, podríamos emplear el siguiente código:
<- outer(10*1:4, 1:2, "+")
xy xy
## [,1] [,2]
## [1,] 11 12
## [2,] 21 22
## [3,] 31 32
## [4,] 41 42
<- as.vector(xy)
z z
## [1] 11 21 31 41 12 22 32 42
<- matrix(z, ncol = 2)
xy xy
## [,1] [,2]
## [1,] 11 12
## [2,] 21 22
## [3,] 31 32
## [4,] 41 42
Suponiendo que la primera componente toma \(I\) valores distintos, la función de etiquetado para calcular el índice unidimensional a partir de uno bidimensional sería: \[l(i, j) = I(j-1) + i\]
<- nrow(xy)
nx <- function(i, j) nx*(j-1) + i
l l(2, 1)] z[
## [1] 21
l(3, 2)] z[
## [1] 32
Para recuperar el índice bidimensional se emplearía la inversa de la función de etiquetado: \[l^{-1}( k ) =\left( (k -1) \operatorname{mod} I + 1, \left\lfloor \frac{k - 1}{I}\right\rfloor + 1\right)\]
<- function(k) cbind((k - 1) %% nx + 1, floor((k - 1)/nx) + 1)
linv # Para el caso multidimensional (1d => md): imd <- arrayInd(i1d, dim(xy))
linv(2)] xy[
## [1] 21
linv(7)] xy[
## [1] 32
Realmente lo que ocurre internamente en R es que un objeto matrix
o array
está almacenado como un vector y admite un indexado multidimensional si está presente un atributo dim
:
dim(z) <- c(4, 2)
z
## [,1] [,2]
## [1,] 11 12
## [2,] 21 22
## [3,] 31 32
## [4,] 41 42
dim(z) <- c(2, 2, 2)
z
## , , 1
##
## [,1] [,2]
## [1,] 11 31
## [2,] 21 41
##
## , , 2
##
## [,1] [,2]
## [1,] 12 32
## [2,] 22 42
dim(z) <- NULL
z
## [1] 11 21 31 41 12 22 32 42
Si la variable discreta multidimensional no tiene soporte finito, se podrían emplear métodos de codificación más avanzados (ver Cao, 2002, Sección 6.3), aunque no se podría guardar la función de masa de probabilidad en una tabla.
No obstante, se podría emplear el indexado anterior si todas las componentes menos una (la correspondiente al índice j
en el ejemplo anterior) toman un número finito de valores.
6.7.1 Simulación de una variable discreta bidimensional
Consideramos datos recogidos en un estudio de mejora de calidad en una fábrica de semiconductores. Se obtuvo una muestra de obleas que se clasificaron dependiendo de si se encontraron partículas en la matriz que producía la oblea y de si la calidad de oblea era buena (para más detalles ver Hall, 1994).
<- c(320, 14, 80, 36)
n <- gl(2, 1, 4, labels = c("no", "si"))
particulas <- gl(2, 2, labels = c("buena", "mala"))
calidad <- data.frame(n, particulas, calidad)
df df
## n particulas calidad
## 1 320 no buena
## 2 14 si buena
## 3 80 no mala
## 4 36 si mala
En lugar de estar en el formato de un conjunto de datos (data.frame
) puede que los datos estén en formato de tabla (table
, matrix
):
<- xtabs(n ~ calidad + particulas)
tabla tabla
## particulas
## calidad no si
## buena 320 14
## mala 80 36
Lo podemos convertir directamente a data.frame
:
as.data.frame(tabla)
## calidad particulas Freq
## 1 buena no 320
## 2 mala no 80
## 3 buena si 14
## 4 mala si 36
En este caso estimamos27 las probabilidades a partir de las frecuencias:
$p <- df$n/sum(df$n)
df df
## n particulas calidad p
## 1 320 no buena 0.71111111
## 2 14 si buena 0.03111111
## 3 80 no mala 0.17777778
## 4 36 si mala 0.08000000
En formato tabla:
<- tabla/sum(tabla)
pij pij
## particulas
## calidad no si
## buena 0.71111111 0.03111111
## mala 0.17777778 0.08000000
Para simular la variable bidimensional consideramos una variable unidimensional de índices:
<- 1:nrow(df)
z z
## [1] 1 2 3 4
Con probabilidades:
<- df$p
pz pz
## [1] 0.71111111 0.03111111 0.17777778 0.08000000
Si las probabilidades estuviesen en una matriz, las convertiríamos a un vector con:
as.vector(pij)
## [1] 0.71111111 0.17777778 0.03111111 0.08000000
Si simulamos la variable unidimensional:
set.seed(1)
<- 20
nsim <- sample(z, nsim, replace = TRUE, prob = pz) rz
Podríamos obtener simulaciones bidimensionales, por ejemplo:
<- as.matrix(df[c('particulas', 'calidad')])
etiquetas <- etiquetas[rz, ]
rxy head(rxy)
## particulas calidad
## [1,] "no" "buena"
## [2,] "no" "buena"
## [3,] "no" "buena"
## [4,] "si" "mala"
## [5,] "no" "buena"
## [6,] "si" "mala"
Alternativamente, si queremos trabajar con data.frames:
<- df[c('particulas', 'calidad')]
etiquetas <- etiquetas[rz, ]
rxy head(rxy)
## particulas calidad
## 1 no buena
## 1.1 no buena
## 1.2 no buena
## 4 si mala
## 1.3 no buena
## 4.1 si mala
# Si se quieren eliminar las etiquetas de las filas:
row.names(rxy) <- NULL
head(rxy)
## particulas calidad
## 1 no buena
## 2 no buena
## 3 no buena
## 4 si mala
## 5 no buena
## 6 si mala
6.7.2 Simulación de tablas de contingencia
Podríamos emplear el código anterior para simular tablas de contingencia. En estos casos se suele mantener fijo el tamaño de la muestra, igual al total de la tabla28:
<- sum(n)
nsim set.seed(1)
<- sample(z, nsim, replace = TRUE, prob = pz)
rz <- table(rz) # Tabla de frecuencias unidimensional
rtable matrix(rtable, ncol = 2, dimnames = dimnames(tabla)) # Tabla de frecuencias bidimensional
## particulas
## calidad no si
## buena 321 78
## mala 15 36
Aunque puede ser preferible emplear directamente rmultinom()
si se van a generar muchas:
<- 1000
ntsim <- rmultinom(ntsim, sum(n), pz)
rtablas 1:5] # Las cinco primeras simulaciones rtablas[ ,
## [,1] [,2] [,3] [,4] [,5]
## [1,] 298 329 323 323 307
## [2,] 15 21 5 15 15
## [3,] 92 68 91 77 92
## [4,] 45 32 31 35 36
Ejemplo 6.10 (Distribución del estadístico chi-cuadrado de independencia)
En el contraste chi-cuadrado (tradicional) de independencia (ver Sección A.1.4) se emplea una aproximación continua de la distribución del estadístico bajo la hipótesis nula (la distribución asintótica \(\chi^2\), con una corrección por continuidad en tablas dos por dos):
<- chisq.test(tabla)
res res
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: tabla
## X-squared = 60.124, df = 1, p-value = 8.907e-15
Sin embargo la distribución exacta del estadístico del contraste es discreta y como alternativa la podríamos aproximar mediante simulación.
Para simular bajo independencia podemos estimar las probabilidades a partir de las frecuencias marginales de la tabla de contingencia:
<- (rowSums(tabla) %o% colSums(tabla))/(sum(tabla)^2)
pind matrix(pind, nrow = nrow(tabla), dimnames = dimnames(tabla))
## particulas
## calidad no si
## buena 0.6597531 0.08246914
## mala 0.2291358 0.02864198
Empleando el código anterior podemos generar las simulaciones de las tablas de contingencia (bajo independencia):
<- 2000
ntsim <- rmultinom(ntsim, sum(n), pind)
rtablas 1:5] # Las cinco primeras simulaciones rtablas[ ,
## [,1] [,2] [,3] [,4] [,5]
## [1,] 292 285 309 303 290
## [2,] 96 105 97 84 113
## [3,] 48 48 36 49 39
## [4,] 14 12 8 14 8
A partir de las cuales podemos aproximar por simulación la distribución exacta del estadístico del contraste chi-cuadrado de independencia:
<- apply(rtablas, 2,
sim.stat function(x) chisq.test(matrix(x, nrow = nrow(tabla)))$statistic)
hist(sim.stat, freq = FALSE, breaks = 'FD')
# lines(density(sim.stat))
# Distribución asintótica (aproximación chi-cuadrado)
curve(dchisq(x, res$parameter), col = 'blue', add = TRUE)
Como se mostrará en la Sección 7.4.3, podríamos aproximar el \(p\)-valor del contraste de independencia a partir de esta aproximación:
<- res$statistic
obs.stat <- mean(sim.stat >= obs.stat)
pvalue.mc pvalue.mc
## [1] 0
Esto es similar a lo que realiza la función chisq.test()
con la opción simulate.p.value = TRUE
(empleando el algoritmo de Patefield, 1981):
chisq.test(tabla, simulate.p.value = TRUE, B = 2000)
##
## Pearson's Chi-squared test with simulated p-value (based on 2000
## replicates)
##
## data: tabla
## X-squared = 62.812, df = NA, p-value = 0.0004998
En R podemos obtener el índice multidimensional empleando la función
arrayInd(ind, .dim, ...)
, siendoind
un vector de índices unidimensionales.↩︎Como ya se comentó, la simulación empleando un modelo estimado también se denomina bootstrap paramétrico.↩︎
También se podría fijar una de las distribuciones de frecuencias marginales y simular las correspondientes distribuciones condicionadas.↩︎