Está en la página 1de 23

Suscríbete a DeepL Pro para poder traducir archivos de mayor tamaño.

Más información disponible en www.DeepL.com/pro.

Actas de la Conferencia de Simulación de Invierno de 2015


L. Yilmaz, W. K. V. Chan, I. Moon, T. M. K. Roeder, C. Macal y M. D. Rossetti, eds.

SIMULACIÓN DE EVENTOS DISCRETOS CON R

Barry Lawson Lawrence M. Leemis

Departamento de Matemáticas e Informática Departamento de Matemáticas


Universidad de Richmond The College of William & Mary
Richmond, VA 23173, EE.UU. Williamsburg, VA 23187,
EE.UU.

RESUMEN
R es un paquete de software libre con amplias capacidades estadísticas, gráficos personalizables y
capacidades de programación imperativa y vectorial. Para su uso en un curso introductorio de simulación,
las capacidades de R para analizar estadísticas de simulación y generar los gráficos correspondientes
ayudan a desarrollar la intuición de los estudiantes. R también proporciona flexibilidad a la hora de
determinar si la simulación y el análisis deben realizarse utilizando código de simulación que los
estudiantes implementan desde cero, utilizando código esqueleto que los estudiantes modifican, o
utilizando código completo dado como caja negra. Estos aspectos de R lo convierten en una plataforma
única para programar y analizar simulaciones de eventos discretos. En este artículo, presentamos una
función de R llamada ssq que escribimos para simular una cola de un solo servidor, y proporcionamos
varias ilustraciones que muestran su uso como ejemplo para utilizar R en un curso introductorio de
simulación. Todo el código para analizar la salida de ssq utiliza funciones de la distribución base de R.

1 INTRODUCCIÓN
La elección de la plataforma informática para un primer curso de simulación de eventos discretos es una
tarea difícil, que normalmente incluye hacer concesiones entre la facilidad de uso, el coste y la capacidad
de personalización. Si el primer curso hace hincapié en el modelado, se deben considerar los paquetes
comerciales que están disponibles para su compra por los proveedores de software de simulación. Sin
embargo, si el primer curso hace hincapié en la programación en un lenguaje de alto nivel, así como en los
aspectos probabilísticos y estadísticos de la simulación, entonces debería considerarse el lenguaje R.
Las razones que hacen de R una buena elección como plataforma informática para un primer curso de
simulación de eventos discretos son las siguientes.

• R es un lenguaje de programación que incluye ejecución condicional, bucles y funciones, de forma


análoga a C o cualquier otro lenguaje de programación imperativo.
• Las funciones de generación de números aleatorios y de generación de variantes aleatorias están
integradas en R.
• R tiene sus raíces en el análisis estadístico de datos, apropiado para el modelado de entrada y el
análisis de salida.
• R tiene una capacidad gráfica de alto nivel que es fácil de usar y de personalizar.

Los principales inconvenientes de utilizar R en un primer curso son que no maneja bien las animaciones,
que se requieren más líneas de programación en comparación con los lenguajes de simulación
comerciales y que, como R es interpretado, el tiempo de ejecución puede ser lento en comparación con
los lenguajes imperativos. Creemos que las ventajas asociadas a R superan a los inconvenientes, e
978-1-4673-9743-8/15/$31.00 ©2015 IEEE 3502
ilustraremos algunas de las capacidades de R para la simulación y el análisis en este artículo.
Dado que la simulación de un modelo de colas de un solo servidor ilustra muchos de los conceptos
importantes que deben cubrirse en la simulación de eventos discretos, utilizamos ese modelo aquí para
ilustrar el uso de R en un curso introductorio de simulación. Hemos escrito un programa de simulación en
R llamado ssq que lleva a cabo una simulación de eventos discretos de una cola de un solo servidor. (El
programa está disponible a través de los autores.) Hemos utilizado R para

978-1-4673-9743-8/15/$31.00 ©2015 IEEE 3502


Lawson y Leemis

varios otros tipos de modelos de simulación, incluyendo colas de múltiples servidores, inventario y
modelos de taller mecánico, pero por brevedad sólo presentamos ssq.

2 EL PROGRAMA SSQ EN R
En el contexto de este artículo, hemos desarrollado un programa R llamado ssq que actúa como una
implementación de caja negra de un modelo de colas de un solo servidor que se utilizará para el análisis de
simulación. En un curso introductorio de simulación, el instructor puede elegir que los estudiantes (a)
implementen su propio programa desde cero, (b) modifiquen una versión básica proporcionada por el
instructor, o (c) utilicen una versión completa proporcionada por el instructor. A continuación, el análisis
de la simulación seguirá muchos de los ejemplos presentados más adelante en este documento.
Nuestra implementación del programa ssq permite la ejecución con valores de parámetros por
defecto, lo que da como resultado la simulación de una cola M/M/1 utilizando las siguientes suposiciones.

• El sistema comienza en el momento 0 sin clientes en el sistema y con un servidor inactivo.


