我完全承认这不是我最好的问题标题。
我试图创造一个卑鄙的领域。
我在下面有一个ID列,范围从1-5。ID列中任何单个值的平均值都是从单个ID值和两个紧挨在前的值的"值"列中的值导出的。
对于ID 5,平均值将是ID为5、4和3的"值"列中的所有值。
我正在寻找一种简洁的方法,它可以根据ID列中的命名值范围计算ID列中单个值的平均值,并仅在单个值中填充结果。
到目前为止,我找到的唯一方法是过滤特定命名范围的主数据集,获得过滤数据集所有行的平均值,再次过滤以只保留单个ID值,然后将其合并回主数据集。这又长又乱,我有很多数据。
下面的代码创建了一个初始数据帧,然后每一步都得到df6的最终结果。
更倾向于采用小规模的解决方案。
我最初的想法是使用ifelse或case_when,但我很快发现,隔离ID列中的特定值并取另一列的平均值可以得到另一列中所有值的平均值,而不是由case或ifelse指定的值的平均数。我曾考虑过rowwise,which((,或者一个在列中指定值的group_by,但无法实现。
df1 <- data.frame(
`ID` = as.character(sample(1:5, 20, replace = TRUE)),
Value = sample(1:50, 20, replace = FALSE))
df1 %>%
mutate(MeanAll = mean(Value)) %>%
arrange(ID) -> df2
df1 %>%
filter(ID %in% c('5', '4', '3')) %>%
mutate(MeanID5 = mean(Value)) %>%
filter(ID == '5') %>%
distinct(ID, MeanID5) -> df3
df1 %>%
filter(ID %in% c('4', '3', '2')) %>%
mutate(MeanID4 = mean(Value)) %>%
filter(ID == '4') %>%
distinct(ID, MeanID4)-> df4
df1 %>%
filter(ID %in% c('3', '2','1')) %>%
mutate(MeanID3 = mean(Value)) %>%
filter(ID == '3') %>%
distinct(ID, MeanID3)-> df5
df1 %>%
left_join(df2, by = c('ID', 'Value')) %>%
left_join(df3, by = c('ID')) %>%
left_join(df4, by = c('ID')) %>%
left_join(df5, by = c('ID')) %>%
arrange(ID, Value) -> df6
下面是一个使用tidyverse
函数的重构:
library(tidyverse)
set.seed(1)
mean_func <- function(data, values) {
max <- max(as.numeric(values))
max_colname <- paste0("Mean", max)
data %>%
filter(ID %in% values) %>%
mutate("{paste0('MeanID', max)}" := mean(Value)) %>%
filter(ID == max(values)) %>%
select(-Value) %>%
distinct()
}
df1 <- data.frame(
`ID` = as.character(sample(1:5, 20, replace = TRUE)),
Value = sample(1:50, 20, replace = FALSE))
df2 <- df1 %>%
mutate(MeanAll = mean(Value)) %>%
arrange(ID)
vals <- list(c('5', '4', '3'), c('4', '3', '2'), c('3', '2', '1'))
df1 %>%
left_join(df2, by = c('ID', 'Value')) %>%
left_join(map_df(vals, ~mean_func(df1, .))) %>%
arrange(ID)
#> Joining, by = "ID"
#> ID Value MeanAll MeanID5 MeanID4 MeanID3
#> 1 1 37 31.6 NA NA NA
#> 2 1 42 31.6 NA NA NA
#> 3 1 6 31.6 NA NA NA
#> 4 1 39 31.6 NA NA NA
#> 5 1 47 31.6 NA NA NA
#> 6 1 48 31.6 NA NA NA
#> 7 2 25 31.6 NA NA NA
#> 8 2 33 31.6 NA NA NA
#> 9 2 43 31.6 NA NA NA
#> 10 2 28 31.6 NA NA NA
#> 11 3 15 31.6 NA NA 32.15385
#> 12 3 20 31.6 NA NA 32.15385
#> 13 3 35 31.6 NA NA 32.15385
#> 14 4 34 31.6 NA 29.125 NA
#> 15 5 44 31.6 28.4 NA NA
#> 16 5 10 31.6 28.4 NA NA
#> 17 5 38 31.6 28.4 NA NA
#> 18 5 23 31.6 28.4 NA NA
#> 19 5 41 31.6 28.4 NA NA
#> 20 5 24 31.6 28.4 NA NA
您可以使用map
和reduce
将所有内容合并到一个表中:
map(1:3, seq, length.out = 3) %>%
setNames(map_dbl(., last)) %>%
imap(
~tibble(
ID = .y,
!!paste0("MeanID", .y) := mean(pull(filter(df1, ID %in% .x), Value))
)
) %>%
reduce(left_join, .init = df1, by = "ID") %>%
arrange(ID) %>%
mutate(MeanAll = mean(Value))