dplyr의 상대 주파수 / 비율


153

각 그룹 내에서 다른 값의 비율을 계산하려고한다고 가정합니다. 예를 들어, mtcars데이터를 사용하여 한 번 에 am (자동 / 수동)으로 기어 수의 상대 주파수를 어떻게 계산 합니까?dplyr

library(dplyr)
data(mtcars)
mtcars <- tbl_df(mtcars)

# count frequency
mtcars %>%
  group_by(am, gear) %>%
  summarise(n = n())

# am gear  n
#  0    3 15 
#  0    4  4 
#  1    4  8  
#  1    5  5 

내가 성취하고 싶은 것 :

am gear  n rel.freq
 0    3 15      0.7894737
 0    4  4      0.2105263
 1    4  8      0.6153846
 1    5  5      0.3846154

1
이 백분율은 원하는 실제 숫자입니까? 대수적으로 어디에서 왔습니까? 아, 79 %는 15 / (15 + 4), 21 %는 4 / (15 + 4), 그리고 am == 1 인 경우 62 %는 8 / (8 + 5) 등입니다.
Spacedman

1
@Spacedman 예, 그 숫자는 내가 원하는 숫자이고 Frank는 정확합니다. am 변수 (79 + 21)와 (62 + 38)에 의해 100 %가됩니다.
jenswirf

2
이것은 실제로 prop.table()/의 dplyr 구현을 찾고있는 것 같습니다 sweep(). 또한, 다른 질문에서 일부 사람들은 변수 또는 변수 상호 작용에 대해 제로 카운트를 포함하는 옵션을 요구하고 있습니다
smci

답변:


285

이 시도:

mtcars %>%
  group_by(am, gear) %>%
  summarise(n = n()) %>%
  mutate(freq = n / sum(n))

#   am gear  n      freq
# 1  0    3 15 0.7894737
# 2  0    4  4 0.2105263
# 3  1    4  8 0.6153846
# 4  1    5  5 0.3846154

로부터 dplyr 비네팅 :

여러 변수로 그룹화하면 각 요약이 그룹화의 한 수준에서 제거됩니다. 따라서 데이터 세트를 점진적으로 롤업 할 수 있습니다.

따라서, 이후 'gear'에 summarise지정된 마지막 그룹화 변수 group_by가 제거됩니다. 이 mutate단계에서 데이터는 나머지 그룹화 변수 (여기서는 'am')로 그룹화됩니다. 로 각 단계에서 그룹화를 확인할 수 있습니다 groups.

필링의 결과는 물론 group_by호출 에서 그룹화 변수의 순서에 따라 다릅니다 . group_by(am)코드를보다 명확하게하기 위해 후속 작업을 수행 할 수 있습니다 .

반올림 및 보존에 대해서는 @Tyler Rinker의 멋진 답변을 참조하십시오.


5
방금 그 해결책도 발견했지만 왜 그룹이 아닌 그룹에 대해 sum(n)작동 하는지 모르겠습니다 .amgear
Spacedman

7
비 네트를 참조하십시오 . "여러 변수로 그룹화하면 각 요약이 그룹화의 한 수준에서 제거됩니다."
Henrik

7
니스-당신이 방금 멈춘다면 summarise어떤 그룹이 남았는지 말합니다. 오 dplyr 바위 ...
Spacedman

간단하고 명확합니다. 나는 이론의 껍질을 벗기는 것을 몰랐다. 고마워!
Shixiang Wang

좋은. 간단하고 효과적입니다. 잘 했어!
user2550228

38

count()버전에 따라 동작이 다른 함수 를 사용할 수 있습니다 dplyr.

  • dplyr 0.7.1 : 그룹화되지 않은 테이블을 반환 합니다.am

  • dplyr <0.7.1 : 그룹화 된 테이블을 리턴 하므로 ungroup()나중에 조작 하기 위해 다시 그룹화 할 필요가 없습니다.

dplyr 0.7.1

mtcars %>%
  count(am, gear) %>%
  group_by(am) %>%
  mutate(freq = n / sum(n))

dplyr <0.7.1

mtcars %>%
  count(am, gear) %>%
  mutate(freq = n / sum(n))

결과적으로 그룹화 된 테이블 이 생성되며, 추가 분석에 사용하려는 경우로 그룹화 된 속성 을 제거하는 것이 유용 할 수 있습니다 ungroup().


