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.

Convertir los números de caracteres a numéricos en una lista anidada con tipos mixtos en R.

Tengo un montón de listas anidadas que llegan con todos sus elementos de tipo carácter. Algunos de estos caracteres son en realidad números que necesitan ser convertidos a elementos de tipo numérico.

¿Cómo puedo modificar estas listas para que todos los números de tipo carácter posibles se conviertan en numéricos, pero los elementos de tipo carácter no numéricos permanezcan intactos (es decir, no se conviertan en NA mediante as.numeric())?

Por ejemplo, comienzo con

raw_list <- list(
      'a' = list('1', '2'),
      'b' = list(
        'c' = list('3', 'x'),
        'd' = c('4', 'z'),
        'e' = '5'))

Pero necesito obtener

cleaned_list <- list(
      'a' = list(1, 2),
      'b' = list(
        'c' = list(3, 'x'),
        'd' = c('4', 'z'),
        'e' = 5))

Bono: Extra gratitud por soluciones basadas en tidyverse/purrr.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Una forma de lograr esto es utilizando el paquete purrr y la función map() para iterar sobre las listas anidadas y aplicar la función as.numeric() a cualquier elemento de tipo caracter que pueda convertirse en número. Aquí tienes un ejemplo de código:

    library(purrr)
    
    clean_list <- map(raw_list, ~{
      map_if(.x, is.character, safely(as.numeric), .else = identity) %>%
        flatten() %>%
        map_if(is_double, na_if, .x = Inf) %>% # opción para reemplazar valores infinitos por NA
        map_if(is_double, na_if, .x = -Inf) 
    })
    
    clean_list
    

    Este código primero itera sobre la lista más externa utilizando map(), y luego aplica la función map_if() a cada elemento para verificar si es un vector de caracteres (is.character()). Si lo es, aplica la función safely() a él, que intenta convertirlo a numérico pero no genera un error si falla. Esto se debe a que algunos vectores de caracteres pueden contener texto no numérico (como “x” y “z” en el ejemplo), y queremos mantenerlos tal cual.

    El argumento .else = identity en map_if() significa que si no se cumple la condición (es decir, el elemento no es un vector de caracteres), se devuelve el elemento sin cambios (identity).

    La función flatten() se utiliza para eliminar un nivel de anidación de la lista resultante, de modo que obtengamos una lista de vectores en lugar de una lista de listas.

    Finalmente, se aplica nuevamente map_if() para reemplazar los elementos numéricos infinitos por NA utilizando la función na_if(). Si no quieres reemplazar los valores infinitos, puedes omitir estas líneas.

    La lista resultante clean_list debería tener la misma estructura que raw_list, pero con todos los elementos de tipo caracter que se puedan convertir a números reemplazados por elementos numéricos.

Comments are closed.