для цикла в R, вложенного в другой

#r #loops

#r #циклы

Вопрос:

У меня есть набор данных, подобный тому, который создан этим кодом:

 data <- data.frame(ID=c(rep("01",3),rep("02",3)), x=c("abc","abc","cde","abc","abc","abc"), t1=c(1,6,9,1,6,11), t2=c(4,7,12,3,10,12))
 

и еще один, созданный:

 data2 <- data.frame(ID=c(rep("01",12),rep("02",12)), t = rep(1:12,2), x= c(rep(NA,24)))
 

и то, что я хотел бы получить, это:

 data_final <- data.frame(ID=c(rep("01",12),rep("02",12)), t = rep(1:12,2), x= c(rep("abc",4),NA,"abc","abc",NA,rep("cde",4),rep("abc",3),rep(NA,2),rep("abc",7)))
 

Этот код работает соответствующим образом только для одного идентификатора, и я не знаю, как это сделать для большего идентификатора:

 for (i in 1:nrow(data)) {
  data2$x[data$t1[i]:data$t2[i]] <- data$x[i]
 }
 

Есть идеи?

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

1. Не могли бы вы опубликовать пример с 2 идентификаторами?

Ответ №1:

Вот как я бы это сделал, используя tidyr / dplyr из tidyverse мета-пакета.

 library(tidyverse)
data_expanded <- data %>%
  uncount(t2 - t1   1, .id = "row") %>%
  mutate(t = t1   row - 1) %>%   # convert to t 
  select(ID, t, x)               # only need columns ID, t, and x

data2 %>%
  select(-x) %>%                 # we'll add x from data_expanded next
  left_join(data_expanded)
 

Сначала преобразуйте data в таблицу, в которой явно перечислены все ID и t к которым они относятся. Я использую tidyr::uncount для копирования каждой строки для каждого t в диапазоне от t1 до t2 .

Как только эта таблица будет готова, это простое соединение с исходным файлом.

Результат:

 Joining, by = c("ID", "t")
   ID  t    x
1  01  1  abc
2  01  2  abc
3  01  3  abc
4  01  4  abc
5  01  5 <NA>
6  01  6  abc
7  01  7  abc
8  01  8 <NA>
9  01  9  cde
10 01 10  cde
11 01 11  cde
12 01 12  cde
13 02  1  abc
14 02  2  abc
15 02  3  abc
16 02  4 <NA>
17 02  5 <NA>
18 02  6  abc
19 02  7  abc
20 02  8  abc
21 02  9  abc
22 02 10  abc
23 02 11  abc
24 02 12  abc
 

Ответ №2:

Если вы хотите сохранить loop in basic R, приведенный ниже код даст вам то, что вы хотите.

 # loop each row of data2
for (i in 1: dim(data2)[1]){
  IDi <- data2[i, 1] # id of ith row
  IDi_idx <-(IDi == data$ID) # use this IDi to find the index (same ID) in data 
  seldf_i <- data[IDi_idx, ] # subset data using IDi_idx
  # if data2$x is NA, then check if data2[i, 2] is in the range [t1:t2] by each row of seldf_i; yes assigns according x, no with NA
  for (j in 1: dim(seldf_i)[1]){
    if (is.na(data2[i, 3])){
      data2[i, 3] <- ifelse(data2[i, 2] %in% (seldf_i[j, 3]:seldf_i[j, 4]), 
                            as.character(seldf_i[j, 2]), NA)}
  }
}

data2
 

Ответ №3:

Опция data.table

 data_final <- setDT(data)[
  ,
  .(t = seq(t1, t2)), .(ID, x, seq(nrow(data)))
][
  setDT(data2),
  on = .(ID, t)
][
  ,
  .(ID, t, x)
][]
 

дает

 > data_final
    ID  t    x
 1: 01  1  abc
 2: 01  2  abc
 3: 01  3  abc
 4: 01  4  abc
 5: 01  5 <NA>
 6: 01  6  abc
 7: 01  7  abc
 8: 01  8 <NA>
 9: 01  9  cde
10: 01 10  cde
11: 01 11  cde
12: 01 12  cde
13: 02  1  abc
14: 02  2  abc
15: 02  3  abc
16: 02  4 <NA>
17: 02  5 <NA>
18: 02  6  abc
19: 02  7  abc
20: 02  8  abc
21: 02  9  abc
22: 02 10  abc
23: 02 11  abc
24: 02 12  abc
    ID  t    x