R语言中修正ifelse循环代码生成目标矩阵G的方法
修正R代码以生成目标比较次数矩阵
我来帮你解决这个问题!你的代码主要有两个核心问题导致结果不符合预期,我们一步步拆解并修正:
原代码的问题分析
- 不必要的行遍历:你用了
apply(dt, 1, ...)按行遍历整个数据框,但函数内部完全没用到每行的y参数,这导致同一组比较被重复计算了12次(数据框总行数),结果被无意义地放大。 - 错误的比较逻辑:
dt$V2[dt$V1==m] < dt$V2[dt$V1==n]是按位置逐元素比较两个组的V2向量,而不是执行所有元素的两两交叉比较——这和你需要的“统计前者所有元素小于后者所有元素的总次数”需求完全不符。
修正后的代码
首先先确认我们的输入数据:
# 构建输入数据框 dt <- data.frame( V1 = rep(1:3, each = 4), V2 = c(60, 30, 38, 46, 29, 35, 13, 82, 100, 72, 63, 45) )
方法1:修正原有循环
我们先按V1分组提取V2值,避免重复计算,然后在循环中执行正确的两两交叉比较:
l1 <- 1:3 G <- matrix(data = 0, nrow = 3, ncol = 3) # 按V1分组提取V2值,存储为列表 groups <- split(dt$V2, dt$V1) for (m in l1) { for (n in l1) { if (m == n) { G[m, n] <- 0 # 同一组元素自己和自己比较,不会有小于的情况 next } # 计算m组所有V2值小于n组所有V2值的总次数 G[m, n] <- sum(outer(groups[[as.character(m)]], groups[[as.character(n)]], "<")) } } # 打印结果 print(G)
方法2:更简洁的向量化实现
利用outer函数直接对分组后的列表进行操作,无需手动循环:
groups <- split(dt$V2, dt$V1) G <- outer(groups, groups, function(x, y) sum(x < y)) # 打印结果 print(G)
两种方法运行后都会得到你期望的结果:
[,1] [,2] [,3] [1,] 0 5 14 [2,] 5 0 13 [3,] 14 13 0
逻辑验证(以G[1,2]为例)
V1=1的V2值为[60, 30, 38, 46],V1=2的V2值为[29, 35, 13, 82],两两交叉比较后统计前者小于后者的次数:
- 60仅小于82 → 1次
- 30小于35、82 → 2次
- 38仅小于82 →1次
-46仅小于82 →1次
总计1+2+1+1=5次,和目标矩阵中的G[1,2]完全一致。
内容的提问来源于stack exchange,提问作者vp_050
相关产品推荐
相关产品推荐

