Как выбрать строку с максимальным значением в каждой группе -- r поле с участием dataframe поле с участием r-faq поле с участием r поле с участием dataframe поле с участием r-faq пол Связанный проблема

How to select the row with the maximum value in each group


99
vote

проблема

русский

В наборе данных с несколькими наблюдениями для каждого предмета я хочу взять подмножество только с максимальным значением данных для каждой записи. Например, с следующим набором данных:

 <код> 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 имеют наибольшее значение Pt 5, 17 и 5 соответственно.

Как я могу сначала найти самое большое значение PT для каждого предмета, а затем, поместите это наблюдение в другом кадре данных? Полученный кадр данных должен иметь только самые большие значения Pt для каждого предмета.

Английский оригинал

In a dataset with multiple observations for each subject I want to take a subset with only the maximum data value for each record. For example, with a following dataset:

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) 

Subject 1, 2, and 3 have the biggest pt value of 5, 17, and 5 respectively.

How could I first find the biggest pt value for each subject, and then, put this observation in another data frame? The resulting data frame should only have the biggest pt values for each subject.

</div
                 
       
               

Список ответов

98
 
vote
vote
Лучший ответ
 
<Р> Вот <код> AVCaptureDevice4 Решение:
 <код> AVCaptureDevice5  
<Р> Если вы хотите сохранить все записи, соответствующие макс значений <код> AVCaptureDevice6 в каждой группе:
 <код> AVCaptureDevice7  
<Р> Если вы хотите только первое максимальное значение <код> AVCaptureDevice8 :
 <код> AVCaptureDevice9  
<Р> В этом случае, это не делает разницы, а не несколько максимальных значений в пределах каких-либо групп в ваших данных.
 

Here's a data.table solution:

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

If you want to keep all the entries corresponding to max values of pt within each group:

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

If you'd like just the first max value of 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 

In this case, it doesn't make a difference, as there aren't multiple maximum values within any group in your data.

</div
 
 
                   
                                       
69
 
vote

Самый интуитивный метод - использовать функцию group_by и top_n в dlyryr

 <код>     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   
 

The most intuitive method is to use group_by and top_n function in dplyr

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

The result you get is

    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 
</div
 
 
       
               
38
 
vote

Более короткое решение, используя <код> 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   
 

A shorter solution using 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 
</div
 
 
           
                       
22
 
vote

Другой вариант <код> 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   
 

Another option is 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 
</div
 
 
14
 
vote

<код> 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   
 

A dplyr solution:

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

This yields the following data frame:

  Subject max.pt 1       1      5 2       2     17 3       3      5 
</div
 
 
   
       
8
 
vote

Я не был уверен, что вы хотели сделать с столбцом события, но если вы тоже хотите этого сохранить, как насчет того,

 <код> 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   

Здесь мы используем <код> 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 0 , чтобы посмотреть столбец «Значение» для каждого «ID». Затем мы определяем, какое значение является максимальным, а затем повернуть это в логическом векторе, мы можем использовать для подмножества исходных данных. Crame.

 

I wasn't sure what you wanted to do about the Event column, but if you want to keep that as well, how about

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 

Here we use ave to look at the "Value" column for each "ID". Then we determine which value is the maximal and then turn that into a logical vector we can use to subset the original data.frame.

</div
 
 
       
               
6
 
vote
 <код>     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 1  

Использование базы <код> 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

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

Using Base R

</div
 
 
6
 
vote

С {dlyrr} v1.0.0 (май 2020) есть новый <код> 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 3 синтаксис, который заменяет <код> 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 4 .

См. Также https://dplyr.tidyverse.org/reference/slice.html.

 <код>     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 5  

создан на 2020-08-18 от Пакет APPREX (v0.3.0.9001) < / sup>

Информация о сеансе
 <код>     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 6  
 

Since {dplyr} v1.0.0 (May 2020) there is the new slice_* syntax which supersedes top_n().

See also 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 

Created on 2020-08-18 by the reprex package (v0.3.0.9001)

Session info
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 
</div
 
 
5
 
vote

Другое базовое решение

 <код>     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 7  

Заказать кадр данных по <код> 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 8 (по убыванию), а затем удалите строки дублированные в <Код> 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 9

 

