Menu

R에서 그룹별 집계와 요약하기 (aggregate, tapply, dplyr)

R에서 그룹별 통계를 계산하는 모든 방법: table()로 세기, 그룹당 통계 하나를 구하는 tapply(), aggregate()의 수식 인터페이스, 그리고 dplyr의 group_by()와 summarize().

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

그룹별 행 수 세기: table()

가장 단순한 그룹화 질문은 "각각 몇 개인가?"이며, base R은 한 번의 호출로 답합니다. table()은 각 값이 얼마나 자주 나타나는지 셉니다:

열 하나면 값별 빈도를, 열 둘이면 완전한 교차표를 줍니다(행은 지역, 열은 요금제). "비율은?"이 궁금하면 prop.table(table(...))로 감싸세요. table()은 R 전체에서 빈도 답을 얻는 가장 빠른 경로입니다 - 단순히 개수만 필요하다면 더 무거운 도구를 찾지 마세요.

그룹당 통계 하나: tapply()

tapply(values, groups, function)은 첫 번째 벡터를 두 번째 벡터로 나누고 각 조각에 함수를 적용합니다:

결과는 이름 있는 벡터 입니다 - 그룹 라벨이 이름, 통계가 값 - 그래서 빠른 조회(means["EU"])에 안성맞춤입니다. 이름은 "table apply"로 풀립니다: 그룹화 테이블을 따라 함수를 적용한다는 뜻이죠. sapply(), lapply()와 같은 가족이며 apply 계열 문서에서 다룹니다.

tapply()의 한계는 형태입니다: 이름 있는 벡터는 병합하거나 그리거나 이어서 처리하기 불편합니다. 요약이 최종 답이 아니라 중간 단계 라면 데이터 프레임으로 돌려받고 싶어지는데, 그것이 바로 다음 도구가 반환하는 형태입니다.

수식 기반의 일꾼: aggregate()

aggregate()는 base R의 완전한 그룹화 도구입니다: 데이터 프레임을 반환하고, 수식 인터페이스가 말로 하는 문장처럼 읽힙니다. value ~ group은 "group으로 나눈 value"를 뜻합니다:

그룹 변수를 추가하려면 수식에 + 다른_열만 더하면 됩니다 - 두 번째 호출은 region quarter 조합별로 합계를 냅니다. cbind(a, b) ~ group으로 여러 값 열을 한 번에 집계할 수도 있습니다. 출력이 평범한 데이터 프레임이므로 병합, 정렬, 그래프로 곧바로 이어집니다 - 그룹 요약에 기본으로 삼을 base R 도구입니다.

알아 둘 조용한 동작이 하나 있습니다: 수식 인터페이스는 집계 전에 사용된 열 중 하나라도 NA인 행을 제거합니다. 대개 원하는 동작이지만, 가끔은 개수가 낮게 나오는 이유가 되기도 합니다.

dplyr 방식: group_by() + summarize()

현대적 표준은 dplyr의 두 동사 패턴입니다 - group_by()가 그룹화를 선언하고, summarize()가 각 그룹을 한 행으로 압축하며 원하는 만큼 통계를 계산합니다(정적 예제입니다. 샌드박스는 base R만 실행합니다):

library(dplyr)

sales |>
    group_by(region) |>
    summarize(
        n     = n(),
        total = sum(amount),
        avg   = mean(amount)
    )

여기가 dplyr이 base R을 진짜로 능가하는 지점입니다: 그룹당 여러 통계를 읽기 좋은 한 번의 호출로 계산하고(aggregate()로는 억지스러운 우회가 필요합니다) n()을 덤으로 얻으며, 결과가 다음 파이프로 곧장 흘러갑니다. (summarise()는 영국식 철자일 뿐 같은 함수입니다.)

초보자를 헷갈리게 하는 점이 하나 있습니다: 그룹 변수가 여러 개일 때 summarize()는 마지막 하나만 벗겨 내므로 결과가 여전히 그룹화된 상태로 남고, 그에 대한 메시지를 출력합니다. .groups 인자로 원하는 바를 명시하세요: summarize(avg = mean(amount), .groups = "drop")은 그룹화되지 않은 평범한 데이터 프레임을 반환하며, 이를 기본 습관으로 삼는 편이 좋습니다. 그룹화된 데이터 프레임이 뒤쪽 코드로 몰래 흘러가면 mutate()와 동료 함수들이 조용히 그룹 단위로 동작해 혼란스러운 결과를 낳는 전형적인 원인이 됩니다.