• Los tiempos entre llegadas son variantes aleatorias exponenciales mutuamente independientes e
idénticamente distribuidas con una tasa de llegada λ = 1.
• Los tiempos de servicio son variantes aleatorias exponenciales mutuamente independientes e
idénticamente distribuidas con una tasa de servicio µ = 10/9. La intensidad de tráfico es λ /µ =
0,9. La intensidad de tráfico es λ /µ = 0,9.
• El servidor no se toma ningún descanso.
• El cliente abandona el sistema una vez finalizado el servicio.

Nuestro programa ssq tiene 16 argumentos opcionales descritos en la Tabla 1. Aquellos argumentos
cuya descripción termina con un signo de interrogación son de tipo lógico en R.

Tabla 1: Argumentos opcionales para ssq.


Argumento Por defecto Descripción
setSeed TRUE ¿establecer una semilla de números aleatorios?
semilla NULL semilla de números aleatorios
función de llegada defaultArrival generador de tiempo de llegada aleatorio
servicioFunción defaultService generador aleatorio de tiempo de servicio
maxTime 10000.0 tiempo máximo de simulación
maxLlegadas Inf número máximo de llegadas al sistema
maxDepartures Inf número máximo de salidas del sistema
saveAllData FALSO guardar las siete categorías de datos siguientes?
guardarLlegadas FALSO ¿Guardar los tiempos individuales de llegada?
guardarServicios FALSO ¿Guardar los tiempos de servicio individuales?
saveWaits FALSO ¿Guardar los tiempos de espera individuales?
saveSojourns FALSO ¿Guardar los tiempos de estancia individuales?
saveNumberInQueue FALSO ¿Guardar el número en la cola?
saveNumberInSystem FALSO guardar el número en el sistema?
saveServerStatus FALSO ¿guardar el estado del servidor?
showOutput TRUE ¿visualizar el progreso y los resultados de la
simulación?
Tenga en cuenta que el argumento setSeed debe establecerse explícitamente a FALSE en los casos en
que el usuario desee establecer la semilla inicial de números aleatorios de forma externa a la llamada
ssq, por ejemplo, para la replicación.
Hay tres formas de terminar la simulación:
• cuando el reloj del sistema alcanza maxTime, la simulación termina inmediatamente;
3503
Lawson y Leemis
• cuando el número de salidas alcanza maxDepartures, la simulación termina inmediatamente;

3504
Lawson y Leemis

• cuando el número de llegadas alcanza maxLlegadas, la entrada a la simulación finaliza y se


procesan los clientes restantes (mientras no se alcancen maxTiempo y maxSalidas mientras
tanto);
lo que ocurra primero.
Hemos diseñado nuestro programa para facilitar el uso de ssq a un nivel básico. Todos los
parámetros del programa tienen valores por defecto, y se ofrecen como salida algunas estadísticas básicas
(véase más adelante). El usuario puede solicitar explícitamente otros datos para las medidas de
rendimiento, como se ilustrará más adelante. Con la excepción de las estadísticas básicas que se ofrecen
como salida, todos los demás análisis estadísticos deben realizarse como post-procesamiento utilizando
funciones nativas de R. Elegimos este enfoque de diseño para que los estudiantes de introducción
pudieran adquirir experiencia de primera mano en el análisis de la salida, en lugar de tener ese análisis
incorporado en la caja negra de la simulación.
Como ejemplo, la sesión de R mostrada abajo a la izquierda llama a ssq, indicando en la salida que,
para el valor maxTime por defecto de 10000 unidades de tiempo, 9914 clientes llegaron y 9913 clientes
salieron del sistema, con un tiempo medio de estancia de 8,82 unidades. La semilla de números aleatorios
estaba predeterminada para utilizar el reloj del sistema, por lo que esta simulación exacta (probablemente)
no se reproducirá en la próxima llamada a ssq. (Los puntos que aparecen justo después de la llamada a
ssq indican el progreso de la simulación durante la ejecución. Esta visualización del progreso y de la
salida puede suprimirse (véase la Tabla 1). Omitiremos los puntos de progreso en todos los ejemplos
futuros). Una segunda llamada a ssq con todos los argumentos por defecto se da en la sesión de R que
se muestra en el medio. Como se ha sugerido, no se reproduce la salida anterior: hubo 10097 llegadas y
10093 salidas, lo que significa que había cuatro clientes en el sistema cuando terminó la simulación.
Una forma de obtener resultados de simulación reproducibles es seleccionar un flujo de números
aleatorios, manifestado por la elección de una semilla inicial especificada. Esta es una buena práctica en
general, ya que el uso del reloj del sistema resulta en una semilla seleccionada al azar de tal manera que
los resultados de la simulación no pueden ser reproducidos. Abajo a la derecha se muestra una tercera
llamada a ssq especificando un argumento de semilla. Esta simulación en particular terminó con
10034 llegadas y 10004 salidas, lo que significa que treinta clientes estaban en el sistema cuando la
simulación terminó. Si se volviera a realizar esta misma llamada a ssq, se obtendrían exactamente los
mismos resultados. En el resto del documento, especificaremos una semilla inicial para el generador de
números aleatorios, de modo que el lector pueda reproducir nuestros resultados.

