如何使用tidyr填充分组变量的每个值中的已完成行?

时间:2015-09-30 19:35:30

标签: r tidyr

说我有关于在多个选项之间进行选择的人的数据。我每人有一排,我希望每人有一排和选择。所以,如果我有10个人有3个选择,现在我有10行,我想要30个。

应将所有其他变量复制到每个新行。因此,例如,如果我有一个性别变量,那么它应该在ID内保持不变。 (我将这些数据设置为以mnlogit进行分析。)

这似乎是两个tidyr函数completefill的设计用于的情况。使用一个简单的例子:

library(lubridate)
library(tidyr)
dat <- data.frame(
    id = 1:3,
    choice = 5:7,
    c = c(9, NA, 11),
    d = ymd(NA, "2015-09-30", "2015-09-29")
    )

dat %>% 
  complete(id, choice) %>%
  fill(everything())

# Source: local data frame [9 x 4]
# 
#      id choice     c          d
#   (int)  (int) (dbl)     (time)
# 1     1      5     9       <NA>
# 2     1      6     9       <NA>
# 3     1      7     9       <NA>
# 4     2      5     9       <NA>
# 5     2      6     9 2015-09-30
# 6     2      7     9 2015-09-30
# 7     3      5     9 2015-09-30
# 8     3      6     9 2015-09-30
# 9     3      7    11 2015-09-29

但这有一些问题 - d的值正确地结转,但ID 1的c值取代了ID 2的(正确的)NA值。

我可以尝试一种解决方法,例如用999替换所有缺失值,运行completefill,然后用NA替换999。 (我想我必须将日期变量转换为字符变量,然后如果我走这条路线就再将它们转换回来。)但也许这里有人知道用tidyr做一些整洁的方法吗?

编辑:这里所需的输出是:

# Source: local data frame [9 x 4]
# 
#     id     c          d choice
#  (int) (dbl)     (time)  (int)
# 1     1     9       <NA>      5
# 2     1     9       <NA>      6
# 3     1     9       <NA>      7
# 4     2    NA 2015-09-30      5
# 5     2    NA 2015-09-30      6
# 6     2    NA 2015-09-30      7
# 7     3    11 2015-09-29      5
# 8     3    11 2015-09-29      6
# 9     3    11 2015-09-29      7

4 个答案:

答案 0 :(得分:13)

作为@jeremycg答案的更新。从tidyr 0.5.1(或者甚至可能是版本0.4.0)开始c()不再有效。请改用nesting()

dat %>% 
 complete(nesting(id, c, d), choice) 

注意我正在尝试编辑@jeremycg答案,因为答案在编写时是正确的(因此不需要新的答案)但不幸的是编辑被拒绝了。 / p>

答案 1 :(得分:9)

您可以使用c()完成“分组”操作的技巧。这使得它只能使用预先存在的分组变量组合来完成。

library(tidyr)
dat %>% complete(c(id, c, d), choice) 
     id     c          d choice
  (int) (dbl)     (time)  (int)
1     1     9       <NA>      5
2     1     9       <NA>      6
3     1     9       <NA>      7
4     2    NA 2015-09-30      5
5     2    NA 2015-09-30      6
6     2    NA 2015-09-30      7
7     3    11 2015-09-29      5
8     3    11 2015-09-29      6
9     3    11 2015-09-29      7

答案 2 :(得分:2)

我认为您最好在准备数据时保持数据分离,然后在需要进行回归之前进行合并。

id="sub" name="sub"

然后

subjectdata <- dat[,c("id", "c", "d")]
questiondata <- dat[,c("id", "choice")] %>% complete(id, choice)
必要时。这样,您还可以获得用户2的有效> merge(questiondata, subjectdata) id choice c d 1 1 5 9 <NA> 2 1 6 9 <NA> 3 1 7 9 <NA> 4 2 5 NA 2015-09-30 5 2 6 NA 2015-09-30 6 2 7 NA 2015-09-30 7 3 5 11 2015-09-29 8 3 6 11 2015-09-29 9 3 7 11 2015-09-29 列,而无需依赖数据框中的问题顺序。

答案 3 :(得分:-1)

看起来另一种方法是使用spreadgatherspread为每个可能的答案创建一列,gather获取单独的列并将其重新整形为行。有了这些数据:

dat %>%
  spread(choice, choice) %>%
  gather(choice, drop_me, `5`:`7`) %>%  # Drop me is a redundant column
  select(-drop_me) %>%
  arrange(id, choice)  # reorders so that the answer matches

#   id  c          d choice
# 1  1  9       <NA>      5
# 2  1  9       <NA>      6
# 3  1  9       <NA>      7
# 4  2 NA 2015-09-30      5
# 5  2 NA 2015-09-30      6
# 6  2 NA 2015-09-30      7
# 7  3 11 2015-09-29      5
# 8  3 11 2015-09-29      6
# 9  3 11 2015-09-29      7

我还没有做过任何测试,看看这些效率如何比较。