You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R语言嵌套foreach循环结果异常求助

嵌套foreach并行循环无法正确填充结果列表的问题解决

我用嵌套for循环能正常生成包含3×9矩阵的allresults_skew列表,但改成嵌套foreach并行循环后,allresults_skew仍全为NA,仅返回少量零散值。不确定两个foreach循环的.combine参数该选'c'、'rbind'还是'cbind',求修改指导。


原嵌套for循环代码

library(sn)
library(mnormt) 
library(mokken)
library(polycor)
library(foreach)
library(parallel)

data("DS14")
data<-DS14[,3:5] # 测试仅用3个变量

source("C:/Users/.../code to apply function fit_skewnorm (Kolbe et al., 2021).R")
# Kolbe et al. 参考文献

allresults_skew <- replicate(ncol(data)-1, matrix(NA,ncol(data),9), simplify = FALSE)
for(p in 1:ncol(data)){
  for(q in 2:ncol(data)){
    if(q<=p){
      next}
    tryCatch({ # 出错时继续循环
      obsn = table(data[,p], data[,q])
      ncats1 = nrow(obsn)
      ncats2 = ncol(obsn)
      ntot = sum(obsn)
      obsp = obsn/ntot
      proportions2 = matrix(colSums(obsp), 1, ncats2)
      proportions1 = matrix(rowSums(obsp), ncats1 , 1)
      premultiplier = matrix(0, ncats1, ncats1)
      for(l in 1:ncats1)for(m in 1:l)premultiplier[l,m] = 1
      postmultiplier = matrix(0, ncats2, ncats2)
      for(l in 1:ncats2)for(m in l:ncats2)postmultiplier[l,m] = 1
      cumulprops2 = proportions2 %*% postmultiplier
      cumulprops1 = premultiplier %*% proportions1
      nthresholds1 = ncats1 - 1
      nthresholds2 = ncats2 - 1
      thresholds1 = matrix(0, 1, nthresholds1)
      for(l in 1:nthresholds1)thresholds1[l] = qnorm(cumulprops1[l])
      thresholds2 = matrix(0, 1, nthresholds2)
      for(l in 1:nthresholds2)thresholds2[l] = qnorm(cumulprops2[l])
      pcorr = polycor::polychor(obsn)
      results_fit = fit_skewnorm(c("th1" = thresholds1, "th2" = thresholds2, "corr" = pcorr, "alpha" = c(2 ,2)))
      allresults_skew[[p]][q,1] <- p
      allresults_skew[[p]][q,2] <- q
      allresults_skew[[p]][q,3] <- results_fit[,1]
      allresults_skew[[p]][q,4] <- results_fit[,2]
      allresults_skew[[p]][q,5] <- results_fit[,3]
      allresults_skew[[p]][q,6] <- results_fit[,4]
      allresults_skew[[p]][q,7] <- results_fit[,5]
      allresults_skew[[p]][q,8] <- results_fit[,6]
      allresults_skew[[p]][q,9] <- results_fit[,7]
    }, error=function(e){cat("ERROR :",conditionMessage(e), "\n")}) # tryCatch结束
  }
}

原for循环运行结果

[[1]]
     [,1] [,2]     [,3] [,4]              [,5]      [,6] [,7]      [,8]      [,9]
[1,]   NA   NA       NA   NA                NA        NA   NA        NA        NA
[2,]    1    2 19.97874   13 0.095741675130554 0.2705112    0 1.4656923 0.7528304
[3,]    1    3 65.49704   13 0.000000005354567 0.8426818    0 0.2512463 2.2963329

[[2]]
     [,1] [,2]     [,3] [,4]        [,5]      [,6] [,7]      [,8]      [,9]
[1,]   NA   NA       NA   NA          NA        NA   NA        NA        NA
[2,]   NA   NA       NA   NA          NA        NA   NA        NA        NA
[3,]    2    3 31.14632   13 0.003209404 0.2753952    0 0.7247398 0.5957852

错误的嵌套foreach并行循环代码

allresults_skew <- replicate(ncol(data)-1, matrix(NA,ncol(data),9), simplify = FALSE)
no_cores <- detectCores(logical = TRUE)
cl <- makeCluster(no_cores-1)
registerDoParallel(cl)
getDoParWorkers()
foreach(i = 1:ncol(data),.combine = 'cbind') %:% 
  foreach(j = 2:ncol(data), .combine = 'rbind') %dopar% {
    if(j<=i){
      return(NA)}
    tryCatch({ # 出错时继续循环
      #progress(i, ncol(data)-1)
      obsn = table(data[,i], data[,j])
      ncats1 = nrow(obsn)
      ncats2 = ncol(obsn)
      ntot = sum(obsn)
      obsp = obsn/ntot
      proportions2 = matrix(colSums(obsp), 1, ncats2)
      proportions1 = matrix(rowSums(obsp), ncats1 , 1)
      premultiplier = matrix(0, ncats1, ncats1)
      for(l in 1:ncats1)for(m in 1:l)premultiplier[l,m] = 1
      postmultiplier = matrix(0, ncats2, ncats2)
      for(l in 1:ncats2)for(m in l:ncats2)postmultiplier[l,m] = 1
      cumulprops2 = proportions2 %*% postmultiplier
      cumulprops1 = premultiplier %*% proportions1
      nthresholds1 = ncats1 - 1
      nthresholds2 = ncats2 - 1
      thresholds1 = matrix(0, 1, nthresholds1)
      for(l in 1:nthresholds1)thresholds1[l] = qnorm(cumulprops1[l])
      thresholds2 = matrix(0, 1, nthresholds2)
      for(l in 1:nthresholds2)thresholds2[l] = qnorm(cumulprops2[l])
      pcorr = polycor::polychor(obsn)
      results_fit = fit_skewnorm(c("th1" = thresholds1, "th2" = thresholds2, "corr" = pcorr, "alpha" = c(2 ,2)))
      allresults_skew[[i]][j,1] <- i
      allresults_skew[[i]][j,2] <- j
      allresults_skew[[i]][j,3] <- results_fit[,1]
      allresults_skew[[i]][j,4] <- results_fit[,2]
      allresults_skew[[i]][j,5] <- results_fit[,3]
      allresults_skew[[i]][j,6] <- results_fit[,4]
      allresults_skew[[i]][j,7] <- results_fit[,5]
      allresults_skew[[i]][j,8] <- results_fit[,6]
      allresults_skew[[i]][j,9] <- results_fit[,7]
    }, error=function(e){cat("ERROR :",conditionMessage(e), "\n")}) # tryCatch结束
    NULL
    }
