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

使用list_rbind()合并数据时遇行数不匹配错误求助

并行化代码map部分报错排查

问题背景

并行化后的代码在map环节出现行数不匹配错误,但单独运行map内部的串行逻辑完全正常,输出符合预期。

并行报错代码

library(terra)
library(stringr)
library(dplyr)
library(purrr)
library(furrr)

g <- terra::vect("prueba.SHP")
x <- list.files(pattern="\\.tif$")

irr <- function(x) {
  
  ra <- rast(x)
  
  segments <- cut(seq_len(nrow(g)), parallel::detectCores())
  slevels <- levels(segments)
  
  l <- future_map(slevels, function(level) {
    
    rows_to_process <- which(segments == level)
    
    map(rows_to_process, function(i) {
    
      d <- terra::extract(ra, g[i], exact = TRUE)
      d <- na.omit(d) 
      
      if (nrow(d)!=0){
        
          d <- d %>% group_by(ID) %>% summarize(ss = sum(fraction * d[,2])) 
          d <- ((d$ss * 250 * 250) * 100) / g[i]$area_m2
          d <- data.frame("gage"=as.numeric(g[i]$GAGE_ID),"perc_irr"=d)
      
      } else {
        
          d <- data.frame("gage"=as.numeric(g[i]$GAGE_ID),"perc_irr"=0)
      }
      
      return(d)
      
      }) %>% list_rbind()
    
  })
  
  val <- list_rbind(l)
  write.csv(val,paste(str_sub(x,end=-5),".csv",sep=""))
  
}

for(tif_file in list.files(pattern="\\.tif$")) {
  irr(tif_file)
}

报错信息

Error in (function (... row.names = NULL check.rows = FALSE check.names = TRUE :
arguments imply differing number of rows: 1 0

串行正常代码

g <- terra::vect("prueba.SHP")
x <- list.files(pattern="\\.tif$")

for  (i in 1:nrow(g)) {
        
        ra <- rast(x[1])
        d <- terra::extract(ra, g[i], exact = TRUE)
        d <- na.omit(d) 
        
        if (nrow(d)!=0){
          
          d <- d %>% group_by(ID) %>% summarize(ss = sum(fraction * d[,2])) 
          d <- ((d$ss * 250 * 250) * 100) / g[i]$area_m2
          d <- data.frame("gage"=as.numeric(g[i]$GAGE_ID),"perc_irr"=d)
          
        } else {
          
          d <- data.frame("gage"=as.numeric(g[i]$GAGE_ID),"perc_irr"=0)
        }

    print(d)
}

串行输出示例

gage  perc_irr
1 1013500 0.0208757
     gage perc_irr
1 1015800        0
     gage perc_irr
1 1011000        0

原因分析

  1. 并行环境对象传递问题:future_map的子进程无法正确序列化访问外部对象g,导致部分循环中g[i]$area_m2或g[i]$GAGE_ID返回空值,生成行数异常的空数据框,合并时触发行数不匹配错误。
  2. 手动分段的空分组问题:用cut按核心数分段时,如果nrow(g)小于核心数,会出现空分组,对应的rows_to_process为空,map返回空列表,list_rbind生成0行数据框,后续合并时与正常1行数据框冲突。
  3. 缺少并行环境初始化:原代码未调用plan()初始化并行策略,furrr默认可能以串行模式运行,但分段逻辑依然存在空分组问题。

解决办法

修改后的并行代码

library(terra)
library(stringr)
library(dplyr)
library(purrr)
library(furrr)

# 初始化多会话并行环境
plan(multisession)

g <- terra::vect("prueba.SHP")
x <- list.files(pattern="\\.tif$")

irr <- function(x) {
  
  ra <- rast(x)
  
  # 直接并行遍历所有要素行,furrr自动处理负载均衡
  l <- future_map(seq_len(nrow(g)), function(i) {
    
    d <- terra::extract(ra, g[i], exact = TRUE)
    d <- na.omit(d) 
    
    if (nrow(d) != 0){
      d <- d %>% group_by(ID) %>% summarize(ss = sum(fraction * !!sym(names(d)[2]))) 
      # 使用sym避免直接引用d[,2]的列名问题
      d <- ((d$ss * 250 * 250) * 100) / g[i]$area_m2
      d <- data.frame(gage = as.numeric(g[i]$GAGE_ID), perc_irr = d)
    } else {
      d <- data.frame(gage = as.numeric(g[i]$GAGE_ID), perc_irr = 0)
    }
    
    return(d)
    
  }, .options = furrr_options(globals = list(g = g, ra = ra)))
  # 显式传递全局对象到子进程
  
  val <- list_rbind(l)
  write.csv(val, paste0(str_sub(x, end=-5), ".csv"), row.names = FALSE)
  
}

for(tif_file in list.files(pattern="\\.tif$")) {
  irr(tif_file)
}

关键修改点

  • 调用plan(multisession)初始化并行环境,确保furrr能正常启动子进程。
  • 移除手动分段逻辑,直接用future_map遍历所有要素行,由furrr自动分配任务到各个核心,避免空分组问题。
  • 使用.options = furrr_options(globals = list(g = g, ra = ra))显式传递g和ra到子进程,解决对象序列化问题。
  • 将d[,2]替换为!!sym(names(d)[2]),避免直接引用列索引可能导致的列名识别问题,提升代码鲁棒性。
  • 用paste0替代paste(..., sep=""),简化字符串拼接。

额外注意事项

  • 如果要素数量较少,并行可能比串行效率更低,此时可以切换为串行模式:plan(sequential)。
  • 运行完成后可以用plan(sequential)关闭并行环境,释放资源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 00:22:17