Her grupta maksimum değere sahip satır nasıl seçilir


94

Her konu için birden çok gözlem içeren bir veri kümesinde, her kayıt için yalnızca maksimum veri değerine sahip bir alt küme almak istiyorum. Örneğin, aşağıdaki veri kümesiyle:

ID    <- c(1,1,1,2,2,2,2,3,3)
Value <- c(2,3,5,2,5,8,17,3,5)
Event <- c(1,1,2,1,2,1,2,2,2)

group <- data.frame(Subject=ID, pt=Value, Event=Event)

Konu 1, 2 ve 3, sırasıyla 5, 17 ve 5 olan en büyük pt değerine sahiptir.

Her konu için ilk olarak en büyük pt değerini nasıl bulabilirim ve sonra bu gözlemi başka bir veri çerçevesine yerleştirebilirim? Ortaya çıkan veri çerçevesi, her konu için yalnızca en büyük pt değerlerine sahip olmalıdır.


2
Bu çok yakından ilişkilidir, ancak maksimum stackoverflow.com/questions/24070714/…
David Arenburg

Yanıtlar:


96

İşte bir data.tableçözüm:

require(data.table) ## 1.9.2
group <- as.data.table(group)

ptHer bir grubun maksimum değerlerine karşılık gelen tüm girişleri tutmak istiyorsanız :

group[group[, .I[pt == max(pt)], by=Subject]$V1]
#    Subject pt Event
# 1:       1  5     2
# 2:       2 17     2
# 3:       3  5     2

Şunun yalnızca ilk maksimum değerini istiyorsanız pt:

group[group[, .I[which.max(pt)], by=Subject]$V1]
#    Subject pt Event
# 1:       1  5     2
# 2:       2 17     2
# 3:       3  5     2

Bu durumda, verilerinizdeki herhangi bir grupta birden fazla maksimum değer olmadığından, bir fark yaratmaz.


2
data.table olarak görüldüğünde 2014'ten beri çok fazla değişiklik oldu, bu hala bu sorunun en hızlı / en iyi çözümü mü?
Ben

2
@Ben, bu durumda en hızlı cevap hala bu, evet. .SDbu durumlar için optimizasyon hala listede. # 735'e bir göz atın .
Arun

6
Merhaba, burada $ V1 nedir? #noob
sriharsha KB

1
Otomatik adlandırılmış sütuna erişiliyor. Daha iyi anlamak için onsuz çalıştırın.
Arun

2
@HappyCoding, bir göz atın ?`.I`ve oradaki açıklama ve örneklerin yardımcı olup olmadığına bakın.
Arun

63

En sezgisel yöntem dplyr'de group_by ve top_n işlevini kullanmaktır.

    group %>% group_by(Subject) %>% top_n(1, pt)

Elde ettiğiniz sonuç

    Source: local data frame [3 x 3]
    Groups: Subject [3]

      Subject    pt Event
        (dbl) (dbl) (dbl)
    1       1     5     2
    2       2    17     2
    3       3     5     2

2
dplyr, bir gruptaki en küçük ve en büyük değere erişmek istediğinizde de yararlıdır çünkü değerler bir dizi olarak mevcuttur. Böylece önce azalan pt'ye göre sıralayabilir ve ardından en yüksek değeri elde etmek için pt [1] veya ilk (pt) kullanabilirsiniz: group %>% group_by(Subject) %>% arrange(desc(pt), .by_group = TRUE) %>% summarise(max_pt=first(pt), min_pt=last(pt), Event=first(Event))
cw '

3
Bağlar varsa bu, birden çok satırı içerecektir. slice(which.max(pt))Grup başına yalnızca bir satır eklemek için kullanın .
cakraww

36

Kullanan daha kısa bir çözüm data.table:

setDT(group)[, .SD[which.max(pt)], by=Subject]
#    Subject pt Event
# 1:       1  5     2
# 2:       2 17     2
# 3:       3  5     2

4
Bunun group[group[, .I[which.max(pt)], by=Subject]$V1]yukarıda @Arun tarafından önerilenden daha yavaş olabileceğini unutmayın; karşılaştırmaları burada görün
Valentin

1
Bunu beğendim çünkü mevcut bağlamım için yeterince hızlı ve .Iversiyona göre benim için daha kolay
sallanıyor

setDT (grup) [, .SD [pt == max (pt)], by = Konu]
Ferroao

19

Başka bir seçenek de slice

library(dplyr)
group %>%
     group_by(Subject) %>%
     slice(which.max(pt))
#    Subject    pt Event
#    <dbl> <dbl> <dbl>
#1       1     5     2
#2       2    17     2
#3       3     5     2

