2016-02-05 23 views
6

Mam tabeli tak,Rozprzestrzenianie vs dcast

> head(dt2) 
    Weight Height Fitted interval limit value 
1 65.6 174.0 71.91200  pred lwr 53.73165 
2 80.7 193.5 91.63237  pred lwr 73.33198 
3 72.6 186.5 84.55326  pred lwr 66.31751 
4 78.8 187.2 85.26117  pred lwr 67.02004 
5 74.8 181.5 79.49675  pred lwr 61.29244 
6 86.4 184.0 82.02501  pred lwr 63.80652 

chcę go mieć w ten sposób,

> head(reshape2::dcast(dt2, 
     Weight + Height + Fitted + interval ~ limit, 
     fun.aggregate = mean)) 
    Weight Height Fitted interval  lwr  upr 
1 42.0 153.4 51.07920  conf 49.15463 53.00376 
2 42.0 153.4 51.07920  pred 32.82122 69.33717 
3 43.2 160.0 57.75378  conf 56.35240 59.15516 
4 43.2 160.0 57.75378  pred 39.54352 75.96404 
5 44.8 149.5 47.13512  conf 44.87642 49.39382 
6 44.8 149.5 47.13512  pred 28.83891 65.43133 

Ale używając tidyr::spread, W jaki sposób można to zrobić?

używałem,

> tidyr::spread(dt2, limit, value) 

Ale uzyskiwanie błąd,

Error: Duplicate identifiers for rows (1052, 1056), (238, 242), (1209, 1218), (395, 404), (839, 1170), (25, 356), (1173, 1203, 1215), (359, 389, 401), (1001, 1200), (187, 386), (906, 907), (92, 93), (930, 1144), (116, 330), (958, 1171), (144, 357), (902, 1018), (88, 204), (960, 1008), (146, 194), (1459, 1463), (645, 649), (1616, 1625), (802, 811), (1246, 1577), (432, 763), (1580, 1610, 1622), (766, 796, 808), (1408, 1607), (594, 793), (1313, 1314), (499, 500), (1337, 1551), (523, 737), (1365, 1578), (551, 764), (1309, 1425), (495, 611), (1367, 1415), (553, 601) 

Losowe 10 Wiersze ::

> dt[sample(nrow(dt), 10), ] 
    Weight Height Fitted interval limit value 
1253 52.2 162.5 60.28203  conf upr 61.51087 
426 49.1 158.8 56.54022  pred upr 74.75756 
1117 78.4 184.5 82.53066  conf lwr 80.98778 
1171 85.9 166.4 64.22611  conf lwr 63.21254 
948 61.4 177.8 75.75494  conf lwr 74.66393 
384 90.9 172.7 70.59731  pred lwr 52.41828 
289 75.9 172.7 70.59731  pred lwr 52.41828 
3  44.8 149.5 47.13512  pred lwr 28.83891 
774 87.3 182.9 80.91258  pred upr 99.12445 
772 86.4 175.3 73.22669  pred upr 91.40919 
+0

Ci przykład nie zawiera 'upr' w' limit', ani 'conf' w' interval', co oznacza, że ​​oczekiwany wynik nie jest powtarzalna – mtoto

+0

