2014-07-16 27 views
0

我想根據行計算函數,而不是與mutate()一樣計算列。例如,具有dplyr:行的功能

library(dplyr) 

set.seed(1) 
dfx <- data.frame(
    date = rep(seq(1,5),3), 
    type = c(rep('A', 5), rep('B1', 5), rep('B2', 5)), 
    value = runif(n = 15, min = 0, max = 20) 
    ) 

這導致數據幀

# date type  value 
# 1  1 A 5.310173 
# 2  2 A 7.442478 
# 3  3 A 11.457067 
# 4  4 A 18.164156 
# 5  5 A 4.033639 
# 6  1 B1 17.967794 
# 7  2 B1 18.893505 
# 8  3 B1 13.215956 
# 9  4 B1 12.582281 
# 10 5 B1 1.235725 
# 11 1 B2 4.119491 
# 12 2 B2 3.531135 
# 13 3 B2 13.740457 
# 14 4 B2 7.682074 
# 15 5 B2 15.396828 

欲計算每個date差異A-B1和相應value S的A-B2。雖然

library(reshape2) 
dfx %>% 
    dcast(date~type) %>% 
    group_by(date) %>% 
    summarise(a1=A-B1, a2=A-B2) 

作品,重塑似乎有點難看。據我瞭解整理數據的概念,數據結構不應該適應工具一旦整齊的形式,但工具應該只適用於整潔的數據格式。但也許這只是我以及整形是好的...

+0

整形步驟對我來說似乎是完全合乎邏輯的...... – A5C1D2H2I1M1N2O1R2T1

+1

引用Wickham之書的章節和詩句:「一般的經驗法則是描述變量之間的函數關係比描述行,而且更容易在各組之間進行比較[...],而不是在各組之間進行比較。「 vita.had.co.nz/papers/tidy-data.pdf – AndrewMacDonald

回答

4

如果問題是如何使用tidyr包這裏,那麼我們就可以用spread這樣的替換dcast

library(dplyr) 
library(tidyr) 

dfx %>% 
    spread(type, value) %>% 
    group_by(date) %>% 
    summarise(a1 = A-B1, a2 = A-B2) 

,並提供:

Source: local data frame [5 x 3] 

    date   a1   a2 
1 1 -12.657620 1.190682 
2 2 -11.451027 3.911343 
3 3 -1.758889 -2.283390 
4 4 5.581875 10.482081 
5 5 2.797913 -11.363190 

注意

1)這是真的,至少在這種情況下,一旦我們有別其餘的計算不會進一步涉及tidyr。

2)如果你想避免長到寬的轉變完全是可以這樣做:

dfx %>% 
    group_by(date) %>% 
    summarize(a1 = value[type=="A"]-value[type=="B1"], 
       a2 = value[type=="A"]-value[type=="B2"]) 

或假設的問題顯示的排序順序:

dfx %>% 
    group_by(date) %>% 
    summarize(a1 = value[1]-value[2], a2 = value[1]-value[3]) 

這兩個答案都與第一個解決方案中給出的答案相同。

添加了兩個注意事項。

+0

感謝您的輸入。其他人似乎同意重塑是好的,所以我會堅持。 – sebschub

1

非整形解決方案是可行的,但如果輸出的任何組的長度超過了就必須要經過do(.)dplyr(特別是如果你多組從組A減去),爲summarise錯誤1.

dfx %>% group_by(date) %>% do(data.frame(ans=tail(.$value[1]-.$value, -1L))) 
# Source: local data frame [10 x 2] 
# Groups: date 

# date  ans 
# 1  1 -12.657620 
# 2  1 1.190682 
# 3  2 -11.451027 
# 4  2 3.911343 
# 5  3 -1.758889 
# 6  3 -2.283390 
# 7  4 5.581875 
# 8  4 10.482081 
# 9  5 2.797913 
# 10 5 -11.363190 

但大概相比整形答案(由於data.frame(.)對每個組),這是低效的。

PS:請注意,在您的dcast答案或其他答案中,鑄造後不需要group_by(date)


要回答@的Gabor的評論:

我會做這樣的事情:

dfx %>% spread(type, value) %>% 
     do(data.frame(date=.$date, a1=.$A-.$B1, a2=.$A-.$B2)) 

分組是不必要的,利用它的緊湊這裏是不是一個很好的妥協(想象一下100000團體或更多)。

使用mutate,我們希望用各自的差異替換所有B*列,這些差異僅導致必須刪除A列。我認爲這是可行的,使用dplyr,但我不夠精通到達那裏。

+0

關於PS,如果沒有使用'group_by(date)',那麼需要'mutate'而不是'summarise',因此需要刪除'group_by'消除的不需要的變量,所以刪除'group_by'不會導致更緊湊的解決方案。 –