stopCluster(cl)

错误代码运行结果

返回的零散值:

[,1]      [,2] [,3]
result.1 0.7528304        NA   NA
result.2 2.2963329 0.5957852   NA

allresults_skew仍全为NA:

[[1]]
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,]   NA   NA   NA   NA   NA   NA   NA   NA   NA
[2,]   NA   NA   NA   NA   NA   NA   NA   NA   NA
[3,]   NA   NA   NA   NA   NA   NA   NA   NA   NA

[[2]]
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
[1,]   NA   NA   NA   NA   NA   NA   NA   NA   NA
[2,]   NA   NA   NA   NA   NA   NA   NA   NA   NA
[3,]   NA   NA   NA   NA   NA   NA   NA   NA   NA

问题原因与解决方案

核心问题

  1. 并行环境无法修改主环境变量:foreach并行子进程有独立内存空间,直接修改主环境的allresults_skew只会修改副本,主环境变量不会更新。
  2. .combine参数与返回值不匹配:原代码用cbind/rbind合并,但最后返回NULL,导致有效结果丢失;return(NA)会引入无效值干扰结果结构。

修改后的代码

library(sn)
library(mnormt) 
library(mokken)
library(polycor)
library(foreach)
library(parallel)
library(doParallel)

data("DS14")
data <- DS14[,3:5] # 测试仅用3个变量

source("C:/Users/.../code to apply function fit_skewnorm (Kolbe et al., 2021).R")

# 初始化结果结构模板
result_template <- replicate(ncol(data)-1, matrix(NA,ncol(data),9), simplify = FALSE)

no_cores <- detectCores(logical = TRUE)
cl <- makeCluster(no_cores-1)
registerDoParallel(cl)

# 嵌套foreach,收集所有有效结果记录
all_records <- foreach(i = 1:ncol(data), .combine = 'c') %:% 
  foreach(j = 2:ncol(data), .combine = 'c') %dopar% {
    if(j <= i){
      return(NULL) # 跳过无效组合,返回NULL不参与合并
    }
    tryCatch({
      obsn = table(data[,i], data[,j])
      ncats1 = nrow(obsn)
      ncats2 = ncol(obsn)
      ntot = sum(obsn)
      obsp = obsn/ntot
      proportions2 = matrix(colSums(obsp), 1, ncats2)
      proportions1 = matrix(rowSums(obsp), ncats1 , 1)
      premultiplier = matrix(0, ncats1, ncats1)
      for(l in 1:ncats1)for(m in 1:l)premultiplier[l,m] = 1
      postmultiplier = matrix(0, ncats2, ncats2)
      for(l in 1:ncats2)for(m in l:ncats2)postmultiplier[l,m] = 1
      cumulprops2 = proportions2 %*% postmultiplier
      cumulprops1 = premultiplier %*% proportions1
      nthresholds1 = ncats1 - 1
      nthresholds2 = ncats2 - 1
      thresholds1 = matrix(0, 1, nthresholds1)
      for(l in 1:nthresholds1)thresholds1[l] = qnorm(cumulprops1[l])
      thresholds2 = matrix(0, 1, nthresholds2)
      for(l in 1:nthresholds2)thresholds2[l] = qnorm(cumulprops2[l])
      pcorr = polycor::polychor(obsn)
      results_fit = fit_skewnorm(c("th1" = thresholds1, "th2" = thresholds2, "corr" = pcorr, "alpha" = c(2 ,2)))
      
      # 返回包含位置信息和拟合结果的记录
      list(
        i = i,
        j = j,
        values = c(i, j, results_fit[,1], results_fit[,2], results_fit[,3], results_fit[,4], results_fit[,5], results_fit[,6], results_fit[,7])
      )
    }, error=function(e){
      cat("ERROR :",conditionMessage(e), "\n")
      return(NULL) # 出错时返回NULL,不影响合并
    })
  }

stopCluster(cl)

# 将收集到的记录填充到结果结构中
allresults_skew <- result_template
for(record in all_records){
  if(!is.null(record)){
    allresults_skew[[record$i]][record$j,] <- record$values
  }
}

# 查看结果
allresults_skew

修改说明

  1. 避免直接修改主环境变量:每个并行任务返回独立的结果记录(含位置i,j和对应值),而非直接修改主环境的allresults_skew。
  2. 调整.combine参数:内外层foreach都用.combine='c',将所有有效记录合并为一个列表,方便后续统一处理。
  3. 优化无效组合处理:j<=i时返回NULL,不会被合并到结果列表,避免无效值干扰。
  4. 统一结果填充:先收集所有有效结果,再批量填充到初始化的结果结构中,确保与原for循环输出结构一致。

内容的提问来源于stack exchange,提问作者Stanleee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 21:20:33