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值。
#1 楼
这是一个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
在这种情况下,它没有什么区别,因为数据中任何组中都没有多个最大值。
评论
鉴于data.table自2014年以来发生了很多变化,这是否仍然是解决此问题最快/最好的解决方案?
–本
16年5月24日在21:03
@Ben,在这种情况下,最快的答案仍然是这个,是的。针对这些情况的.SD优化仍在列表中。看看#735。
–阿伦
16年5月24日在22:26
嗨,什么是$ V1? #菜鸟
– sriharsha KB
16年6月1日于13:53
访问自动命名的列。如果没有它,请运行它以更好地理解。
–阿伦
2016年6月1日14:19
@HappyCoding,看看?`.I`,看看那里的解释和例子是否有帮助?
–阿伦
17年6月29日在23:15
#2 楼
最直观的方法是在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
评论
当您要访问组中的最小和最大值时,dplyr也很有用,因为这些值可以作为数组使用。因此,您可以先按pt降序排序,然后使用pt [1]或first(pt)获得最大值:group%>%group_by(Subject)%>%ranging(desc(pt),.by_group = TRUE)% >%摘要(max_pt = first(pt),min_pt = last(pt),Event = first(Event))
– cw'
19年1月16日在9:39
如果有联系,它将包括多行。使用slice(which.max(pt))每组仅包含一行。
– cakraww
19年7月18日在15:14
#3 楼
使用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
评论
注意,这可能比@Arun上面建议的group [group [,.I [that.max(pt)] by = Subject] $ V1]慢。在这里查看比较
–华伦丁
19年1月21日在16:56
我喜欢这个,因为它对于我当前的上下文来说足够快,并且与.I版本相比更容易理解
– arvi1000
19年7月19日在22:07
setDT(group)[,.SD [pt == max(pt)],by = Subject]
– Ferroao
2月20日22:03
#4 楼
另一个选择是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
#5 楼
一个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
评论
我认为OP希望将“事件”列保留在子集中,在这种情况下,您可以执行以下操作:df%>%group_by(Subject)%>%filter(pt == max(pt))(如果存在,则包括联系)
–talat
2014年7月3日在18:11
#6 楼
我不确定您要对“事件”列进行什么操作,但是如果您也想保留该内容,那么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
来查找在每个“ ID”的“值”列中。然后,我们确定哪个值是最大值,然后将其转化为逻辑向量,可用于子集原始数据。评论
非常感谢,但我在这里还有另一个问题。为什么在此方法中使用函数,因为ave(Value,ID,FUN = function(x)seq_along(x)== which.max(x))== 1效果很好?我有点困惑。
–王欣婷
2014年7月4日在12:38
我使用过,因为在组data.frame的内部和外部都有可用数据有点奇怪。如果使用read.table或其他方式读取数据,则需要使用with,因为这些列名称在data.frame之外不可用。
– MrFlick
2014年7月4日15:56
#7 楼
do.call(rbind, lapply(split(group,as.factor(group$Subject)), function(x) {return(x[which.max(x$pt),])}))
使用底座
R
#8 楼
从{dplyr} v1.0.0(2020年5月)开始,有新的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
由reprex程序包(v0.3.0.9001)创建于2020-08-18
会话信息
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
#9 楼
另一个基本解决方案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
中重复的行#10 楼
另一种基本的R解决方案:merge(aggregate(pt ~ Subject, max, data = group), group)
Subject pt Event
1 1 5 2
2 2 17 2
3 3 5 2
#11 楼
这是另一种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]
#12 楼
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
#13 楼
在基础上,您可以使用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
#14 楼
另一个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
#15 楼
另一个data.table
解决方案:library(data.table)
setDT(group)[, head(.SD[order(-pt)], 1), by = .(Subject)]
#16 楼
使用dplyr 1.0.2,现在有两种方法可以做到这一点,一种是长手,另一种是使用动词cross(): # 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(),但请注意.rm = TRUE,对于以下已解决的问题中存在NA的示例很有用:合并数据帧中行不相交并包含NA的行:
group %>%
group_by(Subject) %>%
summarise(pt = max(pt, na.rm = TRUE),
Event = max(Event, na.rm = TRUE))
如果只有一个几列,但如果表中有很多列,则cross()很有用。此动词的示例通常带有summarise(across(start_with ...,但在此示例中,列的开头不是相同的字符。可以更改它们或列出的位置:
group %>%
group_by(Subject) %>%
summarise(across(1:ncol(group)-1, max, na.rm = TRUE, .names = "{.col}"))
请注意动词cross()1指的是第一列实际之后的第一列,因此使用ncol(group)将不起作用,因为列太多(将其置于第4位而不是第3位)。
#17 楼
如果要获得最大的pt值,可以使用: pt_max = as.data.frame(aggregate(pt~Subject, group, max))
评论
这是密切相关的,但是为了最小而不是最大stackoverflow.com/questions/24070714/…相关:使用data.table
按组分组