2015-05-27 27 views
23

Bir çalışma çözümüm var ama belki daha yeni dplyr pencere işlevlerinden bazılarını kullanan daha temiz, daha okunabilir bir çözüm arıyorum.Yüzlerce pencere fonksiyonunu kullanarak yüzdelik hesaplarını hesaplama

mtcars veri kümesini kullanarak, 25, 50, 75. persentillere bakmak istiyorum ve silindir sayısı ("silindir") tarafından galon başına mil ("mpg") ortalama ve sayım yapmak istiyorum aşağıdaki kodu:

library(dplyr) 
library(tidyr) 

# load data 
data("mtcars") 

# Percentiles used in calculation 
p <- c(.25,.5,.75) 

# old dplyr solution 
mtcars %>% group_by(cyl) %>% 
    do(data.frame(p=p, stats=quantile(.$mpg, probs=p), 
       n = length(.$mpg), avg = mean(.$mpg))) %>% 
    spread(p, stats) %>% 
    select(1, 4:6, 3, 2) 

# note: the select and spread statements are just to get the data into 
#  the format in which I'd like to see it, but are not critical 

Ben özet fonksiyonlarının bazılarını kullanarak dplyr ile daha temiz yapabilirsiniz bir yolu (n_tiles, percent_rank, vs.) var mı? Temiz olarak, "do" ifadesi olmadan demek istiyorum.

teşekkür ederiz

+0

Bu kodun, "spread" işlevinin – dreww2

cevap

32

do'u engelleyen bir dplyr yaklaşımıdır, ancak her bir değer için quantile'a ayrı bir çağrı gerektirir.

mtcars %>% group_by(cyl) %>% 
    summarise(`25%`=quantile(mpg, probs=0.25), 
      `50%`=quantile(mpg, probs=0.5), 
      `75%`=quantile(mpg, probs=0.75), 
      avg=mean(mpg), 
      n=n()) 

    cyl 25% 50% 75%  avg n 
1 4 22.80 26.0 30.40 26.66364 11 
2 6 18.65 19.7 21.00 19.74286 7 
3 8 14.40 15.2 16.25 15.10000 14 

summarisequantile tek bir çağrı ile birden çok değer geri dönebilirler daha iyi olurdu, ancak bu dplyr gelişiminde an open issue olarak görünmektedir.

GÜNCELLEME: İşte quantiles almak için iç içe kullanır JuliaSilge cevabı @ üzerinde bir varyasyonu, ama map kullanılmadan. Bununla birlikte, kuantum seviyelerini listeleyen bir sütun eklemek için fazladan bir kod satırına ihtiyaç duyuyor, çünkü niceliklerin isimlerini doğrudan aramadan quantile'a doğru ayrı bir sütuna çekmek için nasıl (veya mümkün ise) emin değilim .

p = c(0.25,0.5,0.75) 

mtcars %>% 
    group_by(cyl) %>% 
    summarise(quantiles = list(sprintf("%1.0f%%", p*100)), 
      mpg = list(quantile(mpg, p))) %>% 
    unnest 
cyl quantiles mpg 
1  4  25% 22.80 
2  4  50% 26.00 
3  4  75% 30.40 
4  6  25% 18.65 
5  6  50% 19.70 
6  6  75% 21.00 
7  8  25% 14.40 
8  8  50% 15.20 
9  8  75% 16.25 
+0

Teşekkürler - aradığım cevap budur, ki bunu yapabilirsin, ama kuantile tek bir çağrı ile sorunsuz bir şekilde (ve dplyr geliştirme açık bir sorundur). – dreww2

9

Değil dplyr yılında do() önlemek için, ancak oldukça basit bir şekilde data.table ile c() ve as.list() ile bunu nasıl emin: İsterseniz

require(data.table) 
as.data.table(mtcars)[, c(as.list(quantile(mpg, probs=p)), 
         avg=mean(mpg), n=.N), by=cyl] 
# cyl 25% 50% 75%  avg n 
# 1: 6 18.65 19.7 21.00 19.74286 7 
# 2: 4 22.80 26.0 30.40 26.66364 11 
# 3: 8 14.40 15.2 16.25 15.10000 14 

keyby ile by değiştirin cyl sütun tarafından emredilir.

+0

Good'den geldiği "tidyr" paketini de kullandığını eklemeliyim. [.data.table'daki 'as.list 'yönteminin farkındaydım ve bunu dplyr'de denedim ancak başarısız oldum. –

+0

Bu güzel bir çözümdür - keşke kendi özel projem için kullanabilseydim ama cevabın kendisi ile ilgisi olmayan nedenlerden ötürü yapamam. – dreww2

11

Bu maalesef hala do() gerektirir broom paketin tidy() fonksiyonunu kullanan bir dplyr yaklaşımdır, ama çok daha basittir.

