【问题标题】:Replace Inf/-Inf values from vector of variable names, with values from similarly named vector of variables (substr/grep/gsub)将来自变量名称向量的 Inf/-Inf 值替换为来自类似命名的变量向量 (substr/grep/gsub) 的值
【发布时间】:2018-10-15 18:09:01
【问题描述】:

我目前很难编写一些高效的代码。我有一个变量向量(med.vars),这些变量由年内全球中位数转换。有时全局中位数为 0,这会创建 Inf/-Inf 值,我想将其替换为预转换的变量值 (vars)。我无法弄清楚如何使用某种类型的 data.table 'dat[,:=lapply(.SD), .SDcols=med.vars] 函数或带有 get()noquotes() 等的 for 循环来有效地做到这一点。

dat<-data.table(v1=c(2,10,7),v2=c(5,6,5),v3=c(10,15,20),v1.med=c(1,Inf,5),v2.med=c(5,6,5),v3.med=c(-Inf,2,3))
vars<-c("v1","v2","v3")
med.vars<-c("v1.med","v2.med","v3.med")

   v1 v2 v3 v1.med v2.med v3.med
1:  2  5 10      1      5   -Inf
2: 10  6 15    Inf      6      2
3:  7  5 20      5      5      3

实际上,这些向量是我从 names(dat)grep() 中提取的 50 多个变量,并使用 gsub(".med","",med.vars) 创建第二个预转换变量名称的向量。

我想高效地执行

dat[v1.med==Inf | v1.med==-Inf, v1.med:=v1]
dat[v3.med==Inf | v3.med==-Inf, v3.med:=v3]

对于每个元素 med.vars[i] 及其对应的元素 vars[i] 使得生成的 data.table 为:

   v1 v2 v3 v1.med v2.med v3.med
1:  2  5 10      1      5    -10
2: 10  6 15     10      6      2
3:  7  5 20      5      5      3

感谢您的宝贵时间

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    OP 提到了效率,所以可能会改用长格式。那么就可以使用标准语法了:

    DT = melt(dat, meas=list(vars, med.vars), value.name=c("var", "med"))
    
    DT[!is.finite(med), med := sign(med)*var]
    
       variable var med
    1:        1   2   1
    2:        1  10  10
    3:        1   7   5
    4:        2   5   5
    5:        2   6   6
    6:        2   5   5
    7:        3  10 -10
    8:        3  15   2
    9:        3  20   3
    

    【讨论】:

      【解决方案2】:

      由于这些是对应的列,我们可以使用Map

      dat[, (med.vars) := Map(function(x, y) ifelse(is.finite(y), y,
                  x * sign(y)), .SD[, vars, with = FALSE], 
                    .SD[, med.vars, with = FALSE])]
      
      dat
      #   v1 v2 v3 v1.med v2.med v3.med
      #1:  2  5 10      1      5    -10
      #2: 10  6 15     10      6      2
      #3:  7  5 20      5      5      3
      

      或者另一个选项是set,通过使用for 循环遍历列

      for(j in seq_along(vars)) {
        i1 <- !is.finite(dat[[med.vars[j]]])
        v1 <- dat[[vars[j]]]
        v2 <- dat[[med.vars[j]]]
      
        set(dat, i = which(i1), j = med.vars[j], value = sign(v2[i1]) * v1[i1])
      
       }
      

      这也可以在base R 中完成(在data.frame 上)

      i1 <- !sapply(dat[med.vars], is.finite)
      dat[med.vars][i1] <- dat[vars][i1] * sign(dat[med.vars][i1])
      

      【讨论】:

      • 这在我的测试框架上有效,但你能解释一下警告:警告消息:1:在[.data.table(.SD, , ..vars) 中:'vars' 和 '.. vars' 存在于调用范围内。为清楚起见,请删除调用范围中的“..vars”变量。 2:在[.data.table(.SD, , ..med.vars) 中:“med.vars”和“..med.vars”都存在于调用范围内。为了清楚起见,请删除调用范围中的“..med.vars”变量。
      • @Josh 这可能是由于.. 替换为.SD[, vars, with = FALSE].SD[, med.vars, with = FALSE],更新了代码
      • 感谢您消除了警告。我将测试完整的 data.table 并证明答案。
      • @user5249203 帖子里的功能不清楚Bob("id1")
      • 你能对帖子发表评论吗,我不想向 josh wall 发送垃圾邮件。谢谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-14
      • 2023-04-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多