R dataframe crear nuevas columnas mulitple de las columnas existentes utilizando a través / all_of / mutate_if

Tengo un marco de datos (ejemplo abajo) que tiene respuestas a un cuestionario en varios días.

        > df %>% 
            mutate (Sigma_Bucket_Q1  = if_else(Sigma_Q1 >= Median_Sigma_Q1, 
                    "Above Median Volatility", "Below Median Volatility"))
    # A tibble: 19 x 12
       UserId Days_From_First_Use    Q1    Q2    Q3 Sigma_Q1 Sigma_Q2 Sigma_Q3 Median_Sigma_Q1 Median_Sigma_Q2 Median_Sigma_Q3 Sigma_Bucket_Q1        
                                                                                          
     1 A                        0     3     2     1     1.10    0.837    0.548            1.45            1.59            1.53 Below Median Volatility
     2 A                        1     1     0     0     1.10    0.837    0.548            1.45            1.59            1.53 Below Median Volatility
     3 A                        2     1     1     0     1.10    0.837    0.548            1.45            1.59            1.53 Below Median Volatility
     4 A                        3     0     2     0     1.10    0.837    0.548            1.45            1.59            1.53 Below Median Volatility
     5 A                        4     1     1     1     1.10    0.837    0.548            1.45            1.59            1.53 Below Median Volatility
     6 B                        0     4     8     2     1.26    2.5      2.06             1.45            1.59            1.53 Below Median Volatility
     7 B                        2     2     2     1     1.26    2.5      2.06             1.45            1.59            1.53 Below Median Volatility
     8 B                        4     5     6     5     1.26    2.5      2.06             1.45            1.59            1.53 Below Median Volatility
     9 B                        5     4     5     5     1.26    2.5      2.06             1.45            1.59            1.53 Below Median Volatility
    10 C                        0     5     7     2     1.64    1.87     1                1.45            1.59            1.53 Above Median Volatility
    11 C                        1     2     2     2     1.64    1.87     1                1.45            1.59            1.53 Above Median Volatility
    12 C                        2     5     5     4     1.64    1.87     1                1.45            1.59            1.53 Above Median Volatility
    13 C                        3     6     5     3     1.64    1.87     1                1.45            1.59            1.53 Above Median Volatility
    14 C                        4     6     6     4     1.64    1.87     1                1.45            1.59            1.53 Above Median Volatility
    15 D                        0     5     3     5     2.35    1.30     2.30             1.45            1.59            1.53 Above Median Volatility
    16 D                        1     5     3     4     2.35    1.30     2.30             1.45            1.59            1.53 Above Median Volatility
    17 D                        2     4     2     6     2.35    1.30     2.30             1.45            1.59            1.53 Above Median Volatility
    18 D                        3     0     0     1     2.35    1.30     2.30             1.45            1.59            1.53 Above Median Volatility
    19 D                        4     1     1     1     2.35    1.30     2.30             1.45            1.59            1.53 Above Median Volatility

Columnas Q1, Q2 y Q3 tener las respuestas, mientras Sigma_Q1, Sigma_Q2 y Sigma Q3 tener la serie de tiempo desviaciones estándar de las respuestas de cada sujeto a cada pregunta. Median_Sigma_1, Median_Sigma_2, y Median_Sigma_3 tener la mediana desviación estándar entre sujetos para sus respuestas a Q1, Q2 y Q3. Quiero clasificar a cada sujeto como un sujeto de volatilidad mediana superior o inferior según sea o no Sigma_Q1 > Median_Sigma_Q1 y así sucesivamente. Mi expresión para generar Sigma_Bucket_Q1 funciona bien; es visible justo antes de la tibble.

