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
问题原因与解决方案
核心问题
- 并行环境无法修改主环境变量:foreach并行子进程有独立内存空间,直接修改主环境的
allresults_skew只会修改副本,主环境变量不会更新。 .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
修改说明
- 避免直接修改主环境变量:每个并行任务返回独立的结果记录(含位置
i,j和对应值),而非直接修改主环境的allresults_skew。 - 调整
.combine参数:内外层foreach都用.combine='c',将所有有效记录合并为一个列表,方便后续统一处理。 - 优化无效组合处理:
j<=i时返回NULL,不会被合并到结果列表,避免无效值干扰。 - 统一结果填充:先收集所有有效结果,再批量填充到初始化的结果结构中,确保与原for循环输出结构一致。
内容的提问来源于stack exchange,提问作者Stanleee
相关产品推荐
相关产品推荐