> ssq() $avgNumInQueue > ssq()


.................... [1] 7.8559 ....................
clientesLlegadas clientesLlegadas
[1] 9914 [1] 10097

customerDepartures customerDepartures
[1] 9913 [1] 10093

$avgWait $avgWait
[1] 7.9241 [1] 7.2437

$avgSojourn $avgSojourn
[1] 8.8236 [1] 8.1387

$utilización $utilización
[1] 0.89105 [1] 0.90275

$avgNumInSys $avgNumInSys
[1] 8.747 [1] 8.2147

3505
$avgNumInQueue Lawson y Leemis
> ssq(seed=8675309)
[1] 7.3119 ....................
....
clientesLlegadas
[1] 10034

customerDepartures
[1] 10004

$avgWait
[1] 9.0524

$avgSojourn
[1] 9.9666

$utilización
[1] 0.91627

$avgNumInSys
[1] 10.017

$avgNumInQueue
[1] 9.1004

3506
Lawson y Leemis

3 ALTERAR LAS DISTRIBUCIONES DEL MODELO DE ENTRADA


Es importante que los estudiantes experimenten con diversos modelos de llegadas y servicios,
comparando el impacto resultante en el sistema. En consecuencia, hemos diseñado nuestro programa ssq
para que el usuario pueda especificar fácilmente su propio modelo de llegada o servicio con tan solo una
línea adicional de código R.
Los modelos de entrada predeterminados para nuestro programa ssq dan como resultado una cola
M/M/1: los tiempos entre llegadas son exponenciales con una media de 1, mientras que los tiempos de
servicio son exponenciales con una media de 0,9. Estas distribuciones están predeterminadas en la
implementación de ssq mediante las dos funciones de R siguientes:
defaultArrival <- function() return(rexp(1, 1.0))
defaultService <- function() return(rexp(1, 1.0 / 0.9))
La función rexp en R se utiliza para generar una variante exponencial aleatoria. El primer argumento
de rexp corresponde al número de variantes aleatorias necesarias y el segundo parámetro corresponde a
la tasa. Consideremos una situación alternativa con tiempo Weibull entre llegadas y tiempos de servicio
gamma, es decir, una cola G/G/1. Esto puede lograrse fácilmente escribiendo dos nuevas funciones de una
línea en R, pasadas a ssq
como se muestra a continuación. (Por brevedad, sólo se muestran las primeras líneas de salida de ssq).
> myArr <- function() return(rweibull(1, shape=2, scale=1))
> mySvc <- function() return(rgamma(1, shape=2, scale=1))

> ssq(seed=8675309, arrivalFunction=myArr,


serviceFunction=mySvc) customerArrivals
[1] 11267

customerDepartures
[1] 5053

El uso de las distribuciones Weibull y gamma da lugar a un patrón de llegadas y servicios muy
diferente. Los resultados muestran que hay 11267 - 5053 = 6214 clientes en el sistema cuando la simulación
termina en el tiempo máximo por defecto de 10000. Intuitivamente, esto sugiere al alumno que esta
combinación de modelos de llegada y servicio da como resultado una cola más congestionada en
comparación con los modelos anteriores.

4 ANÁLISIS DE LOS PROCESOS DE LLEGADA


Volviendo a la cola M/M/1, ahora mostramos cómo se puede utilizar R para analizar el proceso de llegada
del sistema utilizando las observaciones generadas por la simulación. Nuestra implementación permite al
usuario guardar los tiempos individuales entre llegadas de los clientes que llegan al sistema. Por ejemplo,
los comandos siguientes utilizan ssq para crear una lista denominada output con ocho componentes,
que puede visualizarse utilizando la función str (estructura):
> output = ssq(seed=8423089, saveArrivals=TRUE, showOutput=FALSE)
> str(salida)
Lista de 8
$ customerArrivals : num 10260
$ customerDepartures: num 10252
$ avgWait : num 8.38
$ avgSojourn : num 9.28
$ utilización : num 0.923
$ avgNumInSys : num 9.52
$ avgNumInQueue : num 8.59
$ interarrivalTimes : num [1:10260] 0.175 1.143 1.303 2.723 0.703 ...

3507
Lawson y Leemis
Hubo 10260 llegadas de clientes correspondientes a 10260 tiempos entre llegadas, que son 0,175, 1,143, etc.

3508
Lawson y Leemis

La media muestral y la desviación típica muestral de los tiempos entre llegadas pueden calcularse
utilizando los comandos adicionales de R

> mean(output$interarrivalTimes)
[1] 0.9745776
> sd(output$interarrivalTimes)
[1] 0.9681507