Another base solution

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 

Order the data frame by pt (descending) and then remove rows duplicated in Subject

</div
 
 
3
 
vote

Еще одно решение Base R:

 <код> data.table0  
 

One more base R solution:

merge(aggregate(pt ~ Subject, max, data = group), group)    Subject pt Event 1       1  5     2 2       2 17     2 3       3  5     2 
</div
 
 
2
 
vote

Вот еще один <код> data.table1 решение, поскольку <код> 99887776622 не работает на символах

 <код> data.table3  
 

Here's another data.table solution, since which.max does not work on characters

library(data.table) group <- data.table(Subject=ID, pt=Value, Event=Event)  group[, .SD[order(pt, decreasing = TRUE) == 1], by = Subject] 
</div
 
 
1
 
vote

<Код> data.table4 - версия <код> data.table5 для кадров данных:

 <код> data.table6  

Это возвращает объект класса <код> data.table7 , поэтому мы преобразуем его в рамку данных:

 <код> data.table8  
 

by is a version of tapply for data frames:

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

It returns an object of class by so we convert it to data frame:

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

в базе Вы можете использовать <код> data.table9 , чтобы получить <код> setDT(group)[, .SD[which.max(pt)], by=Subject] # Subject pt Event # 1: 1 5 2 # 2: 2 17 2 # 3: 3 5 2 0 на группу и сравнить это с <код> setDT(group)[, .SD[which.max(pt)], by=Subject] # Subject pt Event # 1: 1 5 2 # 2: 2 17 2 # 3: 3 5 2 1 и получить Логический вектор для подмножества <код> setDT(group)[, .SD[which.max(pt)], by=Subject] # Subject pt Event # 1: 1 5 2 # 2: 2 17 2 # 3: 3 5 2 2 .

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

или сравните его уже в функции.

 <код> setDT(group)[, .SD[which.max(pt)], by=Subject] #    Subject pt Event # 1:       1  5     2 # 2:       2 17     2 # 3:       3  5     2 4  
 

In base you can use ave to get max per group and compare this with pt and get a logical vector to subset the 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 

Or compare it already in the function.

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 
</div
 
 
0
 
vote

Другой <код> setDT(group)[, .SD[which.max(pt)], by=Subject] # Subject pt Event # 1: 1 5 2 # 2: 2 17 2 # 3: 3 5 2 5 опция:

 <код> setDT(group)[, .SD[which.max(pt)], by=Subject] #    Subject pt Event # 1:       1  5     2 # 2:       2 17     2 # 3:       3  5     2 6  

или другой (менее читаемый, но немного быстрее):

 <код> setDT(group)[, .SD[which.max(pt)], by=Subject] #    Subject pt Event # 1:       1  5     2 # 2:       2 17     2 # 3:       3  5     2 7  

код времени:

 <код> setDT(group)[, .SD[which.max(pt)], by=Subject] #    Subject pt Event # 1:       1  5     2 # 2:       2 17     2 # 3:       3  5     2 8  

Timings:

 <код> setDT(group)[, .SD[which.max(pt)], by=Subject] #    Subject pt Event # 1:       1  5     2 # 2:       2 17     2 # 3:       3  5     2 9  
 

Another data.table option:

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

Or another (less readable but slightly faster):

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

timing code:

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 

timings:

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 
</div
 
 
0
 
vote

Другой <Код> data.table Решение:

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

Another data.table solution:

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

Использование DPLYR 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)   

Длинная рука Глагол - max (), но обратите внимание на na.rm = true, что полезно для примеров, где есть NAS, как в закрытом вопросе: сливаются строки в DataFrame, где строки неселены и содержат NAS :

 <код>        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 (group), не будет работать так, как это слишком много столбцов (делает его положением 4 чем 3).

 

Using dplyr 1.0.2 there are now two ways to do this, one is long hand and the other is using the verb across():

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

Long hand the verb is max() but note the na.rm = TRUE which is useful for examples where there are NAs as in the closed question: Merge rows in a dataframe where the rows are disjoint and contain NAs:

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

