programing

각 그룹에서 최대값이 있는 행 선택

abcjava 2023. 6. 5. 23:32
반응형

각 그룹에서 최대값이 있는 행 선택

각 주제에 대해 여러 개의 관측치가 있는 데이터 집합입니다.각 제목에 대해 최대값이 'pt'인 행을 선택합니다.예를 들어, 다음과 같은 데이터 집합이 있습니다.

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 pt Event
# 1       1  2     1
# 2       1  3     1
# 3       1  5     2 # max 'pt' for Subject 1
# 4       2  2     1
# 5       2  5     2
# 6       2  8     1
# 7       2 17     2 # max 'pt' for Subject 2
# 8       3  3     2
# 9       3  5     2 # max 'pt' for Subject 3

주제 1, 2, 3의 pt 값이 각각 5, 17, 5로 가장 큽니다.

먼저 각 주제에 대한 가장 큰 pt 값을 찾은 다음 이 관찰을 다른 데이터 프레임에 넣을 수 있는 방법은 무엇입니까?결과 데이터 프레임은 각 주제에 대해 가장 큰 pt 값만 가져야 합니다.

여기에 여에가 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

▁value▁of▁▁just▁first▁max▁you▁if▁like오'd시하십첫같이.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

이 경우 데이터 그룹 내에 여러 최대값이 없으므로 차이가 없습니다.

은 가장직관방다같법습다니음과은인적▁is를 사용하는 것입니다.group_by그리고.top_n에서 합니다.dplyr

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

다음을 사용하여 보다 짧은 솔루션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

다른 은 또다옵은입니다.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

용사를 합니다.dplyr1.1.0

slice_max(group, pt, by = 'Subject')

{) {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에 생성되었습니다.

A 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
do.call(rbind, lapply(split(group,as.factor(group$Subject)), function(x) {return(x[which.max(x$pt),])}))

사용하기R

이벤트 열에 대해 무엇을 하고 싶은지 확신할 수 없었지만, 만약 당신이 그것도 유지하고 싶다면, 어때요?

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"Value"합니다. "ID"는 "Value"입니다.그런 다음 어떤 값이 최대값인지 결정한 다음 원래 data.frame의 부분 집합을 만드는 데 사용할 수 있는 논리 벡터로 변환합니다.

기본 R 솔루션 하나 더:

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

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

다른 기본 솔루션

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

사용할 수 있는 베이스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

로 는또추사용을 것.with.

group[with(group, pt == ave(pt, Subject, FUN=max)),]

또는 함수에서 이미 비교할 수 있습니다.

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

또 의 여또있다니습이 있습니다.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]

하나의 른다.data.table솔루션:

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

by는 의버니다입의 입니다.tapply데이터 프레임의 경우:

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

▁object의 객체를 합니다.by데이터 프레임으로 변환합니다.

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

하나의 른다.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

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가 있는 예에 유용한 na.rm = TRUE를 기록합니다.행이 분리되고 NA가 포함된 데이터 프레임에서 행을 병합합니다.

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

열이 몇 개만 있는 경우에는 괜찮지만 테이블에 가로()로 열이 여러 개 있는 경우에는 유용합니다.이 동사의 예는 종종 요약(cross(start_with...)과 함께 있습니다.그러나 이 예제에서는 열이 동일한 문자로 시작하지 않습니다.변경할 수 있거나 나열된 위치:

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

동사 가로쓰기() 1은 첫 번째 실제 열 뒤의 첫 번째 을 참조하므로 ncol(그룹)을 사용하면 열이 너무 많기 때문에 작동하지 않습니다(3이 아닌 위치 4가 됩니다).

저는 때때로 해결책에 의존합니다.order함수는 모든 유형의 열(즉, 열)에 대해 작동합니다.숫자 뿐만 아니라).기본적으로 테이블을 최대 또는 최소로 정렬한 다음 각 그룹의 첫 번째 또는 마지막을 선택합니다.

저는 또한 이것이 꽤 쉽게 읽을 수 있다고 생각합니다.data.table초보자

library(data.table)

setDT(group)[order(pt)][, last(.SD), by = Subject]

참고: 대체last와 함께first최소값에 해당하는 값을 달성합니다.

와 함께dplyr 1.1.0사용할 수 있습니다.slice_max와 함께by인라인 그룹화 슬라이싱을 수행하는 방법

library(dplyr)
group %>% 
  slice_max(pt, n = 1, by = Subject)

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

제목에 대해 가장 큰 pt 값을 원하는 경우 다음을 사용할 수 있습니다.

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

언급URL : https://stackoverflow.com/questions/24558328/select-the-row-with-the-maximum-value-in-each-group

반응형