dplyrを使用した相対周波数/比率


153

各グループ内の異なる値の比率を計算したいとします。たとえば、mtcarsデータを使用して、歯車の数の相対頻度をどのように計算しますか午前と一度に(自動/手動)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、2014

1
@Spacedmanはい、それらは私が欲しいとフランクが正しい数が、彼らは午前変数(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ビネットから:

複数の変数でグループ化すると、各要約はグループ化の1つのレベルからはがれます。これにより、データセットを段階的にロールアップすることが容易になります。

したがって、の後、summariseで指定された最後のグループ化変数group_by'gear'が剥離されます。このmutateステップでは、データは残りのグループ化変数(ここでは「am」)によってグループ化されます。各ステップのグループ化はで確認できますgroups

ピーリングの結果はもちろん、group_by呼び出しのグループ化変数の順序に依存します。group_by(am)コードをより明確にするために、後続のを実行することができます。

丸めと見栄えについては、@ Tyler Rinkerによるいい答えを参照してください。


5
私もその解決策を発見しましたが、なぜグループではなくグループでsum(n)機能するのかわかりません...amgear
Spacedman

7
ビネットを参照してください:「複数の変数でグループ化すると、各要約はグループ化の1つのレベルからはがれます。」
Henrik

7
いいですね-ちょうど後に停止したsummarise場合、残っているグループが表示されます。Oh dplyr rocks ...
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」で全体的に周波数計算を行います。
エドウィン

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%

スペースマンがそれを求めたので編集 :-)

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 2017年

6

これは、dplyr0.7.1でのヘンリックのソリューションを実装する一般的な関数です。

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と組み合わせて使用するもう1つのアプローチ。dplyrdata.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
はるかに簡単なアプローチ
パーセルトング

1

この答えはマティフーの答えに基づいています。

最初に、scipenオプションを使用してfreq列が科学表記列として返されないように変更しました。

次に、答えを100倍して、小数ではなくパーセントを得て、freq列をパーセントとして読みやすくしています。

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.