#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