그룹별로 변수를 합산하는 방법


357

두 개의 열이있는 데이터 프레임이 있습니다. 첫 번째 열에는 "첫 번째", "두 번째", "세 번째"와 같은 범주가 있고 두 번째 열에는 "범주"에서 특정 그룹을 본 횟수를 나타내는 숫자가 있습니다.

예를 들면 다음과 같습니다.

Category     Frequency
First        10
First        15
First        5
Second       2
Third        14
Third        20
Second       3

범주별로 데이터를 정렬하고 모든 빈도를 합치고 싶습니다.

Category     Frequency
First        30
Second       5
Third        34

R에서 어떻게해야합니까?


1
기본 R에서 가장 빠른 방법은 rowsum입니다.
Michael M

답변:


387

사용 aggregate:

aggregate(x$Frequency, by=list(Category=x$Category), FUN=sum)
  Category  x
1    First 30
2   Second  5
3    Third 34

위의 예에서 여러 치수를에 지정할 수 있습니다 list. 동일한 데이터 유형의 여러 집계 메트릭은 다음을 통해 통합 될 수 있습니다 cbind.

aggregate(cbind(x$Frequency, x$Metric2, x$Metric3) ...

(@thelatemail 주석 포함), aggregate수식 인터페이스도 있습니다

aggregate(Frequency ~ Category, x, sum)

또는 여러 열을 집계하려는 경우 .표기법을 사용할 수 있습니다 (한 열에도 적용 가능)

aggregate(. ~ Category, x, sum)

또는 tapply:

tapply(x$Frequency, x$Category, FUN=sum)
 First Second  Third 
    30      5     34 

이 데이터를 사용하여 :

x <- data.frame(Category=factor(c("First", "First", "First", "Second",
                                      "Third", "Third", "Second")), 
                    Frequency=c(10,15,5,2,14,20,3))

4
@AndrewMcKinlay, R은 물결표를 사용하여 통계 및 기타 함수에 대한 기호 공식을 정의합니다. "범주 별 모델 빈도" 또는 " 범주에 따른 주파수" 로 해석 될 수 있습니다 . 여기서 R 에서처럼 모든 언어가 특수 연산자를 사용하여 기호 함수를 정의하는 것은 아닙니다. 아마도 틸드 연산자의 "자연어 해석"으로 인해 더 의미 있고 직관적입니다. 나는 개인적으로이 상징적 공식 표현이 좀 더 장황한 대안들보다 더 낫다는 것을 안다.
r2evans

1
R에 익숙하지 않고 (OP와 같은 종류의 질문을하면) 각 대안의 구문에 대한 자세한 내용이 도움이됩니다. 예를 들어 더 큰 소스 테이블이 있고 2 차원과 합산 된 메트릭 만 하위 선택하려는 경우 이러한 방법 중 하나를 적용 할 수 있습니까? 말하기 어렵다.
Dodecaphone

236

해당 용도로 dplyr 패키지를 사용할 수도 있습니다 .

library(dplyr)
x %>% 
  group_by(Category) %>% 
  summarise(Frequency = sum(Frequency))

#Source: local data frame [3 x 2]
#
#  Category Frequency
#1    First        30
#2   Second         5
#3    Third        34

또는 여러 요약 열의 경우 (하나의 열에서도 작동) :

x %>% 
  group_by(Category) %>% 
  summarise_all(funs(sum))

다음은 내장 데이터 세트를 사용하여 dplyr 함수를 사용하여 그룹별로 데이터를 요약하는 방법에 대한 몇 가지 예입니다 mtcars.

# several summary columns with arbitrary names
mtcars %>% 
  group_by(cyl, gear) %>%                            # multiple group columns
  summarise(max_hp = max(hp), mean_mpg = mean(mpg))  # multiple summary columns

# summarise all columns except grouping columns using "sum" 
mtcars %>% 
  group_by(cyl) %>% 
  summarise_all(sum)

# summarise all columns except grouping columns using "sum" and "mean"
mtcars %>% 
  group_by(cyl) %>% 
  summarise_all(funs(sum, mean))

# multiple grouping columns
mtcars %>% 
  group_by(cyl, gear) %>% 
  summarise_all(funs(sum, mean))

# summarise specific variables, not all
mtcars %>% 
  group_by(cyl, gear) %>% 
  summarise_at(vars(qsec, mpg, wt), funs(sum, mean))

# summarise specific variables (numeric columns except grouping columns)
mtcars %>% 
  group_by(gear) %>% 
  summarise_if(is.numeric, funs(mean))

%>%연산자를 포함한 자세한 정보 는 dplyr 소개를 참조하십시오 .


1
data.table 및 다른 답변에 제시된 대체 대안과 비교할 때 얼마나 빠릅니까?
asieira

5
@asieira는 가장 빠르며 그 차이가 얼마나 큰지 (또는 그 차이가 눈에 띄는 경우) 항상 데이터 크기에 따라 다릅니다. 일반적으로 GB와 같은 대용량 데이터 세트의 경우 data.table이 가장 빠릅니다. 더 작은 데이터 크기에서 data.table 및 dplyr은 종종 그룹 수에 따라 가깝습니다. 그러나 data, table 및 dplyr은 기본 기능보다 훨씬 빠릅니다 (일부 작업의 경우 100-1000 배 더 빠를 수 있음). 또한 참조 여기
탈랏

1
두 번째 예에서 "재미"란 무엇입니까?
lauren.marietta

@ lauren.marietta 당신은 funs()인수 summarise_all와 관련 함수 ( summarise_at, summarise_if) 내에서 요약으로 적용하려는 함수를 지정할 수 있습니다
talat

76

rcs가 제공하는 대답은 간단하며 간단합니다. 그러나 더 큰 데이터 세트를 처리하고 성능 향상이 필요한 경우 더 빠른 대안이 있습니다.

library(data.table)
data = data.table(Category=c("First","First","First","Second","Third", "Third", "Second"), 
                  Frequency=c(10,15,5,2,14,20,3))
data[, sum(Frequency), by = Category]
#    Category V1
# 1:    First 30
# 2:   Second  5
# 3:    Third 34
system.time(data[, sum(Frequency), by = Category] )
# user    system   elapsed 
# 0.008     0.001     0.009 

data.frame과 위의 내용을 사용하여 동일한 내용과 비교해 보겠습니다.

data = data.frame(Category=c("First","First","First","Second","Third", "Third", "Second"),
                  Frequency=c(10,15,5,2,14,20,3))
system.time(aggregate(data$Frequency, by=list(Category=data$Category), FUN=sum))
# user    system   elapsed 
# 0.008     0.000     0.015 

그리고 열을 유지하려면 다음 구문을 사용하십시오.

data[,list(Frequency=sum(Frequency)),by=Category]
#    Category Frequency
# 1:    First        30
# 2:   Second         5
# 3:    Third        34

아래 코드에서 알 수 있듯이 더 큰 데이터 세트에서는 차이가 더 두드러집니다.

data = data.table(Category=rep(c("First", "Second", "Third"), 100000),
                  Frequency=rnorm(100000))
system.time( data[,sum(Frequency),by=Category] )
# user    system   elapsed 
# 0.055     0.004     0.059 
data = data.frame(Category=rep(c("First", "Second", "Third"), 100000), 
                  Frequency=rnorm(100000))
system.time( aggregate(data$Frequency, by=list(Category=data$Category), FUN=sum) )
# user    system   elapsed 
# 0.287     0.010     0.296 

여러 집계를 들어, 결합 할 수 lapply.SD같은 다음

data[, lapply(.SD, sum), by = Category]
#    Category Frequency
# 1:    First        30
# 2:   Second         5
# 3:    Third        34

13
+1 그러나 0.296 대 0.059는 특별히 인상적이지 않습니다. data.table이 빛을 발하기 위해서는 데이터 크기가 300k 행보다 훨씬 크고 그룹이 3 개 이상이어야합니다. 예를 들어, 일부 데이터 사용자는 250GB의 RAM을 가지고 있고 GNU R은 길이가 2 ^ 31보다 길기 때문에 20 억 개 이상의 행을 곧 지원할 것입니다.
매트 Dowle

2
진실. 나는 모든 RAM을 가지고 있지는 않지만 data.table의 우수한 성능에 대한 증거를 제공하려고했습니다. 데이터가 많을수록 그 차이가 더 커질 것이라고 확신합니다.
asieira

1
dplyr은 .3 초가 걸리고 7 (mil)의 관측 값을 보았으며, 집계를 완료하는 데 22 초가 걸렸습니다. 나는이 주제에 그것을 게시하려고하고 당신은 그것을 이길!
zazu

3
이것을 쓰는 더 짧은 방법이 data[, sum(Frequency), by = Category]있습니다. 함수 .N를 대체하는 것을 사용할 수 있습니다 sum(). data[, .N, by = Category]. 다음은 유용한
치트 시트입니다

3
.N은 각 집계 된 세트 (.SD)의 행 수를 계산하므로 빈도 열의 모든 값이 1 인 경우에만 .N을 사용하는 것은 sum (Frequency)와 같습니다. 그리고 여기서는 그렇지 않습니다.
asieira

41

by () 함수를 사용할 수도 있습니다 .

x2 <- by(x$Frequency, x$Category, sum)
do.call(rbind,as.list(x2))

다른 패키지 (plyr, reshape)는 data.frame을 반환하는 이점이 있지만 기본 함수이기 때문에 by ()에 익숙 할 가치가 있습니다.


28

몇 년 후 여기에 존재하지 않는 또 다른 간단한 기본 R 솔루션을 추가하기 위해 xtabs

xtabs(Frequency ~ Category, df)
# Category
# First Second  Third 
#    30      5     34 

또는 당신은 원하는 경우 data.frame다시

as.data.frame(xtabs(Frequency ~ Category, df))
#   Category Freq
# 1    First   30
# 2   Second    5
# 3    Third   34

27
library(plyr)
ddply(tbl, .(Category), summarise, sum = sum(Frequency))

23

x데이터가있는 데이터 프레임 인 경우 다음이 원하는 것을 수행합니다.

require(reshape)
recast(x, Category ~ ., fun.aggregate=sum)

19

최근 dplyr에 이러한 유형의 작업 대부분에 대한 변환 sqldf이되었지만 패키지는 여전히 유용한 것으로 보입니다 (일부 IMHO는 더 읽기 쉽습니다).

다음은이 질문에 어떻게 대답 할 수 있는지에 대한 예입니다. sqldf

x <- data.frame(Category=factor(c("First", "First", "First", "Second",
                                  "Third", "Third", "Second")), 
                Frequency=c(10,15,5,2,14,20,3))

sqldf("select 
          Category
          ,sum(Frequency) as Frequency 
       from x 
       group by 
          Category")

##   Category Frequency
## 1    First        30
## 2   Second         5
## 3    Third        34

18

세 번째 옵션을 추가하려면 다음을 수행하십시오.

require(doBy)
summaryBy(Frequency~Category, data=yourdataframe, FUN=sum)

편집 : 이것은 매우 오래된 답변입니다. 이제 @docendo answer 에서 와 같이 group_byand summarisefrom을 사용하는 것이 좋습니다 dplyr.


7

내가 찾을 ave서로 다른 열을 다른 집계 함수를 적용 할 필요가있을 때 매우 도움 (효율적인) (당신은 / 기본 R에 충실하고자합니다) :

예 :

이 입력이 주어지면 :

DF <-                
data.frame(Categ1=factor(c('A','A','B','B','A','B','A')),
           Categ2=factor(c('X','Y','X','X','X','Y','Y')),
           Samples=c(1,2,4,3,5,6,7),
           Freq=c(10,30,45,55,80,65,50))

> DF
  Categ1 Categ2 Samples Freq
1      A      X       1   10
2      A      Y       2   30
3      B      X       4   45
4      B      X       3   55
5      A      X       5   80
6      B      Y       6   65
7      A      Y       7   50

우리는 그룹에 의해 원하는 Categ1Categ2와의 합을 계산 Samples하고의 의미 Freq.
다음을 사용하여 가능한 해결책이 있습니다 ave.

# create a copy of DF (only the grouping columns)
DF2 <- DF[,c('Categ1','Categ2')]

# add sum of Samples by Categ1,Categ2 to DF2 
# (ave repeats the sum of the group for each row in the same group)
DF2$GroupTotSamples <- ave(DF$Samples,DF2,FUN=sum)

# add mean of Freq by Categ1,Categ2 to DF2 
# (ave repeats the mean of the group for each row in the same group)
DF2$GroupAvgFreq <- ave(DF$Freq,DF2,FUN=mean)

# remove the duplicates (keep only one row for each group)
DF2 <- DF2[!duplicated(DF2),]

결과 :

> DF2
  Categ1 Categ2 GroupTotSamples GroupAvgFreq
1      A      X               6           45
2      A      Y               9           40
3      B      X               7           50
6      B      Y               6           65

6

최근에 추가 된 기능은 dplyr::tally()이제 그 어느 때보 다 쉬워졌습니다.

tally(x, Category)

Category     n
First        30
Second       5
Third        34

6

Rfast 패키지 의 함수 group.sum를 사용할 수 있습니다 .

Category <- Rfast::as_integer(Category,result.sort=FALSE) # convert character to numeric. R's as.numeric produce NAs.
result <- Rfast::group.sum(Frequency,Category)
names(result) <- Rfast::Sort(unique(Category)
# 30 5 34

Rfast 는 많은 그룹 기능을 가지고 있으며group.sum그중 하나입니다.


4

사용하는 cast대신 recast(참고 'Frequency'지금 'value')

df  <- data.frame(Category = c("First","First","First","Second","Third","Third","Second")
                  , value = c(10,15,5,2,14,20,3))

install.packages("reshape")

result<-cast(df, Category ~ . ,fun.aggregate=sum)

얻을 :

Category (all)
First     30
Second    5
Third     34


0

이후 dplyr 1.0.0across()기능을 사용할 수 있습니다 :

df %>%
 group_by(Category) %>%
 summarise(across(Frequency, sum))

  Category Frequency
  <chr>        <int>
1 First           30
2 Second           5
3 Third           34

여러 변수에 관심이있는 경우 :

df %>%
 group_by(Category) %>%
 summarise(across(c(Frequency, Frequency2), sum))

  Category Frequency Frequency2
  <chr>        <int>      <int>
1 First           30         55
2 Second           5         29
3 Third           34        190

그리고 선택 도우미를 사용하여 변수를 선택하십시오.

df %>%
 group_by(Category) %>%
 summarise(across(starts_with("Freq"), sum))

  Category Frequency Frequency2 Frequency3
  <chr>        <int>      <int>      <dbl>
1 First           30         55        110
2 Second           5         29         58
3 Third           34        190        380

샘플 데이터 :

df <- read.table(text = "Category Frequency Frequency2 Frequency3
                 1    First        10         10         20
                 2    First        15         30         60
                 3    First         5         15         30
                 4   Second         2          8         16
                 5    Third        14         70        140
                 6    Third        20        120        240
                 7   Second         3         21         42",
                 header = TRUE,
                 stringsAsFactors = FALSE)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.