我想根据action
列的记录和time
列填充该列。action
列中的NA应根据以前的操作记录和时间间隔填充。假设我们将时间间隔设置为10
,这意味着如果动作A
并且时间1
,则action
中的所有NA
都应该A
到time==11 (1+10)
。
请注意,如果action
或ID
发生变化,则应重置此过程。例如(在第 3 行(我们用time==11
B
,我想用B
填充下一个 NA 直到time==21
,但我们在time==16
中C
,所以我们继续用 C 填充 NA 直到time==26
个。
df<-read.table(text="
id action time
1 A 1
1 NA 4
1 NA 9
1 B 11
1 NA 12
1 C 16
1 NA 19
1 NA 30
1 A 31
1 NA 32
2 NA 1
2 A 2
2 NA 6",header=T,stringsAsFactors = F)
Desired Result:
id action time
1 A 1
1 A 4
1 A 9
1 B 11
1 B 12
1 C 16
1 C 19
1 NA 30
1 A 31
1 A 32
2 NA 1
2 A 2
2 A 6
我们可以提取非 NA 行作为填充值的参考,然后遍历数据集并根据值是否满足id
和时间间隔的要求有条件地替换值。
# Use row numbers as an index (unique Id)
df$idx <- 1:nrow(df)
# Find the non-NA rows to use a reference for imputation
idx <- df %>%
group_by(id) %>%
na.omit(action)
临时数据集idx
用作参考,列idx
是我们的唯一标识符。我们先来看看查找和填写缺失值的逻辑,不用担心时间间隔,这样就更容易阅读和理解了:
# Ignoring the 'interval' limitation, we'd fill them in like this:
for(r in 1:nrow(df)){
if(is.na(df$action[r])){
df$action[r] <- dplyr::last(idx$action[idx$idx < df$idx[r] & idx$id == df$id[r]])
}
}
如果运行此示例代码,请确保在继续之前重新创建df
并idx
,因为它将被最后一个示例代码块修改。
时间间隔要求我们对time
的值进行逻辑测试,并要求我们对 NA 值进行另一个测试,以避免尝试对 NA 值进行time
比较:
# Accounting for the max interval:
interval <- 10
for(r in 1:nrow(df)){
if(is.na(df$action[r])){
if(!is.na(dplyr::last(idx$time[idx$idx < df$idx[r] & idx$id == df$id[r]]))){
if(dplyr::last(idx$time[idx$idx < df$idx[r] & idx$id == df$id[r]]) + interval >= df$time[r])
df$action[r] <- dplyr::last(idx$action[idx$idx < df$idx[r] & idx$id == df$id[r]])
}
}
}
df
这为我们提供了:
id action time idx 1 1 A 1 1 2 1 A 4 2 3 1 A 9 3 4 1 B 11 4 5 1 B 12 5 6 1 C 16 6 7 1 C 19 7 8 1 <NA> 30 8 9 1 A 31 9 10 1 A 32 10 11 2 <NA> 1 11 12 2 A 2 12 13 2 A 6 13
匹配您想要的输出。