#r #data.table
#r #данные.таблица
Вопрос:
WANT=data.frame(STUDENT=c(1,1,1,2,2,2,3,3,3,4,4,4),
X1=c(0,0,0,1,1,1,1,1,1,0,0,0),
X2=c(1,1,1,0,0,0,1,1,1,1,1,1),
CAT=c(9,6,8,8,9,8,5,9,8,8,7,7),
TIME=c(1,2,3,1,2,3,1,2,3,1,2,3),
EVENT=c(0,0,0,0,1,1,1,1,1,0,0,1))
HAVE=data.frame(STUDENT=c(1,2,3,4),
X1=c(0,1,1,0),
X2=c(1,0,1,1),
CAT1=c(9,8,5,8),
CAT2=c(6,9,9,7),
CAT3=c(8,8,8,7),
TIME=c(NA,2,1,3),
EVENT=c(0,1,1,1))
У меня есть данные «ЕСТЬ» и я желаю получить данные «ХОЧУ»
В данных «ЕСТЬ» у каждого УЧАЩЕГОСЯ есть одна строка. X1 и X2 фиксированы, CAT # — изменяемая во времени переменная, TIME указывает, когда произошло событие — если оно не произошло, то ВРЕМЯ равно NA, а EVENT указывает, произошло ли СОБЫТИЕ.
Я хочу преобразовать «ИМЕТЬ» в «ХОЧУ», где каждый УЧЕНИК получает необходимое количество строк, ВРЕМЯ идет от 1 до 3; и СОБЫТИЕ заполняется, как показано.
Я пытался сделать это с помощью dcast и reshape2, но безуспешно. Пожалуйста, посоветуйте!
Ответ №1:
Вот базовый параметр R, использующий rep
inds <- grep("CAT", names(HAVE))
WANT <- `row.names<-`(transform(
HAVE[rep(1:nrow(HAVE), each = length(inds)), ],
CAT = c(t(HAVE[inds]))
)[-inds], NULL)
что дает
> WANT
STUDENT X1 X2 TIME EVENT CAT
1 1 0 1 NA 0 9
2 1 0 1 NA 0 6
3 1 0 1 NA 0 8
4 2 1 0 2 1 8
5 2 1 0 2 1 9
6 2 1 0 2 1 8
7 3 1 1 1 1 5
8 3 1 1 1 1 9
9 3 1 1 1 1 8
10 4 0 1 3 1 8
11 4 0 1 3 1 7
12 4 0 1 3 1 7
Ответ №2:
Мы можем использовать melt
из data.table
. Преобразуйте набор данных в длинный формат с melt
, сгруппированный по ‘STUDENT’, мы можем заменить значения столбца ‘EVENT’ на 0, если значение ‘TIME’ больше или равно последовательности строк
library(data.table)
melt(setDT(HAVE), measure = paste0('CAT',1:3), value.name = 'CAT')[,
variable := NULL][, c('EVENT', 'TIME') :=
.(seq_len(.N) >= TIME, seq_len(.N)), STUDENT][is.na(EVENT),
EVENT := 0][order(STUDENT)]
# STUDENT X1 X2 TIME EVENT CAT
# 1: 1 0 1 1 0 9
# 2: 1 0 1 2 0 6
# 3: 1 0 1 3 0 8
# 4: 2 1 0 1 0 8
# 5: 2 1 0 2 1 9
# 6: 2 1 0 3 1 8
# 7: 3 1 1 1 1 5
# 8: 3 1 1 2 1 9
# 9: 3 1 1 3 1 8
#10: 4 0 1 1 0 8
#11: 4 0 1 2 0 7
#12: 4 0 1 3 1 7
Или с помощью tidyverse
library(dplyr)
library(tidyr)
HAVE %>%
pivot_longer(cols = CAT1:CAT3, values_to = 'CAT') %>%
select(-name) %>%
group_by(STUDENT) %>%
mutate(EVENT = (replace_na(row_number() >= TIME, 0)), TIME = row_number())
# A tibble: 12 x 6
# Groups: STUDENT [4]
# STUDENT X1 X2 TIME EVENT CAT
# <dbl> <dbl> <dbl> <int> <dbl> <dbl>
# 1 1 0 1 1 0 9
# 2 1 0 1 2 0 6
# 3 1 0 1 3 0 8
# 4 2 1 0 1 0 8
# 5 2 1 0 2 1 9
# 6 2 1 0 3 1 8
# 7 3 1 1 1 1 5
# 8 3 1 1 2 1 9
# 9 3 1 1 3 1 8
#10 4 0 1 1 0 8
#11 4 0 1 2 0 7
#12 4 0 1 3 1 7
Ответ №3:
Это довольно сложно. Мне пришлось включить некоторую базу R в это решение tidyverse:
library(dplyr)
library(tidyr)
HAVE %>%
pivot_longer(cols = tidyselect::starts_with("CAT")) %>%
mutate(EVENT = do.call(c, lapply(split(TIME, STUDENT),
function(x) if(any(is.na(x))) rep(0, length(x))
else cumsum(`[<-`(rep(0, 3), median(x), 1)))),
TIME = rep(seq(length(unique(name))), length.out = length(TIME))) %>%
select(-name)
#> # A tibble: 12 x 6
#> STUDENT X1 X2 TIME EVENT value
#> <dbl> <dbl> <dbl> <int> <dbl> <dbl>
#> 1 1 0 1 1 0 9
#> 2 1 0 1 2 0 6
#> 3 1 0 1 3 0 8
#> 4 2 1 0 1 0 8
#> 5 2 1 0 2 1 9
#> 6 2 1 0 3 1 8
#> 7 3 1 1 1 1 5
#> 8 3 1 1 2 1 9
#> 9 3 1 1 3 1 8
#> 10 4 0 1 1 0 8
#> 11 4 0 1 2 0 7
#> 12 4 0 1 3 1 7
Создано 2020-09-11 пакетом reprex (версия 0.3.0)