Genere 3 números aleatorios que sumen 1 en R
Frecuentes
Visto 9,234 veces
13
Espero crear 3 números cuasialeatorios (no negativos) que sumen uno y se repitan una y otra vez.
Básicamente, estoy tratando de dividir algo en tres partes aleatorias durante muchas pruebas.
Mientras soy consciente de
a = runif(3,0,1)
Estaba pensando que podría usar 1-a
como el máximo en el próximo runif
, pero parece desordenado.
Pero estos, por supuesto, no suman uno. ¿Alguna idea, oh sabios stackoverflow-ers?
6 Respuestas
16
Esta pregunta implica cuestiones más sutiles de lo que podría parecer a primera vista. Después de ver lo siguiente, es posible que desee pensar detenidamente en el proceso que está utilizando para representar estos números:
## My initial idea (and commenter Anders Gustafsson's):
## Sample 3 random numbers from [0,1], sum them, and normalize
jobFun <- function(n) {
m <- matrix(runif(3*n,0,1), ncol=3)
m<- sweep(m, 1, rowSums(m), FUN="/")
m
}
## Andrie's solution. Sample 1 number from [0,1], then break upper
## interval in two. (aka "Broken stick" distribution).
andFun <- function(n){
x1 <- runif(n)
x2 <- runif(n)*(1-x1)
matrix(c(x1, x2, 1-(x1+x2)), ncol=3)
}
## ddzialak's solution (vectorized by me)
ddzFun <- function(n) {
a <- runif(n, 0, 1)
b <- runif(n, 0, 1)
rand1 = pmin(a, b)
rand2 = abs(a - b)
rand3 = 1 - pmax(a, b)
cbind(rand1, rand2, rand3)
}
## Simulate 10k triplets using each of the functions above
JOB <- jobFun(10000)
AND <- andFun(10000)
DDZ <- ddzFun(10000)
## Plot the distributions of values
par(mfcol=c(2,2))
hist(JOB, main="JOB")
hist(AND, main="AND")
hist(DDZ, main="DDZ")
Respondido el 12 de junio de 12 a las 21:06
Genial, estaba pensando en graficar los resultados pero ya lo hiciste. Es interesante ver que aparentemente ninguna de las soluciones realmente hace lo que a uno le hubiera gustado intuitivamente. También es interesante que en estas gráficas realmente no se puede ver que DDZ hace lo correcto según los medios, mientras que AND ni siquiera hace eso. - cristiano
11
solo al azar 2 dígitos de (0, 1) y si se asume que es a
y b
entonces tienes:
rand1 = min(a, b)
rand2 = abs(a - b)
rand3 = 1 - max(a, b)
Respondido el 12 de junio de 12 a las 21:06
Además, debe repetir la generación del segundo número si a == b ... (debería ser un caso MUY raro) - ddzialak
@usuario entonces a=0.85, b=0.99 entonces obtuviste números: 0.85, 0.14, 0.01 (en cuanto a mí estos son muy buenos 3 números aleatorios de 0..1) - ddzialak
La distribución resultante parece no ser exactamente trivial: jstor.org/discover/10.2307/… y un documento posterior al que se puede acceder libremente doc.utwente.nl/70657/1/Sleutel67random.pdf - cristiano
9
Cuando desee generar aleatoriamente números que sumen 1 (o algún otro valor), debe mirar el Distribución de Dirichlet.
Hay un rdirichlet
en función de la gtools
paquete y funcionando RSiteSearch('Dirichlet')
presenta bastantes resultados que podrían conducirlo fácilmente a herramientas para hacer esto (y no es difícil codificar a mano tampoco para distribuciones simples de Dirichlet).
Respondido el 12 de junio de 12 a las 22:06
6
Supongo que depende de la distribución que desee en los números, pero aquí hay una forma:
diff(c(0, sort(runif(2)), 1))
Utiliza replicate
para obtener tantos juegos como quieras:
> x <- replicate(5, diff(c(0, sort(runif(2)), 1)))
> x
[,1] [,2] [,3] [,4] [,5]
[1,] 0.66855903 0.01338052 0.3722026 0.4299087 0.67537181
[2,] 0.32130979 0.69666871 0.2670380 0.3359640 0.25860581
[3,] 0.01013117 0.28995078 0.3607594 0.2341273 0.06602238
> colSums(x)
[1] 1 1 1 1 1
Respondido el 12 de junio de 12 a las 21:06
4
Simplemente seleccionaría al azar 3 números de una distribución uniforme y luego los dividiría por su suma. Codifique como se muestra a continuación.
n <- 3
x <- runif(3, 0, 1)
y <- x/sum(x)
sum(y)== 1
n podría ser cualquier número que desee.
Respondido el 21 de Septiembre de 18 a las 16:09
2
Este problema y las diferentes soluciones propuestas me intrigaron. Hice una pequeña prueba de los tres algoritmos básicos sugeridos y qué valores promedio arrojarían para los números generados.
choose_one_and_divide_rest
means: [ 0.49999212 0.24982403 0.25018384]
standard deviations: [ 0.28849948 0.22032758 0.22049302]
time needed to fill array of size 1000000 was 26.874945879 seconds
choose_two_points_and_use_intervals
means: [ 0.33301421 0.33392816 0.33305763]
standard deviations: [ 0.23565652 0.23579615 0.23554689]
time needed to fill array of size 1000000 was 28.8600130081 seconds
choose_three_and_normalize
means: [ 0.33334531 0.33336692 0.33328777]
standard deviations: [ 0.17964206 0.17974085 0.17968462]
time needed to fill array of size 1000000 was 27.4301018715 seconds
Las medidas de tiempo deben tomarse con cautela, ya que pueden estar más influenciadas por la gestión de la memoria de Python que por el propio algoritmo. Soy demasiado perezoso para hacerlo correctamente con timeit
. Hice esto en Atom de 1 GHz, eso explica por qué tomó tanto tiempo.
De todos modos, choose_one_and_divide_rest es el algoritmo sugerido por Andrie y el propio cartel de la pregunta (Y DE): eliges un valor a en [0,1], luego uno en [a,1] y luego miras lo que te queda. Suma uno pero eso es todo, la primera división es el doble de grande que las otras dos. Uno podría haber adivinado tanto ...
elegir_dos_puntos_y_usar_intervalos es la respuesta aceptada por ddzialak (DDZ). Toma dos puntos en el intervalo [0,1] y usa el tamaño de los tres subintervalos creados por estos puntos como los tres números. Funciona de maravilla y los medios son todos 1/3.
elegir_tres_y_normalizar es la solución de Anders Gustafsson y Josh O'Brien (TRABAJO). Simplemente genera tres números en [0,1] y los normaliza a una suma de 1. Funciona igual de bien y sorprendentemente un poco más rápido en mi implementación de Python. La varianza es un poco menor que para la segunda solución.
Ahí tienes. No tengo idea de a qué distribución beta corresponden estas soluciones o qué conjunto de parámetros en el documento correspondiente al que me referí en un comentario, pero tal vez alguien más pueda resolverlo.
contestado el 23 de mayo de 17 a las 13:05
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas r random or haz tu propia pregunta.
¿Es una opción volver a normalizar los números aleatorios después de la generación? - Anders Gustafsson
¿Qué tal generar 2 números aleatorios a y b? Entonces a+b+c = 1 => c = 1 - (a+b) - Frank Schmitt
y si a y b suman más de 1? - mmann1123
¿Qué distribución quieres en los intervalos? Por ejemplo, ¿debería elegirse uniformemente la longitud del primer intervalo en (0,1)? - ALiX
El problema que tienes parece llamarse "división aleatoria de un intervalo". Es un problema clásico en estadística y buscar en Google produce imágenes sorprendentemente pequeñas y bonitas... - Christian