Pero cuando intento generalizarlo para generar todos los Sigma_Buckets simultáneamente (mi verdadero problema tiene 21 nombres), me encuentro con un problema. Lo intenté:

        df %>% 
  mutate (across(all_of(paste0("Sigma_Bucket_", c("Q1", "Q2", "Q3")) = if_else(paste0("Sigma_", {.col}) >= paste0("Median_Sigma_",  {.col}), 
          "Above Median Volatility", "Below Median Volatility")))

Recibo un mensaje de error críptico y no puedo determinar lo que necesito arreglar:

> df %>% 
+   mutate (across(all_of(paste0("Sigma_Bucket_", c("Q1", "Q2", "Q3")) = if_else(paste0("Sigma_", {.col}) >= paste0("Median_Sigma_",  {.col}), 
Error: unexpected '=' in:
"df %>% 
  mutate (across(all_of(paste0("Sigma_Bucket_", c("Q1", "Q2", "Q3")) ="
>           "Above Median Volatility", "Below Median Volatility")))
Error: unexpected ',' in "          "Above Median Volatility","

¿Cómo puedo modificar mi declaración para hacer las 3 columnas (las 21 en el problema real) sin escribir una línea para cada pregunta?

Mirando a través de varias respuestas en StackOverflow sugiere que mutate_if podría ser la base de una solución, pero no veo cómo se puede utilizar en este entorno particular.

Muchas gracias por adelantado por su ayuda

Thomas Philips

Pregunta hecha hace 3 años, 4 meses, 26 días - Por codervoyager


4 Respuestas:

  • Aquí hay una solución usando map:

    map2_df(
        df %>% select(starts_with("Sigma_Q")), 
        df %>% select(starts_with("Median_Sigma_Q")),
        ~if_else(.x >= .y, "Above Median Volatility", "Below Median Volatility")) %>%
      rename_with(~str_replace(.x, "Sigma", "Sigma_Bucket"))
    

    Producto:

    # A tibble: 19 x 3
       Sigma_Bucket_Q1         Sigma_Bucket_Q2         Sigma_Bucket_Q3        
                                                               
     1 Below Median Volatility Below Median Volatility Below Median Volatility
     2 Below Median Volatility Below Median Volatility Below Median Volatility
     3 Below Median Volatility Below Median Volatility Below Median Volatility
     4 Below Median Volatility Below Median Volatility Below Median Volatility
     5 Below Median Volatility Below Median Volatility Below Median Volatility
     6 Below Median Volatility Above Median Volatility Above Median Volatility
     7 Below Median Volatility Above Median Volatility Above Median Volatility
     8 Below Median Volatility Above Median Volatility Above Median Volatility
     9 Below Median Volatility Above Median Volatility Above Median Volatility
    10 Above Median Volatility Above Median Volatility Below Median Volatility
    11 Above Median Volatility Above Median Volatility Below Median Volatility
    12 Above Median Volatility Above Median Volatility Below Median Volatility
    13 Above Median Volatility Above Median Volatility Below Median Volatility
    14 Above Median Volatility Above Median Volatility Below Median Volatility
    15 Above Median Volatility Below Median Volatility Above Median Volatility
    16 Above Median Volatility Below Median Volatility Above Median Volatility
    17 Above Median Volatility Below Median Volatility Above Median Volatility
    18 Above Median Volatility Below Median Volatility Above Median Volatility
    19 Above Median Volatility Below Median Volatility Above Median Volatility
    

    Respondida el Dec 21, 2020 a las 03:26 - por devdynamox

    Votos positivos: 0 | Votos negativos: 0

  • across no tienen acceso a los nombres de las columnas, sólo pasan los valores de la columna. Puedes probar este enfoque de base R vectorizado sin bucles.

    col1 <- grep('^Sigma_Q\\d$', names(df), value = TRUE)
    col2 <- grep('^Median_Sigma_Q\\d$', names(df), value = TRUE)
    
    df[paste0(col1, '_Bucket')] <- c("Below Median Volatility", "Above Median Volatility")[(df[col1] >= df[col2]) + 1]
    

    Respondida el Dec 21, 2020 a las 03:33 - por binarybrainiac

    Votos positivos: 0 | Votos negativos: 0

  • Parece que hay un pequeño error en la forma en que estás intentando utilizar la función across en combinación con all_of para generar las nuevas columnas "Sigma_Bucket_Q1", "Sigma_Bucket_Q2" y "Sigma_Bucket_Q3".

    Aquí te dejo una forma de hacerlo utilizando la función across y all_of, así como if_else para generar las nuevas columnas de forma simultánea:

    R
    df %>%
      mutate(
        across(all_of(paste0("Sigma_", c("Q1", "Q2", "Q3"))),
               ~ if_else(. >= get(paste0("Median_Sigma_", sub("Sigma_", "", cur_column()))),
                         "Above Median Volatility", "Below Median Volatility"),
               .names = "Sigma_Bucket_{.col}")
      )
    

    Lo que hemos hecho aquí es utilizar across para aplicar la condición de if_else a las columnas seleccionadas, usando get para obtener el valor de la columna Median_Sigma correspondiente. La opción .names nos permite especificar el nombre de las nuevas columnas generadas.

    Espero que esta solución te sea de ayuda. ¡Déjame saber si tienes alguna otra pregunta!

    Respondida el Dec 22, 2020 a las 03:26 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Para crear varias columnas nuevas en un marco de datos R utilizando across() y if_else() para una lista de variables especificada, puedes utilizar el siguiente código:

    r
    df %>% 
      mutate(across(all_of(c("Sigma_Q1", "Sigma_Q2", "Sigma_Q3")), 
                     ~ if_else(. >= get(paste0("Median_Sigma_", .)), 
                               "Above Median Volatility", 
                               "Below Median Volatility")))
    

    En este código:

    across(all_of(c("Sigma_Q1", "Sigma_Q2", "Sigma_Q3"))) selecciona todas las columnas especificadas en la lista c("Sigma_Q1", "Sigma_Q2", "Sigma_Q3"). ~ if_else(. >= get(paste0("Median_Sigma_", .)), "Above Median Volatility", "Below Median Volatility") es una función anónima que aplica la condición if_else() a cada una de las columnas seleccionadas. . representa el valor actual de la columna. get(paste0("Median_Sigma_", .)) recupera el valor de la columna Median_Sigma_ correspondiente a la columna actual.

    • if_else(. >= get(paste0("Median_Sigma_", .)), "Above Median Volatility", "Below Median Volatility") comprueba si el valor de la columna actual es mayor o igual que el valor de la columna Median_Sigma_ correspondiente y devuelve "Above Median Volatility" o "Below Median Volatility" en consecuencia.
    Este código creará tres nuevas columnas en tu marco de datos df: Sigma_Bucket_Q1, Sigma_Bucket_Q2 y Sigma_Bucket_Q3, que clasifican a cada sujeto como "Above Median Volatility" o "Below Median Volatility" según sus valores de desviación estándar para las preguntas Q1, Q2 y Q3, respectivamente.

    Respondida el Dec 22, 2020 a las 03:32 - por Gemini

    Votos positivos: 0 | Votos negativos: 0