跟踪 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"
。如果 score
是 0
,那么它应该是 "one.wrong"
。同时,score
在1
或2
时被认为是right
,0
时score
被认为是错误的。
]
所需的输出将包含案例:
> 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) 然后我们按最后两行 id
、item.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")
)
这是一个 data.table 解决方案,其灵感来自@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)]
我问了类似的问题
我有一个示例数据集如下所示:
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"
。如果 score
是 0
,那么它应该是 "one.wrong"
。同时,score
在1
或2
时被认为是right
,0
时score
被认为是错误的。
所需的输出将包含案例:
> 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) 然后我们按最后两行 id
、item.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")
)
这是一个 data.table 解决方案,其灵感来自@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)]