R语言中如何根据行列分类值从3x3评分矩阵提取对应分值?
解决R中按行提取矩阵对应元素的问题
问题背景
需要从以下3x3评分矩阵中,根据数据框每行的level.cats(行索引)和slope.cats(列索引)提取对应分值:
scoring.matrix <- matrix(c(-2, -1, 0, -1, 0, 1, 0, 1, 2), nrow = 3, byrow = TRUE)
数据框示例:
resfil2 <- data.frame( network_id = 1:10, level.cats = c(3,3,3,3,1,3,3,2,1,2), slope.cats = c(2,1,3,2,2,3,2,3,1,3) )
尝试批量提取时执行代码:
resfil3 <- resfil2 %>% mutate(score=unlist(scoring.df[level.cats, slope.cats]))
报错提示score必须为43或1长度,而非1849,原因是R将向量索引做了交叉匹配,生成了43x43的元素集合。
错误原因
当用两个向量作为矩阵的行、列索引时,R默认执行外积匹配:即每个行索引与所有列索引组合,每个列索引与所有行索引组合,最终生成length(行索引) * length(列索引)个元素,而非按位置一一对应提取。
解决方案
方法1:用cbind构造索引矩阵
这是最高效的基础R方法,将行、列索引组合成两列矩阵,强制R按行一一对应提取元素:
resfil3 <- resfil2 %>% mutate(score = scoring.matrix[cbind(level.cats, slope.cats)])
cbind(level.cats, slope.cats)生成n行2列的索引矩阵,每一行对应一个元素的位置,矩阵索引会逐个提取这些位置的值,返回与数据框行数一致的向量。
方法2:使用rowwise()逐行处理
如果偏好tidyverse语法,用rowwise()让代码逐行执行,避免向量化的交叉匹配:
resfil3 <- resfil2 %>% rowwise() %>% mutate(score = scoring.matrix[level.cats, slope.cats]) %>% ungroup() # 处理完成后取消逐行模式,避免后续操作性能下降
方法3:用purrr::map2()逐个映射
利用purrr的映射函数,将两个索引向量逐个配对提取:
library(purrr) resfil3 <- resfil2 %>% mutate(score = map2_dbl(level.cats, slope.cats, ~ scoring.matrix[.x, .y]))
map2_dbl会把level.cats和slope.cats的元素一一配对,传入匿名函数提取对应值,返回数值向量。
额外修正:cut函数参数优化
你之前的cut函数存在参数误用,levels=1:3是无效参数,正确的分类转换代码应为:
resfil2 <- resfil %>% mutate( level.cats = as.numeric(cut(intrcpt.est, breaks = c(-Inf, int.qcuts, Inf), labels = c("Bottom Quartile", "Middle 50%", "Top Quartile"))), slope.cats = as.numeric(cut(slope.est, breaks = c(-Inf, sl.qcuts, Inf), labels = c("Bottom Quartile", "Middle 50%", "Top Quartile"))) )
as.numeric()会将因子转换为对应的整数1/2/3,与评分矩阵的索引完全匹配。
内容的提问来源于stack exchange,提问作者Stuart
相关产品推荐
相关产品推荐

