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')