14

Bir dplyrçözüm:

library(dplyr)
ID <- c(1,1,1,2,2,2,2,3,3)
Value <- c(2,3,5,2,5,8,17,3,5)
Event <- c(1,1,2,1,2,1,2,2,2)
group <- data.frame(Subject=ID, pt=Value, Event=Event)

group %>%
    group_by(Subject) %>%
    summarize(max.pt = max(pt))

Bu, aşağıdaki veri çerçevesini verir:

  Subject max.pt
1       1      5
2       2     17
3       3      5

11
Bence OP Eventsütunu alt kümede tutmak istiyor , bu durumda şunları yapabilirsiniz: df %>% group_by(Subject) %>% filter(pt == max(pt))(varsa bağları da içerir)
talat

8

Etkinlik sütunuyla ilgili ne yapmak istediğinizden emin değildim, ama bunu da sürdürmek istiyorsanız, peki ya

isIDmax <- with(dd, ave(Value, ID, FUN=function(x) seq_along(x)==which.max(x)))==1
group[isIDmax, ]

#   ID Value Event
# 3  1     5     2
# 7  2    17     2
# 9  3     5     2

Burada aveher "ID" için "Değer" sütununa bakmak için kullanıyoruz . Sonra hangi değerin maksimal olduğunu belirleriz ve bunu, orijinal data.frame'i altküme yapmak için kullanabileceğimiz mantıksal bir vektöre dönüştürürüz.


Çok teşekkürler ama burada başka bir sorum var. Ave (Value, ID, FUN = function (x) seq_along (x) == which.max (x)) == 1 son derece iyi çalıştığı için bu yöntemde neden function ile kullanılsın? Biraz kafam karıştı.
Xinting WANG

kullandım with mevcut verileri hem içinde hem dışında olması biraz tuhaf çünkü groupdata.frame. Verileri ile read.tableveya başka bir şeyle okursanız, kullanmanız gerekir withçünkü bu sütun adları data.frame dışında kullanılamayacaktır.
MrFlick

6
do.call(rbind, lapply(split(group,as.factor(group$Subject)), function(x) {return(x[which.max(x$pt),])}))

Baz Kullanımı R


6

{Dplyr} v1.0.0'dan (Mayıs 2020) bu yana, slice_*yerini alan yeni sözdizimi var top_n().

Ayrıca bkz . Https://dplyr.tidyverse.org/reference/slice.html .

library(tidyverse)

ID    <- c(1,1,1,2,2,2,2,3,3)
Value <- c(2,3,5,2,5,8,17,3,5)
Event <- c(1,1,2,1,2,1,2,2,2)

group <- data.frame(Subject=ID, pt=Value, Event=Event)

group %>% 
  group_by(Subject) %>% 
  slice_max(pt)
#> # A tibble: 3 x 3
#> # Groups:   Subject [3]
#>   Subject    pt Event
#>     <dbl> <dbl> <dbl>
#> 1       1     5     2
#> 2       2    17     2
#> 3       3     5     2

2020-08-18 tarihinde tarafından oluşturuldu reprex paketi (v0.3.0.9001)

