प्रत्येक समूह में अधिकतम मान वाली पंक्ति का चयन कैसे करें


99

प्रत्येक विषय के लिए कई टिप्पणियों के साथ एक डेटासेट में, मैं प्रत्येक रिकॉर्ड के लिए केवल अधिकतम डेटा मान के साथ एक सबसेट लेना चाहता हूं। उदाहरण के लिए, निम्नलिखित डेटासेट के साथ:

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)

विषय 1, 2, और 3 में क्रमशः 5, 17 और 5 का सबसे बड़ा pt मान है।

मैं पहली बार प्रत्येक विषय के लिए सबसे बड़ा pt मान कैसे पा सकता हूं, और फिर, इस अवलोकन को किसी अन्य डेटा फ़्रेम में डाल सकता हूं? परिणामी डेटा फ़्रेम में प्रत्येक विषय के लिए केवल सबसे बड़ा pt मान होना चाहिए।


2
यह बहुत निकट से संबंधित है, लेकिन अधिकतम करने के बजाय कम से कम के लिए stackoverflow.com/questions/24070714/...
डेविड Arenburg

जवाबों:


98

यहाँ एक data.tableसमाधान है:

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

यदि आप ptप्रत्येक समूह के अधिकतम मूल्यों के अनुरूप सभी प्रविष्टियाँ रखना चाहते हैं :

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

यदि आप इसका पहला अधिकतम मूल्य चाहते हैं 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

इस स्थिति में, इससे कोई फर्क नहीं पड़ता, क्योंकि आपके डेटा में किसी भी समूह के भीतर कई अधिकतम मान नहीं हैं।


2
2014 के बाद से डेटा के रूप में देखने में बहुत सारे बदलाव हुए हैं, क्या यह अभी भी इस सवाल का सबसे तेज़ / सबसे अच्छा समाधान है?
बेन

2
@ इस मामले में, सबसे तेज़ जवाब अभी भी है, हाँ। .SDइन मामलों के लिए अनुकूलन अभी भी सूची में है। # 735 पर नजर रखें ।
अरुण

6
हाय, यहाँ $ V1 क्या है? # कोई
केबी

1
ऑटो नाम वाले कॉलम तक पहुँचना। इसे बिना बेहतर समझे इसे चलाएं।
अरुण

2
@ हेप्पीकोडिंग, एक नज़र है ?`.I`और देखें कि क्या स्पष्टीकरण और उदाहरण वहाँ मदद करते हैं?
अरुण

68

सबसे सहज विधि dplyr में group_by और top_n फ़ंक्शन का उपयोग करना है

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

परिणाम आपको मिल रहा है

    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 उपयोगी है क्योंकि मान एक सरणी के रूप में उपलब्ध हैं। तो आप सबसे पहले pt उतर कर छँटाई कर सकते हैं और फिर उच्चतम मान प्राप्त करने के लिए pt [1] या पहला (pt) का उपयोग कर सकते हैं: group %>% group_by(Subject) %>% arrange(desc(pt), .by_group = TRUE) %>% summarise(max_pt=first(pt), min_pt=last(pt), Event=first(Event))
cw '

4
यदि संबंध हैं तो इसमें कई पंक्तियाँ शामिल होंगी। slice(which.max(pt))प्रति समूह केवल एक पंक्ति शामिल करने के लिए उपयोग करें ।
१०:१४ पर केकराव

38

एक छोटा सा समाधान का उपयोग 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
ध्यान दें, यह group[group[, .I[which.max(pt)], by=Subject]$V1]@Arun द्वारा ऊपर प्रस्तावित की तुलना में धीमा हो सकता है ; यहां
वैलेंटाइन

1
मुझे यह पसंद है क्योंकि यह मेरे वर्तमान संदर्भ के लिए काफी तेज़ है और मेरे लिए .Iसंस्करण बनाम
ग्रो

setDT (समूह) [, .SD [pt == मैक्स (pt)], द्वारा = विषय]
फेरो

22

एक और विकल्प है 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

एक dplyrसमाधान:

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))

इससे निम्न डेटा फ़्रेम प्राप्त होता है:

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

11
मुझे लगता है कि ओपी Eventउस उपसमुदाय में कॉलम रखना चाहता है जिस स्थिति में आप कर सकते हैं: df %>% group_by(Subject) %>% filter(pt == max(pt))(संबंधों को वर्तमान में शामिल करता है)
ताल

8

मुझे यकीन नहीं था कि आप ईवेंट कॉलम के बारे में क्या करना चाहते हैं, लेकिन अगर आप इसे और साथ ही, कैसे रखना चाहते हैं

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

