[英]R function to extract top n scores from a dataframe and find their average using `apply` or dplyr `rowwise`
dataframe 看起来像这样
df = data.frame(name = c("A","B","C"),
exam1 = c(2,6,4),
exam2 = c(3,5,6),
exam3 = c(5,3,3),
exam4 = c(1,NA,5))
我想提取每个“名称”的前 3 个考试分数,并使用apply()或 dplyr rowwise()函数找到它们的平均值。
使用apply
,使用MARGIN = 1
,循环遍历数字列上的行, sort
,根据decreasing = TRUE/FALSE
获取head/tail
,并返回base R
中的mean
apply(df[-1], 1, FUN = function(x) mean(head(sort(x, decreasing = TRUE), 3)))
[1] 3.333333 4.666667 5.000000
或使用dplyr/rowwise
library(dplyr)
df %>%
rowwise %>%
mutate(Mean = mean(head(sort(c_across(where(is.numeric)),
decreasing = TRUE), 3))) %>%
ungroup
# A tibble: 3 × 6
name exam1 exam2 exam3 exam4 Mean
<chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 A 2 3 5 1 3.33
2 B 6 5 3 NA 4.67
3 C 4 6 3 5 5
这是一种使用旋转和使用top_n
的替代方法:这将只返回前 3 个:
library(dplyr)
library(tidyr)
df %>%
pivot_longer(
-name,
names_to = "exam",
values_to = "value"
) %>%
group_by(name) %>%
top_n(3, value) %>%
mutate(mean = mean(value)) %>%
pivot_wider(
names_from = exam,
values_from = value
)
name mean exam1 exam2 exam3 exam4
<chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 A 3.33 2 3 5 NA
2 B 4.67 6 5 3 NA
3 C 5 4 6 NA 5
或者:
library(tidyr)
df %>%
pivot_longer(
-name,
names_to = "exam",
values_to = "value"
) %>%
group_by(name) %>%
top_n(3, value) %>%
summarise(mean = mean(value))
name mean
<chr> <dbl>
1 A 3.33
2 B 4.67
3 C 5
我回到这个问题并尝试使用基本的 dplyr 操作“df”,这也有效,就像早期帖子中的一些真正有用的解决方案一样。
df_long <- df %>%
pivot_longer(cols = -name,
names_to = "exam",
values_to = "score")
df_long %>%
group_by(name) %>%
arrange(desc(score)) %>%
slice(1:3) %>%
summarise(mean_score = mean(score))
@Paul Smith 添加inner_join(df)
的好主意
另一种可能的解决方案,基于tidyr::pivot_longer
并且不使用rowwise
:
library(tidyverse)
df = data.frame(name = c("A","B","C"),
exam1 = c(2,6,4),
exam2 = c(3,5,6),
exam3 = c(5,3,3),
exam4 = c(1,NA,5))
df %>%
pivot_longer(cols = 2:5, names_to = "names") %>%
group_by(name) %>%
slice_max(value, n=3) %>%
summarise(mean = mean(value)) %>%
inner_join(df)
#> Joining, by = "name"
#> # A tibble: 3 × 6
#> name mean exam1 exam2 exam3 exam4
#> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 A 3.33 2 3 5 1
#> 2 B 4.67 6 5 3 NA
#> 3 C 5 4 6 3 5
我会采用@akrun 并添加na.rm
参数,以防万一您在未来的方法中需要它,最高分可以通过 NA 结果进行搜索。
最终结果将是:
df <- data.frame(name = c("A","B","C"),
exam1 = c(2,6,4),
exam2 = c(3,5,6),
exam3 = c(5,3,3),
exam4 = c(1,NA,5))
results <- apply(df[-1], 1, FUN = function(x) mean(
head(sort(x, decreasing = TRUE), 3),
na.rm=TRUE))
names(results) <- df$name
results
结果应如下所示:
> results
A B C
3.333333 4.666667 5.000000
>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.