library(dplyr) 
library(broom) 

mtcars %>% 
    group_by(cyl) %>% 
    do(tidy(t(quantile(.$mpg)))) 

veren:

cyl X0. X25. X50. X75. X100. 
    (dbl) (dbl) (dbl) (dbl) (dbl) (dbl) 
1  4 21.4 22.80 26.0 30.40 33.9 
2  6 17.8 18.65 19.7 21.00 21.4 
3  8 10.4 14.40 15.2 16.25 19.2 

Not broom pakette beri t() kullanımı adında numerics için bir yöntem yoktur.

Bu, earlier answer for summary() here numaralı telefon numarasına dayanmaktadır.

11

purrr::map'u kullanmaya devam ediyorsanız, bunu böyle yapabilirsiniz!Bu yaklaşım hakkında

library(dplyr) 
library(tidyr) 
library(broom) 
library(purrr) 

mtcars %>% 
    nest(-cyl) %>% 
    mutate(Quantiles = map(data, ~ quantile(.$mpg))) %>% 
    unnest(map(Quantiles, tidy)) 

#> # A tibble: 15 × 3 
#>  cyl names  x 
#> <dbl> <chr> <dbl> 
#> 1  6 0% 17.80 
#> 2  6 25% 18.65 
#> 3  6 50% 19.70 
#> 4  6 75% 21.00 
#> 5  6 100% 21.40 
#> 6  4 0% 21.40 
#> 7  4 25% 22.80 
#> 8  4 50% 26.00 
#> 9  4 75% 30.40 
#> 10  4 100% 33.90 
#> 11  8 0% 10.40 
#> 12  8 25% 14.40 
#> 13  8 50% 15.20 
#> 14  8 75% 16.25 
#> 15  8 100% 19.20 

Güzel bir şey çıktı bir gözlem satır başına, düzenli olmasıdır.

+0

Teşekkürler, bence bu en temiz yaklaşım. – Fato39

0

Burada düzenli biçimde quantiles dönmek için dplyr ve purrr kullanan oldukça okunabilir çözüm:

Kod

library(dplyr) 
library(purrr) 

mtcars %>% 
    group_by(cyl) %>% 
    do({x <- .$mpg 
     map_dfr(.x = c(.25, .5, .75), 
       .f = ~ data_frame(Quantile = .x, 
            Value = quantile(x, probs = .x))) 
     }) 

Sonucu

# A tibble: 9 x 3 
# Groups: cyl [3] 
    cyl Quantile Value 
    <dbl> <dbl> <dbl> 
1  4  0.25 22.80 
2  4  0.50 26.00 
3  4  0.75 30.40 
4  6  0.25 18.65 
5  6  0.50 19.70 
6  6  0.75 21.00 
7  8  0.25 14.40 
8  8  0.50 15.20 
9  8  0.75 16.25 
0

Bu çözüm dplyr kullanır veYalnızca,, miktarlarınızı dplyr zincirinde belirtmenize izin verir ve tidyr::crossing(), gruplama ve özetlemeden önce veri kümesinin çoklu kopyalarını "istifleme" amacıyla kullanır.

diamonds %>% # Initial data 
    tidyr::crossing(pctile = 0:4/4) %>% # Specify quantiles; crossing() is like expand.grid() 
    dplyr::group_by(cut, pctile) %>% # Indicate your grouping var, plus your quantile var 
    dplyr::summarise(quantile_value = quantile(price, unique(pctile))) %>% # unique() is needed 
    dplyr::mutate(pctile = sprintf("%1.0f%%", pctile*100)) # Optional prettification 

Sonuç:

# A tibble: 25 x 3 
# Groups: cut [5] 
     cut pctile quantile_value 
     <ord> <chr>   <dbl> 
1  Fair  0%   337.00 
2  Fair 25%  2050.25 
3  Fair 50%  3282.00 
4  Fair 75%  5205.50 
5  Fair 100%  18574.00 
6  Good  0%   327.00 
7  Good 25%  1145.00 
8  Good 50%  3050.50 
9  Good 75%  5028.00 
10  Good 100%  18788.00 
11 Very Good  0%   336.00 
12 Very Good 25%   912.00 
13 Very Good 50%  2648.00 
14 Very Good 75%  5372.75 
15 Very Good 100%  18818.00 
16 Premium  0%   326.00 
17 Premium 25%  1046.00 
18 Premium 50%  3185.00 
19 Premium 75%  6296.00 
20 Premium 100%  18823.00 
21  Ideal  0%   326.00 
22  Ideal 25%   878.00 
23  Ideal 50%  1810.00 
24  Ideal 75%  4678.50 
25  Ideal 100%  18806.00 

unique()dplyr::summarise() yalnızca grubun başına bir değer istediğinizi bildirmek için gereklidir.