그룹별 평균 계산
다음과 유사한 대형 데이터 프레임이 있습니다.
df <- data.frame(dive = factor(sample(c("dive1","dive2"), 10, replace=TRUE)),
speed = runif(10)
)
> df
dive speed
1 dive1 0.80668490
2 dive1 0.53349584
3 dive2 0.07571784
4 dive2 0.39518628
5 dive1 0.84557955
6 dive1 0.69121443
7 dive1 0.38124950
8 dive2 0.22536126
9 dive1 0.04704750
10 dive2 0.93561651
나의 목표는 다른 열이 어떤 값과 같을 때 한 열에 있는 값들의 평균을 구하고 모든 값에 대해 이를 반복하는 것입니다. 즉 위의 예에서 나는 열에 대한 평균을 반환하고 싶습니다.speed
열의 모든 고유 값에 대해dive
. 그래서 언제dive==dive1
, 에 대한 평균speed
이것은 각각의 가치에 대한 것입니까?dive
.
R에서 이것을 하는 방법은 여러 가지가 있습니다.구체적으로.by
,aggregate
,split
,그리고.plyr
,cast
,tapply
,data.table
,dplyr
대체로, 이러한 문제는 분할 적용 결합 형태입니다.해들리 위컴은 문제의 모든 범주에 대해 더 깊은 통찰력을 줄 아름다운 글을 썼으며, 이 글은 읽을 가치가 있습니다.plyr
패키지는 일반적인 데이터 구조에 대한 전략을 구현합니다.dplyr
는 데이터 프레임에 맞게 조정된 최신 구현 성능입니다.이들은 같은 형태이지만 이 문제보다 훨씬 더 복잡한 문제를 해결할 수 있습니다.데이터 조작 문제를 해결하는 일반적인 도구로서 충분히 배울 가치가 있습니다.
성능은 매우 큰 데이터셋에서 문제가 되며, 이 때문에 다음을 기반으로 한 솔루션을 능가하기가 어렵습니다.data.table
. 그러나 중간 규모 이하의 데이터셋만 다루면 시간을 들여 학습할 수 있습니다.data.table
노력할 가치가 없는 것 같습니다dplyr
또한 속도가 빠를 수 있으므로 작업 속도를 높이고 싶지만 확장성이 필요하지 않은 경우에는 좋은 선택입니다.data.table
.
아래의 다른 솔루션들 중 대부분은 추가 패키지를 필요로 하지 않습니다.그 중 일부는 중 대규모 데이터 세트에서도 상당히 빠릅니다.그들의 주된 단점은 은유 혹은 유연성 중 하나입니다.은유적으로 말하면, 저는 이 특정 유형의 문제를 '재치 있는' 방법으로 해결하기 위해 다른 것을 강요하기 위해 고안된 도구라는 것을 의미합니다.유연성이 있다면, 이들은 유사한 문제를 광범위하게 해결하거나 깔끔한 결과물을 쉽게 만들어낼 수 있는 능력이 부족하다는 것을 의미합니다.
예
base
기능들
tapply
:
tapply(df$speed, df$dive, mean)
# dive1 dive2
# 0.5419921 0.5103974
aggregate
:
aggregate
data.frame을 가져오고 data.frame을 출력하며 공식 인터페이스를 사용합니다.
aggregate( speed ~ dive, df, mean )
# dive speed
# 1 dive1 0.5790946
# 2 dive2 0.4864489
by
:
가장 사용자 친화적인 형태로 벡터를 받아들여 함수를 적용합니다.그러나 출력은 조작 가능한 형태가 아닙니다.
res.by <- by(df$speed, df$dive, mean)
res.by
# df$dive: dive1
# [1] 0.5790946
# ---------------------------------------
# df$dive: dive2
# [1] 0.4864489
이 문제를 해결하기 위해, 간단한 사용을 위해by
as.data.frame
메소드 인 더taRifx
라이브러리 작업:
library(taRifx)
as.data.frame(res.by)
# IDX1 value
# 1 dive1 0.6736807
# 2 dive2 0.4051447
split
:
이름에서 알 수 있듯이 분할 적용 결합 전략의 "분할" 부분만 수행합니다.나머지가 잘 될 수 있도록 다음과 같은 작은 함수를 쓰겠습니다.sapply
combine용으로sapply
결과를 최대한 자동으로 단순화합니다.우리의 경우, 결과가 1차원 밖에 없기 때문에, 그것은 data.frame이 아닌 벡터를 의미합니다.
splitmean <- function(df) {
s <- split( df, df$dive)
sapply( s, function(x) mean(x$speed) )
}
splitmean(df)
# dive1 dive2
# 0.5790946 0.4864489
외부 패키지
data.table:
library(data.table)
setDT(df)[ , .(mean_speed = mean(speed)), by = dive]
# dive mean_speed
# 1: dive1 0.5419921
# 2: dive2 0.5103974
dplyr
:
library(dplyr)
group_by(df, dive) %>% summarize(m = mean(speed))
(의 cursor 전에dplyr
)
여기 공식 페이지에서 말하는 내용이 있습니다.plyr
:
이것은 이미 가능합니다.
base
R수크)와 )split
그리고.apply
함수군),,plyr
다음을 통해 모든 것을 좀 더 쉽게 해줍니다.
- 완전히 일관된 이름, 인수 및 결과
- 를 통한 편리한 병렬화
foreach
꾸러미- 데이터에 입력 및 출력.프레임, 행렬 및 목록
- 장기간 실행 중인 작업을 추적하는 프로그레스 막대
- 기본 제공 오류 복구 및 유용한 오류 메시지
- 모든 변환에 걸쳐 유지되는 레이블
다시 말해, 분할 적용-결합 조작을 위한 하나의 도구를 배운다면 다음과 같이 해야 합니다.plyr
.
library(plyr)
res.plyr <- ddply( df, .(dive), function(x) mean(x$speed) )
res.plyr
# dive V1
# 1 dive1 0.5790946
# 2 dive2 0.4864489
모양 변경2:
reshape2
라이브러리는 분할 apply-combine를 주된 초점으로 하여 설계되지 않았습니다.대신, 2부 멜트/캐스트 전략을 사용하여 다양한 데이터 재구성 작업을 수행합니다.그러나 집계 기능을 허용하기 때문에 이 문제에 사용할 수 있습니다.분할 적용-결합 작업의 첫 번째 선택은 아니지만 재구성 기능이 강력하므로 이 패키지도 학습해야 합니다.
library(reshape2)
dcast( melt(df), variable ~ dive, mean)
# Using dive as id variables
# variable dive1 dive2
# 1 speed 0.5790946 0.4864489
벤치마크
열개의 행, 두 그룹
library(microbenchmark)
m1 <- microbenchmark(
by( df$speed, df$dive, mean),
aggregate( speed ~ dive, df, mean ),
splitmean(df),
ddply( df, .(dive), function(x) mean(x$speed) ),
dcast( melt(df), variable ~ dive, mean),
dt[, mean(speed), by = dive],
summarize( group_by(df, dive), m = mean(speed) ),
summarize( group_by(dt, dive), m = mean(speed) )
)
> print(m1, signif = 3)
Unit: microseconds
expr min lq mean median uq max neval cld
by(df$speed, df$dive, mean) 302 325 343.9 342 362 396 100 b
aggregate(speed ~ dive, df, mean) 904 966 1012.1 1020 1060 1130 100 e
splitmean(df) 191 206 249.9 220 232 1670 100 a
ddply(df, .(dive), function(x) mean(x$speed)) 1220 1310 1358.1 1340 1380 2740 100 f
dcast(melt(df), variable ~ dive, mean) 2150 2330 2440.7 2430 2490 4010 100 h
dt[, mean(speed), by = dive] 599 629 667.1 659 704 771 100 c
summarize(group_by(df, dive), m = mean(speed)) 663 710 774.6 744 782 2140 100 d
summarize(group_by(dt, dive), m = mean(speed)) 1860 1960 2051.0 2020 2090 3430 100 g
autoplot(m1)
평소처럼.data.table
오버헤드가 조금 더 크기 때문에 소규모 데이터셋의 경우 평균적으로 제공됩니다.그러나 이들은 마이크로초이므로 차이점은 사소한 것입니다.여기서는 모든 접근 방식이 정상적으로 작동하며, 다음을 기준으로 선택해야 합니다.
- 이미 잘 알고 있거나 알고 싶은 것 (
plyr
유연성에 대해서는 항상 배울 가치가 있습니다.data.table
거대한 데이터셋을 분석할 계획이라면 배울 가치가 있습니다.by
그리고.aggregate
그리고.split
모든 기본 R 함수이므로 보편적으로 사용할 수 있습니다. - 반환하는 출력(숫자, data.frame 또는 data.table -- 후자가 data.frame에서 상속됨)
천만 줄, 열 그룹
하지만 우리가 큰 데이터 세트를 가지고 있다면 어떨까요?10개의 그룹으로 나누어진 10^7개의 열을 시도해 보겠습니다.
df <- data.frame(dive=factor(sample(letters[1:10],10^7,replace=TRUE)),speed=runif(10^7))
dt <- data.table(df)
setkey(dt,dive)
m2 <- microbenchmark(
by( df$speed, df$dive, mean),
aggregate( speed ~ dive, df, mean ),
splitmean(df),
ddply( df, .(dive), function(x) mean(x$speed) ),
dcast( melt(df), variable ~ dive, mean),
dt[,mean(speed),by=dive],
times=2
)
> print(m2, signif = 3)
Unit: milliseconds
expr min lq mean median uq max neval cld
by(df$speed, df$dive, mean) 720 770 799.1 791 816 958 100 d
aggregate(speed ~ dive, df, mean) 10900 11000 11027.0 11000 11100 11300 100 h
splitmean(df) 974 1040 1074.1 1060 1100 1280 100 e
ddply(df, .(dive), function(x) mean(x$speed)) 1050 1080 1110.4 1100 1130 1260 100 f
dcast(melt(df), variable ~ dive, mean) 2360 2450 2492.8 2490 2520 2620 100 g
dt[, mean(speed), by = dive] 119 120 126.2 120 122 212 100 a
summarize(group_by(df, dive), m = mean(speed)) 517 521 531.0 522 532 620 100 c
summarize(group_by(dt, dive), m = mean(speed)) 154 155 174.0 156 189 321 100 b
autoplot(m2)
그리고나서data.table
아니면dplyr
조작을 사용하여data.table
s는 분명히 가야할 길입니다.특정 접근 방식(aggregate
그리고.dcast
매우 느리게 보이기 시작했습니다.
천만 줄, 천 그룹
더 많은 그룹이 있으면 차이가 더 두드러집니다.1,000개의 그룹과 동일한 10^7개의 행이 있는 경우:
df <- data.frame(dive=factor(sample(seq(1000),10^7,replace=TRUE)),speed=runif(10^7))
dt <- data.table(df)
setkey(dt,dive)
# then run the same microbenchmark as above
print(m3, signif = 3)
Unit: milliseconds
expr min lq mean median uq max neval cld
by(df$speed, df$dive, mean) 776 791 816.2 810 828 925 100 b
aggregate(speed ~ dive, df, mean) 11200 11400 11460.2 11400 11500 12000 100 f
splitmean(df) 5940 6450 7562.4 7470 8370 11200 100 e
ddply(df, .(dive), function(x) mean(x$speed)) 1220 1250 1279.1 1280 1300 1440 100 c
dcast(melt(df), variable ~ dive, mean) 2110 2190 2267.8 2250 2290 2750 100 d
dt[, mean(speed), by = dive] 110 111 113.5 111 113 143 100 a
summarize(group_by(df, dive), m = mean(speed)) 625 630 637.1 633 644 701 100 b
summarize(group_by(dt, dive), m = mean(speed)) 129 130 137.3 131 142 213 100 a
autoplot(m3)
그렇게data.table
계속해서 잘 확장되고 있습니다.dplyr
작동하는data.table
또한 잘 작동합니다.dplyr
위에data.frame
거의 10배 가까이 더 느린 속도입니다.split
/sapply
전략은 그룹의 수에서 형편없이 확장되는 것처럼 보입니다(즉,split()
느릴 가능성이 높고 그리고sapply
빠름).by
5초면 사용자에게 확실히 눈에 띄지만 이 정도 크기의 데이터셋의 경우에는 여전히 합리적이지 않습니다.하지만 이 정도 크기의 데이터셋을 일상적으로 사용한다면data.table
100% data.table을 통해 최고의 성능을 발휘할 수 있습니다.dplyr
와 함께dplyr
data.table
실행 가능한 대안으로
dplyr를 사용한 2015 업데이트:
df %>% group_by(dive) %>% summarise(percentage = mean(speed))
Source: local data frame [2 x 2]
dive percentage
1 dive1 0.4777462
2 dive2 0.6726483
aggregate(speed~dive,data=df,FUN=mean)
dive speed
1 dive1 0.7059729
2 dive2 0.5473777
다양한 경우에도 빠르게 유지되는 대체 베이스 R 접근법을 추가합니다.
rowsummean <- function(df) {
rowsum(df$speed, df$dive) / tabulate(df$dive)
}
@Ari에서 벤치마크를 빌리는 중:
열개의 행, 두 그룹
천만 줄, 열 그룹
1000만 행, 1000개
새로운 기능으로across
:
df %>%
group_by(dive) %>%
summarise(across(speed, mean, na.rm = TRUE))
우리는 이미 그룹별로 비열한 선택을 할 수 있는 수많은 옵션을 가지고 있고, 여기에 하나를 더 추가했습니다.mosaic
꾸러미의
mosaic::mean(speed~dive, data = df)
#dive1 dive2
#0.579 0.440
이것은 명명된 숫자 벡터를 반환합니다. 필요한 경우 데이터 프레임으로 감쌀 수 있습니다.stack
stack(mosaic::mean(speed~dive, data = df))
# values ind
#1 0.579 dive1
#2 0.440 dive2
데이터.
set.seed(123)
df <- data.frame(dive=factor(sample(c("dive1","dive2"),10,replace=TRUE)),
speed=runif(10))
으로.collapse
library(collapse)
library(magrittr)
df %>%
fgroup_by(dive) %>%
fsummarise(speed = fmean(speed))
# dive speed
#1 dive1 0.5788479
#2 dive2 0.4401514
데이터.
set.seed(123)
df <- data.frame(dive=factor(sample(c("dive1","dive2"),10,replace=TRUE)),
speed=runif(10))
RCchelsie에서 제공하는 답변 확장 - 평균을 구하려면 데이터 프레임의 모든 열에 대해 그룹별로 계산합니다.
df %>%
group_by(dive) %>%
summarise(across(.cols=everything(), mean, na.rm=TRUE))
1.1.0
(그리고 위)를 사용하여 일시적으로 그룹화할 수 있습니다..by
논쟁.
이렇게 하면 코드가 짧아집니다(피합니다).group_by
그리고.ungroup
및문)를 포함합니다..by
그룹화되지 않은 데이터 프레임을 항상 반환합니다.
library(dplyr)
df %>% summarise(speed = mean(speed), .by = dive)
# dive speed
#1 dive1 0.5788479
#2 dive2 0.4401514
와 함께timeplyr
케이크도 먹고 먹을 수 있습니다.
케이크로 말입니다.tidy
구문과 그것을 먹는다는 것은 케이크가 엄청 빠르다는 것을 의미합니다.
stat_summarise()
혼합하여 사용합니다.collapse
,data.table
그리고.dplyr
희생하지 않고 최적의 성능을 발휘합니다.tidy
통사론
가장 효율적인 방법은 다음과 같습니다.data.table
타임플라이어와 동등한 속도를 볼 수 있습니다.
# remotes::install_github("NicChr/timeplyr")
library(plyr)
library(dplyr)
library(ggplot2)
library(timeplyr)
library(data.table)
dt <- data.table(dive = factor(sample.int(10^6, size = 10^7, replace=TRUE)),
speed = runif(10^7))
setkey(dt, dive)
m2 <- microbenchmark::microbenchmark(
dt[,mean(speed),by=dive],
stat_summarise(dt, .cols = "speed",
.by = dive, stat = "mean", sort = F),
times = 15
)
print(m2, signif = 3)
#> Unit: milliseconds
#> expr
#> dt[, mean(speed), by = dive]
#> stat_summarise(dt, .cols = "speed", .by = dive, stat = "mean", sort = F)
#> min lq mean median uq max neval cld
#> 148 184 272 261 344 499 15 a
#> 139 197 283 221 328 540 15 a
autoplot(m2)
#> Coordinate system already present. Adding new coordinate system, which will
#> replace the existing one.
천만 행, ~ 백만 그룹
메모리 사용량을 비교할 때,stat_summarise()
실제로 보다 훨씬 더 효율적입니다.data.table
.
# Memory comparison
bench::mark(
DT = dt[, list(speed = mean(speed)), by = dive],
TP = stat_summarise(dt, .cols = "speed",
.by = dive, stat = "mean", sort = F),
check = FALSE
)
#> 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 DT 194ms 308ms 3.25 248MB 4.87
#> 2 TP 133ms 277ms 3.61 68.7MB 1.81
2023-05-19에 repex v2.0.2로 생성됨
언급URL : https://stackoverflow.com/questions/11562656/calculate-the-mean-by-group
'programing' 카테고리의 다른 글
nodejs - 인증서 체인에서 자체 서명된 인증서 오류 (0) | 2023.10.21 |
---|---|
jQuery에서 선택한 태그에 있는 옵션 태그 수 (0) | 2023.10.21 |
양식에 대한 AJAX 포스트 요청에서 CSRF 토큰을 전달하는 방법은? (0) | 2023.10.21 |
C#의 잘못된 XML 문자 탈출 (0) | 2023.10.21 |
모범 사례:HTML ID 또는 이름 속성별 양식 요소에 액세스하시겠습니까? (0) | 2023.10.21 |