Dplyr ile bağıl frekanslar / oranlar


153

Her bir grup içindeki farklı değerlerin oranını hesaplamak istediğimi varsayalım. Örneğin, kullanarak mtcarsverileri, nasıl hesaplarım göreceli sayısının sıklığını dişlileri tarafından am ile tek seferde (/ otomatik manuel) 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 

Ne elde etmek istiyorum:

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
Bu yüzdeler istediğiniz gerçek sayılar mı? Cebirsel olarak nereden geliyorlar? Ah,% 79 15 / (15 + 4),% 21 4 / (15 + 4) ve sonra am == 1 için% 62 8 / (8 + 5) vb.
Spacedman

1
@Spacedman Evet, bunlar istediğim sayı ve Frank doğrudur, am değişkeni (79 + 21) ve (62 + 38) tarafından% 100'e
çıkarlar

2
Bu gerçekten bir yerli dplyr uygulaması arıyorsanız gibi görünüyor prop.table()/ ' sweep(). Ayrıca, diğer sorularda bazı insanlar değişkenler veya değişken etkileşimleri için sıfır sayım ekleme seçeneğini
istiyorlar

Yanıtlar:


285

Bunu dene:

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

Gönderen dplyr skeç :

Birden çok değişkene göre gruplandırdığınızda, her özet gruplamanın bir düzeyini soyar. Bu, bir veri kümesini aşamalı olarak toplamayı kolaylaştırır.

Böylece, 'dişli' summarisebölümünde belirtilen son gruplama değişkeni group_bysoyulur. İçinde mutateaşama, veri, burada kalan gruplama değişken (ler) ile 'am' gruplandırılır. Her adımda gruplandırmayı ile kontrol edebilirsiniz groups.

Soyulmanın sonucu elbette çağrıdaki gruplama değişkenlerinin sırasına bağlıdır group_by. group_by(am)Kodunuzu daha açık hale getirmek için bir sonrakini yapmak isteyebilirsiniz .

Yuvarlama ve zenginleştirme için lütfen @Tyler Rinker'ın güzel cevabına bakın.


5
Ben de bu çözümü keşfettim, ama neden grup sum(n)üzerinde amdeğil de geargrup üzerinde çalıştığını bilmiyorum ...
Spacedman

7
Vinyet bölümüne bakın : "Birden çok değişkene göre gruplandırdığınızda, her özet gruplamanın bir düzeyini soyar."
Henrik

7
Nice - sadece sonra durursanız summarisehangi grupların kaldığını söyler. Oh dplyr rocks ...
Spacedman

Basit ve anlaşılır. Daha önce soyma teorisini hiç bilmiyordum, teşekkürler!
Shixiang Wang

Güzel. basit ve etkili. iyi iş!
user2550228

38

count()Ancak, sürümüne bağlı olarak farklı bir davranışı olan işlevi kullanabilirsiniz dplyr:

  • dplyr 0.7.1: gruplanmamış bir tablo döndürür :am

  • dplyr <0.7.1: gruplandırılmış bir tablo döndürür , bu nedenle ungroup()daha sonra manipülasyon yapmak isteyebileceğiniz halde tekrar gruplandırmanıza gerek yoktur

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))

Bu , gruplandırılmış bir tabloyla sonuçlanır; daha fazla analiz için kullanmak istiyorsanız, gruplandırılmış özniteliğin kaldırılması yararlı olabilir ungroup().


1
Bu dplyr0.7.1'de geçersiz bir cevap gibi görünüyor . Her bir "am" seviyesi yerine, genel olarak "dişli" üzerinde frekans hesaplamasını yapar.
Edwin

30

@ Henrik's kullanılabilirlik açısından daha iyidir, çünkü bu sütun karakterini yapacak ve artık sayısal olmayacak, ancak istediğinizle eşleşecektir ...

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 Çünkü Spacedman istedi :-)

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
Her zaman formatyüzde işareti ekleyen bir yöntemle bir S3 "yüzde" sınıfı oluşturabilirsiniz ... #overkill
Spacedman

Bunu uygulamak da ilginç olabilir: stackoverflow.com/questions/13483430/…
Spacedman

Ya bu örnekte de ortalama, sd ve SE hesaplanırsa?
user3655531

6

İşte dplyrHenrik'in çözümünü 0.7.1'de uygulayan genel bir işlev .

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` sayısaldan karaktere dönüştürülemiyor`
f0nzie

5

Bu yinelenen görev için küçük bir işlev yazdım:

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

Sonra şöyle kullanabilirsiniz:

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

Döndürür:

# 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

Birçok cevaba rağmen, veya prop.tableile birlikte kullanılan bir yaklaşım daha .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
En basit yaklaşım
Parseltongue

1

Bu cevap Matifou'nun cevabına dayanıyor.

İlk olarak, freq sütununu scipen seçeneğini kullanarak bilimsel bir gösterim sütunu olarak döndürmemeyi sağlamak için değiştirdim.

Daha sonra, frekans sütununu yüzde olarak okunmasını kolaylaştırmak için ondalık yerine yüzde almak için cevabı 100 ile çarptım.

getOption("scipen") 
options("scipen"=10) 
mtcars %>%
count(am, gear) %>% 
mutate(freq = (n / sum(n)) * 100)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.