R si otra condición: frecuencia de continuamente NA

Soy nuevo en R, y estaba buscando preguntas similares, pero no pude encontrar una para solucionar la mía, cualquier ayuda sería apreciada.

Tengo un marco de datos M:

            date value
1 182-2002-01-01 23.95
2 182-2002-01-02 17.47
3 182-2002-01-03  NA
4 183-2002-01-01  NA
5 183-2002-01-02  5.50
6 183-2002-01-03 17.02

Lo que debo hacer es: si hay menos de 5 NA (continuamente), solo repetiré el número anterior (17.47), y si hay más de 5 NA seguidos, tendré que borrar todo el mes.

Probé la función rle muchas veces, pero no funcionó, muchas gracias por su ayuda.

preguntado el 28 de julio de 12 a las 03:07

¡Bienvenido a Stack Overflow! Descubrirá que obtiene mejores respuestas si se toma el tiempo para hacer que su pregunta sea reproducible. Siga las instrucciones (stackoverflow.com/questions/5963269/…), prestando especial atención a la parte sobre dput(). ¡Gracias! -

2 Respuestas

Voy a ajustar su pregunta un poco con fines de demostración. Voy a usar un conjunto de datos similar al tuyo, pero para 2 NA seguidas. Esto se generaliza a 5 muy fácilmente, no te preocupes. También voy a usar un conjunto de datos que demuestre mejor la solución.

Entonces, primero, cómo hacer que sus datos se vean como lo que voy a usar:

library(reshape)
M2<-data.frame(colsplit(M$date, "-", c("ID", "year", "month", "day")), 
               value=M$value)

Ahora que está fuera del camino, estos son los datos con los que voy a trabajar:

library(reshape)
M2<-data.frame(colsplit(M$date, "-", c("ID", "year", "month", "day")), 
               value=M$value)

set.seed(1234)
M2<-expand.grid(ID=182, year=2002:2004, month=1:2, day=1:3, KEEP.OUT.ATTRS=FALSE)
M2 <- M2[with(M2, order(year, month, day, ID)),] #sort the data
M2$value <- sample(c(NA, rnorm(100)), nrow(M2), 
                   prob=c(0.5, rep(0.5/100, 100)), replace=TRUE)
M2

    ID year month day      value
1  182 2002     1   1 -0.5012581
7  182 2002     1   2  1.1022975
13 182 2002     1   3         NA
4  182 2002     2   1 -0.1623095
10 182 2002     2   2  1.1022975
16 182 2002     2   3 -1.2519859
2  182 2003     1   1         NA
8  182 2003     1   2         NA
14 182 2003     1   3         NA
5  182 2003     2   1  0.9729168
11 182 2003     2   2  0.9594941
17 182 2003     2   3         NA
3  182 2004     1   1         NA
9  182 2004     1   2 -1.1088896
15 182 2004     1   3  0.9594941
6  182 2004     2   1 -0.4027320
12 182 2004     2   2 -0.0151383
18 182 2004     2   3 -1.0686427

Primero, vamos a eliminar todos los casos en los que, dentro de un mes, haya 2 o más NA seguidos:

NA_run <- function(x, maxlen){
  runs <- rle(is.na(x$value))
  if(any(runs$lengths[runs$values] >= maxlen)) NULL else x
  }

library(plyr)
rem <- ddply(M2, .(ID, year, month), NA_run, 2)
rem

    ID year month day      value
1  182 2002     1   1 -0.5012581
2  182 2002     1   2  1.1022975
3  182 2002     1   3         NA
4  182 2002     2   1 -0.1623095
5  182 2002     2   2  1.1022975
6  182 2002     2   3 -1.2519859
7  182 2003     2   1  0.9729168
8  182 2003     2   2  0.9594941
9  182 2003     2   3         NA
10 182 2004     1   1         NA
11 182 2004     1   2 -1.1088896
12 182 2004     1   3  0.9594941
13 182 2004     2   1 -0.4027320
14 182 2004     2   2 -0.0151383
15 182 2004     2   3 -1.0686427

Puede ver que se han eliminado los dos NA consecutivos. El que queda está ahí porque pertenece a dos meses diferentes. Ahora vamos a completar las NA restantes. Él na.rm=FALSE el argumento está ahí para mantener las NA si están bien al principio (que es lo que quieres, creo).

library(zoo)
rem$value <- na.locf(rem$value, na.rm=FALSE)
rem

    ID year month day      value
