【问题标题】:Reduce dataset based on value根据值减少数据集
【发布时间】:2012-12-09 22:15:46
【问题描述】:

我有一个数据集

dtf<-data.frame(id=c("A","A","A","A","B","B","B","B"), value=c(2,4,6,8,4,6,8,10))

对于每个 id,值按升序排序

我想减少 dtf 以仅包含值超过指定限制的每个 id 的第一行。每个id 只有一行,这应该是value 首先超过指定限制的那一行。

对于这个例子和5的限制,dtf应该减少到:

A 6
B 6

这是一个很好的方法吗?

非常感谢

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

    可以使用aggregate:

    dtf<-data.frame(id=c("A","A","A","A","B","B","B","B"), value=c(2,4,6,8,4,6,8,10))
    
    limit <- 5
    
    aggregate(value ~ id, dtf, function(x) x[x > limit][1])
    

    结果:

      id value
    1  A     6
    2  B     6
    

    更新:多列的解决方案:

    一个示例数据框,dtf2

    dtf2 <- data.frame(id=c("A","A","A","A","B","B","B","B"), 
                       value=c(2,4,6,8,4,6,8,10),
                       col3 = letters[1:8],
                       col4 = 1:8)
    

    一个解决方案包括ave:

    with(dtf2, dtf2[ave(value, id, FUN = function(x) cumsum(x > limit)) == 1, ])
    

    结果:

      id value col3 col4
    3  A     6    c    3
    6  B     6    f    6
    

    【讨论】:

    • 此方案不依赖于顺序。不错。
    • 然而,此解决方案会删除 dtf 数据框中潜在的其他变量。
    • @SvenHohenstein,随着您的更新,最好考虑with(dtf2, dtf2[value == ave(value, id, FUN = function(x) min(x[x &gt; 5])), ]) 之类的东西,以防值列实际上 排序。
    【解决方案2】:

    这取决于您的 data.frame 被排序:

    threshold <- 5
    foo <- dtf[dtf$value>=threshold,]
    foo[c(1,which(diff(as.numeric(as.factor(foo$id)))>0)),]
    

    【讨论】:

      【解决方案3】:

      aggregate 的另一种方法:

      > aggregate(value~id, dtf[dtf[,'value'] > 5,], min)
        id value
      1  A     6
      2  B     6
      

      这取决于被排序的元素,因为那将是min返回的条目

      【讨论】:

        【解决方案4】:

        这是一个使用data.table 的“不错”选项:

        library(data.table)
        DT <- data.table(dft, key = "id")
        
        DT[value > 5, head(.SD, 1), by = key(DT)]
        #    id value
        # 1:  A     6
        # 2:  B     6
        

        并且,本着分享的精神,一个使用 sqldf 的选项可能会更好,这取决于您是否对 SQL 感觉更舒服。

        sqldf("select id, min(value) as value from dtf where value > 5 group by id")
        #   id value
        # 1  A     6
        # 2  B     6
        

        更新:源数据无序,data.frame 包含多列

        根据您对某些答案的 cmets,您的“值”列可能不像您的示例中那样排序,并且您的 data.frame 中还有其他列.

        对于这些场景,这里有两种选择,一种是data.table,我觉得它最容易阅读,而且很可能是最快的,另一种是这种任务通常需要的典型“拆分-应用-组合”方法.

        首先,一些示例数据:

        dtf2 <- data.frame(id = c("A","A","A","A","B","B","B","B"),
                           value = c(6,4,2,8,4,10,8,6),
                           col3 = letters[1:8],
                           col4 = 1:8)
        dtf2 # Notice that the value column is not ordered
        #   id value col3 col4
        # 1  A     6    a    1
        # 2  A     4    b    2
        # 3  A     2    c    3
        # 4  A     8    d    4
        # 5  B     4    e    5
        # 6  B    10    f    6
        # 7  B     8    g    7
        # 8  B     6    h    8
        

        二,data.table 方法:

        library(data.table)
        DT <- data.table(dtf2)
        DT # Verify that the data are not ordered
        #    id value col3 col4
        # 1:  A     6    a    1
        # 2:  A     4    b    2
        # 3:  A     2    c    3
        # 4:  A     8    d    4
        # 5:  B     4    e    5
        # 6:  B    10    f    6
        # 7:  B     8    g    7
        # 8:  B     6    h    8
        DT[order(value)][value > 5, head(.SD, 1), by = "id"]
        #    id value col3 col4
        # 1:  A     6    a    1
        # 2:  B     6    h    8
        

        二、base R 常用的“split-apply-combine”方式:

        do.call(rbind,
                lapply(split(dtf2, dtf2$id), 
                       function(x) x[x$value > 5, ][which.min(x$value[x$value > 5]), ]))
        #   id value col3 col4
        # A  A     6    a    1
        # B  B     6    h    8
        

        【讨论】:

        • +1 顺便说一句,您不需要设置密钥。 Ad hoc by 通常就足够了,并且具有维护组顺序的优势。
        • 这个解决方案是否依赖于被排序的 dtf data.frame?此解决方案保留了 dtf 数据帧的潜在其他变量
        • @ECII,我相信确实如此。有几种方法可以解决这个问题。一种是在创建数据表时设置key为"id,value",然后运行DT[value &gt; 5, head(.SD, 1), by = "id"];另一个是做类似DT[order(id, value)][value &gt; 5, head(.SD, 1), by = "id"]的事情。
        【解决方案5】:

        也可以,plyrhead 的替代方案:

        library(plyr)
        dtf<-data.frame(id=c("A","A","A","A","B","B","B","B"), value=c(2,4,6,8,4,6,8,10))
        limit <- 5
        result <- ddply(dtf, "id", function(x) head(x[x$value > limit ,],1) )
        
        
            > result
          id value
        1  A     6
        2  B     6
        

        【讨论】:

          猜你喜欢
          • 2017-08-25
          • 2018-04-15
          • 2019-04-02
          • 1970-01-01
          • 2020-06-27
          • 2021-07-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多