La media del tiempo entre llegadas de la muestra está ligeramente por debajo de su valor poblacional de
1,0, lo que indica que esta simulación en particular está ligeramente más congestionada que la media. La
desviación típica de la muestra también se aproxima a su valor poblacional de 1,0.
Las capacidades gráficas de R también pueden utilizarse para analizar los tiempos entre llegadas. Por
ejemplo, como se muestra a continuación, se puede generar un histograma de los tiempos entre llegadas
utilizando la función hist de R, representada en la Figura 1(a). (El argumento xlim en la llamada a
hist controla los límites en el eje horizontal).

> hist(output$interarrivalTimes, xlim=c(0,6))

Para mostrar que los tiempos entre llegadas se asemejan mucho a la distribución de la población, la
función de densidad de probabilidad de la población puede superponerse al histograma utilizando el
siguiente código R. (Obsérvese que el argumento prob=TRUE en la llamada a hist fuerza a que el
área bajo el histograma sea 1,0 para que pueda compararse fácilmente con la función de densidad de
probabilidad de la población. El argumento add=TRUE en la llamada a curve le dice a R que dibuje
la función encima del histograma existente). No es sorprendente que el histograma proporcione una
aproximación cercana a la distribución de la población, como se muestra en la Figura 1(b).

> hist(output$interarrivalTimes, xlim=c(0,6), ylim=c(0,1), prob=TRUE)


> curve(exp(-x), from=0, to=6, add=TRUE)

Histograma de output$interarrivalTimesHistograma de
output$interarrivalTimes
1.0
400

0.8
300
Frecuencia

0.6
Densid
200

ad
0.4
100

0.0
0

0.2

0 1 2 3 4 5 6 0 1 2 3 4 5 6

output$interarrivalTimes output$interarrivalTimes

(a) (b)
Figura 1: (a) Histograma de tiempos entre llegadas. (b) Histograma con el pdf de la población
superpuesto.

Esta presentación visual, facilitada por el sencillo uso de gráficos de R, resulta especialmente
atractiva para los que se inician en la simulación y permite intuir mejor los efectos de las distintas
distribuciones. Además, para los cursos que se centran en la implementación y simulación de "visiones
del mundo", ofrecer la posibilidad de guardar estadísticas individuales de los clientes permite un debate
significativo sobre las ventajas y desventajas entre los enfoques orientados al proceso (fácil de recopilar
3509
Lawson y Leemis
estadísticas individuales) frente a los orientados al evento (se requieren estructuras de datos adicionales).

3510
Lawson y Leemis

5 ANALIZAR LOS PROCESOS DE SERVICIO


A continuación mostramos cómo puede utilizarse R para analizar el proceso de servicio de un sistema
utilizando las observaciones generadas por la simulación. Al igual que para el proceso d e llegadas,
nuestra implementación permite al usuario guardar los tiempos de servicio individuales de los clientes. A
continuación utilizamos ssq (con salida inmediata omitida), limitando el número de llegadas, y por
tanto el número de tiempos de servicio, a 50. Otro ejemplo de las capacidades estadísticas de R viene dado
por la función fivenum, que muestra el resumen de cinco números de Tukey de los tiempos de servicio:
mínimo, percentil 25 estimado, mediana de la muestra, percentil 75 estimado y máximo.

> output = ssq(seed=3, maxArrivals=50, saveServices=TRUE, showOutput=FALSE)


> fivenum(output$serviceTimes)
[1] 0.133141 0.484717 0.712196 1.170141 2.461797

A continuación, se puede utilizar un gráfico de la función de distribución acumulativa empírica,


generado mediante la función plot.ecdf, para visualizar esas estadísticas en el contexto de la
distribución general de los tiempos de servicio. Por ejemplo, las estimaciones de los percentiles 25 y 75
del resumen de cinco números de Tukey pueden superponerse utilizando segmentos de línea azul de
puntos gruesos en el gráfico ecdf. El gráfico resultante en la Figura 2(a) indica claramente que la mayoría
de los 50 tiempos de servicio son aproximadamente de una unidad de tiempo o menos.

> plot.ecdf(output$serviceTimes, xlim=c(0,5), verticals=TRUE, pch="")


> xvals.25 = c(-0.5,0.485,0.485,0.485); yvals.25 = c(0.25,0.25,0.25,-0.5)
> xvals.75 = c(-0.5,1.170,1.170,1.170); yvals.75 = c(0.75,0.75,0.75,-0.5)
> lines(x=xvals.25, y=yvals.25, col="azul", lwd=4, lty="punteado")
> lines(x=xvals.75, y=yvals.75, col="azul", lwd=4, lty="punteado")

Como antes, la función curva también puede utilizarse para superponer la función de distribución
acumulativa de la población. El gráfico resultante, que aparece en la Figura 2(b), muestra que hay menos
observaciones en ambas colas de la distribución de lo esperado, lo que da lugar a 50 tiempos de servicio
comprimidos con respecto a los valores de la población. Estos tiempos de servicio, que expresan menos
variabilidad de lo habitual, repercutirán en los tiempos de espera y de permanencia de los clientes.

