2011-11-21 9 views
48

estoy tratando de entender cómo reemplazar los valores condicionales en una trama de datos sin necesidad de utilizar un bucle. Mi trama de datos está estructurada de la siguiente manera:sustitución condicional de valores en una hoja.de.datos

> df 
      a b est 
1 11.77000 2 0 
2 10.90000 3 0 
3 10.32000 2 0 
4 10.96000 0 0 
5 9.90600 0 0 
6 10.70000 0 0 
7 11.43000 1 0 
8 11.41000 2 0 
9 10.48512 4 0 
10 11.19000 0 0 

y la salida dput es la siguiente:

structure(list(a = c(11.77, 10.9, 10.32, 10.96, 9.906, 10.7, 
11.43, 11.41, 10.48512, 11.19), b = c(2, 3, 2, 0, 0, 0, 1, 2, 
4, 0), est = c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)), .Names = c("a", 
"b", "est"), row.names = c(NA, -10L), class = "data.frame") 

Lo que yo quiero hacer, es comprobar el valor de b. Si b es 0, deseo establecer est a un valor entre a. Entiendo que df$est[df$b == 0] <- 23 establecerá todos los valores de est en 23, cuando b==0. Lo que no entiendo es cómo establecer est en un valor de a cuando esa condición es verdadera. Por ejemplo:

df$est[df$b == 0] <- (df$a - 5)/2.533 

da la siguiente advertencia:

Warning message: 
In df$est[df$b == 0] <- (df$a - 5)/2.533 : 
    number of items to replace is not a multiple of replacement length 

¿Hay alguna manera de que me puede pasar la celda correspondiente, en lugar de vectores?

Respuesta

53

Puesto que usted está condicionalmente indexando df$est, también hay que condicionalmente índice del vector de reemplazamiento df$a:

index <- df$b == 0 
df$est[index] <- (df$a[index] - 5)/2.533 

Por supuesto, la variable index es sólo temporal, y lo uso para hacer el código un poco más legible Se puede escribir en un solo paso:

df$est[df$b == 0] <- (df$a[df$b == 0] - 5)/2.533 

para una mejor legibilidad, puede utilizar within:

df <- within(df, est[b==0] <- (a[b==0]-5)/2.533) 

Los resultados, sin importar el método que elija:

df 
      a b  est 
1 11.77000 2 0.000000 
2 10.90000 3 0.000000 
3 10.32000 2 0.000000 
4 10.96000 0 2.352941 
5 9.90600 0 1.936834 
6 10.70000 0 2.250296 
7 11.43000 1 0.000000 
8 11.41000 2 0.000000 
9 10.48512 4 0.000000 
10 11.19000 0 2.443743 

Como han señalado otros, una solución alternativa en su ejemplo es usar ifelse .

11

Aquí hay un enfoque. ifelse es vectorizado y comprueba todas las filas de los valores cero de b y reemplaza est con (a - 5)/2.53 si ese es el caso.

df <- transform(df, est = ifelse(b == 0, (a - 5)/2.53, est)) 
5

El R-inferno, o el R-documentación básica va a explicar por qué el uso de df $ * no es el mejor enfoque aquí. Desde la página de ayuda para "[":

"Indexación por [es similar a los vectores atómicas y selecciona una lista de elemento (s) especificada Tanto [[y $ seleccionar un solo elemento de la lista La principal.. la diferencia es que $ no permite índices computados, mientras que [[hace. x $ nombre es equivalente a x [["nombre", exacto = FALSO]]. Además, el comportamiento de coincidencia parcial de [puede controlarse usando el argumento exacto . "

recomiendo el uso de la notación [row,col] lugar.Ejemplo:

Rgames: foo 
     x y z 
    [1,] 1e+00 1 0 
    [2,] 2e+00 2 0 
    [3,] 3e+00 1 0 
    [4,] 4e+00 2 0 
    [5,] 5e+00 1 0 
    [6,] 6e+00 2 0 
    [7,] 7e+00 1 0 
    [8,] 8e+00 2 0 
    [9,] 9e+00 1 0 
    [10,] 1e+01 2 0 
Rgames: foo<-as.data.frame(foo) 

Rgames: foo[foo$y==2,3]<-foo[foo$y==2,1] 
Rgames: foo 
     x y  z 
1 1e+00 1 0e+00 
2 2e+00 2 2e+00 
3 3e+00 1 0e+00 
4 4e+00 2 4e+00 
5 5e+00 1 0e+00 
6 6e+00 2 6e+00 
7 7e+00 1 0e+00 
8 8e+00 2 8e+00 
9 9e+00 1 0e+00 
10 1e+01 2 1e+01 
+0

Esto merece un upvote si primero añadir ya sea un enlace a la página de I-Inferno , o resuma los problemas con '$' (o idealmente ambos). – Andrie

+0

+1 Aunque creo que el operador '$' está perfectamente bien en este caso. (Además, observo que a pesar de tu advertencia, usas '$' tú mismo ...) – Andrie

+0

@Andrie: sí, lo usé donde funciona (no es mucha la ayuda :-)). El OP intentó usarlo para definir en qué elementos se estaba actuando, que es donde comenzó el problema. Acabo de usarlo para definir una condición que selecciona elementos de marco de datos. Pero lo sabías :-) –

24

Try data.table 's := operador:

DT = as.data.table(df) 
DT[b==0, est := (a-5)/2.533] 

Es rápido y corto. Ver estas cuestiones vinculadas para obtener más información sobre :=:

Why has data.table defined :=

When should I use the := operator in data.table

How do you remove columns from a data.frame

R self reference

+0

Hermoso, gracias por las referencias +1 para todo. – PKumar

+0

Muy útil respuesta. Si usa esto, asegúrese de tener en cuenta que DT no es una función en el paquete data.table, sino una referencia para el objeto de la tabla de datos. –

Cuestiones relacionadas