跟踪 R 中序列的变化

Tracking the change in a sequence in R

我问了类似的问题但是函数出了点问题,我会尽量问清楚。

我有一个示例数据集如下所示:

 id <-       c(1,1,1, 2,2,2, 3,3, 4,4, 5,5,5,5, 6,6,6, 7, 8,8)
    item.id <-  c(1,1,2, 1,1,1 ,1,1, 1,2, 1,2,2,2, 1,1,1, 1, 1,2)
    sequence <- c(1,2,1, 1,2,3, 1,2, 1,1, 1,1,2,3, 1,2,3, 1, 1,1)
    score <-    c(0,0,0, 0,0,1, 2,0, 1,1, 1,0,1,1, 0,0,0, 1, 0,2)

    data <- data.frame("id"=id, "item.id"=item.id, "sequence"=sequence, "score"=score)
> data
    id item.id sequence score
1   1       1        1     0
2   1       1        2     0
3   1       2        1     0
4   2       1        1     0
5   2       1        2     0
6   2       1        3     1
7   3       1        1     2
8   3       1        2     0
9   4       1        1     1
10  4       2        1     1
11  5       1        1     1
12  5       2        1     0
13  5       2        2     1
14  5       2        3     1
15  6       1        1     0
16  6       1        2     0
17  6       1        3     0
18  7       1        1     1
19  8       1        1     0
20  8       2        1     2

id代表每个学生,item.id代表学生做的题目,sequence是每个item.id的尝试次数,score是每次尝试的分数,取 0,1 或 2。学生可以更改他们的答案。

对于每个 id 中的 item.id,我想通过查看最后两个序列(更改)来创建一个变量 (status):

a) assign "WW" for those who changed from wrong to wrong,
b) assign "WR" for those who changed from wrong to right,
c) assign "RW" for those who changed from right to wrong, and
d) assign "RR" for those who changed from right to right.

分数从 0 到 1 或 0 到 2 的变化被认为是正确的(正确的)变化,同时, 分数从 1 到 0 或 2 到 0 的变化被认为是不正确的(错误的)变化。

如果 item.id 只有一次尝试 id=7,那么 status 应该是 "one.right"。如果 score0,那么它应该是 "one.wrong"。同时,score12时被认为是right0score被认为是错误的。

]

所需的输出将包含案例:

 > desired
  id item.id    status
  1   1       1        WW
  2   1       2 one.wrong
  3   2       1        WR
  4   3       1        RW
  5   4       1 one.right
  6   4       2 one.right
  7   5       1 one.right
  8   5       2        RR
  9   6       1        WW
  10  7       1 one.right
  11  8       1 one.wrong
  12  8       2 one.right

有什么意见吗? 谢谢!

library(dplyr)
library(purrr)
library(forcats)

data %>% 
  mutate(status = ifelse(score > 0, "R", "W")) %>% 
  group_by(id, item.id) %>% 
  filter(sequence == n() - 1 | sequence == n()) %>%  
  summarise(status = paste(status, collapse = "")) %>% 
  ungroup() %>% 
  mutate(status = fct_recode(status, "one.wrong" = "W", "one.right" = "R"))

我相信它几乎是自我描述的,但我会分解它:

1) 在第一个 mutate 中,我们从 score 创建一个 W/R 列:0 给出 'W',上面的所有内容都给出 'R'.

2) 然后我们按最后两行 iditem.id 和 select 对数据进行分组,或者如果组中只有一行则保留该行 (filter).

3) 之后我们将这个 status 列压缩为每组中的一个字符串 (summarize)。所以可能的值是:'W'、'R'、'WW'、'WR'、'RW'、'RR'.

4) 剩下要做的最后一件事是使用 forcats::fct_recode 将 'W' 重新编码为 'one.wrong',将 'R' 重新编码为 'one.right'。 =19=]

与@laroslav Domin 的回答相似但不那么优雅:

library(tidyverse) 
data %>%
  group_by(id, item.id) %>%
  top_n(2, sequence) %>%
  mutate(sequence = row_number()) %>%
  pivot_wider(names_from = sequence, 
              names_prefix = "c", 
              values_from = score) %>%
  mutate(result = case_when(
    c1 == 0 & c2 == 0 ~ "WW",
    c1 == 0 & c2 >  0 ~ "WR",
    c1 >  1 & c2 == 0 ~ "RW",
    c1 >  1 & c2 >  0 ~ "RR",
    c1 == 0 ~ "one.wrong",
    c1 >  0 ~ "one.right",
    TRUE ~ "OTHER")
  )

这是一个 解决方案,其灵感来自@laroslavDomin:

library(data.table)
setDT(data)

data[, {
  if (.N == 1) {
    if (score == 0) {
      'one.wrong'
    } else {
      'one.right'
    }
  } else {
    paste0(ifelse(score > 0, 'R', 'W')[c(1, .N)], collapse = '')
  }
},
by = .(id, item.id)]