【问题标题】:Need to fetch only first two highest records by grouping two columns of dataframe in R只需通过在 R 中对两列数据框进行分组来获取前两个最高记录
【发布时间】:2016-11-30 11:14:06
【问题描述】:

我有一个包含 4 列 13 行的 data.frame。下面是样本数据。 [列名大写,数据小写]

示例输入数据:

NAME.  MARKS  MONTH COUNTRY
ram       20. jan   India
ranjith   40.  jan   India
naren.    80.  jan.  India
Amir.     90.  feb.   India
kumar.    60.  feb     India
azhar     80.  feb   India
mark      90.  feb.  US
Alex.     55   feb.  US
chris     20   feb   US
rakesh    60.  jan   US
Mona.     70.   jan.  US
mano.     90.  mar.   UK
Ron.       37.  mar.  UK

预期输出:

NAME    MARKS. MONTH  COUNTRY
naren    80.    jan.    India
ranjith  40.    jan.    India
Amir.    90.    feb.    India
Azhar.   80.    feb.    India
mark.    90.    feb.     US
Alex     55.    feb.     US
Mona.    70.    jan.     US
Rakesh.   60.    jan.    US
mano.     90.    mar.    UK
Ron.      37.    mar.    UK

问题:从输入数据框中,我只想从每个名为 MONTH 和 COUNTRY 的组中选择最高的两个标记值。上面给出了示例输出。

任何人都可以分享示例代码以生成正确的输出并将其分配给新的数据帧。任何方法都可取,包括sqldf

【问题讨论】:

  • 你的.s 会打乱分组,除非它们是一致的。此外,您的数字看起来很可能是字符串,而不是实际数字。
  • Alistaire..那些我手动输入的数字没有粘贴。所以请忽略错字。通过忽略“。”将它们视为数字。

标签: r dataframe


【解决方案1】:

您可以使用data.table 执行以下操作。感谢@Arun 对改进答案的建议。

require(data.table)
dat <- fread(txt)
dat[order(MARKS), tail(.SD, 2L), by=c("MONTH", "COUNTRY")]

请注意,这仅计算顺序向量,并不会在执行分组操作之前先重新排列整个 data.table(因此内存效率更高)。 .SD 包含每个组的数据子集,它本身就是一个 data.table。

如果组太多,tail(.SD, 2L) 可能会稍微慢一些,这种情况下,我们可以使用返回索引的.I,然后最后一次执行子集,如下所示:

ix = dat[order(MARKS), .(I=tail(.I, 2L)), by=c("MONTH", "COUNTRY")][, I]
dat[ix]

这会导致:

    MONTH COUNTRY    NAME MARKS
 1:   jan   India ranjith    40
 2:   jan   India   naren    80
 3:   feb   India   kumar    60
 4:   feb   India   azhar    80
 5:   feb      US    Alex    55
 6:   feb      US   chris    20
 7:   feb   India  rakesh    60
 8:   feb   India    Mona    70
 9:   mar      UK    mano    90
10:   mar      UK     Ron    37

txt 是您的数据,没有结尾 .

txt <- "NAME  MARKS  MONTH COUNTRY
    ram       20 jan   India
    ranjith   40  jan   India
    naren    80  jan  India
    Amir     90  feb   India
    kumar    60  feb     India
    azhar     80  feb   India
    mark      90  feb  US
    Alex     55   feb  US
    chris     20   feb   US
    rakesh    60  jan   US
    Mona     70   jan  US
    mano     90  mar   UK
    Ron       37  mar  UK"

【讨论】:

  • 感谢 FlooO 的回复。上面的代码也会生成名称列吗?因为我的输出需要全部 4 列。
  • 我不确定数据是否按照tail 选择正确的行进行排序。现在我认为选择on="MARKS" 是正确的...这是错的吗?它应该按“MARKS”排序,然后按 GROUP BY by=...
  • @Arun,感谢您的评论。所以也许我在这里确实理解了一些错误:setkey 键 = 对data.table 进行排序。二级索引应该在没有排序的情况下做类似的事情。那么我如何即时data.table 进行排序,例如按“MARKS”和然后by=...分组。所以j 中的数据例如.SDMARKS 排序并按...分组我认为这也是 on 可以用于的。
  • 那么 Arun 建议的代码会解决这个问题吗?通过使用 order 函数基于标记进行排序,然后使用五尾函数仅选择最后 2 个值,然后使用 2 列 c() 进行分组。请确认一次
  • @Arun:谢谢你的解释。刚刚编辑了答案。
【解决方案2】:

这是一个带有base R 的选项(不使用任何包)。我们使用substr从“MONTH”中提取前3个字母(因为在某些情况下有一些.)。使用ave,我们得到基于rank的逻辑索引,通过'COUNTRY'和'MONTH'分组后,可用于对行进行子集化。

df1$MONTH <- substr(df1$MONTH, 1, 3)
df1[with(df1, as.logical(ave(MARKS, COUNTRY, MONTH,
                    FUN = function(x) rank(-x) %in% 1:2))),]

【讨论】:

    【解决方案3】:

    在 dplyr 中,您可以group_byarrangeslice。进行一些清洁:

    library(dplyr)
    
           # take out .s
    df %>% mutate_all(sub, pattern = '.', replacement = '', fixed = TRUE) %>% 
      # convert to numbers, if necessary
      mutate_all(type.convert, as.is = TRUE) %>% 
      # set grouping for following operations
      group_by(MONTH, COUNTRY) %>% 
      # sort by MARKS, descending
      arrange(desc(MARKS)) %>%
      # subset to top two rows of each group
      slice(1:2)
    
    ## Source: local data frame [10 x 4]
    ## Groups: MONTH, COUNTRY [5]
    ## 
    ##      NAME. MARKS MONTH COUNTRY
    ##      <chr> <int> <chr>   <chr>
    ## 1     Amir    90   feb   India
    ## 2    azhar    80   feb   India
    ## 3     mark    90   feb      US
    ## 4     Alex    55   feb      US
    ## 5    naren    80   jan   India
    ## 6  ranjith    40   jan   India
    ## 7     Mona    70   jan      US
    ## 8   rakesh    60   jan      US
    ## 9     mano    90   mar      UK
    ## 10     Ron    37   mar      UK
    

    【讨论】:

    • 感谢 Alistaire..wll 实施它并与您分享详细信息..wll 让您保持发布
    猜你喜欢
    • 1970-01-01
    • 2019-07-03
    • 2016-07-03
    • 2022-06-14
    • 1970-01-01
    • 2012-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多