2010-12-02 12 views
23

¿Cómo puedo trazar un conjunto de datos muy grande en R?Trazado de conjuntos de datos muy grandes en R

Me gustaría utilizar un diagrama de caja, violín o similar. Todos los datos no pueden caber en la memoria. ¿Puedo leer incrementalmente y calcular los resúmenes necesarios para hacer estos gráficos? ¿Si es así, cómo?

+1

¿Qué significa exactamente "muy grande" en su caso? – radek

+3

@radek: "Todos los datos no pueden caber en la memoria" parece una buena aproximación de "demasiado grande para que R lo maneje". Si realmente es 2Gb o 20Gb en realidad ya no importa, ¿verdad? –

+1

@ Joris A menos que OP tenga memory.limit demasiado pequeño o muchas columnas innecesarias o algo más. Esta información podría ser relevante. – Marek

Respuesta

10

En complemento a mi comentario a Dmitri answer, una función para calcular cuantiles utilizando ff gran paquete de manejo de datos:

ffquantile<-function(ffv,qs=c(0,0.25,0.5,0.75,1),...){ 
stopifnot(all(qs<=1 & qs>=0)) 
ffsort(ffv,...)->ffvs 
j<-(qs*(length(ffv)-1))+1 
jf<-floor(j);ceiling(j)->jc 
rowSums(matrix(ffvs[c(jf,jc)],length(qs),2))/2 
} 

Este es un algoritmo exacto, por lo que utiliza la clasificación - y por lo tanto puede toma mucho tiempo.

+2

parece que está tratando de lograr algún tipo de simetría <-...-> en su código;) – VitoshKa

+0

Gracias, le daré una oportunidad.Sospecho que tomará tiempo, pero para eso sirven los servidores;) mientras tanto, intentaré tomar muestras, ya que Joris Meys había sugerido –

3

Todo lo que necesita para un diagrama de caja son los cuantiles, los extremos "bigote" y los valores atípicos (si se muestran), que son todos fácilmente calculados. Eche un vistazo a la función boxplot.stats.

+3

Pero no es posible calcularlos exactamente sin cargar todos los datos en la memoria. – hadley

+3

@hadley No, el paquete 'ff' le permite contar los cuantiles como de costumbre, pero en los datos almacenados parcialmente en el disco duro. – mbq

+0

@mbq: por curiosidad: ¿qué función en ff haría eso? Vi ff especialmente como una interfaz para almacenar de manera eficiente grandes cantidades de datos, principalmente en combinación con la genómica. Pero puedo estar totalmente equivocado. –

2

Puede hacer gráficos de una muestra manejable de sus datos. P.ej. si usa solo 10% de las filas elegidas al azar, el diagrama de caja en esta muestra no debe diferir del diagrama de caja de todos los datos.

Si sus datos se encuentran en alguna base de datos, puede crear una bandera aleatoria (ya que sé que casi todos los motores de bases de datos tienen algún tipo de generador de números aleatorios).

En segundo lugar, ¿qué tan grande es su conjunto de datos? Para boxplot necesita dos columnas: variable de valor y variable de grupo. Este ejemplo:

N <- 1e6 
x <- rnorm(N) 
b <- sapply(1:100, function(i) paste(sample(letters,40,TRUE),collapse="")) 
g <- factor(sample(b,N,TRUE)) 
boxplot(x~g) 

necesita 100MB de RAM. Si N=1e7, entonces usa < 1GB de RAM (que aún es manejable para la máquina moderna).

2

Este es un problema interesante.

Los diagramas de caja requieren cuantiles. Calcular cuantiles en conjuntos de datos muy grandes es complicado.

La solución más simple que puede funcionar o no en su caso es reducir la resolución de los datos primero y generar gráficos de la muestra. En otras palabras, lea un montón de registros a la vez y conserve un subconjunto de ellos en la memoria (eligiendo de forma determinista o aleatoria). Al final, genere gráficos en función de los datos que se han conservado en la memoria. De nuevo, si esto es viable o no depende en gran medida de las propiedades de sus datos.