> plot.ecdf(output$serviceTimes, xlim=c(0,5), verticals=TRUE, pch="")


> curve(1 - exp(-10 * x / 9), from=0, to=5, add=TRUE)

De nuevo, las capacidades gráficas de R, fáciles de usar, permiten al usuario novato intuir aspectos de los
modelos subyacentes en la simulación.
ecdf(x) ecdf(x)
1.0

1.0
0.8

0.8
0.6

0.6
Fn(x)

Fn(x)
0.4

0.4
0.2

0.2
0.0

0.0

0 1 2 3 4 5 0 1 2 3 4 5

x x

(a) (b)
Figura 2: CDF empírica con superposiciones: (a) estimaciones de los percentiles 25 y 75; (b) CDF de la
población.
3511
Lawson y Leemis

6 ANÁLISIS DE ESTADÍSTICAS DE OBSERVACIÓN PERSISTENTE


Un concepto muy importante a discutir en un curso introductorio de simulación es la generación y análisis
de estadísticas persistentes en la observación frente a estadísticas persistentes en el tiempo. En esta
sección, mostramos el poder de R para las estadísticas de observación persistente; discutimos las
estadísticas de tiempo persistente en la siguiente sección.
En un modelo de colas, el tiempo de permanencia (suma del tiempo de espera y el tiempo de servicio)
de cada cliente es una cantidad interesante de observar en conjunto. Como ejemplo, mostramos a
continuación el uso de ssq para guardar los tiempos de permanencia de los primeros 8000 clientes en la
salida de lista, seguido del resumen de cinco números de Tukey de esos 8000 tiempos de
permanencia.

> output = ssq(seed=8675309, maxArrivals=8000, saveSojourns=T, showOutput=F)


> fivenum(output$sojournTimes)
[1] 0.001658612 3.131279795 7.121564269 13.382116960 49.428772754

El tiempo mínimo en el sistema es 0,0017, el tiempo medio en el sistema es 7,1216 y el tiempo máximo
en el sistema es 49,4288.
A menudo, en una aplicación de colas, lo que interesa son los clientes con tiempos de espera largos,
ya que una espera larga puede provocar la insatisfacción del cliente. El percentil 95, por ejemplo, puede
estimarse con cualquiera de los dos siguientes comandos de R.

> sort(output$sojournTimes)[0.95 * 8000]


[1] 24.7899
> cuantil(output$tiempos de estancia, 0,95)
95%
24.7902

La estimación del percentil 95 de la distribución de los tiempos de permanencia es 24,79, tanto si se


obtiene extrayendo el valor del percentil 95 de los tiempos de permanencia ordenados como utilizando la
función de cuantiles (ligeramente más precisa) que proporciona R. Este enfoque dual proporciona
una importante comprobación de coherencia y ayuda al estudiante a intuir los valores que devuelven
funciones como la de cuantiles.
La autocorrelación es un concepto muy importante en las estadísticas de simulación.
gracias a las potentes funciones estadísticas y gráficas de R. Por ejemplo, un gráfico del número de
clientes (en el eje horizontal) frente al tiempo de permanencia (en el eje vertical) se realiza fácilmente
utilizando el comando de R

> plot(output$sojournTimes, pch=".")

(El argumento pch, o carácter de trazado, coloca un pequeño punto para cada tiempo de permanencia).
Como muestra la Figura 3(a), está claro que la cola sube y baja de forma cíclica, lo que corresponde a un
alto grado de autocorrelación entre los tiempos de permanencia.
Para demostrar aún más la potencia de R en este contexto, los primeros 40 rezagos de la función de
autocorrelación de la muestra (es decir, el correlograma) se pueden trazar simplemente utilizando el
comando adicional de R

> acf(output$sojournTimes, lag.max=40)

Como muestra la Figura 3(b), el correlograma muestra una autocorrelación positiva fuerte y
estadísticamente significativa que se extiende mucho más allá de los primeros 40 rezagos. Las líneas
discontinuas a ambos lados del eje horizontal son límites de confianza del 95%, útiles para determinar la
3512
Lawson y Leemis
significación estadística.

3513
Lawson y Leemis

Serie output$sojournTimes
50

1.0
0.8
40
output$tiempos de

30

0.4 0 .6
ACF
20
estancia

0.2
10

0.0
0

0 2000 4000 6000 8000 0 10 20 30 40

Índice Retraso

(a) (b)
Figura 3: (a) Tiempos de estancia individuales trazados en orden. (b) Función de autocorrelación de los
tiempos de estancia.

Otro gráfico de interés asociado a los tiempos de permanencia es la función de densidad espectral, es
decir, el periodograma. El comando adicional de R para calcular y trazar la función de densidad espectral es
simplemente

> spectrum(output$sojournTimes)