1
이것은 dplyr0.7.1 에 대한 잘못된 답변 인 것 같습니다 . 각 레벨 "am"이 아닌 "gear"에 대한 전체 주파수 계산을 수행합니다.
Edwin

30

@ Henrik 's는 열 문자를 만들고 더 이상 숫자를 만들지 않지만 요청한 것과 일치하므로 유용성에 더 좋습니다 ...

mtcars %>%
  group_by (am, gear) %>%
  summarise (n=n()) %>%
  mutate(rel.freq = paste0(round(100 * n/sum(n), 0), "%"))

##   am gear  n rel.freq
## 1  0    3 15      79%
## 2  0    4  4      21%
## 3  1    4  8      62%
## 4  1    5  5      38%

Spacedman이 그것을 요구했기 때문에 편집 하십시오 :-)

as.rel_freq <- function(x, rel_freq_col = "rel.freq", ...) {
    class(x) <- c("rel_freq", class(x))
    attributes(x)[["rel_freq_col"]] <- rel_freq_col
    x
}

print.rel_freq <- function(x, ...) {
    freq_col <- attributes(x)[["rel_freq_col"]]
    x[[freq_col]] <- paste0(round(100 * x[[freq_col]], 0), "%")   
    class(x) <- class(x)[!class(x)%in% "rel_freq"]
    print(x)
}

mtcars %>%
  group_by (am, gear) %>%
  summarise (n=n()) %>%
  mutate(rel.freq = n/sum(n)) %>%
  as.rel_freq()

## Source: local data frame [4 x 4]
## Groups: am
## 
##   am gear  n rel.freq
## 1  0    3 15      79%
## 2  0    4  4      21%
## 3  1    4  8      62%
## 4  1    5  5      38%

6
format퍼센트 부호를 추가하는 방법으로 항상 S3 "백분율"클래스를 만들 수 있습니다 ... #overkill
Spacedman

이것을 구현하는 것도 흥미로울 수 있습니다 : stackoverflow.com/questions/13483430/…
Spacedman

이 예제에서 평균, sd 및 SE를 계산한다면 어떻게 될까요?
user3655531

6

dplyr0.7.1 에서 Henrik 솔루션을 구현하는 일반적인 기능은 다음과 같습니다 .

freq_table <- function(x, 
                       group_var, 
                       prop_var) {
  group_var <- enquo(group_var)
  prop_var  <- enquo(prop_var)
  x %>% 
    group_by(!!group_var, !!prop_var) %>% 
    summarise(n = n()) %>% 
    mutate(freq = n /sum(n)) %>% 
    ungroup
}

Error in bind_rows_(x, .id) : Column am`는 숫자에서 문자로 변환 할 수 없습니다`
f0nzie

5

이 반복 작업에 작은 기능을 작성했습니다.

count_pct <- function(df) {
  return(
    df %>%
      tally %>% 
      mutate(n_pct = 100*n/sum(n))
  )
}

그런 다음 다음과 같이 사용할 수 있습니다.

mtcars %>% 
  group_by(cyl) %>% 
  count_pct

다음을 반환합니다.

# A tibble: 3 x 3
    cyl     n n_pct
  <dbl> <int> <dbl>
1     4    11  34.4
2     6     7  21.9
3     8    14  43.8

3

많은 답변, 사용하는 또 하나의 접근 방식에도 불구 prop.table과 함께 dplyr또는 data.table.

library("dplyr")
mtcars %>%
    group_by(am, gear) %>%
    summarise(n = n()) %>%
    mutate(freq = prop.table(n))

library("data.table")
cars_dt <- as.data.table(mtcars)
cars_dt[, .(n = .N), keyby = .(am, gear)][, freq := prop.table(n) , by = "am"]

1
가장 간단한 방법
Parseltongue

1

이 답변은 Matifou의 답변을 기반으로합니다.

먼저 scipen 옵션을 사용하여 freq 열이 과학적 표기법 열로 반환되지 않도록 수정했습니다.

그런 다음 freq 열을 백분율로 쉽게 읽을 수 있도록 10이 아닌 백분율을 얻기 위해 답을 100으로 곱합니다.

getOption("scipen") 
options("scipen"=10) 
mtcars %>%
count(am, gear) %>% 
mutate(freq = (n / sum(n)) * 100)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.