Создание столбцов для каждого наблюдаемого значения переменной - PullRequest
1 голос
/ 15 мая 2019

Предположим, респонденту (id) предлагается сделать выбор в пяти заданиях (t = 1,2,3,4,5) (набор данных панели с пятью наблюдениями на респондента). Как только выбор сделан, то результат показывается респонденту. Предположим, что данные выглядят так, как показано ниже.

+----+---+---------+
| id | t | outcome |
+----+---+---------+
|  1 | 1 |      10 |
|  1 | 2 |      20 |
|  1 | 3 |      30 |
|  1 | 4 |      40 |
|  1 | 5 |      40 |
|  2 | 1 |      20 |
|  2 | 2 |      30 |
|  2 | 3 |      40 |
|  2 | 4 |      40 |
|  2 | 5 |      20 |
|  . | . |       . |
|  . | . |       . |
|  . | . |       . |
+----+---+---------+

Теперь мне интересно сохранить историю переменной исход для каждой задачи t-1 . Я стремлюсь к следующему выводу.


+----+---+---------+------------+------------+------------+------------+------------+
| id | t | outcome | outcome_t1 | outcome_t2 | outcome_t3 | outcome_t4 | outcome_t5 |
+----+---+---------+------------+------------+------------+------------+------------+
|  1 | 1 |      10 | NA         | NA         | NA         | NA         | NA         |
|  1 | 2 |      20 | 10         | NA         | NA         | NA         | NA         |
|  1 | 3 |      30 | 10         | 20         | NA         | NA         | NA         |
|  1 | 4 |      40 | 10         | 20         | 30         | NA         | NA         |
|  1 | 5 |      40 | 10         | 20         | 30         | 40         | NA         |
|  2 | 1 |      20 | NA         | NA         | NA         | NA         | NA         |
|  2 | 2 |      30 | 20         | NA         | NA         | NA         | NA         |
|  2 | 3 |      40 | 20         | 30         | NA         | NA         | NA         |
|  2 | 4 |      40 | 20         | 30         | 40         | NA         | NA         |
|  2 | 5 |      20 | 20         | 30         | 40         | 40         | NA         |
|  . | . |       . | .          | .          | .          | .          | .          |
|  . | . |       . | .          | .          | .          | .          | .          |
|  . | . |       . | .          | .          | .          | .          | .          |
+----+---+---------+------------+------------+------------+------------+------------+

Я рассмотрел большинство вопросов на этом форуме, но большинство из них касаются отстающих столбцов, которые не применимы к этому случаю.

Возможно, может быть простой и эффективный способ использования mutate с dplyr, но я пока не могу заставить его работать.

Ответы [ 4 ]

2 голосов
/ 15 мая 2019

Вот подход tidyverse.

library(tidyverse)

df %>% 
  mutate(rn = 1:n(),
         t = paste0("outcome_t", t)) %>%
  group_by(id) %>%
  spread(t, outcome) %>%
  mutate_at(vars(-rn, -id), lag) %>%
  fill(-rn, -id)

# A tibble: 10 x 7
# Groups:   id [2]
      id    rn outcome_t1 outcome_t2 outcome_t3 outcome_t4 outcome_t5
   <int> <int>      <int>      <int>      <int>      <int>      <int>
 1     1     1         NA         NA         NA         NA         NA
 2     1     2         10         NA         NA         NA         NA
 3     1     3         10         20         NA         NA         NA
 4     1     4         10         20         30         NA         NA
 5     1     5         10         20         30         40         NA
 6     2     6         NA         NA         NA         NA         NA
 7     2     7         20         NA         NA         NA         NA
 8     2     8         20         30         NA         NA         NA
 9     2     9         20         30         40         NA         NA
10     2    10         20         30         40         40         NA
2 голосов
/ 15 мая 2019

Подход Base R, мы можем split столбец outcome на основе id и создать фрейм данных, постепенно добавляя по одному значению за раз в переменную outcome и заполняя остальные из них NA и, наконец, rbind это список фреймов данных в один фрейм данных.

n <- 5
df[paste0("outcome_t", seq_len(n))] <- do.call(rbind, 
    lapply(split(df$outcome, df$id), function(x) 
  t(sapply(seq_along(x), function(y) c(x[seq_len(y - 1)], rep(NA, n - (y - 1)))))))

df
#   id t outcome outcome_t1 outcome_t2 outcome_t3 outcome_t4 outcome_t5
#1   1 1      10         NA         NA         NA         NA         NA
#2   1 2      20         10         NA         NA         NA         NA
#3   1 3      30         10         20         NA         NA         NA
#4   1 4      40         10         20         30         NA         NA
#5   1 5      40         10         20         30         40         NA
#6   2 1      20         NA         NA         NA         NA         NA
#7   2 2      30         20         NA         NA         NA         NA
#8   2 3      40         20         30         NA         NA         NA
#9   2 4      40         20         30         40         NA         NA
#10  2 5      20         20         30         40         40         NA

