2015-05-13 13 views
8

Stavo cercando un modo per dividere il contenuto della colonna da un separatore e convertire una tabella in un formato lungo. Ho trovato cSplit dal pacchetto splitstackshape e sta quasi facendo ciò che stavo cercando.c La libreria di spaccatura (splitstackshape) fa sempre cadere la colonna

Il problema è ora con l'opzione drop. Mi aspettavo che la mia colonna divisa venisse copiata in un modo, ma questo non succede. Sto sbagliando? Qualcuno ha avuto il problema?

Non sono sicuro di fare qualcosa di sbagliato, ma l'opzione drop = FALSE non funziona nel mio caso.

Ecco un esempio:

library(splitstackshape) 
jnk <- data.table(a = '1,2,3,4,5', b = 5) 
jnk 
#   a b 
# 1: 1,2,3,4,5 5 

cSplit(jnk, 'a', ',', 'long', drop = FALSE) 
# a b 
# 1: 1 5 
# 2: 2 5 
# 3: 3 5 
# 4: 4 5 
# 5: 5 5 

Quello che mi aspettavo era qualcosa di simile:

cSplit(jnk, 'a', ',', 'long', drop = FALSE) 
# a b a.orig 
# 1: 1 5 1,2,3,4,5 
# 2: 2 5 1,2,3,4,5 
# 3: 3 5 1,2,3,4,5 
# 4: 4 5 1,2,3,4,5 
# 5: 5 5 1,2,3,4,5 

Sto usando la versione 1.4.2

+0

Questo non fa di sicuro non funziona se ci sono più linee nel DF, dato che il 'JNK [[ 'a']]' deve avere la stessa lunghezza o si arriva aggiunto ogni volta ... Così è non funziona con 'jnk <- data.table (a = c ('1,2,3,4,5', '1,2,3', '2,3'), b = c (5,4 , 3)) ' – drmariod

risposta

10

Il formato "lungo" modifica la colonna in posizione utilizzando list(unlist(...)) all'interno di "data.table", assegnato con . Quindi, se sono stati utilizzati drop, si sarebbe dividere la colonna e quindi rimuoverla!

Cercherò di renderlo esplicito nella documentazione che drop è solo per il formato wide, oppure aggiungere un message se un utente tenta di utilizzare drop nel formato lungo. Sentiti libero di file a FR or submit a PR.

La soluzione sarebbe quella di assegnare un'altra colonna (ad esempio, "a_orig") e poi fare la scissione:

jnk <- data.table(a=c('1,2,3,4,5','1,2,3','2,3'),b=c(5,4,3)) 
cSplit(jnk[, a_orig := a], "a", ",", "long") 
#  a b a_orig 
# 1: 1 5 1,2,3,4,5 
# 2: 2 5 1,2,3,4,5 
# 3: 3 5 1,2,3,4,5 
# 4: 4 5 1,2,3,4,5 
# 5: 5 5 1,2,3,4,5 
# 6: 1 4  1,2,3 
# 7: 2 4  1,2,3 
# 8: 3 4  1,2,3 
# 9: 2 3  2,3 
# 10: 3 3  2,3 

non ho ancora testato estensivamente, ma una possibile soluzione potrebbe essere:

cSplit2 <- function(indt, splitCols, sep = ",", direction = "wide", 
        fixed = TRUE, drop = TRUE, stripWhite = TRUE, 
        makeEqual = NULL, type.convert = TRUE) { 
    if (direction == "long" & !drop) { 
    indt <- as.data.table(indt) 
    indt[, `:=`(eval(paste(splitCols, "orig", sep = "_")), 
       lapply(splitCols, function(x) indt[[x]]))] 
    } 
    cSplit(indt, splitCols, sep, direction, fixed, drop, stripWhite, 
     makeEqual, type.convert) 
} 

l'idea di base è quella di modificare solo il set di dati di ingresso se direction == "wide" e drop = FALSE. Questo è simile all'idea che avevi, ma può possibilmente essere la soluzione integrata nel pacchetto reale, da qualche parte intorno a line 94. In questo caso, dovrebbe essere necessaria solo la parte indt[, `:=`(eval(paste(splitCols, "orig", sep = "_")), lapply(splitCols, function(x) indt[[x]]))].

0

Grazie per il feedback, ho scritto una piccola funzione come soluzione alternativa. Ho dovuto cambiare il data.table in data.frame per farlo funzionare correttamente. In caso di data.table ho bisogno di impostare un parametro aggiuntivo ma si blocca con data.frame. Nel mio caso ho bisogno della maggior parte del tempo data.frame quindi l'ho ottimizzato per questo.

library(splitstackshape) 
jnk <- data.frame(a = c('1,2,3,4,5','1,2,3','2,3'), 
        b = c('a,b,c,d,e','a,b,c','a,b'), 
        c = c(5,4,3)) 
jnk 

myCSplit <- function(data_set, splitCols, sep = ',', direction = 'long', drop = TRUE, ...) { 
    if(direction == 'long' & !drop) { 
    orig_names <- sub('$', '_orig', splitCols) 
    df <- as.data.frame(data_set[,splitCols]) 
    names(df) <- orig_names 
    df2 <- cbind(data_set, df) 
    return(cSplit(df2, splitCols, sep, 'long')) 
    } else { 
    return(cSplit(data_set, splitCols, sep, direction, drop = drop,...)) 
    } 
} 
myCSplit(jnk, 'a', ',') 
myCSplit(jnk, 'a', ',', drop = FALSE) 
myCSplit(jnk, 'a', ',', 'wide') 
myCSplit(jnk, 'a', ',', 'wide', drop = FALSE) 
myCSplit(jnk, c('a','b'), ',', 'long', drop = FALSE) 
+2

Lasciami tornare da pranzo con una soluzione più generale. – A5C1D2H2I1M1N2O1R2T1

+0

Hey @AnandaMahto forse potresti aggiungere questa funzione alla prossima versione ... Nel mio caso sarebbe molto utile. – drmariod

+2

Per quanto posso dire, * dovrebbe * essere possibile per me fare la correzione con una sola riga. Dovrò fare alcuni test per vedere però. – A5C1D2H2I1M1N2O1R2T1

Problemi correlati