使用包含行的重复标识符的spread

Pol*_*ear 30 r dplyr tidyr

我有一个长格式数据框,有相同日期和人的多个条目.

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))
Run Code Online (Sandbox Code Playgroud)

我想将它转换为宽泛的形式,并使它像这样:

month Amy.A Bob.A Amy.B Bob.B
1     
2     
3
1
2
3
1
2
3
1
2
3
Run Code Online (Sandbox Code Playgroud)

我的问题与非常相似.我在答案中使用了给定的代码:

kk <- jj %>% 
  gather(variable, value, -(month:student)) %>% 
  unite(temp, student, variable) %>% 
  spread(temp, value)
Run Code Online (Sandbox Code Playgroud)

但它给出了以下错误:

错误:行(1,4),(2,5),(3,6),(13,16),(14,17),(15,18),(7,10),(8)的重复标识符,11),(9,12),(19,22),(20,23),(21,24)

提前致谢.注意:我不想删除多个条目.

小智 29

你的回答是缺少mutate id!这是仅使用dplyr packge的解决方案.

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
Run Code Online (Sandbox Code Playgroud)

  • 这是一个很好的技巧.简要说明:如果在收集之前每行没有唯一的id,则无法确定传播时哪些值属于哪些观察值.添加充当主键的任何列可以缓解此问题. (3认同)
  • 如果不想使用* id *列,只需在末尾添加%&gt;%select(-id)。 (2认同)

Pie*_*une 21

问题是两个A和两个列B.如果我们可以创建一个值列,我们可以按您的意愿传播数据.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
Run Code Online (Sandbox Code Playgroud)

我不会将此标记为副本,因为另一个问题没有总结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
Run Code Online (Sandbox Code Playgroud)

如果您想使用该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
Run Code Online (Sandbox Code Playgroud)

编辑

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

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
Run Code Online (Sandbox Code Playgroud)

也可以使用其他解决方案.这里我添加了一个可选表达式来按活动编号排列最终输出:

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)