Escriba un código para calcular puntajes y agréguelos a un data.frame

Tengo un marco de datos con 6 columnas. El primero es para sujetos, el segundo para bloques en un experimento, y las columnas 3,4, 5 y 0 son valores que necesito para calcular un puntaje binario (1 o 0), que quiero agregar en la sexta columna (por eso ahora, está lleno de XNUMXs).

head(kfdblock3to9)
    subject time        gr       ugr      sdugr IL
40002.3   40002    3 0.4475618 0.3706000 0.02994533  0
40002.4   40002    4 0.4361786 0.3901111 0.01846110  0
40002.5   40002    5 0.4279880 0.4550000 0.02811839  0
40002.6   40002    6 0.4313647 0.4134444 0.04352974  0
40002.7   40002    7 0.4420889 0.4394286 0.02883143  0
40002.8   40002    8 0.4325227 0.3960000 0.06559222  0

Estoy tratando de hacer esto con un ciclo for, pero soy un principiante en R y tengo dificultades con esto. La fórmula de puntuación que intento implementar es una en la que: Si el valor de la columna 3 ($gr) es menor que la diferencia entre el valor de la columna 4 ($ugr) y 35 veces el valor de la columna 5 ($sdugr ), entonces el sujeto recibe un 1, de lo contrario un 0.

Lo que he probado hasta ahora es:

for (i in kfdblock3to9$subject) {
     if (kfdblock3to9$gr<(kfdblock3to9$ugr-(.35*kfdblock3to9$sdugr))) 
                 kfdblock3to9$IL=1
         else kfdblock3to9$IL=0
    }

Esto me da 50 advertencias, todas diciendo: "la condición tiene una longitud> 1 y solo se usará el primer elemento"

Entonces supongo que estoy haciendo algo mal con los índices, pero no he podido resolverlo. Cualquier ayuda es muy apreciada.

preguntado el 22 de mayo de 12 a las 12:05

4 Respuestas

Echa un vistazo a within y ifelse :

kfdblock3to9 <- 
within(kfdblock3to9,
  IL <- ifelse( gr < ugr - 0.35 * dugr, 1, 0)
)

within() no es realmente tan necesario, pero mantiene su código mucho más legible y fácil de entender.

¿Por qué sale mal? Eso es porque su condición está vectorizada: intente

kfdblock3to9$gr<(kfdblock3to9$ugr-(.35*kfdblock3to9$sdugr))

y verás que devuelve un vector lógico. ahora un if() La cláusula solo puede tratar con un valor booleano a la vez. Si tiene un resultado vectorizado, necesita una solución vectorizada y eso es ifelse()

contestado el 22 de mayo de 12 a las 12:05

Para resolver su problema, sugeriría algo como esto:

kfdblock3to9[, "IL"] <- ifelse(kfdblock3to9$gr < (kfdblock3to9$ugr-(0.35*kfdblock3to9$sdugr)), 1, 0);

(Un enfoque vectorizado es mayormente más rápido que un bucle).

Tu bucle está mal porque no respetas tu índice i. Tienes que usar i para acceder a la fila en el bucle:

for (i in seq(along=kfdblock3to9)) {
    cat("row:", i, kfdblock3to9[i, "subject"], "\n");
}

contestado el 22 de mayo de 12 a las 12:05

Lo que quieres es una prueba lógica. De este modo, puede evitar el uso de la loop, e incluso ifelse, y simplemente hacer:

kfdblock3to9$IL <- with(kfdblock3to9, gr < (ugr-0.35*sdugr))

La columna IL incluirá VERDADERO o FALSO, en lugar de 1 o 0. Si prefiere tener números enteros, puede hacer lo siguiente:

kfdblock3to9$IL <- as.integer(with(kfdblock3to9, gr < (ugr-0.35*sdugr)))

contestado el 22 de mayo de 12 a las 12:05

Tenga en cuenta que IL será un vector lógico en este caso, que es diferente del resultado del código de OP. - joris meys

¡Gracias! gran uso de la función with, que no conocía - HernanLG

No deberías usar un bucle en este caso. Cada vez que use un bucle en el futuro, debe usar índices:

for (i in 1:length(kfdblock3to9$subject)) {
     if (kfdblock3to9[i,"gr"] < (kfdblock3to9[i, "ugr"] - .35 * kfdblock3to9[i, "sdugr"])) 
                 kfdblock3to9[i,"IL"]=1
     else  kfdblock3to9[i,"IL"]=0
}


kfdblock3to9
     subject time        gr       ugr      sdugr IL
40002.3   40002    3 0.4475618 0.3706000 0.02994533  0
40002.4   40002    4 0.4361786 0.3901111 0.01846110  0
40002.5   40002    5 0.4279880 0.4550000 0.02811839  1
40002.6   40002    6 0.4313647 0.4134444 0.04352974  0
40002.7   40002    7 0.4420889 0.4394286 0.02883143  0
40002.8   40002    8 0.4325227 0.3960000 0.06559222  0

contestado el 22 de mayo de 12 a las 13:05

No usas índices para esto, eso es ridículo. joris meys

Escribí si él/ella quería usar un bucle - Alex

que no debería. Hay una solución perfectamente vectorizada para esto, usar un bucle es una pérdida de recursos y hace que su código sea mucho más propenso a errores. Edité su primera oración para reflejar esto (y así pude eliminar el voto negativo): joris meys

Sí, por eso comenté tu solución y dije que era mejor. Si bien hay mejores soluciones, creo que también es útil señalar el problema con el código original del OP. Sin saber cuál es el problema con el código original, el OP puede cometer errores similares en el futuro. Eso es todo. - Alex

Gracias por todos sus consejos y "notificaciones de error" en mi nombre. De hecho, sus respuestas también son buenas para saber qué estaba haciendo mal "en bucle". - HernanLG

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