무엇을 고를까

  • 개수 - table(), 한 번의 호출을 이길 수 없습니다.
  • 통계 하나, 빠른 확인 - tapply(), 이름 있는 벡터에서 답을 바로 읽으세요.
  • 데이터 프레임 출력, base R만 쓰는 환경 - 수식과 함께 aggregate().
  • 여러 통계, 파이프라인의 일부, 또는 야심 찬 무엇이든 - group_by() |> summarize().

이 중에 틀린 답은 없습니다 - 모두 같은 숫자를 계산합니다 - 하지만 필요한 출력 형태에 맞는 도구를 고르면 변환 단계를 아낄 수 있습니다. 평균, 중앙값, 산포 자체는 기술통계에서 다룹니다.

실전 예제: 실린더 수별 mtcars

내장 데이터셋으로 모든 것을 종합해 봅니다 - 실린더 수별로 자동차가 몇 대인지, 평균 연비와 마력은 얼마인지:

4기통 자동차 11대의 평균은 약 26.7 mpg, 6기통 7대는 약 19.7, 8기통 14대는 약 15.1이며, 마력은 정반대 방향으로 움직입니다. 두 번의 호출로 요약 표 하나가 완성됩니다: 그룹 집계가 존재하는 이유가 바로 이런 질문에 답하기 위해서입니다.

핵심 정리

  • 개수에는 table(), 비율에는 prop.table().
  • tapply(values, groups, fn)은 이름 있는 벡터를 반환합니다 - 빠른 확인과 손쉬운 조회에 좋습니다.
  • aggregate(value ~ group, data, FUN)은 데이터 프레임을 반환하며, +로 그룹 변수를, cbind()로 값 열을 추가합니다.
  • dplyr의 group_by() |> summarize(n = n(), avg = mean(x), .groups = "drop")은 다중 통계 요약의 현대적 표준입니다.
  • 출력 형태로 도구를 고르세요. 숫자는 모두 일치합니다.

다음 주제: 키를 공유하는 표 결합하기 - merge()와 dplyr의 join 계열.

자주 묻는 질문

R에서 그룹별 평균은 어떻게 계산하나요?

base R에는 두 가지 도구가 있습니다: tapply(df$value, df$group, mean)은 그룹별 평균을 담은 이름 있는 벡터를 반환하고, aggregate(value ~ group, data = df, FUN = mean)은 같은 결과를 데이터 프레임으로 반환합니다. dplyr에서는 df |> group_by(group) |> summarize(avg = mean(value))입니다.

R에서 그룹별 빈도는 어떻게 세나요?

table(df$group)은 한 번의 호출로 그룹 값마다 행 수를 셉니다. table(df$a, df$b)는 두 열을 교차표로 만듭니다. dplyr에서는 count(df, group)이 같은 일을 하며 데이터 프레임을 반환해 이어서 처리하기 쉽습니다.

R에서 aggregate()는 무엇을 하나요?

aggregate()는 하나 이상의 그룹 열로 데이터 프레임을 나누고, 각 조각에 함수를 적용한 뒤 결과를 데이터 프레임으로 반환합니다. 수식 인터페이스는 자연스럽게 읽힙니다: aggregate(sales ~ region + quarter, data = df, FUN = mean)은 region과 quarter로 그룹화한 sales의 평균을 뜻합니다.

tapply와 aggregate의 차이는 무엇인가요?

계산은 같고 출력 형태가 다릅니다. tapply()는 이름 있는 벡터(그룹 변수가 둘이면 배열)를 반환해 빠른 조회에 편리합니다. aggregate()는 데이터 프레임을 반환하므로 결과를 이어지는 분석, 병합, 그래프로 넘길 때 더 낫습니다. 애매하면 aggregate()를 쓰세요.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기