Ricerca Sociale con R

Una wiki per l'analisi dei dati con R

Strumenti Utente

Strumenti Sito


r:tidyverse:tidyr_unite_separate

unite, separate (tidyr)

Unire i valori di due o più colonne di un dataframe in una (unite), oppure dividere una colonna di un dataframe in due o più colonne (separate).

library(tidyverse)

unite

Vedi anche, per l'unione di stringhe, paste().

  unite(data, col, ..., sep = "_", remove = TRUE, na.rm = FALSE)
col nome della nuova variabile
variabili da unire
sep = "_" il separatore di default è "_".
remove = TRUE le colonne originali vengono eliminate di default. Per conservarle, specificare l'argomento remove = FALSE
na.rm = FALSE i campi vuoti (NA) vengono mantenuti di defaulti

ad esempio:

unite(starwars,     # data
      height_mass,  # col, nuova variabile
      height, mass  # variabili da unire
      )

Vediamo il risultato:

starwars %>% 
  # riduciamo il numero di variabili
  select(name, hair_color, eye_color) %>% 
  unite(hair_eye_col, hair_color, eye_color, 
        # indichiamo una stringa come separatore
        sep=" & ") 
# A tibble: 87 x 2
   name               hair_eye_col             
   <chr>              <chr>                    
 1 Luke Skywalker     blond & blue             
 2 C-3PO              NA & yellow              
 3 R2-D2              NA & red                 
 4 Darth Vader        none & yellow            
 5 Leia Organa        brown & brown            
 6 Owen Lars          brown, grey & blue       
 7 Beru Whitesun lars brown & blue             
 8 R5-D4              NA & red                 
 9 Biggs Darklighter  black & brown            
10 Obi-Wan Kenobi     auburn, white & blue-gray
# ... with 77 more rows

Unendo due colonne in questo modo, otteniamo sempre una colonna di testo:

starwars %>% 
  select(1:3) %>% 
  unite(height_mass, height, mass, 
        # manteniamo le colonne originali
        remove = FALSE) 
# A tibble: 87 x 4
   name               height_mass height  mass
   <chr>              <chr>        <int> <dbl>
 1 Luke Skywalker     172_77         172    77
 2 C-3PO              167_75         167    75
 3 R2-D2              96_32           96    32
 4 Darth Vader        202_136        202   136
 5 Leia Organa        150_49         150    49
 6 Owen Lars          178_120        178   120
 7 Beru Whitesun lars 165_75         165    75
 8 R5-D4              97_32           97    32
 9 Biggs Darklighter  183_84         183    84
10 Obi-Wan Kenobi     182_77         182    77
# ... with 77 more rows

Apprezziamo in questi casi il vantaggio di usare il pipe operator: trasformiamo le variabili e controlliamo i risultati fino a quando non siano soddisfacenti; poi aggiungiamo starwars ← (o un nuovo nome), all'inizio, e salviamo le trasformazioni.

separate

Vedi anche, per la divisione di stringhe, str_split().

  separate(}
    data,            
    col,                    # colonna da dividere
    into,                   # colonne da creare
    sep = "[^[:alnum:]]+",
    remove = TRUE,
    convert = FALSE,        # non cambia il formato
    extra = "warn",
    fill = "warn",
    ...
  )

In questo caso, rispetto a unite():

  • le colonne da creare vanno indicate con un vettore carattere: into=c(“skin1”, “skin2”);
  • è possibile adattare il tipo di variabile creata ai valori contenuti (ad esempio, creare una variabile numerica se la stringa di partenza conteneva numeri): convert = TRUE.
