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.

Aplicar diferentes funciones a columnas de un dataframe seleccionando las funciones por su nombre.

Digamos que tengo un dataframe con varias columnas, algunas de las cuales quiero transformar. Los nombres de las columnas definen qué transformación debe usarse.

library(tidyverse)
set.seed(42)
df <- data.frame(A = 1:100, B = runif(n = 100, 0, 1), log10 = runif(n = 100, 10, 100), log2 = runif(n = 100, 10, 100), log1p = runif(n = 100, 10, 100), sqrt = runif(n = 100, 10, 100))
trans <- list()
trans$log10 <- log10
trans$log2 <- log2
trans$log1p <- log1p
trans$sqrt <- sqrt

Idealmente, me gustaría usar una llamada across donde los nombres de las columnas se emparejen con los nombres de las funciones trans y las transformaciones se realicen sobre la marcha.
La salida deseada es la siguiente:

df_trans <- df %>% 
  dplyr::mutate(log10 = trans$log10(log10),
                log2 = trans$log2(log2),
                log1p = trans$log1p(log1p),
                sqrt = trans$sqrt(sqrt))
df_trans

Sin embargo, no quiero especificar manualmente cada transformación por separado. En el ejemplo representativo solo tengo 4, pero este número podría variar ser significativamente mayor, lo que haría que la especificación manual fuera engorrosa y propensa a errores.

He logrado emparejar los nombres de las columnas con las funciones convirtiendo la lista trans en un dataframe y realizando un left_join, pero luego no puedo llamar a la función en la columna trans_function.

trans_df <- enframe(trans, value = "trans_function")
df %>% 
  pivot_longer(cols = everything()) %>% 
  left_join(trans_df) %>% 
  dplyr::mutate(value = trans_function(value))

Error: Problema con la columna mutate() value.
i value = trans_function(value).
x no se pudo encontrar la función "trans_function"

Creo que necesito encontrar una forma de llamar a las funciones de las columnas de la lista o encontrar otra forma de hacer coincidir los nombres de las funciones con los nombres de las columnas. Todas las ideas son bienvenidas.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Una solución es usar purrr::imap() para iterar sobre la lista trans y aplicar la función de transformación adecuada a cada columna que coincida en el dataframe. Aquí tienes un ejemplo de código:

    df_trans = df %>%
      mutate(across(names(trans), ~ .x)) %>% #crear nuevas columnas con los mismos nombres que trans
      imap(trans, ~ if_else(names(.) %in% names(df), .(df[[names(.)]]), NA)) %>% #coincidir las columnas según el nombre
      mutate(across(where(is.list), ~ map2(.x, trans[[names(.)]], ~ .y(.x)))) %>% #aplicar transformaciones correspondientes
      select(-names(trans)) #eliminar columnas temporales
    
    df_trans
    

    El código primero crea nuevas columnas con los mismos nombres que aquellos en la lista trans, usando mutate(across()). Luego, usa imap() para iterar sobre la lista trans y retornar valores NA para cualquier función de transformación que no coincida con un nombre de columna en df. El resultado de esta operación es un dataframe con columnas que coinciden en nombres y valores para la función de transformación a aplicar.

    Finalmente, mutate(across(where(is.list), ~ map2(.x, trans[[names(.)]], ~ .y(.x)))) aplica cada función de transformación a la respectiva columna en el dataframe. El where(is.list) filtra solo las columnas que son listas (es decir, las columnas con valores temporales NA). map2() itera sobre los elementos coincidentes del dataframe y la lista trans en paralelo, y aplica la función de transformación a cada elemento usando .y(.x).

    El dataframe resultante df_trans es el dataframe transformado con las columnas originales y nuevas. Las columnas temporales creadas por la operación mutate() en la línea 2 pueden ser eliminadas usando select(-names(trans)).

    ¡Espero que esto te ayude!

Comments are closed.