各グループ内の異なる値の割合を計算するとします。たとえば、mtcars
データを使用して、ギアの数のrelative頻度の計算方法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
これを試して:
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 vignette から:
複数の変数でグループ化すると、各サマリーはグループ化の1つのレベルから切り離されます。これにより、データセットを段階的に簡単にロールアップできます。
したがって、summarise
の後に、グループ化変数 'gear'が剥がされ、データは 'am'によって 'only'にグループ化され(結果データでgroups
で確認するだけです)、そこでmutate
計算を実行します。
「剥離」の結果は、もちろんgroup_by
呼び出しのグループ化変数の順序に依存します。今回は、希望の変数を剥がしてくれたので幸運でした。コードをより明確にするために、後続のgroup_by(am)
を実行することもできます。
丸めとプリティフィケーションについては、@ Tyler RinkerによるNiceの回答を参照してください。
count()
関数を使用できますが、dplyr
のバージョンに応じて動作が異なります。
dplyr 0.7.1:ungroupedテーブルを返します:am
で再度グループ化する必要があります
dplyr <0.7.1:はgroupedテーブルを返すため、再度グループ化する必要はありませんが、後で操作するために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))
これはグループ化されたテーブルになります。さらに分析するために使用する場合は、groupedを削除すると便利です。 ungroup()
を持つ属性。
@Henrikの方が使い勝手が良くなります。これにより、列の文字が作成され、数値ではなくなりますが、要求したものと一致します...
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%
EDIT 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%
dplyr
0.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
}
この繰り返しタスク用の小さな関数を作成しました。
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
この答えは、マティフォーの答えに基づいています。
まず、scipenオプションを使用して、freq列が科学表記列として返されないように変更しました。
次に、回答を100倍して小数ではなくパーセントを取得し、freq列をパーセンテージで読みやすくします。
getOption("scipen")
options("scipen"=10)
mtcars %>%
count(am, gear) %>%
mutate(freq = (n / sum(n)) * 100)
多くの答えにもかかわらず、prop.table
をdplyr
またはdata.table
と組み合わせて使用するもう1つのアプローチ。
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"]