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

data.table中两种自定义函数行运算结果为何不一致?

问题:sapply逐行调用函数与data.table批量赋值结果不一致

问题描述

通过sapply逐行调用自定义函数Function得到Test1,再用data.table的赋值语法生成Data$Test1,但二者结果不一致,代码如下:

library("data.table")

Data <- fread("
V1 V2 V3
14   24.70762         17.3329292
8   25.01303         19.7530632
1   18.87427         -0.7832386
14   23.43488         14.9795652
14   24.43762         20.7145533
8   29.85930          3.7763770
17   27.66289          1.8315841
1   21.28808         79.7883210
1   24.55836         70.0779117
1   13.01046         27.3039891")

Function <- function(v1, v2, v3){
    
    ff <- function(wt){
            mod2 <- 1.399666
            j2 <- -0.4142602
            alpha <- 0.895474
            
            X_mu <- ifelse(wt >= j2*100,
                           wt - j2*100, 
                           0)
            mia <- X_mu/(alpha*100)
            weibull <- mod2/(alpha*100) * mia^(mod2 - 1) *
                exp(-mia^mod2)    
            return(weibull)
        }        
    my.f.si <- function(wt){
            epsilon = 0.008213571
            
            fnl <- (ff(wt) / epsilon)
            return(fnl)
        }

    SiS <- lapply(1:5, function(XX){
        pot = c(0.1012141, 0.1012141, 0.1410539,
                0.1581489, 0.1775243)
        theta0 = c(-3.651407, -3.651407, -3.804682,
                   -3.607503, -3.603890)
        theta1 = 0.2181257
        
        Pot <- pot[XX]
        The0 <- theta0[XX]
        The1 <- theta1
        
        Si <- 6 + (Pot*100 - 6) *
            my.f.si(wt = v3) *
            ((1 + exp(-(The0 + The1 * v2)))^-1)
        
        return(Si)
    })
    SiS <- do.call("c", SiS)
    
    MiN <- abs((SiS - v1) / v1)
  
    ## return(MiN)
    GetQ <- which(MiN == min(MiN))
    LengTh <- length(GetQ)
    return(LengTh)
}

##################################
Test1 <- sapply(1:nrow(Data), function(T){
    Function(v1 = Data[T, V1],
             v2 = Data[T, V2],
             v3 = Data[T, V2])})

##################################
Data[, Test1 := Function(v1 = V1,
                         v2 = V2,
                         v3 = V2)]

##################################
Test1
Data$Test1

原因分析

核心差异在于函数的输入类型:

  • sapply是逐行调用,每次传入Function的v1、v2、v3都是单个标量值,函数内部的计算仅针对当前行的单个值。
  • data.table的赋值语法是把整列向量直接传入Function,此时函数内部逻辑完全改变:
    1. SiS的每个元素会生成长度等于输入向量长度的结果,最终SiS是一个长度为5*nrow(Data)的长向量。
    2. MiN <- abs((SiS - v1)/v1)中,v1会被循环补齐到5*nrow(Data)长度,计算的是全局所有行的差值,而非逐行独立计算的差值。
    3. min(MiN)取的是全局最小值,which(MiN == min(MiN))会找出所有全局最小的位置,最终返回的LengTh是全局符合条件的数量,而非逐行的结果。

解决方法

要让两种调用方式结果一致,需要让函数支持逐行处理向量输入,或者在data.table中显式逐行调用:

方法1:修改函数为向量化版本

用mapply封装原函数,让每个输入元素独立计算:

Function_vec <- function(v1, v2, v3){
  mapply(function(v1_i, v2_i, v3_i){
    ff <- function(wt){
      mod2 <- 1.399666
      j2 <- -0.4142602
      alpha <- 0.895474
      
      X_mu <- ifelse(wt >= j2*100,
                     wt - j2*100, 
                     0)
      mia <- X_mu/(alpha*100)
      weibull <- mod2/(alpha*100) * mia^(mod2 - 1) *
        exp(-mia^mod2)    
      return(weibull)
    }        
    my.f.si <- function(wt){
      epsilon = 0.008213571
      fnl <- (ff(wt) / epsilon)
      return(fnl)
    }
    
    SiS <- lapply(1:5, function(XX){
      pot = c(0.1012141, 0.1012141, 0.1410539,
              0.1581489, 0.1775243)
      theta0 = c(-3.651407, -3.651407, -3.804682,
                 -3.607503, -3.603890)
      theta1 = 0.2181257
      
      Pot <- pot[XX]
      The0 <- theta0[XX]
      The1 <- theta1
      
      Si <- 6 + (Pot*100 - 6) *
        my.f.si(wt = v3_i) *
        ((1 + exp(-(The0 + The1 * v2_i)))^-1)
      
      return(Si)
    })
    SiS <- do.call("c", SiS)
    
    MiN <- abs((SiS - v1_i) / v1_i)
    
    GetQ <- which(MiN == min(MiN))
    LengTh <- length(GetQ)
    return(LengTh)
  }, v1, v2, v3)
}

调用方式:

Data[, Test1 := Function_vec(v1 = V1, v2 = V2, v3 = V2)]

方法2:在data.table中逐行调用

利用by = .I实现逐行处理,每次传入当前行的标量值:

Data[, Test1 := Function(v1 = V1, v2 = V2, v3 = V2), by = .I]

验证

运行修改后的代码,Test1和Data$Test1的结果会完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 14:20:36