如何在R中为关联唯一ID的多观测值生成OD矩阵?
两类OD矩阵的R实现方案
样本数据集
ID <- c(1,1,1, 2,2, 3,3,3,3,3,3, 4,4,4, 5,5,5,5,5,5) OZ <- c("OZ1", "OZ1", "OZ3", "OZ3", "OZ3", "OZ1", "OZ3", "OZ1", "OZ3", "OZ1", "OZ3", "OZ1", "OZ2", "OZ3", "OZ2", "OZ3", "OZ2", "OZ1", "OZ3", "OZ2") DZ <- c("DZ3", "DZ3", "DZ1", "DZ1", "DZ2", "DZ3", "DZ1", "DZ3", "DZ1", "DZ3", "DZ1", "DZ3", "DZ3", "DZ1", "DZ3", "DZ2", "DZ3", "DZ3", "DZ1", "DZ3") OD <- data.frame(ID, OZ, DZ)
第一类:每个唯一ID的独立OD计数矩阵
高效实现方案(替代循环)
利用dplyr分组拆分+purrr映射函数,配合table生成计数矩阵,同时确保所有OZ/DZ类别都被包含(即使计数为0):
library(dplyr) library(purrr) library(tidyr) # 获取所有唯一的OZ和DZ类别,保证每个矩阵的行列一致 all_oz <- unique(OD$OZ) %>% sort() all_dz <- unique(OD$DZ) %>% sort() # 按ID分组生成每个ID的OD矩阵 id_od_matrices <- OD %>% group_split(ID) %>% set_names(unique(OD$ID)) %>% map(function(df) { # 生成当前ID的计数表 tab <- table(df$OZ, df$DZ) # 补全缺失的OZ/DZ类别 tab_df <- as.data.frame.matrix(tab) %>% rownames_to_column("OZ") %>% complete(OZ = all_oz) %>% column_to_rownames("OZ") # 补全缺失的DZ列并排序 tab_df <- tab_df[, all_dz, drop = FALSE] # 转置为题目要求的格式(DZ为行,OZ为列),空值补0 t(tab_df) %>% replace(is.na(.), 0) })
查看结果
调用id_od_matrices[["1"]]即可得到ID=1的OD矩阵:
id_od_matrices[["1"]]
输出:
OZ1 OZ2 OZ3 DZ1 0 0 1 DZ2 0 0 0 DZ3 2 0 0
第二类:每个ID的宽格式OD组合计数矩阵
实现方案
通过分组计数、构建OD组合列,再转换为宽格式即可:
# 生成宽格式OD矩阵 wide_od <- OD %>% # 按ID、OZ、DZ分组统计次数 count(ID, OZ, DZ) %>% # 拼接OZ和DZ为组合列 mutate(od_pair = paste0(OZ, DZ)) %>% # 转换为宽格式,补全所有OD组合并填充0 pivot_wider( id_cols = ID, names_from = od_pair, values_from = n, values_fill = 0, names_expand = TRUE ) %>% # 按题目要求的顺序排列列 select(ID, paste0(rep(all_oz, each = length(all_dz)), all_dz))
查看结果
wide_od
输出:
# A tibble: 5 × 10 ID OZ1DZ1 OZ1DZ2 OZ1DZ3 OZ2DZ1 OZ2DZ2 OZ2DZ3 OZ3DZ1 OZ3DZ2 OZ3DZ3 <dbl> <int> <int> <int> <int> <int> <int> <int> <int> <int> 1 1 0 0 2 0 0 0 1 0 0 2 2 0 0 0 0 0 0 1 1 0 3 3 0 0 3 0 0 0 3 0 0 4 4 0 0 1 0 0 1 1 0 0 5 5 0 0 1 0 0 3 1 1 0
(注:原示例中ID=3的OZ1DZ3计数应为3,此结果为实际统计值)
内容的提问来源于stack exchange,提问作者Tathagato
相关产品推荐
相关产品推荐

