У меня есть фрейм данных с целочисленными столбцами x1, x2, x3,... и логическими столбцами x1_status, x2_status, x3_status,...
df = tibble(
x1 = 1:5,
x1_status = c(T, T, T, F, F),
x2 = 6:10,
x2_status = c(F, T, T, T, F),
x3 = 11:15,
x3_status = c(F, F, T, T, T)
)
Как вычислить среднее значение x1, x2, x3,... для значений, где x1_status равен True
, x2_status равен True
, x3_status равен True
и т. д. соответственно? Я бы хотел использовать across()
внутри summarize()
, чтобы мне не приходилось перечислять каждый столбец x отдельно.
То есть я надеюсь получить фрейм данных со столбцами mean_x1 = 2
, mean_x2 = 8
и mean_x3 = 14
.
Я думал о чем-то вроде
df |>
summarize(
across(
!matches("_"),
\(value_col) {
status_col = str_c(cur_column(), "_status")
mean(value_col[.data[[status_col]]])
},
.names = "mean_{col}"
)
)
но это не работает. Я также хотел бы избежать использования df[[status_col]]
, чтобы я мог включить его в конвейер, который мог бы создавать столбцы x1, x2, x3,... без необходимости промежуточного назначения df.
Использование pivot_longer()
может быть более интуитивным:
library(tidyverse)
df = tibble(
x1 = 1:5,
x1_status = c(T, T, T, F, F),
x2 = 6:10,
x2_status = c(F, T, T, T, F),
x3 = 11:15,
x3_status = c(F, F, T, T, T)
)
# Pivot to longer dataset
df_long <- df %>%
rename_with(
~ paste0(., "_value"),
c(x1, x2, x3)
) %>%
pivot_longer(
cols = everything(),
names_sep = "_",
names_to = c("name", ".value")
)
# Summarize
long_summary <- df_long %>%
filter(status) %>%
group_by(name) %>%
summarize(value = mean(value))
# Pivot to wide summary
wide_summary <- long_summary %>%
pivot_wider(
names_from = "name",
values_from = "value",
names_prefix = "mean_"
)
print(wide_summary)
Другой подход — NA
выделить x*
, имеющие статус FALSE
, и использовать na.rm
при применении mean
.
Как и следующее
library(tidyverse)
df = tibble(
x1 = 1:5,
x1_status = c(T, T, T, F, F),
x2 = 6:10,
x2_status = c(F, T, T, T, F),
x3 = 11:15,
x3_status = c(F, F, T, T, T)
)
df %>%
mutate(across(matches("_"), ~ ifelse(.x, T, NA))) %>%
reframe(across(!matches("_"), .names = '{col}_mean') * pick(matches("_"))) %>%
summarize(across(everything(), ~ mean(.x, na.rm = TRUE)))
#> # A tibble: 1 × 3
#> x1_mean x2_mean x3_mean
#> <dbl> <dbl> <dbl>
#> 1 2 8 14
Created on 2024-08-28 with reprex v2.1.1
Добро пожаловать в ТАК! Попробуйте использовать
get
вместо местоимения.data
, т. е. используйтеmean(value_col[get(status_col)])
. См., например, stackoverflow.com/questions/68349087/… (хотя в этом вопросе.data
тоже работает (;)