【问题标题】:How to dynamically use lapply in data.table?如何在 data.table 中动态使用 lapply?
【发布时间】:2017-11-17 08:46:17
【问题描述】:

我有一个看起来像

的数据集
set.seed(18)
library(data.table)
site1 <- data.table(id = 1:10, A = c(sample(c(NA, letters[1:10]),10)), 
                    B = sample(c(NA, LETTERS[1:7]), 10, replace = T),
                    C = sample(c(NA, 1:4), 10, replace = T))

site2 <- data.table(id = c(1:4, sample(5:15, 6)), 
                    A = c(NA, NA, NA, sample(letters, 1), NA, NA, NA, sample(letters, 1), NA, NA), 
                    B = sample(LETTERS, 10), d = sample(1:5, replace = T))

还有一个看起来像

的函数
col.smash <- function(a, b, linkvars){
  require(data.table)
  
  ##### CONVERT TO DATA.TABLES FOR EASIER USE, AND MERGE
  if(dim(a)[1] <= dim(b)[1]){
    c <- data.table(a); setkeyv(c, linkvars)
    d <- data.table(b); setkeyv(d, linkvars)
  } else {
    c <- data.table(b); setkeyv(c, linkvars)
    d <- data.table(a); setkeyv(d, linkvars)
  }
 
  k <- c[d]
  
  rep.list<- names(a)[names(a) %in% names(b) & !(names(a) %in% linkvars)]
  i.combo <- paste0("i.",rep.list)

  f <- k[ , (rep.list) := lapply(.SD, function(x){ifelse(is.na(x), 
                                                   get("i.", names(x)), x)}), 
          .SDcols = rep.list]
  return(f)
  }

此函数的目标是查看site1site2 中都有哪些变量,如果其中有“NA”,比如说site1$A,将其替换为site2$A 中的相应值。在site2 上存在site1 的层次结构,这就是ifelse 语句只检查一个带有“NA”的变量的原因。

lapply 函数出现错误,因为第一个 ifelse 结果 (get("i.",names(x))) 在条件无法正常工作之后。这样做时,我收到以下错误:

Error in as.environment(pos) : using 'as.environment(NULL)' is defunct

我不明白。理想情况下,我会得到一个data.table,其中所有值在site1site2 中,变量为ABCD,而不是i.Ai.B这样的,

    id  A  B  C  d
 1:  1  i  E NA  4
 2:  2  g  F NA  4
 3:  3  h NA  4  1
 4:  4  x  B  4  2
 5:  5  j  G NA  NA
 6:  6  c NA  3  4
 7:  7  a  D  2  NA
 8:  8  b NA  2  NA
 9:  9  d  G  1  4
10: 10  f NA  1  NA
11: 12 NA  V NA  2
12: 13  n  J NA  1
13: 14 NA  T NA  1
14: 15 NA  X NA  1

所以我认为我真的有两个问题。第一个是错误,第二个是我没有在我的函数中获取k 中的所有行。他们似乎没有关系。

感谢任何帮助。

此外,谁能够找出 令人难以置信 col.smash 参考的人也可以加分。

【问题讨论】:

  • 如果您通过 rbind-ing site1site2 在彼此下方创建一个长 data.table,则可以将其作为 by= 组中的聚合操作来执行。
  • 澄清一下,您说的是完整的列,对吧?措辞如果有一个“NA”,比如说site1$A,用site2$A中的相应值替换它有点不幸,因为它暗示你要求一行明智的替换。但在这种情况下,预期结果将在B 列的第 3 行显示“C”,例如
  • @UweBlock 我不明白你的问题。请澄清

标签: r data.table apply


【解决方案1】:

此函数的目标是查看site1site2 中都有哪些变量,如果其中有“NA”,比如site1$A,则将其替换为site2$A 中的相应值。 site1site2 有一个层次结构

输出可以是这样的

g <- function(d1, d2, byvars){
  D = funion(d1[, ..byvars], d2[, ..byvars])

  d2vars = setdiff(names(d2), byvars)
  D[d2, on=byvars, (d2vars) := mget(sprintf("i.%s", d2vars))]

  d1vars = setdiff(names(d1), byvars)
  D[d1, on=byvars, (d1vars) := mget(sprintf("i.%s", d1vars))]  

  setcolorder(D, c(byvars, d1vars, setdiff(d2vars, d1vars)))
  setorderv(D, byvars)[]
}

g(site1, site2, "id")

给了

    id  A  B  C  d
 1:  1  i  E NA  4
 2:  2  g  F NA  4
 3:  3  h NA  4  1
 4:  4 NA  B  4  2
 5:  5  j  G NA NA
 6:  6  c NA  3  4
 7:  7  a  D  2 NA
 8:  8  b NA  2 NA
 9:  9  d  G  1  4
10: 10  f NA  1 NA
11: 12 NA  V NA  2
12: 13  n  J NA  1
13: 14 NA  T NA  1
14: 15 NA  X NA  1

它是如何工作的

byvars 参数允许列名向量。

相当新的.. 语法允许引用存储在data.table 之外的列的索引。我查看了常见问题解答和?data.table,但找不到任何文档。现在是the first changelog item in 1.10.2 at least

为了给出“site1 在site2 上的层次结构”,我们先从site2 添加,然后从site1 添加,所以它得到最后的编辑。

funion 的使用假定每个表中没有重复项。如果有,则需要更复杂的方法来完成该步骤,可能类似于

D = rbind(d1[, ..byvars], d2[,..byvars][!d1, on=byvars])

【讨论】:

  • (我不了解 col.smash 参考,也不了解相关功能,因此无法真正评论为什么它不起作用。)
  • @akrun 是的,有 fsetdiff。你觉得这里适合哪里?我正在考虑如何使用它,但后来又开始使用 funion。
  • 这是一个 hulk-smash 参考。但谢谢你。为什么在 byvars 之前有一个..?我不太明白
  • 另外,值得注意的是,这适用于多个byvars
猜你喜欢
  • 2020-03-12
  • 2015-11-23
  • 1970-01-01
  • 2020-01-21
  • 1970-01-01
  • 1970-01-01
  • 2018-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多