1  182 2002     1   1 -0.5012581
2  182 2002     1   2  1.1022975
3  182 2002     1   3  1.1022975
4  182 2002     2   1 -0.1623095
5  182 2002     2   2  1.1022975
6  182 2002     2   3 -1.2519859
7  182 2003     2   1  0.9729168
8  182 2003     2   2  0.9594941
9  182 2003     2   3  0.9594941
10 182 2004     1   1  0.9594941
11 182 2004     1   2 -1.1088896
12 182 2004     1   3  0.9594941
13 182 2004     2   1 -0.4027320
14 182 2004     2   2 -0.0151383
15 182 2004     2   3 -1.0686427

Ahora todo lo que necesita hacer para hacer este 5 o más con sus datos es cambiar el valor de la maxlen argumento en NA_run a 5.

EDITAR: Alternativamente, si no desea que los valores se copien de meses anteriores:

library(zoo)
rem$value <- ddply(rem, .(ID, year, month), summarise, 
                   value=na.locf(value, na.rm=FALSE))$value
rem

    ID year month day      value
1  182 2002     1   1 -0.5012581
2  182 2002     1   2  1.1022975
3  182 2002     1   3  1.1022975
4  182 2002     2   1 -0.1623095
5  182 2002     2   2  1.1022975
6  182 2002     2   3 -1.2519859
7  182 2003     2   1  0.9729168
8  182 2003     2   2  0.9594941
9  182 2003     2   3  0.9594941
10 182 2004     1   1         NA
11 182 2004     1   2 -1.1088896
12 182 2004     1   3  0.9594941
13 182 2004     2   1 -0.4027320
14 182 2004     2   2 -0.0151383
15 182 2004     2   3 -1.0686427

Respondido 02 ago 12, 02:08

Esto funciona perfectamente, ¡muchas gracias! Por cierto, tengo otra condición que dice que si faltan días entre 2 y 4 días, necesito hacer una interpolación lineal, esto es lo que probé: NA_run <- function(x, maxlen){ run <- rle(is.na (x$value)) miss <- corre$longitudes[runs$values] ifelse(miss >= maxlen, NULL, ifelse((miss > maxlen-3)&(miss < maxlen), approx(x$value, n= length(x$value))$y, x)) } Pero recibe un error que dice: el reemplazo tiene una longitud cero - Rosa

Esa es una pregunta completamente diferente, pero lo que yo haría es establecer na.locf's máximo NA llene a 1, luego use rle para calcular los índices de las ejecuciones NA restantes. Encuentre el índice antes y después y las ejecuciones y realice una interpolación lineal sobre ellas. - sebastian-c

Tenía la intención de probar un ejemplo más simple, pero parece que lo hizo más complejo. :p Lo que tengo que hacer es decir si hay menos de 5 NA seguidos, repetir los datos anteriores, si son de 5 a 10 NA, hacer una interpolación lineal, pero si hay más de 10 NA, eliminar el mes. Sus códigos funcionaron muy bien para esas dos partes, pero me confundo con el comentario, ¿quiere decir comenzar de nuevo o simplemente hacer cambios en NA_run? ¡Muchos gracias! - Rosa

Sugiero: 1. Usar NA_run para eliminar todos los >10 NA; 2. Uso na.locf para llenar <5 seguidos; 3. Uso rle para encontrar las corridas más grandes de NA. Encuentra dónde comienzan y dónde terminan. Extráigalos, realice una interpolación lineal, vuelva a colocarlos. - sebastian-c

Hola, volví :( Pensé que mi código funcionaba porque no había ningún error, pero cuando revisé el resultado, descubrí que:1, probé rem$value <- na.locf(rem$value, na.rm =FALSO, maxgap=5), reemplazó todo NA<5, pero el problema es cuando el primer día del mes es NA, repite el día del mes anterior, prefiero hacer na.locf(rem$value, na.rm=FALSE, maxgap=5, fromLast), lo mismo ocurre con la interpolación lineal si hay más de 5 NA en un mes, así que comencé a escribir otra función, pero sigue apareciendo un error, por favor ayuda, me motiva loco - Rosa

Yo haría esto en dos pasos:

  1. An rle, rollapplyo shiftbasada en una estrategia para llenar los pequeños vacíos (menos de 5 AN seguidas).
  2. A by, aggregateo ddplyestrategia basada en tomar cualquier mes con NA restantes después del paso 1 y hacer todo el mes NA.

Respondido 28 Jul 12, 03:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.