У меня есть набор данных с рядом сгруппированных процедур. Параллельно в паре независимых групп собирали положительный и отрицательный контроль. Для построения графиков и дальнейшего анализа я хотел бы продублировать контрольные группы для каждой отдельной лечебной группы. Так что мои сюжеты поворачиваются от этого:
к этому:
В dplyr я понял, как определить и сгенерировать столбец с правильными контрольными значениями, но проблема заключается в том, как дублировать полные строки набора данных и добавлять их, а не просто добавлять «положительный контроль» и «отрицательный контроль». столбец для каждой соответствующей группы. Такой подход работает, но означает, что вы действительно можете хранить только суммарное значение (например, среднее), которое копируется для каждого лечения, а не сохранять отдельные показания.
librar(ggplot)
before <- structure(list(group = c("grp1", "grp1", "grp1", "grp1",
"grp2", "grp2", "grp2", "grp2", "grp3", "grp3", "grp3", "grp3",
"neg", "neg", "pos", "pos"), treatment = c("A", "B", "C",
"D", "A", "B", "C", "D", "A", "B", "C", "D", "none", "none",
"none", "none"), value = c(3L, 5L, 7L, 9L, 2L, 4L, 6L, 8L, 3L,
4L, 6L, 9L, 12L, 10L, 1L, 2L)), class = "data.frame", row.names = c(NA, -16L))
ggplot(data = before, aes(x=treatment, y=value)) + geom_boxplot() + facet_wrap (~group)
after <- structure(list(group = c("grp1", "grp1", "grp1", "grp1", "grp1", "grp1",
"grp1", "grp1", "grp2", "grp2", "grp2", "grp2", "grp2", "grp2",
"grp2", "grp2", "grp3", "grp3", "grp3", "grp3", "grp3", "grp3",
"grp3", "grp3"), treatment = c("A", "B", "C", "D", "neg", "neg",
"pos", "pos", "A", "B", "C", "D", "neg", "neg", "pos", "pos",
"A", "B", "C", "D", "neg", "neg", "pos", "pos"), value = c(3L,
5L, 7L, 9L, 12L, 10L, 1L, 2L, 2L, 4L, 6L, 8L, 12L, 10L, 1L, 2L,
3L, 4L, 6L, 9L, 12L, 10L, 1L, 2L)), class = "data.frame", row.names = c(NA, -24L))
ggplot(data = after, aes(x=treatment, y=value)) + geom_boxplot() + facet_wrap (~group)
Вариант состоит в том, чтобы filter
строки с «neg», «pos» в столбце group
и связать строки с исходными данными group_split
без «neg», «pos» в столбце group
library(dplyr)
library(tidyr)
library(purrr)
tmp <- before %>%
# // filter the rows where the group values are 'neg', 'pos'
filter(group %in% c('neg', 'pos')) %>%
# // then replace the treatment values with the group column values
mutate(treatment = group) %>%
# // remove the group
select(-group)
Теперь мы filter
только строки без «neg», «pos» в group
out <- before %>%
# // remove the rows where the 'neg' and 'pos' values are in group
filter(!group %in% c('neg', 'pos')) %>%
# // returns a list of data.frame/tibbles
group_split(group) %>%
# // loop over the list, then bind the data with the tmp data
# // _dfr binds the list element as row binding
map_dfr(~ bind_rows(.x, tmp) %>%
# // As removed the group column in tmp
# // its values are NA
# // use fill to replace NA with non-NA previous value
fill(group))
-выход
out
# A tibble: 24 x 3
# group treatment value
# <chr> <chr> <int>
# 1 grp1 A 3
# 2 grp1 B 5
# 3 grp1 C 7
# 4 grp1 D 9
# 5 grp1 neg 12
# 6 grp1 neg 10
# 7 grp1 pos 1
# 8 grp1 pos 2
# 9 grp2 A 2
#10 grp2 B 4
# … with 14 more rows
Проверка сюжета
library(ggplot2)
ggplot(data = out, aes(x=treatment, y=value)) +
geom_boxplot() +
facet_wrap (~group)
Это также может быть сделано в одной трубе
before %>%
# // replace the treatment values that 'none' with corresponding group values
mutate(treatment = coalesce(na_if (treatment, 'none'), group)) %>%
# // do a group by group
group_by( group) %>%
# // summarise the columns of interest with across
summarise(across(c(treatment, value),
# // append the values in the full dataset where the group
# // column is 'neg', 'pos'
~ c(., dplyr:::peek_mask()$full_data()[[cur_column()]][
before$group %in% c("neg", "pos")])),
.groups = 'drop') %>%
# // filter out the 'pos', 'neg' group rows
filter(!group %in% c('pos', 'neg'))
-выход
# A tibble: 24 x 3
# group treatment value
# <chr> <chr> <int>
# 1 grp1 A 3
# 2 grp1 B 5
# 3 grp1 C 7
# 4 grp1 D 9
# 5 grp1 neg 12
# 6 grp1 neg 10
# 7 grp1 pos 1
# 8 grp1 pos 2
# 9 grp2 A 2
#10 grp2 B 4
# … with 14 more rows
@MarioNiepel да, это просто filter
объединение этих строк с «neg», «pos» и добавление после разделения отфильтрованных данных без строк «neg», «pos» с «tmp».
Извините, я отправил комментарий случайно, когда еще писал/редактировал.
@MarioNiepel Я добавил описание в каждую строку кода. Надеюсь, это поможет вам
Ты жжешь. Это (и некоторые разумные поиски в Google + метод проб и ошибок) должны меня достать. Спасибо!
к сожалению, мой победный танец был преждевременным. Я сохранил игрушечный пример простым, но теперь я не понимаю, как справиться с реальной сложностью. «Группа» в моем примере на самом деле является всего лишь одной переменной в схеме обработки с более высоким уровнем вложенности. Для каждой группы на самом деле есть четыре дополнительные группирующие переменные, которые необходимо разделить — все с их собственными соответствующими элементами управления pos/neg. Я думаю, что описанный выше подход объединяет все эти категории в одну, но процесс должен работать на уровне by_group
со всеми этими переменными параллельно. (И извините, если непонятно. Попробую отредактировать пост.)
@MarioNiepel, можете ли вы опубликовать новый вопрос, так как вложенное условие будет отличаться от того, которое у вас есть?
Сделаю. Мне потребуется некоторое время, чтобы даже подумать о том, чтобы опубликовать правильный пример. Фактические данные являются конфиденциальными, но я хочу убедиться, что уловил всю сложность проблемы.
@MarioNiepel Спасибо. Я также разместил второе решение. Я надеюсь, что вы можете попробовать их тоже
Привет @akrun, я разместил новый вопрос здесь: stackoverflow.com/questions/65453438/… И я также нашел решение, основанное и вдохновленное большей частью информации, которую вы здесь предоставили. Он полагается на муррр, но один шаг, который действительно упростил его, — это использование (full_join) для распространения управляющих значений на каждое условие. И мне еще предстоит много работы, чтобы понять, как работать с различными функциями муррр...
Спасибо, @akrun. Итак, чтобы пройтись, tmp df представляет собой разделение, чтобы удалить элементы управления из групп обработки и сделать их удобными для добавления. Мы фильтруем все, что не является элементом управления pos/neg, и здесь все становится немного неясным: 'group_split' преобразует каждую группу в отдельные списки? А затем команда map_dfr использует команду, подобную rbind, для добавления tmp df к каждой из разделенных групп (
.x
)? А потомfill
все пересобирает? И если предположить, что это примерно так, будет ли это работать, если будут задействованы дополнительные уровни группировки?