¿Cómo dividir una cadena en múltiples columnas?

Tengo una cuerda que se ve así:

# character string
string <- "lambs:    cows: 281        chickens: 20   goats: 3     trees: 13"

Quiero crear un marco de datos que se parezca a esto:

# structure
lambs <- NA
cows <- 281
chickens <- 20
goats <- 3
trees <- 13

# dataframe
df <- 
  cbind(lambs, cows, chickens, goats, trees)  %>% 
  as.data.frame()

Esto es lo que he intentado hasta ahora:

# split string
test <- strsplit(string, " ")
test

Los datos son bastante inmundos por lo que el espaciado no siempre es consistente, y a veces hay corderos y a veces no hay corderos (como en: "lamb: 5 cow: 50" y "lamb: cow: 40". ¿Cuál es la manera más fácil de hacer esto usando tidyverse?

Pregunta hecha hace 3 años, 4 meses, 29 días - Por devninjax


5 Respuestas:

  • Puedes usar str_match_all y pasar el patrón para extraer.

    tmp <- stringr::str_match_all(string, '\\s*(.*?):\\s*(\\d+)?')[[1]][, -1]
    data <- type.convert(data.frame(tmp), as.is = TRUE)
    
    #        X1  X2
    #1    lambs  NA
    #2     cows 281
    #3 chickens  20
    #4    goats   3
    #5    trees  13
    

    Esto divide los datos en dos columnas donde la primera columna es todo antes del colon (:) excepto el espacio blanco y la segunda columna es el número seguido después de él. He hecho la parte número como opcional para dar cabida a casos como 'lambs' que no tienen número.

    Respondida el Dec 18, 2020 a las 04:00 - por codealchemyf00f

    Votos positivos: 0 | Votos negativos: 0

  • Prueba esto:

    gre <- gregexpr("\\b([A-Za-z]+:\\s*[0-9]*)\\b", string)
    regmatches(string, gre)
    # [[1]]
    # [1] "lambs:    "   "cows: 281"    "chickens: 20" "goats: 3"     "trees: 13"   
    lapply(regmatches(string, gre), strcapture, pattern = "(.*):(.*)", proto = list(anim = character(0), n = character(0)))
    # [[1]]
    #       anim    n
    # 1    lambs     
    # 2     cows  281
    # 3 chickens   20
    # 4    goats    3
    # 5    trees   13
    frames <- lapply(regmatches(string, gre), strcapture,
                     pattern = "(.*):(.*)", proto = list(anim = character(0), n = character(0)))
    

    Si usted tiene múltiples cadenas (y no sólo una), entonces esto asegura que cada cadena se procesa y luego todos los datos se combinan.

    alldat <- do.call(rbind, frames)
    alldat$n <- as.integer(alldat$n)
    alldat
    #       anim   n
    # 1    lambs  NA
    # 2     cows 281
    # 3 chickens  20
    # 4    goats   3
    # 5    trees  13
    

    Si en su lugar realmente necesita los datos en un formato "total", entonces

    do.call(rbind, lapply(frames, function(z) do.call(data.frame, setNames(as.list(as.integer(z$n)), z$anim))))
    #   lambs cows chickens goats trees
    # 1    NA  281       20     3    13
    

    Respondida el Dec 18, 2020 a las 04:08 - por coderchampion

    Votos positivos: 0 | Votos negativos: 0

  • Puedes intentarlo. read.table. El tema "no hay corderos" se puede resolver poniendo en cero con gsub.

    r <- na.omit(unlist(read.table(text=gsub(": ", " 0", string), sep=" ")))
    r <- replace(r, r == 0, NA)
    
    ## long format
    type.convert(as.data.frame(matrix(r, ncol=2, byrow=TRUE)), as.is=TRUE)
    #         V1  V2
    # 1    lambs  NA
    # 2     cows 281
    # 3 chickens  20
    # 4    goats   3
    # 5    trees  13
    
    ## wide format
    setNames(type.convert(r[seq(r) %% 2 == 0]), r[seq(r) %% 2 == 1])
    # lambs     cows chickens    goats    trees 
    #    NA      281       20        3       13 
    

    Respondida el Dec 18, 2020 a las 04:15 - por pixelpioneerbbb5

    Votos positivos: 0 | Votos negativos: 0

  • Parece que estás tratando de dividir una cadena en múltiples columnas para crear un marco de datos en R. Una forma de lograr esto es limpiar la cadena y luego dividirla en columnas utilizando el paquete tidyverse. Aquí tienes un ejemplo de cómo podrías hacerlo:

    ```R library(tidyverse)

    Caracter string

    string <- "lambs: cows: 281 chickens: 20 goats: 3 trees: 13"

    Limpiar la cadena

    string_clean <- gsub(":", "", string)

    Eliminar los ":" de la cadena

    string_clean <- gsub("\\s+", ":", string_clean)

    Reemplazar múltiples espacios en blanco con ":"

    string_clean <- gsub(": ", ":", string_clean)

    Eliminar un espacio después de los ":" para tener un formato consistente

    string_clean <- gsub(":$", "", string_clean)

    Eliminar ":" al final de la cadena

    Dividir la cadena en columnas

    df <- tibble::tibble(strsplit(stringclean, ":", simplify = TRUE)) %>% dplyr::mutate(value = as.numeric(str_trim

    Respondida el Dec 19, 2020 a las 04:01 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Puedes usar la función separate() del paquete tidyr para dividir la cadena en múltiples columnas. Esta función te permite especificar un patrón para dividir la cadena y asignar los resultados a nuevas columnas en un marco de datos. Aquí tienes un ejemplo de cómo puedes usar separate() para resolver tu problema:

    
    library(tidyverse)
    
    string <- "lambs:    cows: 281        chickens: 20   goats: 3     trees: 13"
    
    

    Divide la cadena en columnas usando " " como separador

    test <- strsplit(string, " ")

    Convierte la lista resultante en un marco de datos

    test_df <- data.frame(test)

    Divide las columnas usando ":" como separador y asigna los resultados a nuevas columnas

    result_df <- test_df %>% separate(X1, into = c("animal", "count"), sep = ":")

    Convierte los valores de "count" a numéricos

    result_df$count <- as.numeric(result_df$count)

    El marco de datos resultante tendrá la siguiente estructura:

    
    

    A tibble: 5 x 2

    animal count 1 lambs NA 2 cows 281 3 chickens 20 4 goats 3 5 trees 13

    Como puedes ver, se ha creado una columna animal que contiene los nombres de los animales y una columna count que contiene los recuentos correspondientes. El valor NA en la fila lambs se debe a que no había un valor de recuento para los corderos en la cadena original.

    Respondida el Dec 19, 2020 a las 04:04 - por Gemini

    Votos positivos: 0 | Votos negativos: 0