【发布时间】:2017-02-14 10:21:48
【问题描述】:
我已经在每行包含一个值列表的组内按顺序对数据进行分组,并且在每个组内,我想生成每行贡献给每个组中列表联合的新列表值的计数。
这是一个例子:
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
我想要的输出(按每个组内的降序排序后)如下:
# 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 (累积新)确实比 cc (累积计数)更可取,但上面映射到我下面的尝试,随后很容易计算出 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 列),“a”组的值 2 和 3 颠倒了,而“b”组的第二个值 2 和 3 颠倒了。
实际上我找出了上面的问题,testdf$content(显然)与 dplyr'd 数据框的排序不同。最初我有.$content 而不是testdf$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
所以我现在的问题是有没有更好的方法来引用 do() 内的整个 dplyr 修改的数据框(以便正确排序 content) - 我认为 . 只是当前行不是吗?能够这样做将避免我必须在 do() 之前单独创建有序数据框。
非常感谢
提姆
【问题讨论】:
-
我对所有步骤都感到有些困惑,但假设您已经对数据进行了适当的排序和分组,您可以使用
cumsum(!duplicated(unlist(x)))[cumsum(lengths(x))]进行累积计数,其中x是有序的“内容” ——例如list(c("A", "B", "C"), c("A", "B"), c("D", "E"))用于“a”组中的有序“内容”,list(c("A", "B"), c("A", "B", "C"), c("A", "B"))用于“b”组中。 -
感谢您的回复 - 我很快就开始了,但我不确定在哪里尝试,是否应该替换整个
rowwise()和bind_cols(do())?我天真地尝试了res %>% cumsum(!duplicated(unlist(content)))[cumsum(lengths(content))],它给了NA? -
按照您的代码,我想到了
testdf %>% arrange(id, desc(order)) %>% group_by(id) %>% mutate(cumsum(!duplicated(unlist(content)))[cumsum(lengths(content))])之类的东西 -
好的,谢谢 - 虽然我不太确定使用 cumsum(lengths(content)) 从列表中进行选择是如何工作的。我认为@Psidom 的解决方案可能更容易理解,所以我会接受它作为解决方案。再次感谢您的贡献。
-
顺便说一句 - 我喜欢你为此目的使用带有“累积”命名的方法,尽管双重使用有点令人困惑。