2016-10-05 7 views
3

各行に値のリストが含まれ、各グループ内で各行によって提供される新しいリスト値のカウントを生成したいグループ内で、各グループのリストの和集合に変換する。ここdplyr group_byとrowwiseを使用した累積集計グループ化

は一例であり:

require(dplyr) 
content <- list(c("A", "B"), c("A", "B", "C"), c("D", "E"), c("A", "B"), c("A", "B"), c("A", "B", "C")) 
id <- c("a", "a", "a", "b", "b", "b") 
order <- c(5, 7, 3, 1, 9, 4) 
testdf <- data.frame(id, order, cbind(content)) 
testdf 
# id order content 
# 1 a  5 A, B 
# 2 a  7 A, B, C 
# 3 a  3 D, E 
# 4 b  1 A, B 
# 5 b  9 A, B 
# 6 b  4 A, B, C 

(各グループ内の降順でソートした後)私の所望の出力は次のようであろう:CN(累積新しい)はCCに好ましいであろう

# id order content cc 
# 1 a  7 A, B, C 3 
# 2 a  5 A, B 3 
# 3 a  3 D, E 5 
# 4 b  9 A, B 2 
# 5 b  4 A, B, C 3 
# 6 b  1 A, B 3 

(累積カウント)実際には、上記の私の試行にマップし、cnは後で簡単に計算されます。ここでは動作しません、私試みたソリューションです:

res <- testdf %>% 
    arrange(id, desc(order)) %>% 
    mutate(n=row_number()) %>% 
    group_by(id) %>% 
    mutate(n1=first(n)) %>% 
    rowwise() %>% 
    bind_cols(do(.,data.frame(vars=length(unique(unlist(testdf$content[.$n1:.$n])))))) %>% 
    data.frame 

私は実際にここからその解決策のほとんどを得た:Cumulatively paste (concatenate) values grouped by another variable(感謝akrun)。生成された値は、正しいと思われるが、それらは、ソース・データ・フレームから正しい行に関連付けられていない。

res 
# id order content n n1 vars 
# 1 a  7 A, B, C 1 1 2 
# 2 a  5 A, B 2 1 3 
# 3 a  3 D, E 3 1 5 
# 4 b  9 A, B 4 4 2 
# 5 b  4 A, B, C 5 4 2 
# 6 b  1 A, B 6 4 3 

あなたが見ることができるように「基のために(上記CCに等価であるVARS列を見て) '値2と3は逆になり、グループ' b 'では2番目と3番目の値が逆になります。

実際、私はの上に間違っていますが、testdf $のコンテンツは(明らかに)dplyrのデータフレームと同じように注文されていません。もともと私はtestdf$contentの代わりに.$contentを持っていました。だから私は、二段階でそれをやってみました:

res <- testdf %>% 
    arrange(id, desc(order)) %>% 
    mutate(n=row_number()) %>% 
    group_by(id) %>% 
    mutate(n1=first(n)) 
res <- res %>% 
    rowwise() %>% 
    bind_cols(do(.,data.frame(vars=length(unique(unlist(res$content[.$n1:.$n])))))) %>% 
    data.frame 

、これは私が何を期待生成:

# id order content n n1 vars 
# 1 a  7 A, B, C 1 1 3 
# 2 a  5 A, B 2 1 3 
# 3 a  3 D, E 3 1 5 
# 4 b  9 A, B 4 4 2 
# 5 b  4 A, B, C 5 4 3 
# 6 b  1 A, B 6 4 3 

だから今、私の質問は、全体dplyr、修正されたデータフレームを参照するためのより良い方法があるありますdo()の中にあります(contentが正しく注文されるように) - 私は.が現在の行ではないと思いますか?これを行うことができると、do()の前に注文データフレームを別途作成する必要がなくなります。

感謝

ティム

+1

私はすべてのステップで混乱しますが、データを適切に並べ替えてグループ化したと仮定すると、 'cumsum(!duplicated(unlist(x))) [cumsum(lengths(x))] 'は累積的に数えます。ここで、' x 'は順序付けされた "content"です。グループ内の順序付けされた「コンテンツ」に対する「リスト」(c(「A」、「B」、「C」)、c(「A」、「B」)、c(「D」、「E」)グループ "b"の "a"と "list(c(" A "、" B ")、c(" A "、" B "、" C ")、c(" A "、" B ")) –

+0

あなたの返事をありがとう - 私は急いでいましたが、 'rowwise()'と 'bind_cols(do()) 'を置き換えるべきかどうかは分かりません。 NAを与えた 'res%>%cumsum(!duplicated(unlist(content)))[cumsum(lengths(content))]'を素直に試しましたか? – Tim

+1

あなたのコードに従って、私は 'testdf%>%arrange(id、desc(order))%>%group_by(id)%>%mutate(cumsum(!unlist(content)))[cumsum (コンテンツ))]) ')'心の中で –

答えて

1

あなたは累積的に異なる要素を作成するためにaccumulateモードでReduce機能を使用して、累積個別のカウントを返すためにlengths機能を使用することができますが、これはrowwise()操作を回避:

library(dplyr) 
testdf %>% 
      arrange(desc(order)) %>% 
      group_by(id) %>% 
      mutate(cc = lengths(Reduce(function(x, y) unique(c(x, y)), content, acc = T))) %>% 
      arrange(id) 

#Source: local data frame [6 x 4] 
#Groups: id [2] 

#  id order content cc 
# <fctr> <dbl> <list> <int> 
#1  a  7 <chr [3]>  3 
#2  a  5 <chr [2]>  3 
#3  a  3 <chr [2]>  5 
#4  b  9 <chr [2]>  2 
#5  b  4 <chr [3]>  3 
#6  b  1 <chr [2]>  3 
+0

ありがとう、それは素晴らしい解決策です!行方向が必要な場合とベクトル化されたソリューションを使用できる場合の経験則がありますか? – Tim

+0

私はそれがあるかどうかはわかりませんが、ベクトル化できるときはいつでも行方向操作を使用しないようにしてください。これは私の経験則になります。 – Psidom

+0

上記の最初のアレンジとgroup_byの順序が重要であるかどうか尋ねることはできますか? group_byがグループ内で手配した後に手配してもらえると思うかもしれませんが、期待通りに動くかどうかは分かりません。ありがとう。 – Tim

関連する問題