#r #dplyr #purrr
#r #dplyr #муррр
Вопрос:
У меня есть набор данных с последовательно названными столбцами, и я хотел бы получить среднее значение столбцов по их группе, например,
library(dplyr)
library(purrr)
library(glue)
df <- tibble(`1_x_blind` = 1:3,
`1_y_blind` = 7:9,
`2_x_blind` = 4:6,
`2_y_blind` = 5:7)
df %>%
mutate(`1_overall_test` = rowMeans(select(., matches(glue("^1_.*_blind$")))))
#> # A tibble: 3 x 5
#> `1_x_blind` `1_y_blind` `2_x_blind` `2_y_blind` `1_overall_test`
#> <int> <int> <int> <int> <dbl>
#> 1 1 7 4 5 4
#> 2 2 8 5 6 5
#> 3 3 9 6 7 6
Этот метод работает нормально. Следующим шагом для меня было бы масштабировать его так, чтобы я мог выполнять всю серию столбцов, например, что-то вроде
df %>%
mutate(overall_blind = map(1:2, ~rowMeans(select(., matches(glue("^{.x}_.*_blind$"))))))
#> Error: Problem with `mutate()` input `overall_blind`.
#> x no applicable method for 'select' applied to an object of class "c('integer', 'numeric')"
#> ℹ Input `overall_blind` is `map(1:2, ~rowMeans(select(., matches(glue("^{.x}_.*_blind$")))))`.
Я думаю, что проблема здесь в том, что select
это сбивает с толку .
оператора. Возможно ли map
таким образом переопределить ряд имен столбцов? В идеале я бы хотел, чтобы имена столбцов следовали {.x}_overall
шаблону, как в примере выше.
Комментарии:
1. Вы хотите, чтобы в вашем выводе был только 1 дополнительный
overall_blind
столбец списков для хранения значений строк всех подгрупп, или вам нужно много столбцов, таких как1_overall_test
,2_overall_test
, и т.д.?2. Было бы лучше иметь много столбцов
3. Количество столбцов в группе фиксировано (всегда 2, т.Е. 1_x, 1_y) Или они различаются для каждой группы?
4. Число всегда будет фиксированным
Ответ №1:
Обновление Вот более чистый способ, который не требует rename
или bind_cols
:
map_dfc(1:2,
function(x) df %>%
select(matches(glue("^{x}_.*_blind$"))) %>%
mutate("{x}_overall_blind" := rowMeans(.))
)
# A tibble: 3 x 6
`1_x_blind` `1_y_blind` `1_overall_blind` `2_x_blind` `2_y_blind` `2_overall_blind`
<int> <int> <dbl> <int> <int> <dbl>
1 1 7 4 4 5 4.5
2 2 8 5 5 6 5.5
3 3 9 6 6 7 6.5
Предыдущая страница
Вот такой map
подход.
Задача состоит в изменении двух новых столбцов на основе отдельных групп существующих столбцов. Проще всего просто сделать это самостоятельно map_dfc()
, а затем привязать его к существующему df
.
df %>%
bind_cols(
map_dfc(1:2, ~rowMeans(df %>% select(matches(glue("^{.x}_.*_blind$"))))) %>%
rename_with(~paste0(str_replace(., "\...", ""), "_overall_blind"))
)
# A tibble: 3 x 6
`1_x_blind` `1_y_blind` `2_x_blind` `2_y_blind` `1_overall_blind` `2_overall_blind`
<int> <int> <int> <int> <dbl> <dbl>
1 1 7 4 5 4 4.5
2 2 8 5 6 5 5.5
3 3 9 6 7 6 6.5
И вот способ получить средние значения по группам столбцов по строкам с использованием сводных данных, что позволяет избежать регулярных выражений и mutate
/ map
операций:
df %>%
mutate(row = row_number()) %>%
pivot_longer(-row) %>%
separate(name, c("grp"), sep = "_", extra = "drop") %>%
group_by(row, grp) %>%
summarise(overall_blind = mean(value)) %>%
ungroup() %>%
pivot_wider(id_cols = row, names_from = grp, values_from = overall_blind,
names_glue = "{grp}_{.value}") %>%
bind_cols(df)
# A tibble: 3 x 6
`1_overall_blind` `2_overall_blind` `1_x_blind` `1_y_blind` `2_x_blind` `2_y_blind`
<dbl> <dbl> <int> <int> <int> <int>
1 4 4.5 1 7 4 5
2 5 5.5 2 8 5 6
3 6 6.5 3 9 6 7
Ответ №2:
Вот одно из решений:
map_dfc(1:2, function(x) {
select(df, matches(glue("^{x}_.*_blind$"))) %>%
mutate(overall_blind = rowMeans(select(., matches(glue("^{x}_.*_blind$"))))) %>%
# General but not perfect names
# set_names(paste0(x, "_", names(.)))
# Hand-tailored names
set_names(c(names(.)[1], names(.)[2], paste0(x, "_", names(.)[3])))
})
#> # A tibble: 3 x 6
#> `1_x_blind` `1_y_blind` `1_overall_blind` `2_x_blind` `2_y_blind` `2_overall_blind`
#> <int> <int> <dbl> <int> <int> <dbl>
#> 1 1 7 4 4 5 4.5
#> 2 2 8 5 5 6 5.5
#> 3 3 9 6 6 7 6.5
Я добавил две возможности присвоения имен overall_blind
столбцам для каждой группы: одно более общее, но не идеальное имя (оно дублирует 1_
или 2_
для столбцов данных), а другое, которое дает нужные имена, но требует заранее знать количество столбцов в группе.
Ответ №3:
Мы можем использовать split.default
для разделения данных на list
наборы данных на основе шаблона имен столбцов, затем получить rowMeans
и связать с исходными данными
library(dplyr)
library(purrr)
library(stringr)
df %>%
split.default(readr::parse_number(names(.))) %>%
map_dfc(rowMeans) %>%
set_names(str_c(names(.), "_overall_blind")) %>%
bind_cols(df, .)
# A tibble: 3 x 6
# `1_x_blind` `1_y_blind` `2_x_blind` `2_y_blind` `1_overall_blind` `2_overall_blind`
# <int> <int> <int> <int> <dbl> <dbl>
#1 1 7 4 5 4 4.5
#2 2 8 5 6 5 5.5
#3 3 9 6 7 6 6.5