【问题标题】:R data.table apply function to all pair of columnsR data.table 将函数应用于所有列对
【发布时间】:2017-05-12 02:17:36
【问题描述】:

假设我有一个 data.table,例如:(或带有数字和 NA)

temp <- data.table(M=c(NA,T,T,F,F,F,NA,NA,F), 
                   P=c(T,T,T,F,F,F,NA,NA,NA), S=c(T,F,NA,T,F,NA,NA,NA,NA))

    M     P     S
   NA  TRUE  TRUE
 TRUE  TRUE FALSE
 TRUE  TRUE    NA
FALSE FALSE  TRUE
FALSE FALSE FALSE
FALSE FALSE    NA
   NA    NA    NA
   NA    NA    NA
FALSE    NA    NA

我想检查一个变量是否为 NA 是否意味着第二个变量的值也都是 NA。检查某些变量是否链接到其他变量。

例如,只要 P=NA,我们也有 S=NA。

此代码适用于两个单列:

temp[is.na(P),all(is.na(S))]

给出正确的

和

temp[is.na(S),all(is.na(P))]

给出 FALSE,因为第六行是 S=NA 但 P!=NA。

现在我的问题。 我想概括一下,检查我的 data.table 中的所有对并打印“链接”的对。
我宁愿只打印 TRUE 的结果,忽略 FALSE 的结果,因为我的真实 data.table 中的大多数对都不会链接,而且我有 550 个变量。

我试过这段代码:

temp[, lapply(.SD, function(x) temp[is.na(x), 
                 lapply(.SD, function(y)  all(is.na(y)) )]]

我收到此错误

错误:意外']' in:“temp[, lapply(.SD, function(x) temp[is.na(x), lapply(.SD, function(y) all(is.na(y)) )]]"

我可以尝试使用 for 循环,但我更喜欢典型的 data.table 语法。 欢迎提出任何建议。

我还想知道在嵌套 data.table 调用时如何引用两个不同的 .SD。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    对于成对组合,crossprod 似乎还很有用。

    我们只关心一个值是否为NA:

    NAtemp = is.na(temp)
    

    比较NAs的共存情况:

    crossprod(NAtemp)
    #  M P S
    #M 3 2 2
    #P 2 3 3
    #S 2 3 5
    

    每列有NA 的数量:

    colSums(NAtemp)
    #M P S 
    #3 3 5
    

    喜欢:

    ans = crossprod(NAtemp) == colSums(NAtemp)
    ans
    #      M     P     S
    #M  TRUE FALSE FALSE
    #P FALSE  TRUE  TRUE
    #S FALSE FALSE  TRUE
    

    并使用方便的as.data.frame.table进行格式化:

    subset(as.data.frame(as.table(ans)), Var1 != Var2)
    #  Var1 Var2  Freq
    #2    P    M FALSE
    #3    S    M FALSE
    #4    M    P FALSE
    #6    S    P FALSE
    #7    M    S FALSE
    #8    P    S  TRUE
    

    【讨论】:

    • 难道不能用 data.table 做这一切吗? (出于速度原因)
    • @skan :确实,所有这些矩阵运算都可能会耗尽内存,但在您的 550 列的情况下,我认为应该没有问题。或者,您可以尝试上述的稀疏替代方案——library(Matrix); sNAtemp = as(NAtemp, "sparseMatrix"); crossprod(sNAtemp) == colSums(sNAtemp)
    • @skan :如果我理解正确,假设temp$X = c(TRUE, TRUE, TRUE, NA, NA, FALSE, TRUE, FALSE, NA); temp$Y = c(FALSE, NA, NA, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE),您可以使用NAtemp = is.na(temp); crossprod(NAtemp[, c("M", "S", "X")], NAtemp[, c("P", "Y")]) 并与colSums(NAtemp[, c("M", "S", "X")]) 进行比较
    • @skan :对于列中没有 NA 的情况,您是对的;我错过了。关于您需要的组合,是否总是有两组或更多组,您需要对列组进行成对比较? (我假设ccc 是mycomb?)可能最快的方法是在将NAtemp 传递给crossprod/colSums 之前对其进行子集化。例如这里,我猜你可以使用spl = split(colnames(NAtemp), mycomb); crossprod(NAtemp[, spl[[1]]], NAtemp[, spl[[2]], drop = FALSE]) == colSums(NAtemp[, spl[[1]]]) 等。
    • @skan :我认为一个简单的is.na(temp[, vars_to_change]) = !temp[, vars_to_change] -其中vars_to_change 是一个包含用NA- 替换0 的列名的向量就足够了。 (不过,我认为前面的语法对“data.table”无效;它可能需要调整,或者,如果它只是一个 TRUE/FALSE/NA 结构,您可以将数据强制转换为“矩阵”)跨度>
    【解决方案2】:

    我们可以试试combn

    unlist(combn(names(temp), 2, FUN = function(nm)
      list(setNames(temp[is.na(get(nm[1])), all(is.na(get(nm[2])))], paste(nm, collapse="-"))))) 
    #   M-P   M-S   P-S 
    # FALSE FALSE  TRUE 
    

    或者如果我们还需要所有的组合

    d1 <- CJ(names(temp), names(temp))[V1!=V2]
    d1[,  .(index=temp[is.na(get(V1)), all(is.na(get(V2)))]) , .(V1, V2)]
    #    V1 V2 index
    #1:  M  P FALSE
    #2:  M  S FALSE
    #3:  P  M FALSE
    #4:  P  S  TRUE
    #5:  S  M FALSE
    #6:  S  P FALSE
    

    【讨论】:

    • 您的解决方案非常紧凑并使用 data.table 但我不知道为什么当数据有很多列时(我的有 500 但即使只有 50 列你也可以看到)@alexis_laz 解决方案是订单速度更快。
    • 我认为你的第一个代码 combn(names(temp)) 也需要重复变量顺序。
    猜你喜欢
    • 2015-07-08
    • 2018-11-10
    • 1970-01-01
    • 2014-10-15
    • 1970-01-01
    • 1970-01-01
    • 2017-06-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多