es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo utilizar la función apply() o una función equivalente para realizar operaciones matemáticas en filas actuales y adyacentes de un marco de datos?

Estoy realizando operaciones matemáticas simples por columna en filas de un marco de datos que también implican acceder a filas de marcos de datos adyacentes y anteriores. Aunque el código a continuación funciona, es engorroso (al menos en lo que respecta a mi uso liberal de las funciones cbind() y subset()) y me pregunto si hay una forma más limpia de obtener los mismos resultados usando apply() u otra súper función de R. En R base si es posible.

Estoy sumando y restando valores de columnas en cada fila del marco de datos (refiriéndome a las siguientes columnas, “plus1” + “plus2” – “minus” = “total”), y si el número de identificación es el mismo a medida que se avanza de una fila a la siguiente, se añade el plus1 de la fila anterior. Vea la siguiente ilustración:

   id plus1 plus2 minus total [total explicado]
1  1     3     5    10    -2
2  2     4     5     9     0
3  3     8     5     8     5   [8 + 5 - 8 = 5, se ignora "plus1" en la fila 2 ya que "id" cambió entre las filas 2 y 3]
4  3     1     4     7     6   [1 + 4 - 7, + 8 de la columna "plus1" en la fila 3 ya que "id" es el mismo en las filas 3 y 4, = 6]
5  3     2     5     6     2   [2 + 5 - 6, + 1 de la columna "plus1" en la fila 4 ya que "id" es el mismo en las filas 4 y 5, = 2]
6  5     3     6     5     4   [3 + 6 - 5 = 4, se ignora "plus1" en la fila 5 ya que "id" cambió entre las filas 5 y 6]

Aquí está el código que usé para generar lo anterior:

data <- data.frame(id=c(1,2,3,3,3,5), 
                   plus1=c(3,4,8,1,2,3), 
                   plus2=c(5,5,5,4,5,6),
                   minus = c(10,9,8,7,6,5))

data <- cbind(data,
              tmp1=(data[ ,"plus1"] +
                    data[ ,"plus2"] -
                    data[ ,"minus"]
                   )
              )

grp <- with(rle(data$id), rep(seq_along(values), lengths))
data$tmp2 <- with(data,ave(plus1, grp, FUN = function(x) c(0, x[-length(x)])))

data <- cbind(data, total = round((data[ ,"tmp1"] + data[ ,"tmp2"]),2))
data <- subset(data, select = -c(tmp1,tmp2) )
data

Estoy buscando simplicidad en el mundo de apply() porque estaré usando muchas derivaciones de este tipo en mi proyecto actual. Parece que estoy imitando a Excel en R, y así es.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Una solución potencial para simplificar el código utilizando la función apply() sería dividir el marco de datos por la columna “id” y aplicar una función a cada grupo. La función calcularía la columna “total” para cada fila dentro del grupo, teniendo en cuenta el valor “plus1” de la fila anterior si los valores “id” coinciden.

    Aquí hay un código de ejemplo que utiliza las funciones lapply() y Reduce() para dividir el marco de datos por “id” y aplicar la función de cálculo a cada grupo:

    “`{r}

    Definir una función para calcular la columna “total” para cada fila dentro de un grupo

    calc_total <- function(df) {
    # Inicializar una variable para almacenar los valores de “total”
    total <- numeric(nrow(df))

    # Calcular “total” para la primera fila del grupo
    total[1] <- df[1, “plus1”] + df[1, “plus2”] – df[1, “minus”]

    # Calcular “total” para cada fila consecutiva, teniendo en cuenta “plus1” de la fila anterior si los valores “id” coinciden
    for (i in 2:nrow(df)) {
    if (df[i, “id”] == df[i-1, “id”]) {
    total[i] <- df[i, “plus1”] + df[i, “plus2”] – df[i, “minus”] + df[i-1, “plus1”]
    } else {
    total[i] <- df[i, “plus1”] + df[i, “plus2”] – df[i, “minus”]
    }
    }

    # Agregar la columna “total” al marco de datos y devolverlo
    cbind(df, total = total)
    }

    Dividir el marco de datos por “id” y aplicar la función de cálculo a cada grupo usando lapply()

    grouped_data <- lapply(split(data, data$id), calc_total)

    Combinar los marcos de datos resultantes en un único marco de datos usando Reduce() y rbind()

    final_data <- Reduce(rbind, grouped_data)

    final_data
    “`

    Este código debería producir el mismo resultado que el código original utilizando cbind() y subset(), pero de una manera más concisa y legible.

Comments are closed.