La función de densidad espectral resultante, que se muestra en la figura 4, indica que las frecuencias más
bajas contribuyen más a la variabilidad de los tiempos de permanencia que las frecuencias más altas, lo
que concuerda con los valores de los datos mostrados en la figura 3(a). En otras palabras, si los tiempos
de permanencia trazados presentaran una oscilación de alta frecuencia (por ejemplo, una observación
baja, la siguiente alta, la siguiente baja, etc.), la función de densidad espectral tendría más peso en el
extremo de alta frecuencia. Sin embargo, los tiempos de permanencia tienen ciclos largos que se asocian a
la cola que retrocede para una serie de clientes, luego se vacía, luego se llena para otra serie de clientes.
Esto corresponde a variaciones de baja frecuencia, como se indica en la figura 4.

Serie: x
Periodograma
bruto
1e+04
espectro

1e+00
1e-04

0.0 0.1 0.2 0.3 0.4 0.5

ancho de
banda de frecuencia =
3,61e-05
3514
Lawson y Leemis
Figura 4: Función de densidad espectral de los tiempos de permanencia.

3515
Lawson y Leemis

Además, tras descartar los 2.000 primeros tiempos de permanencia para tener en cuenta un periodo de
calentamiento, se puede calcular una estimación puntual del tiempo de permanencia medio junto con un
intervalo de confianza del 95% (utilizando el procedimiento clásico de intervalo de confianza) con los
comandos adicionales de R

> truncated.times = output$sojournTimes[2001:8000] # descarta las 2000 primeras


veces
> media(truncado.veces)
[1] 9.86094
> t.test(truncado.veces)$conf.int
[1] 9.64135 10.08052

Se devuelve el intervalo de confianza del 95% 9,64 < µ < 10,08, donde µ es el tiempo de permanencia
medio de la población. Sin embargo, el uso de observaciones individuales y la función de autocorrelación
de la muestra que se muestra en la Figura 3b hacen que los supuestos de normalidad e independencia
asociados a este intervalo de confianza sean sospechosos. Un procedimiento de medias por lotes (Law
2015) que incluya n medias por lotes puede implementarse utilizando una sencilla función de R como la
que se muestra a continuación.

batch.means = function(valores, n) {
z = matrix(valores, n) dividir los valores en n
lotes t.test(apply(z, 1, media))$conf.int # prueba t sobre las
medias de los lotes
}

Una vez más, descartando los primeros 2000 tiempos de permanencia para permitir que el sistema se
caliente, y dividiendo los 6000 tiempos de permanencia restantes en 12 lotes de 500 observaciones cada
uno, el comando R adicional

> batch.means(truncado.veces, 12)


[1] 9.82541 9.89646

calcula el intervalo de confianza del 95% 9,83 < µ < 9,90, que es significativamente más estrecho que el
intervalo de confianza del 95% dado por los métodos clásicos.
Se puede realizar otro experimento utilizando los tiempos de permanencia, aunque este experimento
implica los tres primeros tiempos de permanencia en lugar de los 8000 primeros tiempos de permanencia.
Kaczynski et al. (2012) presentan la matriz de varianza-covarianza 3 × 3 de los tres primeros tiempos de
permanencia para una cola M/M/1 con tasa de llegada λ y tasa de servicio µ como
� �
1 λ (2µ + λ λ2 (λ2 + 4λµ + 5µ )2
� µ2 ) (λ + µ)2 (λ + µ)4 µ2 �
µ2
2λ2 + 4λµ + λ (2λ2 + 8λ2 µ + 11λµ 2 + 2µ )3
Σ= � - µ2
� (λ + µ)2 µ2 (λ + µ)4 µ2


� 3λ6 + 18λ5 µ+ 45λ4 µ2 + 54λ3 µ3 + 30λ2 µ4 + 8λµ 5�+ µ6
�- -
(λ + µ)6 µ2
donde los - corresponden a valores simétricos respecto a la diagonal. Utilizando los parámetros por defecto λ
=1y
µ = 10/9 reduce esta matriz a
� �
Σ = ��
� 3516
81 21141
6173901
Lawson y Leemis
100 36100 13032100

�≈ 21141 25191 7230951 � �
36100 18050 6516050 � 0.8100 0.5856 0.4737
6173901 7230951 9202705083 � 0.5856 1.3956 1.1097 �.
13032100 6516050 0.4737
4704588100 1.1097 1.9561

3517
Lawson y Leemis

Nuestra función ssq puede utilizarse para apoyar este resultado limitando el número de llegadas a
tres y guardando después esos tres tiempos de permanencia de los clientes. La función kaczynski que
se muestra a continuación es un buen ejemplo de cómo los estudiantes pueden escribir su propio código R
para apoyar las implementaciones existentes y ayudar en el análisis. Esta función acepta como argumento
el número de réplicas de la simulación. El segundo comando define los tiempos como una matriz
numReps × 3 que contiene 0's como elementos; cada fila se utilizará para contener los tres primeros
tiempos de permanencia del cliente en una cola M/M/1. Dentro del bucle, los tres primeros tiempos de
permanencia generados por ssq se colocan en la fila i de times. Por último, la función devuelve la
matriz de tiempos de espera.