Oturum bilgileri
sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value                                      
#>  version  R version 4.0.2 Patched (2020-06-30 r78761)
#>  os       macOS Catalina 10.15.6                     
#>  system   x86_64, darwin17.0                         
#>  ui       X11                                        
#>  language (EN)                                       
#>  collate  en_US.UTF-8                                
#>  ctype    en_US.UTF-8                                
#>  tz       Europe/Berlin                              
#>  date     2020-08-18                                 
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package     * version    date       lib source                            
#>  assertthat    0.2.1      2019-03-21 [1] CRAN (R 4.0.0)                    
#>  backports     1.1.8      2020-06-17 [1] CRAN (R 4.0.1)                    
#>  blob          1.2.1      2020-01-20 [1] CRAN (R 4.0.0)                    
#>  broom         0.7.0      2020-07-09 [1] CRAN (R 4.0.2)                    
#>  cellranger    1.1.0      2016-07-27 [1] CRAN (R 4.0.0)                    
#>  cli           2.0.2      2020-02-28 [1] CRAN (R 4.0.0)                    
#>  colorspace    1.4-1      2019-03-18 [1] CRAN (R 4.0.0)                    
#>  crayon        1.3.4      2017-09-16 [1] CRAN (R 4.0.0)                    
#>  DBI           1.1.0      2019-12-15 [1] CRAN (R 4.0.0)                    
#>  dbplyr        1.4.4      2020-05-27 [1] CRAN (R 4.0.0)                    
#>  digest        0.6.25     2020-02-23 [1] CRAN (R 4.0.0)                    
#>  dplyr       * 1.0.1      2020-07-31 [1] CRAN (R 4.0.2)                    
#>  ellipsis      0.3.1      2020-05-15 [1] CRAN (R 4.0.0)                    
#>  evaluate      0.14       2019-05-28 [1] CRAN (R 4.0.0)                    
#>  fansi         0.4.1      2020-01-08 [1] CRAN (R 4.0.0)                    
#>  forcats     * 0.5.0      2020-03-01 [1] CRAN (R 4.0.0)                    
#>  fs            1.5.0      2020-07-31 [1] CRAN (R 4.0.2)                    
#>  generics      0.0.2      2018-11-29 [1] CRAN (R 4.0.0)                    
#>  ggplot2     * 3.3.2      2020-06-19 [1] CRAN (R 4.0.1)                    
#>  glue          1.4.1      2020-05-13 [1] CRAN (R 4.0.0)                    
#>  gtable        0.3.0      2019-03-25 [1] CRAN (R 4.0.0)                    
#>  haven         2.3.1      2020-06-01 [1] CRAN (R 4.0.0)                    
#>  highr         0.8        2019-03-20 [1] CRAN (R 4.0.0)                    
#>  hms           0.5.3      2020-01-08 [1] CRAN (R 4.0.0)                    
#>  htmltools     0.5.0      2020-06-16 [1] CRAN (R 4.0.1)                    
#>  httr          1.4.2      2020-07-20 [1] CRAN (R 4.0.2)                    
#>  jsonlite      1.7.0      2020-06-25 [1] CRAN (R 4.0.2)                    
#>  knitr         1.29       2020-06-23 [1] CRAN (R 4.0.2)                    
#>  lifecycle     0.2.0      2020-03-06 [1] CRAN (R 4.0.0)                    
#>  lubridate     1.7.9      2020-06-08 [1] CRAN (R 4.0.1)                    
#>  magrittr      1.5        2014-11-22 [1] CRAN (R 4.0.0)                    
#>  modelr        0.1.8      2020-05-19 [1] CRAN (R 4.0.0)                    
#>  munsell       0.5.0      2018-06-12 [1] CRAN (R 4.0.0)                    
#>  pillar        1.4.6      2020-07-10 [1] CRAN (R 4.0.2)                    
#>  pkgconfig     2.0.3      2019-09-22 [1] CRAN (R 4.0.0)                    
#>  purrr       * 0.3.4      2020-04-17 [1] CRAN (R 4.0.0)                    
#>  R6            2.4.1      2019-11-12 [1] CRAN (R 4.0.0)                    
#>  Rcpp          1.0.5      2020-07-06 [1] CRAN (R 4.0.2)                    
#>  readr       * 1.3.1      2018-12-21 [1] CRAN (R 4.0.0)                    
#>  readxl        1.3.1      2019-03-13 [1] CRAN (R 4.0.0)                    
#>  reprex        0.3.0.9001 2020-08-13 [1] Github (tidyverse/reprex@23a3462) 
#>  rlang         0.4.7      2020-07-09 [1] CRAN (R 4.0.2)                    
#>  rmarkdown     2.3.3      2020-07-26 [1] Github (rstudio/rmarkdown@204aa41)
#>  rstudioapi    0.11       2020-02-07 [1] CRAN (R 4.0.0)                    
#>  rvest         0.3.6      2020-07-25 [1] CRAN (R 4.0.2)                    
#>  scales        1.1.1      2020-05-11 [1] CRAN (R 4.0.0)                    
#>  sessioninfo   1.1.1      2018-11-05 [1] CRAN (R 4.0.2)                    
#>  stringi       1.4.6      2020-02-17 [1] CRAN (R 4.0.0)                    
#>  stringr     * 1.4.0      2019-02-10 [1] CRAN (R 4.0.0)                    
#>  styler        1.3.2.9000 2020-07-05 [1] Github (pat-s/styler@51d5200)     
#>  tibble      * 3.0.3      2020-07-10 [1] CRAN (R 4.0.2)                    
#>  tidyr       * 1.1.1      2020-07-31 [1] CRAN (R 4.0.2)                    
#>  tidyselect    1.1.0      2020-05-11 [1] CRAN (R 4.0.0)                    
#>  tidyverse   * 1.3.0      2019-11-21 [1] CRAN (R 4.0.0)                    
#>  utf8          1.1.4      2018-05-24 [1] CRAN (R 4.0.0)                    
#>  vctrs         0.3.2      2020-07-15 [1] CRAN (R 4.0.2)                    
#>  withr         2.2.0      2020-04-20 [1] CRAN (R 4.0.0)                    
#>  xfun          0.16       2020-07-24 [1] CRAN (R 4.0.2)                    
#>  xml2          1.3.2      2020-04-23 [1] CRAN (R 4.0.0)                    
#>  yaml          2.2.1      2020-02-01 [1] CRAN (R 4.0.0)                    
#> 
#> [1] /Users/pjs/Library/R/4.0/library
#> [2] /Library/Frameworks/R.framework/Versions/4.0/Resources/library

