我想知道是否有比下面的方法更好的解决方案。我有一个数据框,我想根据每个组的最高值来获取每一列的均值。
set.seed(123)
df <- data.frame(
A = sample(c("A","B","C"), 20, replace=TRUE),
B = rnorm(60, 5, 2),
C = rnorm(60, 0, 2),
D = rnorm(60, 10, 2))
library("dplyr")
top <- 5
top.B <- df %>% group_by(A) %>% top_n(n=top, wt=B) %>% summarize(top.A=mean(B))
top.C <- df %>% group_by(A) %>% top_n(n=-top, wt=C) %>% summarize(top.C=mean(C))
top.D <- df %>% group_by(A) %>% top_n(n=top, wt=D) %>% summarize(top.D=mean(D))
top5 <- merge(top.B, top.C, by="A")
top5 <- merge(top5, top.D, by="A")
我能够通过合并数据帧来完成它。结果看起来像:
A top.A top.C top.D
1 A 7.663078 -1.986632 12.62946
2 B 6.926882 -2.186245 13.18132
3 C 7.548887 -2.255001 12.15677
我想知道是否可以在不创建那些新数据框的情况下做到这一点。请注意,C列的平均值是从最低值开始的,或者是从顶部开始按降序排列的。
谢谢。
答案 0 :(得分:2)
一种dplyr
可能是:
df %>%
group_by(A) %>%
summarise_all(list(~ mean(.[dense_rank(desc(.)) <= 5])))
A B C D
<fct> <dbl> <dbl> <dbl>
1 A 7.66 2.16 12.6
2 B 6.93 1.79 13.2
3 C 7.55 2.23 12.2
如果您想要C列的底部5个观察值:
df %>%
group_by(A) %>%
summarise(B = mean(B[dense_rank(desc(B)) <= 5]),
C = mean(C[dense_rank(C) <= 5]),
D = mean(D[dense_rank(desc(D)) <= 5]))
A B C D
<fct> <dbl> <dbl> <dbl>
1 A 7.66 -1.99 12.6
2 B 6.93 -2.19 13.2
3 C 7.55 -2.26 12.2
答案 1 :(得分:2)
一个data.table
选项:
获得前5名的平均值
get_mean_top5 <- function(x) -mean(sort(-x, partial = 1:5)[1:5])
df[, lapply(.SD, get_mean_top5), keyby = A, .SDcols = c("B", "D")]
# A B D
# 1: A 6.097723 12.75887
# 2: B 7.942064 12.33379
# 3: C 8.190137 12.93201
如果是倒数5,则为平均值:
get_mean_bot5 <- function(x) mean(sort(x, partial = 1:5)[1:5])
df[, lapply(.SD, get_mean_bot5), keyby = A, .SDcols = c("C")]
要一步获得完整表格:
setDT(df, key = "A")
df[, lapply(.SD, get_mean_top5), keyby = A, .SDcols = c("B", "D")
][df[, lapply(.SD, get_mean_bot5), keyby = A, .SDcols = c("C")]]
答案 2 :(得分:1)
这是map
library(tidyverse)
map(names(df)[-1], ~
df %>%
select(A, .x) %>%
group_by(A) %>%
top_n(n = top, wt = !! rlang::sym(.x)) %>%
summarise(!! str_c('top.', .x) := mean(!! rlang::sym(.x)))) %>%
reduce(inner_join, by = 'A')
# A tibble: 3 x 4
# A top.B top.C top.D
# <fct> <dbl> <dbl> <dbl>
#1 A 6.10 3.20 12.8
#2 B 7.94 2.17 12.3
#3 C 8.19 1.18 12.9
或者将frank
中的data.table
与summarise_all
一起使用(类似于@tmfmnk帖子中的选项)
library(data.table)
df %>%
group_by(A) %>%
summarise_all(list( ~ mean(.[frank(-.) <= 5])))
# A tibble: 3 x 4
# A B C D
# <fct> <dbl> <dbl> <dbl>
#1 A 6.10 3.20 12.8
#2 B 7.94 2.17 12.3
#3 C 8.19 1.18 12.9
或使用order
df %>%
group_by(A) %>%
summarise_all(list(~ mean(.x[order(-.)][1:5])))
# A tibble: 3 x 4
# A B C D
# <fct> <dbl> <dbl> <dbl>
#1 A 6.10 3.20 12.8
#2 B 7.94 2.17 12.3
#3 C 8.19 1.18 12.9
答案 3 :(得分:1)
以某种方式,我得到的价值与您不同,但是这种方法应该有效
library(dplyr)
df %>%
gather(key, value, -A) %>%
group_by(A, key) %>%
top_n(5, value) %>%
summarise(m = mean(value)) %>%
ungroup() %>%
spread(key, m)
# A tibble: 3 x 4
A B C D
<fct> <dbl> <dbl> <dbl>
1 A 6.10 3.20 12.8
2 B 7.94 2.17 12.3
3 C 8.19 1.18 12.9
这里的数据:
set.seed(123)
df <- data.frame(
A = sample(c("A","B","C"), 20, replace=TRUE),
B = rnorm(60, 5, 2),
C = rnorm(60, 0, 2),
D = rnorm(60, 10, 2))