그룹별 변수의 최소값에 해당하는 행 추출
(1) 데이터를 하나의 변수(State
), (2) 각 그룹 내에서 다른 변수의 최소값 행을 찾습니다(Employees
) 및 (3) 전체 행을 추출합니다.
그리고 (2)는 쉬운 한 줄이고, (3)도 그래야 할 것 같은데 이해가 안 돼요.
다음은 샘플 데이터 세트입니다.
> data
State Company Employees
1 AK A 82
2 AK B 104
3 AK C 37
4 AK D 24
5 RI E 19
6 RI F 118
7 RI G 88
8 RI H 42
data <- structure(list(State = structure(c(1L, 1L, 1L, 1L, 2L, 2L, 2L,
2L), .Label = c("AK", "RI"), class = "factor"), Company = structure(1:8, .Label = c("A",
"B", "C", "D", "E", "F", "G", "H"), class = "factor"), Employees = c(82L,
104L, 37L, 24L, 19L, 118L, 88L, 42L)), .Names = c("State", "Company",
"Employees"), class = "data.frame", row.names = c(NA, -8L))
계산한다.min
그룹별로 쉽게 사용할 수 있습니다.aggregate
:
> aggregate(Employees ~ State, data, function(x) min(x))
State Employees
1 AK 24
2 RI 19
... 또는data.table
:
> library(data.table)
> DT <- data.table(data)
> DT[ , list(Employees = min(Employees)), by = State]
State Employees
1: AK 24
2: RI 19
하지만 이에 해당하는 전체 행을 추출하려면 어떻게 해야 합니까?min
값, 즉, 다음을 포함합니다.Company
결과는?
조금 더 우아함:
library(data.table)
DT[ , .SD[which.min(Employees)], by = State]
State Company Employees
1: AK D 24
2: RI E 19
사용하는 것보다 약간 덜 우아함.SD
그러나 그룹이 많은 데이터의 경우 약간 더 빠릅니다.
DT[DT[ , .I[which.min(Employees)], by = State]$V1]
또한 식을 바꾸기만 하면 됩니다.which.min(Employees)
와 함께Employees == min(Employees)
데이터 세트에 동일한 최소값이 여러 개 있고 모든 최소값을 부분 집합으로 지정하려는 경우.
참고 항목: data.table을 사용하여 그룹별 최대값에 해당하는 행 부분 집합 취하기.
여기서dplyr
솔루션(일반 사용자가 아님):
library(dplyr)
data %>%
group_by(State) %>%
slice(which.min(Employees))
댓글에 재즈우로가 기록한 것처럼,dplyr
버전 1.0.0, 이제 내장 기능도 있습니다.slice_min
:
data %>%
group_by(State) %>%
slice_min(order_by = Employees)
이것이 구글의 최고 히트작이기 때문에, 저는 제가 알기에 유용하다고 생각하는 몇 가지 추가 옵션을 추가할 것이라고 생각했습니다.그 아이디어는 기본적으로 한 번씩 정리하는 것입니다.Employees
그리고 나서 고유한 것들을 가져가세요.State
사용 중 하나data.table
library(data.table)
unique(setDT(data)[order(Employees)], by = "State")
# State Company Employees
# 1: RI E 19
# 2: AK D 24
또는 먼저 주문한 다음 부분 집합을 지정할 수도 있습니다..SD
두 작업 모두 현재 data.table 버전에서 최적화되었습니다.order
겉보기에는 트리거입니다.data.table:::forderv
,하는 동안에.SD[1L]
트리거Gforce
setDT(data)[order(Employees), .SD[1L], by = State, verbose = TRUE] # <- Added verbose
# order optimisation is on, i changed from 'order(...)' to 'forder(DT, ...)'.
# i clause present and columns used in by detected, only these subset: State
# Finding groups using forderv ... 0 sec
# Finding group sizes from the positions (can be avoided to save RAM) ... 0 sec
# Getting back original order ... 0 sec
# lapply optimization changed j from '.SD[1L]' to 'list(Company[1L], Employees[1L])'
# GForce optimized j to 'list(`g[`(Company, 1L), `g[`(Employees, 1L))'
# Making each group and running j (GForce TRUE) ... 0 secs
# State Company Employees
# 1: RI E 19
# 2: AK D 24
또는dplyr
library(dplyr)
data %>%
arrange(Employees) %>%
distinct(State, .keep_all = TRUE)
# State Company Employees
# 1 RI E 19
# 2 AK D 24
@Khasha에서 차용한 또 다른 흥미로운 아이디어는 멋진 답변입니다(형태를 약간 수정했습니다).mult = "first"
여러 일치 항목을 처리하려면) 먼저 그룹당 최소값을 찾은 다음 이진 조인백을 수행합니다.이것의 장점은 data.tables의 활용도입니다.gmin
함수(평가 오버헤드를 건너뛰는 기능) 및 이진 조인 기능
tmp <- setDT(data)[, .(Employees = min(Employees)), by = State]
data[tmp, on = .(State, Employees), mult = "first"]
# State Company Employees
# 1: AK D 24
# 2: RI E 19
일부 벤치마크
library(data.table)
library(dplyr)
library(plyr)
library(stringi)
library(microbenchmark)
set.seed(123)
N <- 1e6
data <- data.frame(State = stri_rand_strings(N, 2, '[A-Z]'),
Employees = sample(N*10, N, replace = TRUE))
DT <- copy(data)
setDT(DT)
DT2 <- copy(DT)
str(DT)
str(DT2)
microbenchmark("(data.table) .SD[which.min]: " = DT[ , .SD[which.min(Employees)], by = State],
"(data.table) .I[which.min]: " = DT[DT[ , .I[which.min(Employees)], by = State]$V1],
"(data.table) order/unique: " = unique(DT[order(Employees)], by = "State"),
"(data.table) order/.SD[1L]: " = DT[order(Employees), .SD[1L], by = State],
"(data.table) self join (on):" = {
tmp <- DT[, .(Employees = min(Employees)), by = State]
DT[tmp, on = .(State, Employees), mult = "first"]},
"(data.table) self join (setkey):" = {
tmp <- DT2[, .(Employees = min(Employees)), by = State]
setkey(tmp, State, Employees)
setkey(DT2, State, Employees)
DT2[tmp, mult = "first"]},
"(dplyr) slice(which.min): " = data %>% group_by(State) %>% slice(which.min(Employees)),
"(dplyr) arrange/distinct: " = data %>% arrange(Employees) %>% distinct(State, .keep_all = TRUE),
"(dplyr) arrange/group_by/slice: " = data %>% arrange(Employees) %>% group_by(State) %>% slice(1),
"(plyr) ddply/which.min: " = ddply(data, .(State), function(x) x[which.min(x$Employees),]),
"(base) by: " = do.call(rbind, by(data, data$State, function(x) x[which.min(x$Employees), ])))
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# (data.table) .SD[which.min]: 119.66086 125.49202 145.57369 129.61172 152.02872 267.5713 100 d
# (data.table) .I[which.min]: 12.84948 13.66673 19.51432 13.97584 15.17900 109.5438 100 a
# (data.table) order/unique: 52.91915 54.63989 64.39212 59.15254 61.71133 177.1248 100 b
# (data.table) order/.SD[1L]: 51.41872 53.22794 58.17123 55.00228 59.00966 145.0341 100 b
# (data.table) self join (on): 44.37256 45.67364 50.32378 46.24578 50.69411 137.4724 100 b
# (data.table) self join (setkey): 14.30543 15.28924 18.63739 15.58667 16.01017 106.0069 100 a
# (dplyr) slice(which.min): 82.60453 83.64146 94.06307 84.82078 90.09772 186.0848 100 c
# (dplyr) arrange/distinct: 344.81603 360.09167 385.52661 379.55676 395.29463 491.3893 100 e
# (dplyr) arrange/group_by/slice: 367.95924 383.52719 414.99081 397.93646 425.92478 557.9553 100 f
# (plyr) ddply/which.min: 506.55354 530.22569 568.99493 552.65068 601.04582 727.9248 100 g
# (base) by: 1220.38286 1291.70601 1340.56985 1344.86291 1382.38067 1512.5377 100 h
기본 함수by
종종 data.frames의 블록 데이터 작업에 유용합니다.예를들면
by(data, data$State, function(x) x[which.min(x$Employees), ] )
목록에 있는 데이터를 반환하지만 다음을 사용하여 데이터를 축소할 수 있습니다.
do.call(rbind, by(data, data$State, function(x) x[which.min(x$Employees), ] ))
사용할 수 있는 베이스ave
갖기 위해min
그룹별로 비교합니다.Employees
그리고 논리 벡터를 얻어 부분 집합을 설정합니다.data.frame
.
data[data$Employees == ave(data$Employees, data$State, FUN=min),]
# State Company Employees
#4 AK D 24
#5 RI E 19
또는 함수에서 이미 비교할 수 있습니다.
data[as.logical(ave(data$Employees, data$State, FUN=function(x) x==min(x))),]
#data[ave(data$Employees, data$State, FUN=function(x) x==min(x))==1,] #Variant
# State Company Employees
#4 AK D 24
#5 RI E 19
수정됨plyr
솔루션:
ddply(df, .(State), function(x) x[which.min(x$Employees),])
# State Company Employees
# 1 AK D 24
# 2 RI E 19
용사를 합니다.collapse
library(collapse)
library(magrittr)
data %>%
fgroup_by(State) %>%
fsummarise(Employees = fmin(Employees))
하나의 른다.data.table
솔루션:
DT[, E_min := min(Employees), by = State][Employees == E_min]
꽤 간단하고 가장 빠른 것 중 하나입니다.아래에서는 David Arenburg의 벤치마킹을 이것과 다른 것으로 재실행합니다.data.table
해결책
library(data.table)
library(microbenchmark)
set.seed(123)
N <- 1e6
data <- data.frame(State = stri_rand_strings(N, 2, '[A-Z]'),
Employees = sample(N * 10, N, replace = TRUE))
DT <- copy(data)
setDT(DT)
DT2 <- copy(DT)
DT3 <- copy(DT)
microbenchmark(
"(data.table) min column: " = DT3[, E_min := min(Employees), by = State][Employees == E_min],
"(data.table) .I[which.min]: " = DT[DT[, .I[which.min(Employees)], by = State]$V1],
"(data.table) order/unique: " = unique(DT[order(Employees)], by = "State"),
"(data.table) self join (setkey):" = {
tmp <- DT2[, .(Employees = min(Employees)), by = State]
setkey(tmp, State, Employees)
setkey(DT2, State, Employees)
DT2[tmp, mult = "first"]
}
)
expr min lq mean median uq max neval
(data.table) min column: 44.30078 52.17932 68.31826 58.65887 76.89786 184.0207 100
(data.table) .I[which.min]: 20.34116 26.31244 39.36874 34.01958 42.65439 124.9204 100
(data.table) order/unique: 70.07820 80.20577 109.71235 95.25586 114.87695 514.4456 100
(data.table) self join (setkey): 13.48105 16.06614 22.58310 17.35083 22.31206 161.9103 100
의 열 중 몇 를 들어, 이 션 은 여 개 반 하 유 용 합 니 가 다 장 경 에 우 는 환 만 몇 솔 루 중 열 러 ▁this ▁returned 니 ▁is 다 ▁among 합[Employees == E_min, ..columns_to_keep]
이 경우에는 훨씬 더 빠를 수 있습니다.
언급URL : https://stackoverflow.com/questions/24070714/extract-row-corresponding-to-minimum-value-of-a-variable-by-group
'programing' 카테고리의 다른 글
MongoDB $pull을 사용하여 배열 내의 문서 삭제 (0) | 2023.06.20 |
---|---|
현재 사용자 언어 찾기 (0) | 2023.06.20 |
i == (i = 2)의 결과는 무엇입니까? (0) | 2023.06.20 |
형식 암시의 하위 클래스 (0) | 2023.06.20 |
Ruby에서 GUID 생성 (0) | 2023.06.20 |