A tidyverse опция с использованием separate

library(tidyverse)

df %>%
   group_by(id) %>%
   mutate(new = map_chr(seq_along(outcome), 
         ~paste0(outcome[seq_len(. - 1)], collapse = ","))) %>%
   separate(new, into = paste0("outcome_t", seq_len(n)), 
                 sep = ",", fill = "right") %>%
   mutate(outcome_t1 = replace(outcome_t1, outcome_t1 == "", NA))

data

df <- data.frame(id = rep(c(1, 2), each = 5), t = 1:5, 
     outcome = c(10, 20, 30, 40, 40, 20, 30, 40, 40, 20))
2 голосов
/ 15 мая 2019

Другой подход к data.table с использованием transpose:

DT[, paste0("outcome_t", 1:5) := 
        transpose(lapply(t, function(x) replace(outcome, t>=x, NA))), 
    by=.(id)]

вывод:

    id t outcome outcome_t1 outcome_t2 outcome_t3 outcome_t4 outcome_t5
 1:  1 1      10         NA         NA         NA         NA         NA
 2:  1 2      20         10         NA         NA         NA         NA
 3:  1 3      30         10         20         NA         NA         NA
 4:  1 4      40         10         20         30         NA         NA
 5:  1 5      40         10         20         30         40         NA
 6:  2 1      20         NA         NA         NA         NA         NA
 7:  2 2      30         20         NA         NA         NA         NA
 8:  2 3      40         20         30         NA         NA         NA
 9:  2 4      40         20         30         40         NA         NA
10:  2 5      20         20         30         40         40         NA

data:

library(data.table)
DT <- fread("| id | t | outcome |
|  1 | 1 |      10 |
|  1 | 2 |      20 |
|  1 | 3 |      30 |
|  1 | 4 |      40 |
|  1 | 5 |      40 |
|  2 | 1 |      20 |
|  2 | 2 |      30 |
|  2 | 3 |      40 |
|  2 | 4 |      40 |
|  2 | 5 |      20 |")[, c(-1,-5)]
2 голосов
/ 15 мая 2019

Мы можем использовать data.table методы для этого.Преобразуйте data.frame в data.table (setDT(df1)), сгруппированные по id, выполните цикл по результату, rep лицензируйте элементы с указанием последовательности из 1:.N и .N:1 с NA в качестве отступа, затем объедините с исходным набором данных в столбцах 'id' и 't'

library(data.table)
df2 <- setDT(df1)[, Map(function(x, y, z) rep(c(NA, x), 
             c(y, z)), outcome, 1:.N, .N:1), id][, t := rowid(id)]
out <- df2[df1, on  = .(id, t)]
setcolorder(out, c(1, 7, 8, 2:6))
setnames(out, 4:ncol(out), paste0("outcome_t", 1:5))
out
#    id t outcome outcome_t1 outcome_t2 outcome_t3 outcome_t4 outcome_t5
# 1:  1 1      10         NA         NA         NA         NA         NA
# 2:  1 2      20         10         NA         NA         NA         NA
# 3:  1 3      30         10         20         NA         NA         NA
# 4:  1 4      40         10         20         30         NA         NA
# 5:  1 5      40         10         20         30         40         NA
# 6:  2 1      20         NA         NA         NA         NA         NA
# 7:  2 2      30         20         NA         NA         NA         NA
# 8:  2 3      40         20         30         NA         NA         NA
# 9:  2 4      40         20         30         40         NA         NA
#10:  2 5      20         20         30         40         40         NA

или опцию с dcast

dcast(setDT(df1), id + t ~ paste0("outcome_t", t), 
       value.var = 'outcome')[, na.locf(.SD, na.rm = FALSE), id]

Или мы можем сделать это более компактно

library(zoo)
nm1 <- paste0("outcome_t", 1:5)
df1[nm1] <- do.call(rbind, lapply(split(df1$outcome, df1$id), 
                function(x) head(rbind(NA, na.locf((NA^!diag(x)) * x)), -1)))

Или используя colCumsums

library(matrixStats)
df1[nm1] <- do.call(rbind, lapply(split(df1$outcome, df1$id), 
          function(x) colCumsums(rbind(0, diag(x)))[-length(x), ]))

data

df1 <- structure(list(id = c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L), 
t = c(1L, 2L, 3L, 4L, 5L, 1L, 2L, 3L, 4L, 5L), outcome = c(10L, 
20L, 30L, 40L, 40L, 20L, 30L, 40L, 40L, 20L)),
 class = "data.frame", row.names = c(NA, -10L))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...