[英]Create multiple columns in summarize
在summarize(...)
(或者,在do(...)
)創建多個列的最佳方法是什么? 如果某些聚合函數返回多個值,則會出現這種情況。 這種功能的一個例子是quantile(...)
。
例如,假設我們有以下數據
library(dplyr)
data.frame(x = runif(1000, min = 0, max = 20)) %>%
mutate(y = rnorm(n(), mean = sin(x))) %>%
group_by(x.category = round(x)) ->
Z
我們可以輕松地計算(和繪制)分位數:
library(ggplot2) # just to display results (not the focus of this question)
Z %>%
summarize(x = mean(x),
y25 = quantile(y, probs = .25),
y50 = quantile(y, probs = .5),
y75 = quantile(y, probs = .75)) %>%
gather(Statistic, y, -x, -x.category) %>%
ggplot(aes(x, y, color = Statistic)) +
geom_line()
但是,上面的代碼有兩個缺點:1) quantile(...)
代碼必須重復(如果需要十幾個分位數,這將變得更加繁瑣),以及2)列名稱(y25,y50, y75)可能與實際分位數不匹配。
這些問題可以通過利用quantile(...)
計算多個分位數的能力並在帶有名稱的向量中返回它們來解決,如下所示:
Z %>%
do(as_data_frame(c(x = mean(.$x),
as.list(quantile(.$y, probs = c(.25,.5,.75)))))) %>%
gather(Statistic, y, -x, -x.category) %>%
ggplot(aes(x, y, color = Statistic)) +
geom_line()
但是上面的代碼對我來說似乎很難看; 特別是它需要as.list(...)
, c(...)
, as_data_frame(...)
和do(...)
才能做一些非常簡單的事情。
有沒有更好的辦法?
處理返回多個值的函數時,一種可能的方法是通過組合這些值來創建字符串,然后使用相應的名稱將該字符串分成多個列。
library(dplyr)
library(tidyr)
data.frame(x = runif(1000, min = 0, max = 20)) %>%
mutate(y = rnorm(n(), mean = sin(x))) %>%
group_by(x.category = round(x)) ->
Z
# specify quantiles
q = c(0.25, 0.5, 0.75)
Z %>%
summarise(x = mean(x),
qtls = paste(quantile(y, q), collapse = ",")) %>% # get quantile values as a string
separate(qtls, paste0("y_", 100*q), sep = ",", convert = T) # separate quantile values and give corresponding names to columns
# # A tibble: 21 x 5
# x.category x y_25 y_50 y_75
# <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 0 0.252 -0.596 0.156 0.977
# 2 1 0.929 -0.191 0.753 1.15
# 3 2 2.07 0.222 0.787 1.26
# 4 3 2.95 -0.488 0.303 1.13
# 5 4 3.92 -1.38 -0.627 -0.0220
# 6 5 4.94 -1.52 -1.08 -0.489
# 7 6 6.03 -0.950 -0.432 0.492
# 8 7 6.97 -0.103 0.602 1.32
# 9 8 7.94 0.350 1.02 1.88
# 10 9 9.00 -0.155 0.393 1.02
# # ... with 11 more rows
受到@AntoniosK答案的啟發,這里有一個解決方案,它也可以在一個列中放置多個數字,但不是將它們轉換為字符串,而是將它們存儲在列表列中:
probs <- c(0.25, 0.5, 0.75)
Z %>%
summarize(x = mean(x),
quantile = list(quantile(y, probs)),
prob = list(probs)) %>%
unnest()
要將結果轉換為寬格式,可以使用%>% mutate(prob = sprintf('%g%%', 100*prob)) %>% spread(prob, quantile)
(如常)來執行上述操作。
我注意到的一件事是, unnest(...)
忽略了向量上的名字。 (事實上,我曾希望.id
參數允許我利用它,但它會在列表中查找名稱而不是列表中的向量)。 如果您真的想使用這些名稱,一種方法是:
library(tibble)
Z %>%
summarize(x = mean(x),
quantile = list(enframe(quantile(y)))) %>%
unnest()
它使用tibble::enframe(...)
將名稱捕獲到一個tibble::enframe(...)
列中。
例如,您可以使用apply系列:
Z %>%
sapply(function(x){c(quantile(x, probs = (0:10)/10), mean = mean(x))}) %>%
data.frame()
# x x.1 y x.category
# 0% 0.001726993 0.00274735 -4.04157670 0.000
# 10% 1.495121921 2.11284993 -1.51783484 1.000
# 20% 3.450423732 4.23374999 -0.92207407 3.000
# 30% 5.366798687 6.13729078 -0.55590328 5.000
# 40% 7.424445083 8.00006315 -0.18782436 7.000
# 50% 9.607056717 10.01599003 0.09847098 10.000
# 60% 11.605829581 11.98377222 0.39765998 12.000
# 70% 13.402578154 13.95268995 0.75339699 13.000
# 80% 15.432076896 16.04652040 1.16335283 15.000
# 90% 17.759217854 17.90820096 1.64737747 18.000
# 100% 19.991569165 19.97475065 3.33769925 20.000
# mean 9.544870438 10.02387573 0.08833454 9.551
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.