그룹화된 데이터에서 첫 번째 행과 마지막 행 선택
질문.
사용.dplyr
하나의 문에서 그룹화된 데이터의 상단 및 하단 관측치/행을 선택하려면 어떻게 해야 합니까?
데이터 & 예제
주어진 데이터 프레임:
df <- data.frame(id=c(1,1,1,2,2,2,3,3,3),
stopId=c("a","b","c","a","b","c","a","b","c"),
stopSequence=c(1,2,3,3,1,4,3,1,2))
다음을 사용하여 각 그룹의 상단 및 하단 관측치를 가져올 수 있습니다.slice
하지만 두 개의 별개의 진술을 사용합니다.
firstStop <- df %>%
group_by(id) %>%
arrange(stopSequence) %>%
slice(1) %>%
ungroup
lastStop <- df %>%
group_by(id) %>%
arrange(stopSequence) %>%
slice(n()) %>%
ungroup
이 두 문장을 위쪽과 아래쪽 관측치를 모두 선택하는 하나의 문장으로 결합할 수 있습니까?
더 빠른 방법이 있을 것입니다.
df %>%
group_by(id) %>%
arrange(stopSequence) %>%
filter(row_number()==1 | row_number()==n())
완전성을 위해:합격할 수 있습니다slice
지수 벡터:
df %>% arrange(stopSequence) %>% group_by(id) %>% slice(c(1,n()))
이는
id stopId stopSequence
1 1 a 1
2 1 c 3
3 2 b 1
4 2 c 4
5 3 b 1
6 3 a 3
것은 아니다.dplyr
하지만 훨씬 더 직접적으로 사용할 수 있습니다.data.table
:
library(data.table)
setDT(df)
df[
df[order(id, stopSequence), .(rows = .I[c(1L,.N)]), by=id]$rows
]
# rows stopId stopSequence
# 1: 1 a 1
# 2: 1 c 3
# 3: 2 b 1
# 4: 2 c 4
# 5: 3 b 1
# 6: 3 a 3
더 자세한 설명:
# 1) get row numbers of first/last observations from each group
# * basically, we sort the table by id/stopSequence, then,
# grouping by id, name the row numbers of the first/last
# observations for each id; since this operation produces
# a data.table
# * .I is data.table shorthand for the row number
# * here, to be maximally explicit, I've named the variable rows
# as row_num to give other readers of my code a clearer
# understanding of what operation is producing what variable
first_last = df[order(id, stopSequence), .(rows = .I[c(1L,.N)]), by=id]
idx = first_last$rows
# 2) extract rows by number
df[idx]
자세한 내용은 시작하기 Wiki를 참조하십시오.data.table
포함된 기본 사항
사용.which.min
그리고.which.max
:
library(dplyr, warn.conflicts = F)
df %>%
group_by(id) %>%
slice(c(which.min(stopSequence), which.max(stopSequence)))
#> # A tibble: 6 x 3
#> # Groups: id [3]
#> id stopId stopSequence
#> <dbl> <fct> <dbl>
#> 1 1 a 1
#> 2 1 c 3
#> 3 2 b 1
#> 4 2 c 4
#> 5 3 b 1
#> 6 3 a 3
기준이 되는
또한 stopSequence 열 전체를 정렬하는 대신 그룹별로 최소값과 최대값을 찾기 때문에 현재 승인된 답변보다 훨씬 빠릅니다.
# create a 100k times longer data frame
df2 <- bind_rows(replicate(1e5, df, F))
bench::mark(
mm =df2 %>%
group_by(id) %>%
slice(c(which.min(stopSequence), which.max(stopSequence))),
jeremy = df2 %>%
group_by(id) %>%
arrange(stopSequence) %>%
filter(row_number()==1 | row_number()==n()))
#> Warning: Some expressions had a GC in every iteration; so filtering is disabled.
#> # A tibble: 2 x 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 mm 22.6ms 27ms 34.9 14.2MB 21.3
#> 2 jeremy 254.3ms 273ms 3.66 58.4MB 11.0
지정된 질문을 알고 있습니다.dplyr
하지만 다른 사람들이 이미 다른 패키지를 사용하여 솔루션을 게시했기 때문에 저는 다른 패키지도 사용해 보기로 결정했습니다.
기본 패키지:
df <- df[with(df, order(id, stopSequence, stopId)), ]
merge(df[!duplicated(df$id), ],
df[!duplicated(df$id, fromLast = TRUE), ],
all = TRUE)
data.table:
df <- setDT(df)
df[order(id, stopSequence)][, .SD[c(1,.N)], by=id]
sqldf:
library(sqldf)
min <- sqldf("SELECT id, stopId, min(stopSequence) AS StopSequence
FROM df GROUP BY id
ORDER BY id, StopSequence, stopId")
max <- sqldf("SELECT id, stopId, max(stopSequence) AS StopSequence
FROM df GROUP BY id
ORDER BY id, StopSequence, stopId")
sqldf("SELECT * FROM min
UNION
SELECT * FROM max")
하나의 쿼리에서:
sqldf("SELECT *
FROM (SELECT id, stopId, min(stopSequence) AS StopSequence
FROM df GROUP BY id
ORDER BY id, StopSequence, stopId)
UNION
SELECT *
FROM (SELECT id, stopId, max(stopSequence) AS StopSequence
FROM df GROUP BY id
ORDER BY id, StopSequence, stopId)")
출력:
id stopId StopSequence
1 1 a 1
2 1 c 3
3 2 b 1
4 2 c 4
5 3 a 3
6 3 b 1
다음과 같은 것:
library(dplyr)
df <- data.frame(id=c(1,1,1,2,2,2,3,3,3),
stopId=c("a","b","c","a","b","c","a","b","c"),
stopSequence=c(1,2,3,3,1,4,3,1,2))
first_last <- function(x) {
bind_rows(slice(x, 1), slice(x, n()))
}
df %>%
group_by(id) %>%
arrange(stopSequence) %>%
do(first_last(.)) %>%
ungroup
## Source: local data frame [6 x 3]
##
## id stopId stopSequence
## 1 1 a 1
## 2 1 c 3
## 3 2 b 1
## 4 2 c 4
## 5 3 b 1
## 6 3 a 3
와 함께do
당신은 그룹에서 많은 수의 작업을 수행할 수 있지만 @tftcg의 대답은 이 작업에만 더 적합합니다.
사용.data.table
:
# convert to data.table
setDT(df)
# order, group, filter
df[order(stopSequence)][, .SD[c(1, .N)], by = id]
id stopId stopSequence
1: 1 a 1
2: 1 c 3
3: 2 b 1
4: 2 c 4
5: 3 b 1
6: 3 a 3
이것은 잘 작동합니다.
df %>%
group_by(id) %>%
arrange(stopSequence) %>%
slice(1,n())
# A tibble: 6 × 3
# Groups: id [3]
# id stopId stopSequence
# <dbl> <chr> <dbl>
#1 1 a 1
#2 1 c 3
#3 2 b 1
#4 2 c 4
#5 3 b 1
#6 3 a 3
lapply 및 applyr 문을 사용한 또 다른 접근법.임의의 수의 요약 함수를 동일한 문에 적용할 수 있습니다.
lapply(c(first, last),
function(x) df %>% group_by(id) %>% summarize_all(funs(x))) %>%
bind_rows()
예를 들어 max stopSequence 값이 있는 행에 관심을 갖고 다음을 수행할 수도 있습니다.
lapply(c(first, last, max("stopSequence")),
function(x) df %>% group_by(id) %>% summarize_all(funs(x))) %>%
bind_rows()
다른 기본 R 대안은 첫 번째가 될 것입니다.order
타고id
그리고.stopSequence
,split
에 근거한 그들.id
그리고 모두에게id
첫 번째 인덱스와 마지막 인덱스만 선택하고 이러한 인덱스를 사용하여 데이터 프레임을 부분 집합화합니다.
df[sapply(with(df, split(order(id, stopSequence), id)), function(x)
c(x[1], x[length(x)])), ]
# id stopId stopSequence
#1 1 a 1
#3 1 c 3
#5 2 b 1
#6 2 c 4
#8 3 b 1
#7 3 a 3
또는 이와 유사한 사용법by
df[unlist(with(df, by(order(id, stopSequence), id, function(x)
c(x[1], x[length(x)])))), ]
언급URL : https://stackoverflow.com/questions/31528981/select-first-and-last-row-from-grouped-data
'programing' 카테고리의 다른 글
파이어베이스로 여러 소셜 서비스로 로그인하려면 어떻게 해야 합니까? (0) | 2023.06.26 |
---|---|
CALayers는 UIView의 경계 변경에 대해 크기를 조정하지 않았습니다. 왜죠? (0) | 2023.06.26 |
Mongoose.js: 항상 채우기 강제 (0) | 2023.06.26 |
오류: 다음 파일에 대한 로컬 변경 내용은 체크아웃 시 덮어씁니다. (0) | 2023.06.26 |
Oracle 시퀀스 트랜잭션 기능 (0) | 2023.06.26 |