Dlaczego nie zachować go w długim formacie i po prostu zagregować? Zobacz [tutaj na przykład] (http://stackoverflow.com/a/32795497/2204410) z bazą R, * dplyr * i * data.table *. – Jaap

+0

Mimo, że zrobiłem to z dcastem, chcę to zrobić za pomocą tidyr tylko po to, żeby się czegoś nauczyć. @mtoto To jest tylko nagłówek mojego zbioru danych, będę go edytować, aby dać ci losową próbkę, dla odtwarzalności. – TheRimalaya

Odpowiedz

9

Powiedzmy, że zaczęły z danymi, które wygląda tak :

mydf 
# Weight Height Fitted interval limit value 
# 1  42 153.4 51.0792  conf lwr 49.15463 
# 2  42 153.4 51.0792  pred lwr 32.82122 
# 3  42 153.4 51.0792  conf upr 53.00376 
# 4  42 153.4 51.0792  pred upr 69.33717 
# 5  42 153.4 51.0792  conf lwr 60.00000 
# 6  42 153.4 51.0792  pred lwr 90.00000 

Zwróć uwagę na duplikację w wierszach 5 i 6 kolumn grupowania (od 1 do 5). Zasadniczo to mówi ci "tidyr". Pierwszy i piąty wiersz to duplikaty, podobnie jak drugi i szósty.

tidyr::spread(mydf, limit, value) 
# Error: Duplicate identifiers for rows (1, 5), (2, 6) 

Zgodnie z sugestią @Jaap rozwiązaniem jest najpierw "podsumowanie" danych. Ponieważ "tidyr" służy tylko do przekształcania danych (w przeciwieństwie do "reshape2", który agregował i przekształcał), przed zmianą formularza danych musisz przeprowadzić agregację z "dplyr". Tutaj, zrobiłem to z summarise dla kolumny "wartość".

Jeśli zatrzymasz wykonywanie w kroku summarise, okaże się, że nasz oryginalny 6-wierszowy zestaw danych "skurczył się" do 4 wierszy. Teraz spread będzie działać zgodnie z oczekiwaniami.

mydf %>% 
    group_by(Weight, Height, Fitted, interval, limit) %>% 
    summarise(value = mean(value)) %>% 
    spread(limit, value) 
# Source: local data frame [2 x 6] 
# 
# Weight Height Fitted interval  lwr  upr 
# (dbl) (dbl) (dbl) (chr) (dbl) (dbl) 
# 1  42 153.4 51.0792  conf 54.57731 53.00376 
# 2  42 153.4 51.0792  pred 61.41061 69.33717 

Dopasowuje oczekiwanego wyjście z dcast z fun.aggregate = mean.

reshape2::dcast(mydf, Weight + Height + Fitted + interval ~ limit, fun.aggregate = mean) 
# Weight Height Fitted interval  lwr  upr 
# 1  42 153.4 51.0792  conf 54.57731 53.00376 
# 2  42 153.4 51.0792  pred 61.41061 69.33717 

dane próbki:

mydf <- structure(list(Weight = c(42, 42, 42, 42, 42, 42), Height = c(153.4, 
    153.4, 153.4, 153.4, 153.4, 153.4), Fitted = c(51.0792, 51.0792,   
    51.0792, 51.0792, 51.0792, 51.0792), interval = c("conf", "pred",   
    "conf", "pred", "conf", "pred"), limit = structure(c(1L, 1L,    
    2L, 2L, 1L, 1L), .Label = c("lwr", "upr"), class = "factor"),    
     value = c(49.15463, 32.82122, 53.00376, 69.33717, 60,   
     90)), .Names = c("Weight", "Height", "Fitted", "interval",  
    "limit", "value"), row.names = c(NA, 6L), class = "data.frame") 
+0

Dzięki! Zastanawiałem się, jak sobie poradzić z funkcją agregującą. Myślę, że Hadely chce używać 'tidyr' razem z' dplyr'. – TheRimalaya

+0

To jest doskonała odpowiedź i pozwoliła mi zrozumieć różnicę między 'dcast' i' spread'. Dziękuję Ci! – Mikko

1

Oto data.table alternatywy dplyr. Użyj odpowiedzi mydf z Anandy.

library(data.table) 
library(magrittr) 
library(tidyr) 

DT <- data.table(mydf) 

Najpierw można użyć by, aby obliczyć średnią z każdego limitu.

DT[, .(lwr = mean(value[limit == "lwr"]), 
     upr = mean(value[limit == "upr"])), 
    by = .(Weight, Height, Fitted, interval)] 

Jeśli limit == ... wygląda zbyt twarde kodowanie, można najpierw kruszywo w długim formacie, a następnie spread. Działa to, ponieważ po zagregowaniu nie ma duplikatu.

DT[, .(value = mean(value)), by = .(Weight, Height, Fitted, interval, limit)] %>% 
    spread(key = "limit", value = "value") 

Zarówno dostaje

# Weight Height Fitted interval  lwr  upr 
#1:  42 153.4 51.0792  conf 54.57731 53.00376 
#2:  42 153.4 51.0792  pred 61.41061 69.33717 
+0

Dzięki, Właściwie mówiłem o 'dplyr' i' tidyr'. Rozwiązałem już problem z 'reshape2', ale chcę wiedzieć, jak to zrobić z tym konkretnym pakietem. Dzięki i tak! – TheRimalaya