2016-08-20 47 views
19

我有一个长的表单数据框,有相同的日期和人的多个条目。使用与重复标识符的行传播

jj <- data.frame(month=rep(1:3,4), 
      student=rep(c("Amy", "Bob"), each=6), 
      A=c(9, 7, 6, 8, 6, 9, 3, 2, 1, 5, 6, 5), 
      B=c(6, 7, 8, 5, 6, 7, 5, 4, 6, 3, 1, 5)) 

我想将其转换为宽的形式,使之像这样:

month Amy.A Bob.A Amy.B Bob.B 
1  
2  
3 
1 
2 
3 
1 
2 
3 
1 
2 
3 

我的问题是非常相似的this。提前

Error: Duplicate identifiers for rows (1, 4), (2, 5), (3, 6), (13, 16), (14, 17), (15, 18), (7, 10), (8, 11), (9, 12), (19, 22), (20, 23), (21, 24)

感谢:我已经使用给定的代码的答案:

kk <- jj %>% 
    gather(variable, value, -(month:student)) %>% 
    unite(temp, student, variable) %>% 
    spread(temp, value) 

但它提供了以下错误。 注意:我不想删除多个条目。

+0

输出没有意义。 Bob.B'5 6 7'怎么样。第1个月有两个Bob B值,'5 3'?而第二个月它是'4和2'。最后,对于3个月的'6 5'。您将这些总结为一个值。 –

回答

14

问题是AB的两列。如果我们可以创建一个价值列,我们可以随意传播数据。使用下面的代码时,请查看jj_melt的输出。

library(reshape2) 
jj_melt <- melt(jj, id=c("month", "student")) 
jj_spread <- dcast(jj_melt, month ~ student + variable, value.var="value", fun=sum) 
# month Amy_A Amy_B Bob_A Bob_B 
# 1  1 17 11  8  8 
# 2  2 13 13  8  5 
# 3  3 15 15  6 11 

我不会将此标记为重复,因为其他的问题没有被sum总结,但data.table答案可能有一个附加参数帮助,fun=sum

library(data.table) 
dcast(setDT(jj), month ~ student, value.var=c("A", "B"), fun=sum) 
# month A_sum_Amy A_sum_Bob B_sum_Amy B_sum_Bob 
# 1:  1  17   8  11   8 
# 2:  2  13   8  13   5 
# 3:  3  15   6  15  11 

如果你想要使用tidyr解决方案,请将其与dcast结合,以sum进行汇总。

as.data.frame(jj) 
library(tidyr) 
jj %>% 
    gather(variable, value, -(month:student)) %>% 
    unite(temp, student, variable) %>% 
    dcast(month ~ temp, fun=sum) 
# month Amy_A Amy_B Bob_A Bob_B 
# 1  1 17 11  8  8 
# 2  2 13 13  8  5 
# 3  3 15 15  6 11 

编辑

根据您的新的要求,我已经添加了一个活动列。

library(dplyr) 
jj %>% group_by(month, student) %>% 
    mutate(id=1:n()) %>% 
    melt(id=c("month", "id", "student")) %>% 
    dcast(... ~ student + variable, value.var="value") 
# month id Amy_A Amy_B Bob_A Bob_B 
# 1  1 1  9  6  3  5 
# 2  1 2  8  5  5  3 
# 3  2 1  7  7  2  4 
# 4  2 2  6  6  6  1 
# 5  3 1  6  8  1  6 
# 6  3 2  9  7  5  5 

其他解决方案也可以使用。在这里,我增加了一个可选的表达,以安排通过活动数量最终输出:

library(tidyr) 
jj %>% 
    gather(variable, value, -(month:student)) %>% 
    unite(temp, student, variable) %>% 
    group_by(temp) %>% 
    mutate(id=1:n()) %>% 
    dcast(... ~ temp) %>% 
    arrange(id) 
# month id Amy_A Amy_B Bob_A Bob_B 
# 1  1 1  9  6  3  5 
# 2  2 2  7  7  2  4 
# 3  3 3  6  8  1  6 
# 4  1 4  8  5  5  3 
# 5  2 5  6  6  6  1 
# 6  3 6  9  7  5  5 

data.table语法是紧凑的,因为它允许多个value.var列,会照顾蔓延的我们。我们可以跳过melt -> cast过程。

library(data.table) 
setDT(jj)[, activityID := rowid(student)] 
dcast(jj, ... ~ student, value.var=c("A", "B")) 
# month activityID A_Amy A_Bob B_Amy B_Bob 
# 1:  1   1  9  3  6  5 
# 2:  1   4  8  5  5  3 
# 3:  2   2  7  2  7  4 
# 4:  2   5  6  6  6  1 
# 5:  3   3  6  1  8  6 
# 6:  3   6  9  5  7  5 
+0

感谢您的回答。我不想总结。不需要算术操作。我想为Amy创建A和B列,为Bob创建A和B列,它们只有它们各自的值。 –

+1

如果同一月份,学生和班级有两个值,您希望选择哪一个? –

+0

我想都。其实我正在处理出价和问题数据,因此有多个条目。 –

10

您的回答缺少mutate id!这是仅使用dplyr打包的解决方案。

jj %>% 
    gather(variable, value, -(month:student)) %>% 
    unite(temp, student, variable) %>% 
    group_by(temp) %>% 
    mutate(id=1:n()) %>% 
    spread(temp, value) 
# A tibble: 6 x 6 
# month id Amy_A Amy_B Bob_A Bob_B 
# * <int> <int> <dbl> <dbl> <dbl> <dbl> 
# 1  1  1  9  6  3  5 
# 2  1  4  8  5  5  3 
# 3  2  2  7  7  2  4 
# 4  2  5  6  6  6  1 
# 5  3  3  6  8  1  6 
# 6  3  6  9  7  5  5 
+0

如果您不想要* id *列,只需在末尾添加'%>%select(-id)'。 – bonna

0
gather(data, key = "key", value = "value", ..., na.rm = FALSE, 
    convert = FALSE, factor_key = FALSE) 

检查,如果你倒键和值。 “密钥”是新密钥的名称,“值”是实际值。