如何用apply系列函数向量化实现列表索引遍历与矩阵更新?
问题描述
我有一个嵌套列表:
xx = list("a_1" = list("A", "C"), "a_2" = list("B", "C"), "a_3" = list("B", "B"), "a_4" = list("C", "B"), "a_5" = list("B", "A"), "a_6" = list("B", "A"))
该列表包含重复子列表(如a_5和a_6)。我需要用它更新一个初始化为0的矩阵:
m = matrix(data = 0, nrow = 3, ncol = 3) # 初始化零矩阵 rownames(m) = c("A", "B", "C") # 设置行名 colnames(m) = c("A", "B", "C") # 设置列名
需求是给每个子列表对应的矩阵索引位置的值加1。用for循环可轻松实现:
for (item in xx) { # 对应矩阵位置加1 m[item[[1]], item[[2]]] = m[item[[1]], item[[2]]] + 1 }
得到预期输出:
A B C A 0 0 1 B 2 1 1 C 0 1 0
但处理大型列表时该方法效率较低,我尝试嵌套使用lapply和sapply未成功,希望用apply系列函数实现向量化操作,请教具体方法?
解决方案
方法1:sapply转矩阵 + 频次统计
先将嵌套列表转换为两行的矩阵,每行对应子列表的第一个和第二个元素,再用table统计组合出现的次数,最后将统计结果映射到目标矩阵中:
# 将嵌套列表转为矩阵,每行对应子列表的两个元素 xx_mat <- sapply(xx, function(x) unlist(x)) # 统计每个(row, col)组合的出现次数 counts <- table(xx_mat[1, ], xx_mat[2, ]) # 将统计结果赋值给初始矩阵 m[rownames(counts), colnames(counts)] <- counts
这种方法完全向量化,处理大型数据集时效率远高于for循环,且代码简洁。
方法2:lapply提取索引 + 批量更新
如果偏好使用lapply,可以先提取所有索引对,合并为矩阵后批量更新矩阵值:
# 提取所有(row, col)索引对 indices <- lapply(xx, function(x) c(x[[1]], x[[2]])) # 将索引对合并为矩阵 indices_mat <- do.call(rbind, indices) # 批量对对应矩阵位置加1 m[indices_mat] <- m[indices_mat] + 1
利用矩阵的索引特性:当传入一个两列矩阵作为索引时,每一行对应一个(row, col)位置,可直接批量完成累加操作。
方法3:vapply高效提取索引
vapply比lapply更高效,因为可以预先指定返回值类型,适合处理大型列表:
# 用vapply提取索引,指定返回长度为2的字符向量 indices <- vapply(xx, function(x) unlist(x), character(2)) # 转置后得到每行是一个索引对的矩阵 indices_mat <- t(indices) # 批量更新矩阵值 m[indices_mat] <- m[indices_mat] + 1
内容的提问来源于stack exchange,提问作者Matthew Cassell
相关产品推荐
相关产品推荐

