Columna de división - pero sólo si contians uno ore más caracteres especiales

Encontré algunas preguntas en esta dirección, pero no pude aplicar las soluciones a mi problema específico: Tengo una columna bastante desordenada de un marco de datos con direcciones. Esto significa que puede haber células vacías, números, números y texto combinados - y puede haber uno o más caracteres especiales entre ellos.

En un primer paso, quiero dividir todos los valores en el primer personaje especial. He probado varias opciones que funcionan parcialmente. Sin embargo, el problema parece ser que algunas células no contienen caracteres especiales, causando un error en la función.

Por ejemplo, el siguiente código pone sólo el carácter especial en la nueva columna b, pero realmente no divide las columnas:

df <- df %>% 
separate(address, into = c("a", "b"), sep = "[^[:punct:]]+", remove = FALSE)

Así que lo ideal que quiero lograr es lo siguiente: Si hay un personaje especial en la celda, dividirlo en el primer personaje especial, todo lo que queda del primer personaje especial en column a, todo bien en column b. Si no hay carácter especial, ponga todo en column a y NA dentro column b.

¿Tengo que envolver mi código en un ifelse- declaración? ¿O hay alguna otra sugerencia?

¡Gracias!

Editar: según lo solicitado, algunos datos de muestra:

library(dplyr)

test <- as.data.frame(c("2", "97/7", "17/7-8", "7E", "800E/7", "17", "", "0", "2/15", "17+18", "17/7/8", "19", "2/2/4", "9-7/8")) %>% 
  rename(address = 1)

Pregunta hecha hace 3 años, 5 meses, 0 días - Por scriptwarrior


5 Respuestas:

  • Puedes usar separate utilizando extra = 'merge' y fill = 'right'

    tidyr::separate(test, address, into = c("a", "b"), '[[:punct:]]', 
                    extra = 'merge', fill = 'right', remove = FALSE)
    
    #   address    a    b
    #1        2    2 
    #2     97/7   97    7
    #3   17/7-8   17  7-8
    #4       7E   7E 
    #5   800E/7 800E    7
    #6       17   17 
    #7               
    #8        0    0 
    #9     2/15    2   15
    #10   17+18   17   18
    #11  17/7/8   17  7/8
    #12      19   19 
    #13   2/2/4    2  2/4
    #14   9-7/8    9  7/8
    

    Respondida el Dec 17, 2020 a las 09:45 - por htmlhelix

    Votos positivos: 0 | Votos negativos: 0

  • Uso strsplit con su expresión regular funciona. Podemos ponerlo en un lapply a bucle sobre las columnas. Uso `length<-()` ajustamos las longitudes de los elementos de la lista a su máximo para poder crear un data.frame.

    r <- el(lapply(test, strsplit, "[[:punct:]]", perl=TRUE))
    as.data.frame(t(sapply(r, `length<-`, max(lengths(r)))))
    #      V1   V2   V3
    # 1     2  
    # 2    97    7 
    # 3    17    7    8
    # 4    7E  
    # 5  800E    7 
    # 6    17  
    # 7    
    # 8     0  
    # 9     2   15 
    # 10   17   18 
    # 11   17    7    8
    # 12   19  
    # 13    2    2    4
    # 14    9    7    8
    

    Del mismo modo podemos hacerlo en la primera ocurrencia: Podemos usar sub para reemplazar la primera ocurrencia con algo, digamos "£" y luego dividirlo ahí.

    test[] <- lapply(test, sub, pat="[[:punct:]]", rep="£")
    r <- el(lapply(test, strsplit, "£"))
    as.data.frame(t(sapply(r, `length<-`, max(lengths(r)))))
    #      V1   V2
    # 1     2 
    # 2    97    7
    # 3    17  7-8
    # 4    7E 
    # 5  800E    7
    # 6    17 
    # 7   
    # 8     0 
    # 9     2   15
    # 10   17   18
    # 11   17  7/8
    # 12   19 
    # 13    2  2/4
    # 14    9  7/8
    

    Respondida el Dec 17, 2020 a las 09:55 - por logicloom

    Votos positivos: 0 | Votos negativos: 0

  • Esto funciona:

    library(dplyr)
    library(tidyr)
    df %>% separate(c1, c('a','b'), sep = '[^A-z0-9_]')
         a    b
    1   ab   cd
    2   pq   rj
    3   xy    z
    4 abcd 
    

    Datos utilizados:

    df
         c1
    1 ab$cd
    2 pq%rj
    3  xy#z
    4  abcd
    

    Respondida el Dec 17, 2020 a las 10:04 - por techtrailblazer

    Votos positivos: 0 | Votos negativos: 0

  • Para lograr la división de la columna de direcciones de acuerdo a la presencia de caracteres especiales, puedes utilizar la función mutate() junto con ifelse() para realizar la condición que mencionas.

    Aquí te dejo un ejemplo de cómo podrías hacerlo:

    ```R library(dplyr)

    Crear los datos de ejemplo

    test <- as.data.frame(c("2", "97/7", "17/7-8", "7E", "800E/7", "17", "", "0", "2/15", "17+18", "17/7/8", "19", "2/2/4", "9-7/8")) %>% rename(address = 1)

    Dividir los valores en dos columnas según la presencia de caracteres especiales

    test <- test %>% mutate(a = ifelse(grepl("[[:punct:]]", address), sub("([[:punct:]]).$", "\1", address), address), b = ifelse(grepl("[[:punct:]]", address), sub(".([[:punct:]]).*", "\1", address), NAcharacter))

    #

    Respondida el Dec 18, 2020 a las 09:44 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Claro, echemos un vistazo a tu problema con la separación de columnas en un DataFrame. Entiendo que deseas dividir los datos en la primera aparición de un carácter especial, pero solo cuando exista ese carácter en la celda. Aquí tienes una solución que puedes usar:

    
    library(dplyr)
    library(stringr)
    
    test <- as.data.frame(c("2", "97/7", "17/7-8", "7E", "800E/7", "17", "", "0", "2/15", "17+18", "17/7/8", "19", "2/2/4", "9-7/8")) |>
      mutate(address = 1)
    
    

    Divide la cadena en el primer carácter especial (si existe)

    test <- test |> mutate( a = case_when( str_contains(address, "[^[:punct:]]+") ~ str_sub(address, 1, str_locate(address, "[^[:punct:]]+") - 1), TRUE ~ address ), b = case_when( str_contains(address, "[^[:punct:]]+") ~ str_sub(address, str_locate(address, "[^[:punct:]]+") + 1), TRUE ~ NA ) ) print(test)

    Explicación:

    • Caso cuando la celda no tiene un carácter especial:
    - `str_contains(address, "[^[:punct:]]+")` verifica si la celda tiene un carácter que no sea un carácter de puntuación.
    • `TRUE ~ address` devuelve el valor de la celda `address` si no hay un carácter especial.
    • Caso cuando la celda tiene un carácter especial:
    - `str_contains(address, "[^[:punct:]]+")` verifica si la celda tiene un carácter que no sea un carácter de puntuación.
    • `str_sub(address, 1, str_locate(address, "[^[:punct:]]+") - 1)` extrae la subsecuencia desde el primer carácter hasta el carácter anterior al primer carácter especial.
    • `str_sub(address, str_locate(address, "[^[:punct:]]+") + 1)` extrae la subsecuencia desde el carácter posterior al primer carácter especial hasta el final de la cadena.

    Espero que esto resuelva tu problema. Avísame si tienes alguna otra inquietud.

    Respondida el Dec 18, 2020 a las 09:54 - por Gemini

    Votos positivos: 0 | Votos negativos: 0