This is ok if there are only a few columns but if the table has many columns across() is useful. The examples for this verb are often with summarise(across(start_with... but in this example the columns don't start with the same characters. Either they could be changed or the positions listed:

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

Note for the verb across() 1 refers to the first column after the first actual column so using ncol(group) won't work as that is too many columns (makes it position 4 rather than 3).

</div
 
 
-1
 
vote

Если вы хотите наибольшее значение PT для предмета, вы можете просто использовать:

 <код>    pt_max = as.data.frame(aggregate(pt~Subject, group, max))   
 

If you want the biggest pt value for a subject, you could simply use:

   pt_max = as.data.frame(aggregate(pt~Subject, group, max)) 
</div
 
 
100
 
vote
vote
Лучший ответ
 

Вот <код> 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   

Если вы хотите только первое максимальное значение Controls0 :

 <код> Controls1  

В этом случае он не имеет значения, так как в ваших данных не имеет нескольких максимальных значений в ваших данных.

 

Here's a data.table solution:

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

If you want to keep all the entries corresponding to max values of pt within each group:

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

If you'd like just the first max value of 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 

In this case, it doesn't make a difference, as there aren't multiple maximum values within any group in your data.

</div
 
 
                   
                                       
70
 
vote

Самый интуитивный метод - использовать функцию group_by и top_n в dlyryr

 <код> Controls2  

Результат, который вы получаете, это

 <код> Controls3  
 

The most intuitive method is to use group_by and top_n function in dplyr

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

The result you get is

    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 
</div
 
 
       
               
38
 
vote

Более короткое решение, используя <код> Controls4 :

 <код> Controls5  
 

A shorter solution using 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 
</div
 
 
           
                       
22
 
vote

Другой вариант <код> Controls6

 <код> Controls7  
 

Another option is 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 
</div
 
 
14
 
vote

<код> Controls8 Решение:

 <код> Controls9  

Это дает следующие рамки данных:

 <код> Grid0  
 

A dplyr solution:

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

This yields the following data frame:

  Subject max.pt 1       1      5 2       2     17 3       3      5 
</div
 
 
   
       
8
 
vote

Я не был уверен, что вы хотели сделать с столбцом события, но если вы тоже хотите этого сохранить, как насчет того,

 <Код> Grid1  

Здесь мы используем <код> Grid2 , чтобы посмотреть столбец «Значение» для каждого «ID». Затем мы определяем, какое значение является максимальным, а затем повернуть это в логическом векторе, мы можем использовать для подмножества исходных данных. Crame.

 

I wasn't sure what you wanted to do about the Event column, but if you want to keep that as well, how about

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 

Here we use ave to look at the "Value" column for each "ID". Then we determine which value is the maximal and then turn that into a logical vector we can use to subset the original data.frame.

</div
 
 
       
               
8
 
vote

С {dlyrr} v1.0.0 (май 2020) Есть новый <код> Grid3 синтаксис, который заменяет <код> Grid4 .

См. Также https://dplyr.tidyverse.org/reference/slice.html.

 <код> Grid5  

создан на 2020-08-18 от Пакет APPREX (v0.3.0.9001) < / sup>

Информация о сеансе
 <код> Grid6  
 

Since {dplyr} v1.0.0 (May 2020) there is the new slice_* syntax which supersedes top_n().

See also 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 

Created on 2020-08-18 by the reprex package (v0.3.0.9001)

Session info
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 
</div
 
 
6
 
vote
 <код> Grid7  

Использование базы <код> Grid8

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

Using Base R

</div
 
 
5
 
vote

Другое базовое решение

 <код> Grid9  

Заказать кадр данных по <код> StackPanel0 (по убыванию), а затем удалите строки дублированные в <Код> StackPanel1

 

Another base solution

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 

Order the data frame by pt (descending) and then remove rows duplicated in Subject

</div
 
 
3
 
vote

Еще одно решение Base R:

 <код> StackPanel2  
 

One more base R solution:

merge(aggregate(pt ~ Subject, max, data = group), group)    Subject pt Event 1       1  5     2 2       2 17     2 3       3  5     2 
</div
 
 
2
 
vote

Вот еще один <код> 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]   
 

Here's another data.table solution, since which.max does not work on characters

library(data.table) group <- data.table(Subject=ID, pt=Value, Event=Event)  group[, .SD[order(pt, decreasing = TRUE) == 1], by = Subject] 
</div
 
 
1
 
vote

<Код> by - версия <код> tapply для кадров данных:

 <код> 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   
 

by is a version of tapply for data frames:

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

It returns an object of class by so we convert it to data frame:

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

в базе Вы можете использовать <код> ave , чтобы получить <код> max на группу и сравнить это с <код> which.max0 и получить Логический вектор для подмножества <код> which.max1 .

 <код> which.max2  

или сравните его уже в функции.

 <код> which.max3  
 

In base you can use ave to get max per group and compare this with pt and get a logical vector to subset the 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 

Or compare it already in the function.

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 
</div
 
 
0
 
vote

Другой <код> which.max4 опция:

 <код> which.max5  

или другой (менее читаемый, но немного быстрее):

 <код> which.max6  

код времени:

 <код> which.max7  

Timings:

 <код> which.max8  
 

Another data.table option:

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

Or another (less readable but slightly faster):

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

timing code:

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 

timings:

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 
</div
 
 
0
 
vote

Другой <код> which.max9 Решение:

 <код> library(data.table) group <- data.table(Subject=ID, pt=Value, Event=Event)  group[, .SD[order(pt, decreasing = TRUE) == 1], by = Subject] 0  
 

Another data.table solution:

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

Использование DPLYR 1.0.2 В настоящее время есть два способа сделать это, одна длинная рука, а другая использует глагол по всему ():

 <Код> library(data.table) group <- data.table(Subject=ID, pt=Value, Event=Event)  group[, .SD[order(pt, decreasing = TRUE) == 1], by = Subject] 1  

Длинная рука Глагол - max (), но обратите внимание на na.rm = true, что полезно для примеров, где есть NAS, как в закрытом вопросе: сливаются строки в DataFrame, где строки неселены и содержат NAS :

 <код> library(data.table) group <- data.table(Subject=ID, pt=Value, Event=Event)  group[, .SD[order(pt, decreasing = TRUE) == 1], by = Subject] 2  

Это нормально, если есть только несколько столбцов, но если таблица имеет много столбцов по всему (), полезно. Примеры для этого глагола часто с суммирования (поперек (start_with ... но в этом примере столбцы не начинаются с тех же символов. Либо они могут быть изменены, либо указаны в списке:

 <код> library(data.table) group <- data.table(Subject=ID, pt=Value, Event=Event)  group[, .SD[order(pt, decreasing = TRUE) == 1], by = Subject] 3  

Примечание для глагола по всему () 1 относится к первому столбцу после того, как первый фактический столбец, поэтому используя ncol (group), не будет работать так, как это слишком много столбцов (делает его положением 4 чем 3).

 

Using dplyr 1.0.2 there are now two ways to do this, one is long hand and the other is using the verb across():

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

Long hand the verb is max() but note the na.rm = TRUE which is useful for examples where there are NAs as in the closed question: Merge rows in a dataframe where the rows are disjoint and contain NAs:

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

This is ok if there are only a few columns but if the table has many columns across() is useful. The examples for this verb are often with summarise(across(start_with... but in this example the columns don't start with the same characters. Either they could be changed or the positions listed:

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

Note for the verb across() 1 refers to the first column after the first actual column so using ncol(group) won't work as that is too many columns (makes it position 4 rather than 3).

</div
 
 
-1
 
vote

Если вы хотите наибольшее значение PT для предмета, вы можете просто использовать:

 <код> library(data.table) group <- data.table(Subject=ID, pt=Value, Event=Event)  group[, .SD[order(pt, decreasing = TRUE) == 1], by = Subject] 4  
 

If you want the biggest pt value for a subject, you could simply use:

   pt_max = as.data.frame(aggregate(pt~Subject, group, max)) 
</div
 
 

Связанный проблема

0  Hexfile Package R  ( Hexfile package r ) 
Я пытаюсь импортировать файл eviews (.wf1) в <код> R с hexView пакет. код: <код> file = readEViews(hexViewFile("eviewsr.wf1"),as.data.frame = TRUE) ...

1  Как избежать проблемы Log-Quartelive Log-Inf в MLE Function из пакета Stat4?  ( How to avoid the inf log likelihood problem in mle function from stat4 package ) 
Я хочу максимизировать функцию вероятности логики, чтобы соответствовать некоторым данным, но функция MLE останавливается с этой ошибкой, когда логическая вер...

1  Замените отсутствующие значения в ячейке со значением из ячейки выше (N-1) с помощью петли  ( Replace missing values in a cell with a value from the cell above n 1 using a ) 
У меня есть файл данных с тысячами строк, у которых есть пробелы, которые я хочу заполнить значением. Мне нужно заменить пустые ячейки со значениями из них вы...

2  dlyryr "не обещание" ошибка  ( Dplyr not a promise error ) 
У меня есть набор набора панели, для которого я создал отсталые переменные с помощью функции LAG (). Когда я пытаюсь рассчитать дельта для каждого TimePoint, ...

0  Извлечение данных из нижних слоев в растробрике  ( Extracting data from lower layers in a rasterbrick ) 
Итак, я извлекаю данные из растробрика, который я сделал, используя метод из этого вопроса: Как извлечь данные из растробрика? В дополнение к получению да...

5  Расчет дней в месяц между интервалом двух дат  ( Calculating days per month between interval of two dates ) 
У меня есть набор событий, которые каждый из которых имеет начало и окончание, но они проходят по объему ряда месяцев. Я хотел бы создать таблицу, которая пок...

2  Как изменить график разброса GGPlot2  ( How to modify ggplot2 scatter plot ) 
Вот мой набор данных: <код> df1 = data.frame(Count.amp = c(8,8,1,2,2,5,8), Count.amp.1 = c(4,4,2,3,2,5,4)) Я попробовал <код> library(ggplot2) qplot(C...

0  Ошибка при использовании списков  ( Error when using lists ) 
У меня есть файл .rdata со списком внутри. Однако я получаю сообщение об ошибке при попытке отобразить список. <код> ls(data$Test$t0) Error in list2env(lis...

2  Вопросы с установкой пакета Caret of R в Archlinux  ( Issues with installing caret package of r in archlinux ) 
Я пытаюсь установить пакет <код> SCRIPT="""UPDATE IND_AFRO.DRIVER SET Emp_Id = 1000, update_user_id = 'RIBST-4059' WHERE Emp_Id IN (SELECT Emp_Id ...

1  Есть ли не-Java внедрение регрессионной модели M5P библиотеки RWEKA?  ( Is there a non java implementation of the m5p regression model of the rweka libr ) 
Я ищу функцию, которая создает модель регрессии M5P, как <код> M5P функция <код> RWeka библиотеки (как <код> M5P функция на основе кода Java, который имеет...

2  Package Desolve Package Can Parames включают в себя матрицу?  ( Desolve package can parameters include a matrix ) 
Я пытаюсь кодировать модель Seir, которая является возрастной, стратифицированной; То есть в моих дифференциальных уравнениях у меня есть параметр для массово...

0  R Язык: Как работать с динамически размером вектора?  ( R language how to work with dynamically sized vector ) 
Я изучаю программирование R, и пытаясь понять лучший подход к работе с вектором, когда вы не знаете, последний размер, он в конечном итоге будет. Например, в ...

0  Скрепление финансовых таблиц с веб-страницы с R, Rvest, RCURL  ( Scraping financial tables from web page with r rvest rcurl ) 
Я пробую разбор финансовых таблиц с веб-страницы. Я продолжал. Но я не могу устраивать список, или данные. Карамент <код> library(rvest) link <- "http://www...

6  403 Ошибка при использовании Rvest для входа в веб-сайт для соскабливания  ( 403 error when using rvest to log into website for scraping ) 
Я пытаюсь высказать страницу на веб-сайте, который требует входа в систему и в целом получение ошибки 403. Я изменил код из этих 2 сообщений для моего сайта...

0  Как сделать бесконечно рекурсивный список в R: путать [и [[  ( How to make an infinitely recursive list in r confuse and ) 
Редактировать: Этот вопрос глупо, я путающую [и [((спасибо @josilber), но я не могу удалить его. Как можно сделать бесконечно рекурсивный список, l == l [1]...




© 2021 www.qaru.top All Rights Reserved. Q&A House все права защищены


Licensed under cc by-sa 3.0 with attribution required.