Данные события преобразования R

#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)