kaczynski <- function(numReps) {


times = matrix(0, numReps, 3) una matriz numReps X 3, todos
0's set.seed(8423089) # replicación: establecer la
semilla una vez for (i in 1:nrep) {
out = ssq(setSeed=F, maxArrivals=3, saveSojourns=T, showOutput=F)
times[i, ] = out$sojournTimes # ith row: first 3 sojourn times
}
return(veces)
}

Utilizando la función anterior con, por ejemplo, 100 000 réplicas, se puede utilizar la función var
disponible en R para calcular la matriz de varianza-covarianza de la muestra de los tiempos de
permanencia, que se muestra a continuación. Esta salida, junto con varias ejecuciones más de la
simulación utilizando diferentes valores iniciales de semillas, coincide con el resultado analítico de
Kaczynski et al. (2012).

> times = kaczynski(100000)


> var(veces)
[,1] [,2] [,3]
[1,] 0.8137554 0.5873098 0.4725895
[2,] 0.5873098 1.3894298 1.1035314
[3,] 0.4725895 1.1035314 1.9593896

De hecho, ya sea utilizando únicamente funciones nativas de R o escribiendo código adicional, la


flexibilidad y potencia de R para ayudar en la experimentación y el análisis de simulaciones es evidente.

7 ANÁLISIS DE ESTADÍSTICAS PERSISTENTES EN EL TIEMPO


Otro concepto muy importante que aparece habitualmente en la simulación es el de la estadística
persistente en el tiempo. En un curso introductorio, la capacidad de visualizar y analizar datos
persistentes en el tiempo y sus estadísticas es fundamental para la comprensión de los estudiantes. De
nuevo, la potencia y facilidad de uso de R son muy adecuadas en este contexto. Mientras que en la
sección anterior utilizamos R para las estadísticas de observación persistente, en esta sección mostramos
el poder de R para las estadísticas de tiempo persistente utilizando el número en la cola en el tiempo
generado por nuestro programa ssq.
En el ejemplo siguiente, utilizamos ssq para ejecutar la simulación para los primeros 50 clientes,
guardando el número en cola a lo largo del tiempo en la lista de salida.

> output = ssq(seed=8675309, maxArrivals=50, saveNumberInQueue=T, showOutput=F)

En la lista de salida resultante hay un vector llamado output$numberInQueueT, con los 68


valores de tiempo en que se produjeron cambios en el número de la cola, que se muestran a continuación.
De forma correspondiente, el vector output$numberInQueueN contiene el número asociado en la
3518
Lawson y Leemis
cola. (Observe que en algunos de los momentos en los que la longitud de la cola es cero, los clientes
llegaron y se marcharon, pero el número en la cola no cambió).

3519
Lawson y Leemis

> out$númeroEnColaT
[1] 0.0 3.9 4.4 4.6 4.6 5.0 5.1 5.2 5.6 15.2 15.8 25.1 25.6 25.6 25.9
[16] 26.3 27.2 27.4 28.1 28.1 28.3 29.5 30.3 31.1 31.1 31.1 31.3 31.4 32.9 33.0
[31] 33.7 34.1 35.8 35.9 36.0 37.6 38.8 39.5 39.7 39.7 39.8 39.9 40.2 40.2 40.9
[46] 41.2 42.0 42.3 42.3 42.4 42.8 44.0 44.6 45.7 45.8 46.2 47.1 48.9 49.4 49.5
[61] 50.3 52.1 52.3 52.4 53.0 53.1 54.9 55.3
> output$númeroEnColaN
[1] 0 1 2 1 2 3 2 1 0 1 0 1 2 3 4 3 4 3 4 5 4 3 4 5 4 5 4 3 4 5 6 5 6 7 6 5 4
[38] 3 2 3 4 3 2 3 2 3 2 1 0 1 2 3 2 3 2 3 4 5 6 7 6 5 4 3 2 1 0 0

Se genera una visualización del número en cola a lo largo del tiempo utilizando la función de trazado de
R como
> plot(output$numberInQueueT, output$numberInQueueN,
type="s", xlab="tiempo", ylab="número en cola", las=1,
bty="l")
Todos los parámetros gráficos de R pueden utilizarse según la convención habitual de R. El argumento
type="s" indica que se debe trazar un gráfico "escalonado". En este gráfico en particular, se colocan
etiquetas personalizadas en los ejes horizontal y vertical utilizando los argumentos xlab e ylab. Las
marcas de graduación del eje vertical se giran 90◦ con el argumentolas, mientras que los ejes superior y
derecho se suprimen con el argumento bty. El gráfico resultante de la Figura 5 muestra que el número de
clientes en cola alcanza su máximo a los siete clientes en línea.
Curiosamente, el gráfico muestra dos periodos iniciales de larga inactividad en el sistema, que
corresponden a dos tiempos de espera relativamente largos entre trabajos. Después de ver el gráfico, estos
tiempos de espera son fáciles de detectar en los resultados de output$numberInQueueT anteriores.

