2016-06-29 13 views
1

"長い"データフレームでユーザーIDでグループ化された複数の変数間の差分を計算する方法はありますか?ユーザーIDでグループ化された複数の変数間のデルタの計算

データ形式:

d1 <- data.frame(
    id = rep(c(1, 2, 3, 4, 5), each = 2), 
    purchased = c(rep(c(T, F), 3), F, T, T, F), 
    product = rep(c("A", "B"), 5), 
    grade = c(1, 2, 1, 2, 2, 3, 7, 5, 1, 2), 
    rate = c(10, 12, 10, 12, 12, 14, 22, 18, 10, 12), 
    fee = rep(c(1, 2), 5)) 

これは私のラウンドアバウトソリューションです:

dA <- d1 %>% 
    filter(product == "A") 

dB <- d1 %>% 
    filter(product == "B") 

d2 <- inner_join(dA, dB, by = "id", suffix = c(".A", ".B")) 

d3 <- d2 %>% 
    mutate(
     purchased = if_else(purchased.A == T, "A", "B"), 
     dGrade = grade.B - grade.A, 
     dRate = rate.B - rate.A, 
     dFee = fee.B - fee.A) %>% 
    select(id, purchased:dFee) 

このすべてがちょうどひどく非効率的で複雑なようです。ここでtidyr::spreadまたは別のdplyr/tidyr関数が適切ですか? (私は仕事に何かを得ることができませんでした)...

答えて

1

gather/spreadでこれを行うことができます。 gatherを 'id'、 'Var'でグループ化して 'wide'から 'long'にデータを変更します。 'product'の論理列に基づいて 'product'を取得し、 'product'の 'Val'それらは 'B'と 'A'であり、spreadは 'long'から 'wide'形式です。

library(dplyr) 
library(tidyr) 
gather(d1, Var, Val, grade:fee) %>% 
      group_by(id, Var) %>% 
      summarise(purchased = product[purchased], 
        Val = Val[product == 'B'] - Val[product == 'A'])%>% 
      spread(Var, Val) 
#  id purchased fee grade rate 
# <dbl> <fctr> <dbl> <dbl> <dbl> 
#1  1   A  1  1  2 
#2  2   A  1  1  2 
#3  3   A  1  1  2 
#4  4   B  1 -2 -4 
#5  5   A  1  1  2 

OPの出力( 'D3')は

d3 
# id purchased dGrade dRate dFee 
#1 1   A  1  2 1 
#2 2   A  1  2 1 
#3 3   A  1  2 1 
#4 4   B  -2 -4 1 
#5 5   A  1  2 1 
あります
関連する問題