2011-06-29 6 views
30

Soy nuevo en R y estoy tratando de sumar 2 columnas de un marco de datos dado, si ambos elementos que se suman satisfacen una condición dada. Para aclarar las cosas, lo que yo quiero hacer es:Bucle sobre filas de la función de aplicación de marco de datos con instrucción if

> t.d<-as.data.frame(matrix(1:9,ncol=3)) 
> t.d 
    V1 V2 V3 
    1 4 7 
    2 5 8 
    3 6 9 

> t.d$V4<-rep(0,nrow(t.d)) 

> for (i in 1:nrow(t.d)){ 
+ if (t.d$V1[i]>1 && t.d$V3[i]<9){ 
+  t.d$V4[i]<-t.d$V1[i]+t.d$V3[i]} 
+  } 

> t.d  
    V1 V2 V3 V4 
    1 4 7 0 
    2 5 8 10 
    3 6 9 0 

necesitar un código eficiente, ya que mi verdadera trama de datos tiene cerca de 150.000 filas y 200 columnas. Esto da un error:

t.d$V4<-t.d$V1[t.d$V1>1]+ t.d$V3[t.d$V3>9] 

¿Es "apply" una opción? Intenté esto:

t.d<-as.data.frame(matrix(1:9,ncol=3)) 
t.d$V4<-rep(0,nrow(t.d)) 

my.fun<-function(x,y){ 
    if(x>1 && y<9){ 
    x+y} 
} 

t.d$V4<-apply(X=t.d,MAR=1,FUN=my.fun,x=t.d$V1,y=t.d$V3) 

pero da un error también. Muchas gracias por su ayuda.

+3

+1 por el esfuerzo en la creación de datos de muestra y sus propios intentos de código. –

+1

Bienvenido a SO. Este es un gran ejemplo de una buena pregunta. – Andrie

Respuesta

39

Esta operación no requiere bucles, aplica sentencias o declaraciones if. vectorizados operaciones y de subconjuntos es todo lo que necesitan:

t.d <- within(t.d, V4 <- V1 + V3) 
t.d[!(t.d$V1>1 & t.d$V3<9), "V4"] <- 0 
t.d 

    V1 V2 V3 V4 
1 1 4 7 0 
2 2 5 8 10 
3 3 6 9 0 

Por qué funciona esto?

En el primer paso creo una nueva columna que es la suma directa de las columnas V1 y V4. Uso within como una forma conveniente de referirme a las columnas de d.f sin tener que escribir d.f$V todo el tiempo.

En el segundo paso que subconjunto todas las filas que no cumplen con sus condiciones y establecer V4 para que éstos 0.

+1

¡Gracias! Tan simple y sin embargo perfecto. No puedo creer que haya pasado medio día pensando en este problema. – Elinka

+2

Si te hace sentir mejor, este tipo de problema hizo que mi cabeza se quedara plana cuando comencé a trabajar con R. :-) – Andrie

+0

¡Respuesta simple increíble! – jcdmb

24

ifelse es tu amigo aquí:

t.d$V4<-ifelse((t.d$V1>1)&(t.d$V3<9), t.d$V1+ t.d$V3, 0) 
+0

+1 Buen uso de ifelse. – Andrie

+0

¡Muchas gracias! – Elinka

9

Voy a CHIP y proporcionar una nueva versión. Puesto que usted quiere cero si la condición no mach, y verdadero/falso son versiones glorificados de 1/0, simplemente multiplicando por la condición también funciona:

t.d<-as.data.frame(matrix(1:9,ncol=3)) 
t.d <- within(t.d, V4 <- (V1+V3)*(V1>1 & V3<9)) 

... y pasa a ser más rápido que el otras soluciones ;-)

t.d <- data.frame(V1=runif(2e7, 1, 2), V2=1:2e7, V3=runif(2e7, 5, 10)) 
system.time(within(t.d, V4 <- (V1+V3)*(V1>1 & V3<9)))   # 3.06 seconds 
system.time(ifelse((t.d$V1>1)&(t.d$V3<9), t.d$V1+ t.d$V3, 0)) # 5.08 seconds 
system.time({ t.d <- within(t.d, V4 <- V1 + V3); 
       t.d[!(t.d$V1>1 & t.d$V3<9), "V4"] <- 0 })  # 4.50 seconds 
Cuestiones relacionadas