Por otra parte, existen algoritmos que económicamente y pueden calcular aproximadamente cuantiles de una manera "en línea", es decir, que se presentan con una observación a la vez, y cada observación se muestra exactamente una vez. Si bien tengo cierta experiencia limitada con dichos algoritmos, no he visto ninguna implementación de R fácilmente disponible.

El siguiente artículo presenta una breve descripción de algunos algoritmos relevantes: Quantiles on Streams.

8

El problema es que no puede cargar todos los datos en la memoria. Entonces podría hacer un muestreo de los datos, como lo indicó anteriormente @Marek. En conjuntos de datos tan grandes, obtienes esencialmente los mismos resultados, incluso si solo tomas el 1% de los datos. Para la trama de violín, esto le dará una estimación decente de la densidad. El cálculo progresivo de los cuantiles es imposible, pero esto debería dar una aproximación muy decente. Es esencialmente lo mismo que el "método aleatorio" descrito en el enlace @aix dio.

Si no puede subconjunto la fecha fuera de R, se puede hacer usando conexiones en combinación con sample(). La siguiente función es la que uso para muestrear los datos de un marco de datos en formato de texto cuando se está haciendo demasiado grande. Si juegas un poco con la conexión, puedes convertirla fácilmente en una conexión de socket u otra para leerla desde un servidor, una base de datos, lo que sea. Solo asegúrate de abrir la conexión en el modo correcto.

Bien, toma un simple.csv, a continuación, siguiendo las muestras de función una fracción p de los datos:

sample.df <- function(f,n=10000,split=",",p=0.1){ 
    con <- file(f,open="rt",) 
    on.exit(close(con,type="rt")) 
    y <- data.frame() 
    #read header 
    x <- character(0) 
    while(length(x)==0){ 
     x <- strsplit(readLines(con,n=1),split)[[1]] 
    } 
    Names <- x 
    #read and process data 
    repeat{ 
     x <- tryCatch(read.table(con,nrows=n,sep=split),error = function(e) NULL) 
     if(is.null(x)) {break} 
     names(x) <- Names 
     nn <- nrow(x) 
     id <- sample(1:nn,round(nn*p)) 
     y <- rbind(y,x[id,]) 
    } 
    rownames(y) <- NULL 
    return(y) 
} 

Un ejemplo del uso:

#Make a file 
Df <- data.frame(
    X1=1:10000, 
    X2=1:10000, 
    X3=rep(letters[1:10],1000) 
) 
write.csv(Df,file="test.txt",row.names=F,quote=F) 

# n is number of lines to be read at once, p is the fraction to sample 
DF2 <- sample.df("test.txt",n=1000,p=0.2) 
str(DF2) 

#clean up 
unlink("test.txt") 
+0

Tenía un algoritmo implementado, pero ese fue tan increíblemente lento cuando lo probé en un conjunto de datos real, lo eliminé de nuevo. No gana nada, y en cualquier caso, el muestreo "bloqueado" como lo hace la función sample.df, es de lejos el mejor enfoque cuando estamos hablando de muestreo sin distorsionar la distribución. –

+0

Esto fue muy útil al final. Muchas gracias por su ayuda Joris Meys. –

4

Usted también debe mirar a la RSQLite, SQLiteDF, RODBC y paquetes biglm. Para grandes conjuntos de datos puede ser útil almacenar los datos en una base de datos y extraer solo fragmentos en R. Las bases de datos también pueden ordenarlo y luego calcular los cuantiles en los datos ordenados es mucho más simple (entonces simplemente use los cuantiles para hacer los gráficos) .

También existe el paquete hexbin (bioconductor) para hacer equivalentes de diagramas de dispersión con conjuntos de datos muy grandes (probablemente aún desee utilizar una muestra de los datos, pero funcione con una muestra grande).

Cuestiones relacionadas