2014-07-22 11 views
24

Niedawno robię wszystkie manipulacje danymi za pomocą dplyr i jest to doskonałe narzędzie do tego. Nie mogę jednak przetopić ani rzucić ramki danych za pomocą programu dplyr. Czy istnieje jakiś sposób, aby to zrobić? W tej chwili używam do tego celu reshape2.Jak topić i rzutować ramki danych za pomocą dplyr?

Chcę rozwiązania 'dplyr' dla:

require(reshape2) 
data(iris) 
dat <- melt(iris,id.vars="Species") 
+13

Następcą "reshape2" jest 'tidyr'. Odpowiednikiem 'melt' i' dcast' są odpowiednio 'gather' i' Spread'. Nie jest jeszcze dostępny na CRAN, ale możesz go pobrać z github (https://github.com/hadley/tidyr)! – konvas

+3

@konvas Aktualizacja: 'tidyr' jest teraz na CRAN (http://cran.r-project.org/web/packages/tidyr/index.html) – dickoa

+0

@konvas dlaczego nie uważasz go za właściwą odpowiedź? – Beasterfield

Odpowiedz

50

Następca reshape2 jest tidyr. Odpowiednikami melt() i dcast() są odpowiednio: gather() i . Odpowiednikiem kodzie byłaby wtedy

library(tidyr) 
data(iris) 
dat <- gather(iris, variable, value, -Species) 

Jeśli masz magrittr importowane można użyć operatora rury jak w dplyr, czyli napisać

dat <- iris %>% gather(variable, value, -Species) 

Zauważ, że musisz określić nazwy zmiennych i wartości wyraźnie, w przeciwieństwie do melt(). Uważam, że składnia jest całkiem wygodna, ponieważ można po prostu określić kolumny, które mają być konwertowane na długi format, lub określić te, które mają pozostać w nowej ramce danych, poprzedzając je "-" (podobnie jak w przypadku gatunków). powyżej), który jest nieco szybszy do wpisania niż w melt(). Zauważyłem jednak, że przynajmniej na moim komputerze tidyr może być zauważalnie wolniejszy niż reshape2.

Edytuj W odpowiedzi na komentarz @hadley poniżej, zamieszczam informacje o czasie, porównując dwie funkcje na moim komputerze.

library(microbenchmark) 
microbenchmark(
    melt = melt(iris,id.vars="Species"), 
    gather = gather(iris, variable, value, -Species) 
) 
# Unit: microseconds 
# expr  min  lq median  uq  max neval 
# melt 278.829 290.7420 295.797 320.5730 389.626 100 
# gather 536.974 552.2515 567.395 683.2515 1488.229 100 

set.seed(1) 
iris1 <- iris[sample(1:nrow(iris), 1e6, replace = T), ] 
system.time(melt(iris1,id.vars="Species")) 
# user system elapsed 
# 0.012 0.024 0.036 
system.time(gather(iris1, variable, value, -Species)) 
# user system elapsed 
# 0.364 0.024 0.387 

sessionInfo() 
# R version 3.1.1 (2014-07-10) 
# Platform: x86_64-pc-linux-gnu (64-bit) 
# 
# locale: 
# [1] LC_CTYPE=en_GB.UTF-8  LC_NUMERIC=C    
# [3] LC_TIME=en_GB.UTF-8  LC_COLLATE=en_GB.UTF-8  
# [5] LC_MONETARY=en_GB.UTF-8 LC_MESSAGES=en_GB.UTF-8 
# [7] LC_PAPER=en_GB.UTF-8  LC_NAME=C     
# [9] LC_ADDRESS=C    LC_TELEPHONE=C    
# [11] LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C  

# attached base packages: 
# [1] stats  graphics grDevices utils  datasets methods base  
# 
# other attached packages: 
# [1] reshape2_1.4   microbenchmark_1.3-0 magrittr_1.0.1  
# [4] tidyr_0.1   
# 
# loaded via a namespace (and not attached): 
# [1] assertthat_0.1 dplyr_0.2  parallel_3.1.1 plyr_1.8.1  Rcpp_0.11.2 
# [6] stringr_0.6.2 tools_3.1.1 
+0

Nie powinien być zauważalnie wolniejszy, ponieważ jest to w zasadzie cały ten sam kod. Jeśli możesz podać powtarzalny przykład, bardzo chciałbym go zobaczyć. – hadley

+0

@ hadley Dodałem trochę informacji. Zdaję sobie sprawę, że prawdopodobnie nie wynika to z kodu i może być specyficzne dla mojego systemu. Wygląda na to, że "użytkownik" w 'system.time()' robi różnicę, chociaż nie jestem do końca pewny, co to oznacza, ale jestem pewien, że się dowiesz :) – konvas

+0

@hadley For me too melt performs szybciej niż zebrać --- utknie w tym przez chwilę. – apc

3

Ponadto, obsada może być używany tidyr::spread()

dla was przykładem

library(reshape2) 
library(tidyr) 
library(dplyr) 

# example data : `mini_iris` 
(mini_iris <- iris[c(1, 51, 101), ]) 

# melt 
(melted1 <- mini_iris %>% melt(id.vars = "Species"))   # on reshape2 
(melted2 <- mini_iris %>% gather(variable, value, -Species)) # on tidyr 

# cast 
melted1 %>% dcast(Species ~ variable, value.var = "value") # on reshape2 
melted2 %>% spread(variable, value)      # on tidyr 
1

Aby dodać do odpowiedzi powyżej używając @mini_iris przykład Lovetoken za (jest to zbyt skomplikowane dla komentarzu) - dla tych przybyszów, którzy nie rozumieją, co rozumie się przez stopienie i odlewanie.

library(reshape2) 
library(tidyr) 
library(dplyr) 

# example data : `mini_iris` 
mini_iris <- iris[c(1, 51, 101), ] 

# mini_iris 
#Sepal.Length Sepal.Width Petal.Length Petal.Width Species 
#1   5.1   3.5   1.4   0.2  setosa 
#51   7.0   3.2   4.7   1.4 versicolor 
#101   6.3   3.3   6.0   2.5 virginica 

Melt przyjmuje ramkę danych i rozwija się na długą listę wartości. Nieefektywny, ale może być przydatny, jeśli chcesz łączyć zbiory danych. Pomyśl o strukturze icecube topi się na stole i rozprzestrzenia.

melted1 <- testiris %>% melt(id.vars = "Species") 

> nrow(melted1) 
[1] 12 

head(melted1) 
# Species  variable  value 
# 1  setosa Sepal.Length 5.1 
# 2 versicolor Sepal.Length 7.0 
# 3 virginica Sepal.Length 6.3 
# 4  setosa Sepal.Width 3.5 
# 5 versicolor Sepal.Width 3.2 
# 6 virginica Sepal.Width 3.3 

Można zobaczyć, w jaki sposób dane został podzielony na wiele rzędów wartości. Nazwy kolumn są teraz tekstami w zmiennej kolumnie.

odlewanie zostanie ponownie połączone z data.table lub data.frame.

Powiązane problemy