다음 데이터 프레임이 있습니다.
x <- read.table(text = " id1 id2 val1 val2
1 a x 1 9
2 a x 2 4
3 a y 3 5
4 a y 4 9
5 b x 1 7
6 b y 4 4
7 b x 3 9
8 b y 2 8", header = TRUE)
id1과 id2로 그룹화 된 val1과 val2의 평균을 계산하고 동시에 각 id1-id2 조합의 행 수를 계산하고 싶습니다. 각 계산을 개별적으로 수행 할 수 있습니다.
# calculate mean
aggregate(. ~ id1 + id2, data = x, FUN = mean)
# count rows
aggregate(. ~ id1 + id2, data = x, FUN = length)
한 번의 호출로 두 가지 계산을 모두 수행하기 위해
do.call("rbind", aggregate(. ~ id1 + id2, data = x, FUN = function(x) data.frame(m = mean(x), n = length(x))))
그러나 경고와 함께 잘못된 출력이 표시됩니다.
# m n
# id1 1 2
# id2 1 1
# 1.5 2
# 2 2
# 3.5 2
# 3 2
# 6.5 2
# 8 2
# 7 2
# 6 2
# Warning message:
# In rbind(id1 = c(1L, 2L, 1L, 2L), id2 = c(1L, 1L, 2L, 2L), val1 = list( :
# number of columns of result is not a multiple of vector length (arg 1)
plyr 패키지를 사용할 수 있지만 데이터 세트의 크기가 커지면 데이터 세트가 상당히 크고 plyr가 매우 느립니다 (거의 사용 불가능).
aggregate
또는 다른 함수를 사용하여 한 번의 호출로 여러 계산을 수행 하려면 어떻게 해야합니까?
답변
한 번에 모든 작업을 수행하고 적절한 라벨링을 얻을 수 있습니다.
> aggregate(. ~ id1+id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) )
# id1 id2 val1.mn val1.n val2.mn val2.n
# 1 a x 1.5 2.0 6.5 2.0
# 2 b x 2.0 2.0 8.0 2.0
# 3 a y 3.5 2.0 7.0 2.0
# 4 b y 3.0 2.0 6.0 2.0
이렇게하면 두 개의 id 열과 두 개의 행렬 열이있는 데이터 프레임이 생성됩니다.
str( aggregate(. ~ id1+id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) ) )
'data.frame': 4 obs. of 4 variables:
$ id1 : Factor w/ 2 levels "a","b": 1 2 1 2
$ id2 : Factor w/ 2 levels "x","y": 1 1 2 2
$ val1: num [1:4, 1:2] 1.5 2 3.5 3 2 2 2 2
..- attr(*, "dimnames")=List of 2
.. ..$ : NULL
.. ..$ : chr "mn" "n"
$ val2: num [1:4, 1:2] 6.5 8 7 6 2 2 2 2
..- attr(*, "dimnames")=List of 2
.. ..$ : NULL
.. ..$ : chr "mn" "n"
아래 @ lord.garbage에서 지적했듯이, 이것은 다음을 사용하여 “간단한”열이있는 데이터 프레임으로 변환 될 수 있습니다. do.call(data.frame, ...)
str( do.call(data.frame, aggregate(. ~ id1+id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) ) )
)
'data.frame': 4 obs. of 6 variables:
$ id1 : Factor w/ 2 levels "a","b": 1 2 1 2
$ id2 : Factor w/ 2 levels "x","y": 1 1 2 2
$ val1.mn: num 1.5 2 3.5 3
$ val1.n : num 2 2 2 2
$ val2.mn: num 6.5 8 7 6
$ val2.n : num 2 2 2 2
다음은 LHS의 여러 변수에 대한 구문입니다.
aggregate(cbind(val1, val2) ~ id1 + id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) )
답변
질문에서 이것을 감안할 때 :
plyr 패키지를 사용할 수 있지만 데이터 세트의 크기가 커지면 데이터 세트가 상당히 크고 plyr가 매우 느립니다 (거의 사용 불가능).
그런 다음 data.table
( 1.9.4+
) 에서 시도해 볼 수 있습니다.
> DT
id1 id2 val1 val2
1: a x 1 9
2: a x 2 4
3: a y 3 5
4: a y 4 9
5: b x 1 7
6: b y 4 4
7: b x 3 9
8: b y 2 8
> DT[ , .(mean(val1), mean(val2), .N), by = .(id1, id2)] # simplest
id1 id2 V1 V2 N
1: a x 1.5 6.5 2
2: a y 3.5 7.0 2
3: b x 2.0 8.0 2
4: b y 3.0 6.0 2
> DT[ , .(val1.m = mean(val1), val2.m = mean(val2), count = .N), by = .(id1, id2)] # named
id1 id2 val1.m val2.m count
1: a x 1.5 6.5 2
2: a y 3.5 7.0 2
3: b x 2.0 8.0 2
4: b y 3.0 6.0 2
> DT[ , c(lapply(.SD, mean), count = .N), by = .(id1, id2)] # mean over all columns
id1 id2 val1 val2 count
1: a x 1.5 6.5 2
2: a y 3.5 7.0 2
3: b x 2.0 8.0 2
4: b y 3.0 6.0 2
비교 타이밍의 경우 aggregate
(질문에 사용되는 모든 3 개 다른 답변)에 data.table
볼
이 벤치 마크 합니다 ( agg
및 agg.x
사례).
답변
count
열을 추가하고 로 집계 sum
한 다음 축소하여 다음을 얻을 수 있습니다 mean
.
x$count <- 1
agg <- aggregate(. ~ id1 + id2, data = x,FUN = sum)
agg
# id1 id2 val1 val2 count
# 1 a x 3 13 2
# 2 b x 4 16 2
# 3 a y 7 14 2
# 4 b y 6 12 2
agg[c("val1", "val2")] <- agg[c("val1", "val2")] / agg$count
agg
# id1 id2 val1 val2 count
# 1 a x 1.5 6.5 2
# 2 b x 2.0 8.0 2
# 3 a y 3.5 7.0 2
# 4 b y 3.0 6.0 2
열 이름을 유지하고 단일 count
열을 만드는 이점이 있습니다 .
답변
dplyr
패키지를 사용하면 summarise_all
. 이 요약 함수를 사용 하여 그룹화되지 않은 각 열에 다른 함수 (이 경우 mean
및 n()
)를 적용 할 수 있습니다 .
x %>%
group_by(id1, id2) %>%
summarise_all(funs(mean, n()))
다음을 제공합니다.
id1 id2 val1_mean val2_mean val1_n val2_n
1 a x 1.5 6.5 2 2
2 a y 3.5 7.0 2 2
3 b x 2.0 8.0 2 2
4 b y 3.0 6.0 2 2
모든 비 그룹화 열에 함수를 적용하지 않으려면 함수를 사용하여 마이너스를 사용하여 원하지 않는 열을 제외하거나 적용해야하는 열을 지정합니다 summarise_at()
.
# inclusion
x %>%
group_by(id1, id2) %>%
summarise_at(vars(val1, val2), funs(mean, n()))
# exclusion
x %>%
group_by(id1, id2) %>%
summarise_at(vars(-val2), funs(mean, n()))
답변
아마 당신은하고 싶은 병합 ?
x.mean <- aggregate(. ~ id1+id2, p, mean)
x.len <- aggregate(. ~ id1+id2, p, length)
merge(x.mean, x.len, by = c("id1", "id2"))
id1 id2 val1.x val2.x val1.y val2.y
1 a x 1.5 6.5 2 2
2 a y 3.5 7.0 2 2
3 b x 2.0 8.0 2 2
4 b y 3.0 6.0 2 2
답변
를 사용하여 plyr::each()
여러 기능을 도입 할 수도 있습니다 .
aggregate(cbind(val1, val2) ~ id1 + id2, data = x, FUN = plyr::each(avg = mean, n = length))
답변
또 다른 dplyr
옵션은 across
현재 개발 버전의 일부입니다.
#devtools::install_github("tidyverse/dplyr")
library(dplyr)
x %>%
group_by(id1, id2) %>%
summarise(across(starts_with("val"), list(mean = mean, n = length)))
결과
# A tibble: 4 x 4
# Groups: id1 [2]
id1 id2 mean$val1 $val2 n$val1 $val2
<fct> <fct> <dbl> <dbl> <int> <int>
1 a x 1.5 6.5 2 2
2 a y 3.5 7 2 2
3 b x 2 8 2 2
4 b y 3 6 2 2
packageVersion("dplyr")
[1] ‘0.8.99.9000’