7
6
5
número en cola

4
3
2
1
0

0 10 20 30 40 50

tiempo

Figura 5: Número en cola de los 50 primeros clientes, con estadística promediada en el tiempo
superpuesta.

El número promediado de tiempo en la cola, que es el área bajo la curva en la Figura 5 dividida por el
tiempo total de simulación, es fácil de calcular utilizando R. La función meanTPS dada a continuación
es otro ejemplo de cómo los estudiantes pueden complementar R utilizando su propio código para ayudar
en el análisis y la comprensión. Dentro de esta función, las tres últimas sentencias utilizan las capacidades
de programación vectorial de R para calcular fácilmente el área normalizada bajo la curva, que luego se
devuelve. (En su lugar podría utilizarse un enfoque iterativo).
meanTPS <- function(times, numbers) {
obsPeriod= times[length(times)]

3520
Lawson y Leemis
- times[1] timeIntervals = diff(times)
areas= c(timeIntervals, 0) *
numbers return(sum(areas) / obsPeriod)
}

3521
Lawson y Leemis

Como se muestra a continuación, nuestra función meanTPS se puede utilizar para calcular y mostrar el
número medio en el tiempo en la cola proporcionando como argumentos los tiempos y los números dados
por ssq. Este valor se puede superponer en el gráfico de tiempo como una línea horizontal discontinua
utilizando la función abline de R, como se muestra en la Figura 5. Esta visualización es
extremadamente útil para ayudar a los estudiantes a entender el significado de las estadísticas persistentes
en el tiempo. Esta visualización es extremadamente útil para ayudar a los estudiantes a comprender el
significado de las estadísticas persistentes en el tiempo.

> meanTPS(output$númeroEnColaT, output$númeroEnColaN)


[1] 2.05734
> abline(h=2.05734, lty="dashed")

Como ejemplo final, la fórmula de Little (Little 1961), que relaciona ciertas estadísticas basadas en
la observación con estadísticas persistentes en el tiempo, también puede verificarse utilizando R. Una
forma de la fórmula de Little establece que la suma de los tiempos de espera debe ser igual al área bajo la
función de la Figura 5. A continuación, utilizamos ssq para generar 50 llegadas de clientes a una cola
M/M/1. A continuación, utilizamos ssq para generar 50 llegadas de clientes a una cola M/M/1 y, a
continuación, utilizamos funciones de R para demostrar que la suma de los 50 tiempos de espera es igual
al área bajo dicha función.
> output = ssq(seed=8675309, maxArrivals=50, saveAllData=T, showOutput=F)
> sum(salida$tiemposespera)
[1] 113.767
> timeIntervals = diff(output$numberInQueueT)
> sum(c(timeIntervals,0) * output$numberInQueueN) # suma áreas rectangulares
[1] 113.767

8 CONCLUSIONES
El lenguaje R ha recibido escasa atención en la comunidad de simulación de eventos discretos. El objetivo
de este artículo era presentar R en el contexto de un modelo de simulación de colas de un solo servidor, y
mostrar cómo puede utilizarse R para realizar fácilmente análisis de postprocesamiento personalizados. A
pesar de las debilidades en la animación y en la velocidad de ejecución debido a ser un lenguaje
interpretado, R tiene muchos otros puntos fuertes que lo convierten en una excelente plataforma
informática para una variedad de enfoques en un primer curso de simulación de eventos discretos.

REFERENCIAS
Kaczynski, W. H., L. M. Leemis y J. H. Drew. 2012. "Análisis de colas transitorias". INFORMS Journal
on Computing 24 (1): 10-28.
Law, A. M. 2015. Modelado y análisis de simulación. 5th ed. Nueva York: McGraw-Hill.
Little, J. 1961. "A Simple Proof of L = λW ". Operations Research 9 (3): 383-387.

BIOGRAFÍAS DE AUTORES
BARRY LAWSON es Profesor Asociado de Informática en la Universidad de Richmond. Es doctor y
máster en Informática por el College of William & Mary y licenciado en Matemáticas por el College at
Wise de la UVA. Sus intereses de investigación se centran en la simulación basada en agentes, con
aplicaciones biológicas. Es miembro de ACM, IEEE e INFORMS. Su dirección de correo electrónico es
blawson@richmond.edu.

LAWRENCE M. LEEMIS es catedrático del Departamento de Matemáticas del College of William &
Mary. Es licenciado y máster en Matemáticas y doctor en Ingeniería Industrial por la Universidad de
Purdue. Sus intereses se centran en la fiabilidad y la simulación, y cuenta con una amplia experiencia en
3522
Lawson y Leemis
consultoría y contratos de investigación. Es miembro de ASA e INFORMS. Su dirección de correo
electrónico es leemis@math.wm.edu.

3523

También podría gustarte