【问题标题】:Compare two rows of a data.table and show only columns with differences [duplicate]比较data.table的两行并仅显示有差异的列[重复]
【发布时间】:2019-07-03 06:57:48
【问题描述】:

我得到了一个大的 data.table,其中包含不同类型的列:例如数字或字符。例如

 data.table(name=c("A","A"),val1=c(1,2),val2=c(3,3),cat=c("u","v"))

       name val1 val2 cat
   1:    A    1    3   u
   2:    A    2    3   v

作为结果,我想要一个只有列的 data.table,其中两行之间的条目不同:

 data.table(val1=c(1,2),cat=c("u","v"))

       val1 cat
   1:    1   u
   2:    2   v

【问题讨论】:

    标签: r data.table compare


    【解决方案1】:

    使用基础 R,您可以这样做:

    library(data.table)
    
    dt <- data.table(name=c("A","A"),val1=c(1,2),val2=c(3,3),cat=c("u","v"))
    
    Filter(function(x) length(unique(x)) > 1, dt)   
    #>    val1 cat
    #> 1:    1   u
    #> 2:    2   v
    

    【讨论】:

    • 或:Filter(function(x) uniqueN(x) &gt; 1, dt)
    • 这个答案和这个评论是很好的解决方案,因为如果一行是 NA 并且另一行有值,它们也会捕获。
    【解决方案2】:

    您可以检查列中是否只有一个值,并仅返回具有多个值的值:

    mydt <- data.table(name=c("A", "A"), val1=c(1, 2), val2=c(3, 3), cat=c("u", "v"))
    mydt_red <- mydt[, lapply(.SD, function(x) if(length(unique(x))!=1) x else NULL)]
    mydt_red
    #   val1 cat
    #1:    1   u
    #2:    2   v
    

    编辑
    正如@kath 所提到的,获得结果的更有效方法是使用minmax 函数并将它们与Filter 结合使用:

    mydt_red2 <- Filter(function(x) min(x)!=max(x), mydt)
    

    一些基本的基准测试

    # Data (inspired by https://stackoverflow.com/a/35746513/680068)
    nrow=10000
    ncol=10000
    mydt <- data.frame(matrix(sample(1:(ncol*nrow),ncol*nrow,replace = FALSE), ncol = ncol))
    setDT(mydt)
    
    system.time(mydt_redUni <- mydt[, lapply(.SD, function(x) if(length(unique(x))>1) x else NULL)])
    #utilisateur     système      écoulé 
    #       2.31        0.52        2.83 
    system.time(mydt_redFilt <- Filter(function(x) length(unique(x)) > 1, mydt))
    #utilisateur     système      écoulé 
    #     1.65        0.22        1.87 
    system.time(mydt_redSort <- mydt[, lapply(.SD, function(x) {xs <- sort(x); if(xs[1]!=tail(xs, 1)) x else NULL})])
    #utilisateur     système      écoulé 
    #    3.87        0.00        3.87 
    system.time(mydt_redMinMax <- mydt[, lapply(.SD, function(x) if(min(x)!=max(x)) x else NULL)])
    #utilisateur     système      écoulé 
    #    0.67        0.00        0.67 
    system.time(mydt_redFiltminmax <- Filter(function(x) min(x)!=max(x), mydt))
    #utilisateur     système      écoulé 
    #    0.13        0.01        0.14 
    system.time(mydt_redSotos <- Filter(function(i)var(as.numeric(as.factor(i))) != 0, mydt))
    #utilisateur     système      écoulé
    #  100.76        0.05      100.84
    

    【讨论】:

    • 或者甚至稍微快一点:Filter(function(x) any(x != x[1]), mydt)
    【解决方案3】:

    这里有一个有趣的想法,适合数学迷。如果值相同,则方差将为 0。因此,在该假设下,我们可以这样做(感谢 @Joris Chau 的 Filter 方法)

    Filter(function(i)var(as.numeric(as.factor(i))) != 0, dt)
    #   val1 cat
    #1:    1   u
    #2:    2   v
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-10
    • 2017-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多