我将以下数据存储为zoo对象:
A B C
2017-05-31 NA NA 3.1
2017-06-30 2.5 2.4 3.2
2017-07-31 2.5 NA 3.3
2017-08-31 2.6 NA 3.4
2017-09-30 2.8 2.5 3.6
2017-10-31 2.3 NA 3.4
2017-11-30 2.5 NA 3.2
2017-12-31 2.7 2.6 2.9
2018-01-31 2.8 NA 3.0
2018-02-28 2.6 NA NA
2018-03-31 NA NA NA
您可以按如下方式重现此zoo对象:
zoo <- data.frame(A=c(NA, 2.5, 2.5, 2.6, 2.8, 2.3, 2.5, 2.7, 2.8, 2.6, NA), B=c(NA, 2.4, NA, NA, 2.5, NA, NA, 2.6, NA, NA, NA), C=c(3.1, 3.2, 3.3, 3.4, 3.6, 3.4, 3.2, 2.9, 3.0, NA, NA), dates=c('2017-05-31', '2017-06-30', '2017-07-31', '2017-08-31', '2017-09-30', '2017-10-31', '2017-11-30', '2017-12-31', '2018-01-31', '2018-02-28', '2018-03-31'))
zoo <- as.zoo(df, order.by=as.Date(df$dates, format="%Y-%m-%d"))[,-4]
A栏和A栏C有月度观察,B栏有季度观察。专栏A&amp; B在开始时有一些NA,最后都有一些NA。我想只填充间歇性的NA(使用前一个值),但不填写开头或结尾的那些。因此,在我的示例中,只应使用之前的值填充2017-06-30和2017-12-31之间的B列中的NA。结果应如下所示:
A B C
2017-05-31 NA NA 3.1
2017-06-30 2.5 2.4 3.2
2017-07-31 2.5 2.4 3.3
2017-08-31 2.6 2.4 3.4
2017-09-30 2.8 2.5 3.6
2017-10-31 2.3 2.5 3.4
2017-11-30 2.5 2.5 3.2
2017-12-31 2.7 2.6 2.9
2018-01-31 2.8 NA 3.0
2018-02-28 2.6 NA NA
2018-03-31 NA NA NA
请注意,我的数据总是看起来不同,可能有间歇性的NA,但在开始和结束时也有不同长度的NA。因此,我需要一个通用的解决方案。
我已经使用以下代码实现了预期的结果,但它非常麻烦,我确信有更优雅的解决方案。
min <- sapply(zoo, function(col) min(which(!is.na(col))))
max <- sapply(zoo, function(col) max(which(!is.na(col))))
k <- ncol(zoo)
l <- length(min)
for (i in 1:l){
orig <- colnames(zoo)[i]
temp_repl <- na.locf(zoo[min[1]:max[i],i])
temp_zoo <- rbind(zoo[1:min[i]-1,i], temp_repl, zoo[(1+max[i]):nrow(zoo),i])
zoo <- cbind(zoo,temp_zoo)
colnames(zoo)[i] <- paste(orig, ", orig", sep="")
colnames(zoo)[k+i] <- orig
i+1
}
zoo <- zoo[,(k+1):ncol(zoo)]
答案 0 :(得分:0)
这也不优雅,但使用dplyr::bind_rows()
和tidyr::fill()
可能会让它更容易理解:
df <- data.frame(A=c(NA, 2.5, 2.5, 2.6, 2.8, 2.3, 2.5, 2.7, 2.8, 2.6, NA), B=c(NA, 2.4, NA, NA, 2.5, NA, NA, 2.6, NA, NA, NA), C=c(3.1, 3.2, 3.3, 3.4, 3.6, 3.4, 3.2, 2.9, 3.0, NA, NA), dates=c('2017-05-31', '2017-06-30', '2017-07-31', '2017-08-31', '2017-09-30', '2017-10-31', '2017-11-30', '2017-12-31', '2018-01-31', '2018-02-28', '2018-03-31'))
df$dates <- as.Date(df$dates)
min_date='2017-06-30'
max_date='2017-12-31'
df_new <- dplyr::bind_rows(
df[df$dates < min_date,],
tidyr::fill(df[df$dates >= min_date & df$dates <= max_date,], A:C),
df[df$dates > max_date,]
)
df_new
A B C dates
1 NA NA 3.1 2017-05-31
2 2.5 2.4 3.2 2017-06-30
3 2.5 2.4 3.3 2017-07-31
4 2.6 2.4 3.4 2017-08-31
5 2.8 2.5 3.6 2017-09-30
6 2.3 2.5 3.4 2017-10-31
7 2.5 2.5 3.2 2017-11-30
8 2.7 2.6 2.9 2017-12-31
9 2.8 NA 3.0 2018-01-31
10 2.6 NA NA 2018-02-28
11 NA NA NA 2018-03-31
zoo
也具有na.locf()
功能,但在应用于整个数据框时,它会将所有列转换为字符。