2015-10-22 6 views
11

Ho un set di dati che consiste in comunicazioni e-mail. Un esempio:Come utilizzare tidyr :: separato quando il numero delle variabili necessarie è sconosciuto

library(dplyr) 
library(tidyr) 

dat <- data_frame('date' = Sys.time(), 
        'from' = c("[email protected]", "[email protected]", 
          "[email protected]", "[email protected]"), 
        'to' = c("[email protected],[email protected]", "[email protected]", 
          "[email protected],[email protected],[email protected]", "[email protected]")) 

Nell'esempio di cui sopra è abbastanza semplice per vedere quante variabili ho bisogno, quindi ho potuto solo effettuare le seguenti operazioni:

dat %>% separate(to, into = paste0("to_", 1:3), sep = ",", extra = "merge", fill = "right") 

#Source: local data frame [4 x 5] 
# 
#     date    from    to_1    to_2    to_3 
#    (time)    (chr)    (chr)    (chr)    (chr) 
#1 2015-10-22 14:52:41 [email protected] [email protected] [email protected]    NA 
#2 2015-10-22 14:52:41 [email protected] [email protected]     NA    NA 
#3 2015-10-22 14:52:41 [email protected]  [email protected] [email protected] [email protected] 
#4 2015-10-22 14:52:41  [email protected] [email protected]     NA    NA 

Tuttavia, il mio set di dati è lungo 4.000 dischi e io Preferisco non passare e trovare la riga con il maggior numero di elementi al suo interno in modo da poter determinare quante variabili ho bisogno di creare. Il mio approccio alla gestione di questo è di prima dividere la colonna di me stesso e ottenere la lunghezza di ogni divisa e poi trovare il massimo:

n_vars <- dat$to %>% str_split(",") %>% lapply(function(z) length(z)) %>% unlist() %>% max() 

ma che sembra inefficiente. C'è un modo migliore per farlo?

+0

Forse anche ' libreria (data.table); cbind (dat, setDT (dat) [, tstrsplit (to, ",")]) ' –

+0

Sembra una soluzione abbastanza ragionevole invece di caricare un altro pacchetto. se stai già caricando 'tidyverse' potresti usare' map_dbl' e rimuovere 'unlist' per renderlo leggermente più pulito. 'dat $ a%>% str_split (", ")%>% map_dbl (~ length (.))%>% max()' – Tunn

risposta

6

potremmo usare cSplit

library(splitstackshape) 
cSplit(dat, 'to', ',') 
9

Questa è una buona domanda - il mio solito repsonse è quello di utilizzare strsplit, quindi unnest e spread, che non è anche super efficiente:

library(dplyr) 
library(tidyr) 

dat %>% mutate(to = strsplit(to, ",")) %>% 
     unnest(to) %>% 
     group_by(from) %>% 
     mutate(row = row_number()) %>% 
     spread(row, to) 

Source: local data frame [4 x 5] 

       date    from     1     2     3 
       (time)    (chr)    (chr)    (chr)    (chr) 
1 2015-10-22 15:03:17 [email protected] [email protected] [email protected]    NA 
2 2015-10-22 15:03:17 [email protected] [email protected]     NA    NA 
3 2015-10-22 15:03:17 [email protected]  [email protected] [email protected] [email protected] 
4 2015-10-22 15:03:17  [email protected] per[email protected]     NA    NA 
+0

Penso che sia meglio, perché puoi opzionalmente non diffonderlo alla fine. Dividere le email in tutte queste colonne separate sembra stupido. – bramtayl

+0

@bramtayl Ho la sensazione che separato lo renda deliberatamente difficile, quindi non si ottengono dati ampi piuttosto che lunghi – jeremycg

+0

@bramtayl Sono d'accordo che avere ampi dati in questo scenario non ha senso (e non la maggior parte delle situazioni), ma è stato un concetto facile da girare intorno alla questione sottostante dell'uso di 'separate' quando non si conoscono le nuove colonne necessarie. La soluzione di Akrun è ancora valida perché hai impostato 'direction =" long "' per ottenere tutte le email in una colonna. – brittenb

Problemi correlati