【问题标题】:Select highest values in a dataframe by group按组选择数据框中的最大值
【发布时间】:2018-08-17 07:19:03
【问题描述】:

我有以下df

dat <- data.frame(Cases = c("Student3","Student3","Student3","Student1","Student1",
"Student2","Student2","Student2","Student4"), Class = rep("Math", 9),
Scores = c(9,5,2,7,3,8,5,1,7), stringsAsFactors = F)


> dat
   Cases    Class   Scores
1 Student3  Math      9
2 Student3  Math      5
3 Student3  Math      2
4 Student1  Math      7
5 Student1  Math      3
6 Student2  Math      8
7 Student2  Math      5
8 Student2  Math      1
9 Student4  Math      7

另一方面,我有另一个包含以下信息的 df:

d <- data.frame(Cases = c("Student3", "Student1",
"Student2", "Student4"), Class = rep("Math", 4), stringsAsFactors = F)

    Cases  Class
1 Student3  Math
2 Student1  Math
3 Student2  Math
4 Student4  Math

有了这两个,我想为每个student提取最高的scores。所以我的输出看起来像这样:

> dat_output
    Cases  Class   Scores
1 Student3  Math      9
2 Student1  Math      7
3 Student2  Math      8
4 Student4  Math      7

我尝试使用merge,但它并没有只提取最高的scores

【问题讨论】:

  • @Tjebo 是的,还有很多其他帖子都带有“find max per group”,但这篇帖子有“过滤”步骤:只对同样在 d 数据框中的学生子集执行此操作。跨度>
  • @Tjebo 请仔细阅读问题,它不要求组中的最大值。
  • @RonakShah 这个标题跟我说的是另一种语言。

标签: r dataframe


【解决方案1】:

我们可以在d 中的每个Cases 上使用sapply,将dat 子集化为Cases 并获得max 分数。

sapply(d$Cases, function(x) max(dat$Scores[dat$Cases %in% x]))

#Student3 Student1 Student2 Student4 
#       9        7        8        7 

将结果作为data.frame

transform(d, Scores = sapply(d$Cases, function(x) 
                     max(dat$Scores[dat$Cases %in% x])))

#    Cases Class Scores
# Student3  Math      9 
# Student1  Math      7
# Student2  Math      8
# Student4  Math      7

注意 - 我假设您的 d

d <- data.frame(Cases = c("Student3", "Student1",
      "Student2", "Student4"), Class = rep("Math", 4), stringsAsFactors = F)

【讨论】:

  • tapply()也能做到
  • 在这种情况下,如何将结果转换为df
  • 有了更新的答案,我只得到scores 没有student#...你得到studentsscores
  • @Cahidora 这些实际上是行名,添加了一个带有transform 的选项,抱歉造成混淆。
  • @Cahidora 抱歉,我的脑子现在有点受阻,目前我想不出比cbind(d, t(sapply(d$Cases, function(x) { sub_df = dat[dat$Cases %in% x,]; inds = which.max(sub_df$Scores); c(sub_df$Scores[inds], sub_df$New[inds]) }))) 更好的方法,New 是您要添加的附加列。跨度>
【解决方案2】:

如果我是正确的,您不需要d,因为在d 中没有其他信息不在dat 中。

你可以这样做:

dat_output <- aggregate(Scores ~ Cases, dat, max)
dat_output

     Cases Scores
1 Student1      7
2 Student2      8
3 Student3      9
4 Student4      7

【讨论】:

  • d 中的某些条目可能在dat 中不存在。样本不一定代表实际数据。
【解决方案3】:

你也可以使用sqldf包如下:

sqldf("select max(Scores), Cases from dat JOIN d USING(Cases) group by Cases")

应用JOIN操作,group by casesselect max(Scores),Cases得到想要的输出:

   max(Scores)    Cases
1           7    Student1
2           8    Student2
3           9    Student3
4           7    Student4

【讨论】:

    【解决方案4】:

    使用dplyr,并考虑到您的d 包含来自您的dat 的学生子集的情况

    library(dplyr)
    inner_join(d, dat %>% group_by(Cases, Class) %>% summarize(Scores=max(Scores)))
    
    # Cases Class Scores
    #1 Student3  Math      9
    #2 Student1  Math      7
    #3 Student2  Math      8
    #4 Student4  Math      7
    

    如果顺序无关紧要,那么以下方法更有效:

    inner_join(dat, d) %>% group_by(Cases, Class) %>% summarize(Scores=max(Scores))
    # A tibble: 4 x 3
    # Groups:   Cases [?]
    #  Cases    Class Scores
    #  <chr>    <chr>  <dbl>
    #1 Student1 Math       7
    #2 Student2 Math       8
    #3 Student3 Math       9
    #4 Student4 Math       7
    

    【讨论】:

    • 这是我更喜欢的答案。我建议先进行连接,然后将合并的数据传输到 group_by 等。
    • 是的,但这会改变最终输出中元素的顺序(顺序将不同于d),尽管它在查询优化等方面会很有效。
    • 好点,我更喜欢效率而不是数据的排序方式。
    【解决方案5】:

    您可以使用order 按降序对Scores 上的数据框进行排序。然后删除重复的Cases。这是base R 解决方案。

    dat <- dat[order(-dat$Scores),]
    dat[duplicated(dat$Cases)==F,]
    
         Cases Class Scores
    1 Student3  Math      9
    6 Student2  Math      8
    4 Student1  Math      7
    9 Student4  Math      7
    

    如果您首先要确保dat 中的所有样本也在d 中,您可以在第一步中执行此操作。 %in% 执行值匹配。但是,根据上面的示例,它并没有什么不同。

    dat <- dat[dat$Cases %in% d$Cases & dat$Class %in% d$Class,]
    

    【讨论】:

      【解决方案6】:

      使用dplyr,按学生分组,并根据分数获得第一个值:

      library(dplyr)
      
      dat %>% 
        filter(Cases %in% d$Cases) %>% 
        group_by(Cases) %>% 
        top_n(1, Scores) %>%
        ungroup()
      
      # # A tibble: 4 x 3
      #   Cases    Class Scores
      #   <chr>    <chr>  <dbl>
      # 1 Student1 Math       7
      # 2 Student2 Math       8
      # 3 Student3 Math       9
      # 4 Student4 Math       7
      

      【讨论】:

        【解决方案7】:

        使用dplyr

        df %>% 
          group_by(Cases, Class) %>% 
          summarise(Scores = max(Scores))
        
        # A tibble: 4 x 3
        # Groups:   Cases [?]
          Cases    Class Scores
          <chr>    <chr>  <dbl>
        1 Student1 Math      7.
        2 Student2 Math      8.
        3 Student3 Math      9.
        4 Student4 Math      7.
        

        考虑到要匹配两个dfs:

        df %>%  
          right_join(df2, by = c("Cases", "Class")) %>% 
          group_by(Cases, Class) %>% 
          summarise(Scores = max(Scores))
        
        # A tibble: 4 x 3
        # Groups:   Cases [?]
          Cases    Class Scores
          <chr>    <chr>  <dbl>
        1 Student1 Math      7.
        2 Student2 Math      8.
        3 Student3 Math      9.
        4 Student4 Math      7.
        

        【讨论】:

        • 你也需要按类分组,以防有多个类值
        • 编辑后,现在这看起来像是@SandipanDey 答案的副本。
        • 我认为很明显我们正在使用(稍微)不同的方法。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-04
        • 1970-01-01
        相关资源
        最近更新 更多