2014-07-04 54 views
72

假設我想計算每個組內不同值的比例。例如,使用所述數據mtcars,如何計算的齒輪通過上午(自動/手動)數的相對頻率一氣呵成與dplyr相對頻率/與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 
+0

這些百分比是你想要的實際數量嗎?它們來自哪裏,代數?啊,79%是15 /(15 + 4),21%是4 /(15 + 4),然後對於== == 1 62%是8 /(8 + 5)等等。 – Spacedman

+0

@Spacedman是的,這些是我想要的數字,弗蘭克是正確的,他們通過am變量(79 + 21)和(62 + 38)總和爲100%。 – jenswirf

+0

這真的好像是在尋找一個本地的dplyr實現''prop.table()'/'sweep()'。此外,在其他問題中,有些人[要求爲變量或變量交互包含零計數](http://stackoverflow.com/questions/23778195/using-dplyr-for-frequency-counts-of- – smci

回答

143

試試這個:

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

當您通過多個變量組,每個彙總剝離分組的一個級別。這使得漸進式彙總數據集變得很容易。

因此,summarise後,分組變量「齒輪」被剝離,然後將數據「僅」通過「AM」(只是groups檢查它產生的數據)分組,在其上我們然後執行mutate計算。

「剝離」的結果當然取決於group_by調用中分組變量的順序。這次我們很幸運,它剝離了所需的變量。您可能希望執行後續的group_by(am),以使您的代碼更加明確。

爲了四捨五入和美化,請參考@Tyler Rinker的好回答。

+3

我剛剛發現了這個解決方案,但是我不知道爲什麼'sum(n)'在'am'組而不是'gear'組上工作... – Spacedman

+4

請參閱[小插曲](http://cran.rstudio.com/web/packages/dplyr/vignettes/introduction.html):「當您通過多個變量進行分組時,每個摘要將剝離分組的一個級別。」 – Henrik

+4

不錯 - 如果你只是在'summarise'後面停下來,它確實說明哪些組會被留下。哦dplyr岩石... – Spacedman

19

@ 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% 

編輯因爲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% 
+3

你總是可以用'format'方法創建一個S3「百分比」類,並添加一個百分號...... #overkill – Spacedman

+0

實現這個也許很有趣:http://stackoverflow.com/questions/13483430/how-to -make-rounded-percentageages-add-up-to-100 – Spacedman

+0

如果在這個例子中計算平均值,sd和SE,該怎麼辦? – user3655531

20

可以使用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()刪除分組屬性很有用。

+0

這似乎是'dplyr' 0.7.1上的無效答案。它在「齒輪」上進行頻率計算,而不是在「am」的每個級別內。 – Edwin

+1

好點,謝謝@Edwin !! – Matifou

2

這個回答基於Matifou的回答。

首先我對其進行了修改,以確保我沒有通過使用scipen選項獲得作爲科學記數法列返回的freq列。

然後,我將答案乘以100得到一個百分比而不是十進制數,以使freq列更容易閱讀爲百分比。

getOption("scipen") 
options("scipen"=10) 
mtcars %>% 
count(am, gear) %>% 
mutate(freq = (n/sum(n)) * 100) 
2

這是一個在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 
} 
0

這裏有一個函數來獲取一對變量的行總數和列總數。

freq_tibble <- function(data, var1, var2) { 
    var1 <- rlang::enquo(var1) 
    var2 <- rlang::enquo(var2) 

    data %>% 
    dplyr::count(!!var1, !!var2) %>% 
    tidyr::spread(!!var2, n, fill = 0) %>% 
    dplyr::mutate(Total := rowSums(dplyr::select(., -!!var1))) %>% 
    dplyr::bind_rows(dplyr::bind_cols(!!rlang::quo_name(var1) := "Total", dplyr::summarize_if(., is.numeric, sum))) 
}