यहां हम aveप्रत्येक "आईडी" के लिए "मान" कॉलम देखने के लिए उपयोग करते हैं। फिर हम यह निर्धारित करते हैं कि कौन सा मान अधिकतम है और फिर इसे एक तार्किक वेक्टर में बदल दें जिसका उपयोग हम मूल डेटा.फ्रेम को कम करने के लिए कर सकते हैं।


बहुत बहुत धन्यवाद, लेकिन मैं यहाँ एक और सवाल है। Ave (मान, ID, FUN = function (x) seq_along (x) == what.max (x)) == 1 के बाद से इस विधि में फ़ंक्शन का उपयोग क्यों करें? मैं थोड़ा उलझन में हूं।
शिन्टिंग वंग

मैंने उपयोग किया withक्योंकि डेटा के अंदर और बाहर दोनों के लिए डेटा उपलब्ध होना थोड़ा अजीब है group। यदि आप डेटा को read.tableकुछ या कुछ के साथ पढ़ते हैं , तो आपको उपयोग करने की आवश्यकता होगी withक्योंकि वे कॉलम नाम data.frame के बाहर उपलब्ध नहीं होंगे।
MrFlick


6

{Dplyr} v1.0.0 (मई 2020) के बाद नया slice_*सिंटैक्स होता है जो कि सुप्त हो जाता है top_n()

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 को रेप्रेक्स पैकेज (v0.3.0.9001) द्वारा बनाया गया

सत्र की जानकारी
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

एक और आधार समाधान

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

pt(नीचे उतरते) द्वारा डेटा फ्रेम का आदेश दें और फिर अंदर डुप्लिकेट पंक्तियों को हटा देंSubject


3

एक और आधार आर समाधान:

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

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

2

यहाँ एक और data.tableसमाधान है, क्योंकि which.maxयह पात्रों पर काम नहीं करता है

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

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

1

bytapplyडेटा फ़्रेम के लिए एक संस्करण है :

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

यह कक्षा की एक वस्तु लौटाता है byइसलिए हम इसे डेटा फ्रेम में परिवर्तित करते हैं:

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

1

में आधार का उपयोग कर सकते aveप्राप्त करने के लिए maxऔर के साथ इस तुलना प्रति समूह ptऔर सबसेट के एक तार्किक वेक्टर मिलता 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

या फ़ंक्शन में पहले से ही इसकी तुलना करें।

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

एक अन्य data.tableविकल्प:

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

या दूसरा (कम पठनीय लेकिन थोड़ा तेज):

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

समय कोड:

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

समय:

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

1.0.2 का उपयोग करते हुए अब ऐसा करने के दो तरीके हैं, एक लंबा हाथ है और दूसरा क्रिया का उपयोग कर रहा है ():

      # create data
      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)

लंबे हाथ क्रिया अधिकतम है (), लेकिन ध्यान दें na.rm = TRUE जो उन उदाहरणों के लिए उपयोगी है जहां बंद प्रश्न के रूप में NA हैं: डेटाफ़्रेम में पंक्तियों को मर्ज करें जहाँ पंक्तियाँ भिन्न होती हैं और NA होती हैं :

       group %>% 
        group_by(Subject) %>% 
        summarise(pt = max(pt, na.rm = TRUE),
                  Event = max(Event, na.rm = TRUE))

यह ठीक है अगर कुछ ही कॉलम हैं लेकिन यदि तालिका में कई कॉलम हैं () उपयोगी है। इस क्रिया के उदाहरण प्रायः संक्षेप में दिए गए होते हैं (आरम्भ में (start_with ...) लेकिन इस उदाहरण में कॉलम एक ही वर्ण से शुरू नहीं होते हैं। या तो उन्हें बदला जा सकता है या सूचीबद्ध किए गए पद:

    group %>% 
        group_by(Subject) %>% 
        summarise(across(1:ncol(group)-1, max, na.rm = TRUE, .names = "{.col}"))

क्रिया के लिए नोट () 1 पहले वास्तविक कॉलम के बाद पहले कॉलम को संदर्भित करता है इसलिए ncol (समूह) का उपयोग करना काम नहीं करेगा क्योंकि यह बहुत अधिक कॉलम है (इसे 3 की बजाय 4 स्थिति बनाता है)।


-1

यदि आप किसी विषय के लिए सबसे बड़ा pt मान चाहते हैं, तो आप बस उपयोग कर सकते हैं:

   pt_max = as.data.frame(aggregate(pt~Subject, group, max))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.