separate(starwars, skin_color, c("skin1", "skin2"))
# A tibble: 87 x 15
   name      height  mass hair_color  skin1 skin2 eye_color birth_year sex    gender
   <chr>      <int> <dbl> <chr>       <chr> <chr> <chr>          <dbl> <chr>  <chr> 
 1 Luke Sky~    172    77 blond       fair  NA    blue            19   male   mascu~
 2 C-3PO        167    75 NA          gold  NA    yellow         112   none   mascu~
 3 R2-D2         96    32 NA          white blue  red             33   none   mascu~
 4 Darth Va~    202   136 none        white NA    yellow          41.9 male   mascu~
 5 Leia Org~    150    49 brown       light NA    brown           19   female femin~
 6 Owen Lars    178   120 brown, grey light NA    blue            52   male   mascu~
 7 Beru Whi~    165    75 brown       light NA    blue            47   female femin~
 8 R5-D4         97    32 NA          white red   red             NA   none   mascu~
 9 Biggs Da~    183    84 black       light NA    brown           24   male   mascu~
10 Obi-Wan ~    182    77 auburn, wh~ fair  NA    blue-gray       57   male   mascu~
# ... with 77 more rows, and 5 more variables: homeworld <chr>, species <chr>,
#   films <list>, vehicles <list>, starships <list>
Warning messages:
1: Expected 2 pieces. Additional pieces discarded in 4 rows [16, 47, 67, 76]. 
2: Expected 2 pieces. Missing pieces filled with `NA` in 71 rows [1, 2, 4, 5, 6, 7, 
9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, ...]. 

Le colonne sono divise correttamente, anche senza indicare il separatore, perché di default sono usati come separatori i caratteri non alfanumerici ([^[:alnum:]]+).

Riceviamo 2 avvisi: il primo riguarda 4 righe in cui la divisione avrebbe portato a più di due elementi (Additional pieces discarded in 4 rows); il secondo riguarda 71 righe con valori mancanti (ovvero righe in cui era indicato un solo colore per la pelle).

Per quanto riguarda il primo avviso, possiamo decidere di ripetere la procedura indicando 3 nuove variabili anziché 2, e di fondere (merge), nella terza, gli eventuali elementi in più (extra = 'merge'):

starwars %>% 
  select(name, skin_color) %>% 
  separate(skin_color, into=c("skin1", "skin2", "skin3"), 
           extra = 'merge')
# A tibble: 87 x 4
   name               skin1 skin2 skin3
   <chr>              <chr> <chr> <chr>
 1 Luke Skywalker     fair  NA    NA   
 2 C-3PO              gold  NA    NA   
 3 R2-D2              white blue  NA   
 4 Darth Vader        white NA    NA   
 5 Leia Organa        light NA    NA   
 6 Owen Lars          light NA    NA   
 7 Beru Whitesun lars light NA    NA   
 8 R5-D4              white red   NA   
 9 Biggs Darklighter  light NA    NA   
10 Obi-Wan Kenobi     fair  NA    NA   
# ... with 77 more rows
Warning message:
Expected 3 pieces. Missing pieces filled with `NA` in 83 rows [1, 2, 3, 4, 5, 6, 7, 8, 
9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, ...]. 

L'avviso sugli spezzoni aggiuntivi non c'è più: bisognerà controllare i valori dell'ultima colonna.

L'argomento extra = 'merge' è molto utile per procedere ad una divisione progressiva delle strighe: applichiamo una volta separate() con un separatore, e poi la applichiamo di nuovo a quel che resta, magari con un altro carattere di separazione, e così via.

Script di esempio

unite_separate.R
# unite
starwars %>% 
  unite(hair_eye_col, hair_color, eye_color, 
        # indichiamo una stringa come separatore
        sep=" & ")
 
# separate
separate(starwars, skin_color, c("skin1", "skin2"))
 
# separate con extra = merge
starwars %>% 
  select(name, skin_color) %>% 
  separate(skin_color, into=c("skin1", "skin2", "skin3"), 
           extra = 'merge')

Domande? Scrivimi

Messenger Telegram Email
r/tidyverse/tidyr_unite_separate.txt · Ultima modifica: 11/08/2025 14:40 da Agnese Vardanega