5

Başka bir temel çözüm

group_sorted <- group[order(group$Subject, -group$pt),]
group_sorted[!duplicated(group_sorted$Subject),]

# Subject pt Event
#       1  5     2
#       2 17     2
#       3  5     2

Veri çerçevesini pt(azalan) sıralayın ve ardından yinelenen satırları kaldırın.Subject


3

Bir tane daha temel R çözümü:

merge(aggregate(pt ~ Subject, max, data = group), group)

  Subject pt Event
1       1  5     2
2       2 17     2
3       3  5     2

2

Karakterler üzerinde çalışmadığından işte başka bir data.tableçözümwhich.max

library(data.table)
group <- data.table(Subject=ID, pt=Value, Event=Event)

group[, .SD[order(pt, decreasing = TRUE) == 1], by = Subject]

1

bytapplyveri çerçeveleri için bir sürümüdür :

res <- by(group, group$Subject, FUN=function(df) df[which.max(df$pt),])

Bir sınıf nesnesi döndürür, byböylece onu veri çerçevesine dönüştürürüz:

do.call(rbind, b)
  Subject pt Event
1       1  5     2
2       2 17     2
3       3  5     2

1

Gelen tabanı kullanabilirsiniz avealmak için maxgrup başına ve bu karşılaştırma ptve subsetine bir mantıksal vektörü olsun data.frame.

group[group$pt == ave(group$pt, group$Subject, FUN=max),]
#  Subject pt Event
#3       1  5     2
#7       2 17     2
#9       3  5     2

Veya zaten işlevde karşılaştırın.

group[as.logical(ave(group$pt, group$Subject, FUN=function(x) x==max(x))),]
#group[ave(group$pt, group$Subject, FUN=function(x) x==max(x))==1,] #Variant
#  Subject pt Event
#3       1  5     2
#7       2 17     2
#9       3  5     2

0

Başka bir data.tableseçenek:

library(data.table)
setDT(group)
group[group[order(-pt), .I[1L], Subject]$V1]

Veya başka (daha az okunabilir ama biraz daha hızlı):

group[group[, rn := .I][order(Subject, -pt), {
    rn[c(1L, 1L + which(diff(Subject)>0L))]
}]]

zamanlama kodu:

library(data.table)
nr <- 1e7L
ng <- nr/4L
set.seed(0L)
DT <- data.table(Subject=sample(ng, nr, TRUE), pt=1:nr)#rnorm(nr))
DT2 <- copy(DT)


microbenchmark::microbenchmark(times=3L,
    mtd0 = {a0 <- DT[DT[, .I[which.max(pt)], by=Subject]$V1]},
    mtd1 = {a1 <- DT[DT[order(-pt), .I[1L], Subject]$V1]},
    mtd2 = {a2 <- DT2[DT2[, rn := .I][
        order(Subject, -pt), rn[c(TRUE, diff(Subject)>0L)]
    ]]},
    mtd3 = {a3 <- unique(DT[order(Subject, -pt)], by="Subject")}
)
fsetequal(a0[order(Subject)], a1[order(Subject)])
#[1] TRUE
fsetequal(a0[order(Subject)], a2[, rn := NULL][order(Subject)])
#[1] TRUE
fsetequal(a0[order(Subject)], a3[order(Subject)])
#[1] TRUE

zamanlamalar:

Unit: seconds
 expr      min       lq     mean   median       uq      max neval
 mtd0 3.256322 3.335412 3.371439 3.414502 3.428998 3.443493     3
 mtd1 1.733162 1.748538 1.786033 1.763915 1.812468 1.861022     3
 mtd2 1.136307 1.159606 1.207009 1.182905 1.242359 1.301814     3
 mtd3 1.123064 1.166161 1.228058 1.209257 1.280554 1.351851     3

0

Başka bir data.tableçözüm:

library(data.table)
setDT(group)[, head(.SD[order(-pt)], 1), by = .(Subject)]

-1

Bir konu için en büyük pt değerini istiyorsanız, şunu kullanabilirsiniz:

   pt_max = as.data.frame(aggregate(pt~Subject, group, max))
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.