需要通过对R中的两列数据帧进行分组来仅获取前两个最高记录

时间:2016-07-26 17:12:29

标签: r dataframe

我有一个data.frame,其中包含4列13行。以下是示例数据。 [列名称为大写,数据为小写]

示例输入数据:

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

3 个答案:

答案 0 :(得分:2)

您可以使用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"

答案 1 :(得分:1)

在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

答案 2 :(得分:0)

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

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