расширить данные с помощью data.table

#r #data.table

#r #данные.таблица

Вопрос:

У меня есть эти данные.таблица

 library(data.table)

data.table(
  id = c(rep(1, 3), rep(2, 2)),
  begin = c(1, 4, 8, 1, 11),
  end = c(3, 7, 12, 10, 12),
  state = c("A", "B", "A", "B", "A")
)
  

Я хотел бы иметь этот вывод :

 data.table(
  id = c(1, 2),
  m1 = c("A", "B"),
  m2 = c("A", "B"),
  m3 = c("A", "B"),
  m4 = c("B", "B"),
  m5 = c("B", "B"),
  m6 = c("B", "B"),
  m7 = c("B", "B"),
  m8 = c("A", "B"),
  m9 = c("A", "B"),
  m10 = c("A", "B"),
  m11 = c("A", "A"),
  m12 = c("A", "A")
)
  

Те, кто раньше выполнял анализ последовательности, возможно, поняли, что я пытаюсь делать то, что seqformat делается в TRaMiNeR пакете, но с более высокой производительностью за счет использования data.table

Комментарии:

1. Я сомневаюсь, что вы сможете добиться высокой производительности при преобразовании таблицы в широкий формат без специализированного пакета. Однако, если вы хотите / способны работать с данными длинного формата, существует DT[, .(seq = seq(first(begin), last(end)), v = inverse.rle(.(values = state, lengths = end - begin 1L))), by=id]

2. Альтернатива варианту @Frank: dt[, unlist(Map(`:`, begin, end)), by = .(id, state)] (смотрите также мой ответ)

Ответ №1:

Одним из вариантов с data.table было бы melt , чтобы после создания столбца последовательности, сгруппированного по ‘i1’, ‘id’, ‘state’, получить seq значение first и last «влияние», dcast от ‘long’ до ‘wide’

 dt1 <- melt(dt[, i1 := seq_len(.N)], id.vars = c("i1", "id", "state"))[,
      paste0("m", seq(first(value), last(value))), .(i1, id, state)]
dcast(dt1, id ~ V1, value.var = "state")[]
#    id m1 m10 m11 m12 m2 m3 m4 m5 m6 m7 m8 m9
#1:  1  A   A   A   A  A  A  B  B  B  B  A  A
#2:  2  B   B   A   A  B  B  B  B  B  B  B  B
  

Ответ №2:

Решение с использованием tidyverse .

 library(tidyverse)
library(data.table)

dat <- data.table(
  id = c(rep(1, 3), rep(2, 2)),
  begin = c(1, 4, 8, 1, 11),
  end = c(3, 7, 12, 10, 12),
  state = c("A", "B", "A", "B", "A")
)

dat2 <- dat %>%
  mutate(Index = map2(begin, end, `:`)) %>%
  unnest() %>%
  mutate(Index = str_c("m", Index)) %>%
  select(id, state, Index) %>%
  spread(Index, state) %>%
  select(id, str_c("m", 1:(ncol(.) - 1)))
dat2
#   id m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12
# 1  1  A  A  A  B  B  B  B  A  A   A   A   A
# 2  2  B  B  B  B  B  B  B  B  B   B   A   A  
  

Ответ №3:

Альтернативное решение:

 dt[, unlist(Map(`:`, begin, end)), by = .(id, state)
   ][, dcast(.SD, id ~ sprintf("md", V1), value.var = "state")]
  

что дает:

    id m01 m02 m03 m04 m05 m06 m07 m08 m09 m10 m11 m12
1:  1   A   A   A   B   B   B   B   A   A   A   A   A
2:  2   B   B   B   B   B   B   B   B   B   B   A   A
  

Возможно, лучше сохранить данные в длинном формате. С длинным форматом часто проще работать в R позже при обработке / анализе данных.

Вы могли бы достичь этого всего лишь:

 dt[, unlist(Map(`:`, begin, end)), by = .(id, state)][order(id, V1)]
  

что дает:

     id state V1
 1:  1     A  1
 2:  1     A  2
 3:  1     A  3
 4:  1     B  4
 5:  1     B  5
 6:  1     B  6
 7:  1     B  7
 8:  1     A  8
 9:  1     A  9
10:  1     A 10
11:  1     A 11
12:  1     A 12
13:  2     B  1
14:  2     B  2
15:  2     B  3
16:  2     B  4
17:  2     B  5
18:  2     B  6
19:  2     B  7
20:  2     B  8
21:  2     B  9
22:  2     B 10
23:  2     A 11
24:  2     A 12
  

(где [order(id, V1)] -часть не является необходимой)


Используемые данные:

 dt <- data.table(
  id = c(rep(1, 3), rep(2, 2)),
  begin = c(1, 4, 8, 1, 11),
  end = c(3, 7, 12, 10, 12),
  state = c("A", "B", "A", "B", "A")
)