【问题标题】:How to create group indices for nested groups in r如何在 r 中为嵌套组创建组索引
【发布时间】:2019-04-21 03:45:02
【问题描述】:

我有一个数据集,其中包含多个嵌套在个体中的观察结果。此示例数据集包括 id 列和星期几(dayweek,1-7)。我从每个人那里得到了 3 天的观察结果。因此,一个人可能只提交了周日/周三/周四(1、4、5)的报告,而另一个人可能已经提交了周日/周一/周二(1、2、3)的报告,如下例所示:

df <- data.frame(
  id = c(rep(1:2, each = 6),2),
  dayweek = c(rep(c(1, 4, 5), each = 2),rep(c(1, 2, 3), each = 2), 3)
)

我想设置一个列来标记每个人的第一天、第二天和第三天,如下所示:

df2 <- data.frame(
  id = c(rep(1:2, each = 6),2),
  dayweek = c(rep(c(1, 4, 5), each = 2),rep(c(1, 2, 3), each = 2), 3),
  daynum = c(rep(1:3, each = 2, times = 2), 3)
)

我尝试过使用

df %>% group_indices(id, dayweek) 

但这会为每个单独的日期组合生成一个新的 ID。有什么好的方法可以做到这一点?

提前致谢!

【问题讨论】:

  • 如果这几天是周五、周六、周日怎么办:那么你会有 6、7、1,但 6 是第一天,1 是第三天,对吧?这些行是否已经按日期顺序排列,因此 id 的第一行会得到 daynum = 1?
  • 嗨,正确:在这种情况下,我想重新编码 6 到 1、7 到 2 和 1 到 3。是的,行是按顺序排列的,但是每个行的观察次数不同个人和每一天。所以他们可能有 4 个 Sat 的观测值,2 个 Sun 的观测值,等等。

标签: r


【解决方案1】:

dplyr

cumsum!duplicateddplyr 一起使用

df %>%
  group_by(id) %>%
  mutate(daynum = cumsum(!duplicated(dayweek)))


# A tibble: 13 x 3
# Groups:   id [2]
      id dayweek daynum
   <dbl>   <dbl>  <int>
 1     1       1      1
 2     1       1      1
 3     1       4      2
 4     1       4      2
 5     1       5      3
 6     1       5      3
 7     2       1      1
 8     2       1      1
 9     2       2      2
10     2       2      2
11     2       3      3
12     2       3      3
13     2       3      3

tapply 来自基地R

unlist(tapply(df$dayweek, df$id, function(x) cumsum(!duplicated(x))))

 1  1  2  2  3  3  1  1  2  2  3  3  3 

【讨论】:

  • 这也很好地处理了“周五、周六、周日”的情况 (dayweek 6, 7, 1)。
【解决方案2】:

我们可以group_byid 并为每个dayweek 创建一个唯一的id

library(dplyr)

df %>%
  group_by(id) %>%
  mutate(daynum = as.integer(factor(dayweek, levels = unique(dayweek))))

#      id dayweek daynum
#   <dbl>   <dbl>  <int>
# 1     1       1      1
# 2     1       1      1
# 3     1       4      2
# 4     1       4      2
# 5     1       5      3
# 6     1       5      3
# 7     2       1      1
# 8     2       1      1
# 9     2       2      2
#10     2       2      2
#11     2       3      3
#12     2       3      3
#13     2       3      3

在基础 R 中,我们可以使用 ave 来表示相同

with(df, ave(dayweek, id, FUN = function(x) 
         as.integer(factor(x, levels = unique(x)))))
#[1] 1 1 2 2 3 3 1 1 2 2 3 3 3

【讨论】:

  • 对于“星期五、星期六、星期日”的情况 (dayweek 6, 7, 1),这将返回 2, 3, 1 而 OP 根据 cmets 期望 1, 2, 3 .
  • @Uwe 谢谢,更新了处理该案例的答案。
  • unique的用法很有意思。不知何故,!duplicated 很容易被理解为 unique,但应用它变得很棘手。
  • @NelsonGon 是的,这里 OP 希望根据观察到 dayweek 的时间遵循正确的顺序,因此使用 unique
【解决方案3】:

根据OP's comment,行是按顺序排列的。

然后,这里有两种不同的方法,它们也将处理 cmets 中提到的“周五、周六、周日”案例 (dayweek6,7,1)。

  1. rleid()
  2. fct_inorder()

rleid()

这使用了data.table 包中的rleid() 函数:

library(dplyr)
df2 %>% 
  group_by(id) %>% 
  mutate(daynum2 = data.table::rleid(dayweek)) 
      id dayweek daynum daynum2
   <dbl>   <dbl>  <dbl>   <int>
 1     1       1      1       1
 2     1       1      1       1
 3     1       4      2       2
 4     1       4      2       2
 5     1       5      3       3
 6     1       5      3       3
 7     2       1      1       1
 8     2       1      1       1
 9     2       2      2       2
10     2       2      2       2
11     2       3      3       3
12     2       3      3       3
13     2       3      3       3
14     3       6      1       1
15     3       7      2       2
16     3       1      3       3

请注意,使用的扩展数据集也涵盖了“周五、周六、周日”的情况 (dayweek 6, 7, 1)。

fct_inorder()

这是Ronak's answer 的增强版本,它还处理“周五、周六、周日”的情况。它使用forcats 包中的fct_inorder(),它按首次出现对因子水平进行重新排序。

df2 %>% 
  group_by(id) %>% 
  mutate(daynum2 = 
           dayweek %>% 
           as.character() %>% 
           forcats::fct_inorder() %>% 
           as.integer()
         ) 

输出同上。

数据

这是一个扩展数据集,其中还包括“周五、周六、周日”案例 (dayweek 6, 7, 1):

df2 <- data.frame(
  id = c(rep(1:2, each = 6), 2, rep(3, 3)),
  dayweek = c(rep(c(1, 4, 5), each = 2),rep(c(1, 2, 3), each = 2), 3, 6, 7, 1),
  daynum = c(rep(1:3, each = 2, times = 2), 3, 1:3)
)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-06
    • 2020-11-23
    • 1970-01-01
    相关资源
    最近更新 更多