如何将非标准化时间值列表转换为标准mxn矩阵格式?
问题描述
我有一组非标准化的时间与值列表,不同数据元素的赋值时间不一致,部分元素在t=1,3,5时赋值,其他元素则在t=2,4,6,8时赋值。需要将这些值转换为标准mxn矩阵格式,可接受用NA填充空缺,但更希望对缺失值进行插补。
示例数据生成代码:
set.seed(1) ids <- 1:5 # 基于时间生成新值的函数,依赖前一个值 age_fn <- function(prior_value, age) prior_value - 1.2*age my_list <- list() for(i in 1:length(ids)) { # 每个id的记录数 N <- sample(c(2:4), 1, replace=TRUE) # 生成时间步长(第一个记录在t=0,所以减1) time_step <- sample(c(1:3), N-1, replace=TRUE) # 记录时间点 t <- rep(0, times=N) for(n in 2:N) { t[n] <- t[n-1] + time_step[n-1] } # 生成对应时间点的值 value <- rep(100, times=N) for(n in 2:N) { value[n] <- age_fn(value[n-1], t[n]) } my_list[[i]] <- list(ids[i], t, value) }
部分示例数据:
> my_list [[3]] [[3]][[1]] [1] 3 [[3]][[2]] [1] 0 3 [[3]][[3]] [1] 100.0 96.4 [[4]] [[4]][[1]] [1] 4 [[4]][[2]] [1] 0 2 4 7 [[4]][[3]] [1] 100.0 97.6 92.8 84.4
期望输出(以id3和id4为例,转换为2x8的[元素, t]矩阵,缺失值用前序值填充):
0 1 2 3 4 5 6 7 values1 100 100 100.0 96.4 96.4 96.4 96.4 96.4 values2 100 100 97.6 97.6 92.8 92.8 92.8 84.4
解决方案
步骤1:确定目标时间范围
先明确需要覆盖的时间点(示例中为t=0到7):
# 指定目标时间点 target_times <- 0:7
步骤2:处理单个元素数据,生成对齐后的序列
针对每个元素,将现有时间-值对与目标时间对齐,用向前填充补全缺失值(即保留最近一次的有效值):
process_id <- function(id_data, target_t) { # 提取id、时间、值 id <- id_data[[1]] t <- id_data[[2]] value <- id_data[[3]] # 创建包含所有目标时间的数据框 full_df <- data.frame(t = target_t) # 合并现有数据 full_df <- merge(full_df, data.frame(t = t, value = value), by = "t", all.x = TRUE) # 向前填充缺失值(需zoo包支持) full_df$value <- zoo::na.locf(full_df$value) # 返回命名向量,方便后续组合 setNames(full_df$value, target_t) }
若未安装zoo包,先执行install.packages("zoo")完成安装。
步骤3:批量处理并转换为矩阵
将所有元素处理后组合成标准矩阵:
library(zoo) # 批量处理所有元素 processed_list <- lapply(my_list, process_id, target_t = target_times) # 转换为矩阵,行对应元素,列对应时间点 result_matrix <- do.call(rbind, processed_list) # 设置行列名称 rownames(result_matrix) <- paste0("values", sapply(my_list, function(x) x[[1]])) colnames(result_matrix) <- target_times # 查看示例元素的结果 result_matrix[c("values3", "values4"), ]
运行后输出与期望一致:
0 1 2 3 4 5 6 7 values3 100 100 100.0 96.4 96.4 96.4 96.4 96.4 values4 100 100 97.6 97.6 92.8 92.8 92.8 84.4
可选:仅用NA填充不插补
若不需要插补,仅保留NA填充空缺,修改处理函数即可:
process_id_na <- function(id_data, target_t) { id <- id_data[[1]] t <- id_data[[2]] value <- id_data[[3]] full_df <- data.frame(t = target_t) full_df <- merge(full_df, data.frame(t = t, value = value), by = "t", all.x = TRUE) setNames(full_df$value, target_t) } # 生成含NA的矩阵 na_matrix <- do.call(rbind, lapply(my_list, process_id_na, target_t = target_times)) rownames(na_matrix) <- paste0("values", sapply(my_list, function(x) x[[1]])) colnames(na_matrix) <- target_times
内容的提问来源于stack exchange,提问作者coolhand
相关产品推荐
相关产品推荐

