Я пытаюсь создать таблицу с заголовками study_id, Conflict и создать третий и четвертый столбцы, содержащие данные, соответствующие значению в столбце: Conflict
Код ниже достигает этой цели. Однако это довольно длинно, особенно потому, что я хочу расширить это, чтобы охватить несколько сотен различных значений в столбце: конфликт
Заранее спасибо за любые указатели
df <- data.frame(study_id=c("1", "1", "4", "4", "5"),
Conflict=c("WATER.START", "WATER.STOP", "OIL.START", "NA", "WATER.STOP"),
Result=c("TRUE", "TRUE", "TRUE", "NA", "TRUE"))
df2 <- data.frame(study_id=c("1", "2", "3", "4", "5"),
WATER.start=c(1, 1, 2, NA, 6),
WATER.truestart=c(1, 1, 2, NA, 25),
WATER.stop=c(33, 3, 2, NA, 8),
WATER.truestop= c(34, 4, 2, NA, 8))
final <- left_join(df, df2, by ='study_id')
dd <- final %>% filter(Result == "TRUE" & Conflict == "WATER.START")
dd <- dd %>% subset(., Conflict == "WATER.START",
select=c(study_id, Conflict, WATER.start, WATER.truestart))
dd <- dd %>% rename(initial=WATER.start) %>% rename(verification=WATER.truestart)
ee <- final %>% filter(Result == "TRUE" & Conflict == "WATER.STOP")
ee <- ee %>% subset(., Conflict == "WATER.STOP",
select=c(study_id, Conflict, WATER.stop, WATER.truestop))
ee <- ee %>% rename(initial=WATER.stop) %>% rename(verification=WATER.truestop)
ff <- bind_rows(dd, ee)
gg <- ff %>% select(study_id, Conflict, initial, verification)
gg
# study_id Conflict initial verification
# 1 1 WATER.START 1 1
# 2 1 WATER.STOP 33 34
# 3 5 WATER.STOP 8 8
Во-первых, кажется, что вы фокусируетесь только на c('WATER.START', 'WATER.STOP'), subset своем первом df. Затем для каждого MARGIN=1 (то есть каждой строки) мы apply анонимную функцию \(x), которая выбирает соответствующие столбцы df2, используя tolower для соответствия регистру и cbinds вместе. Наконец, переименуйте столбцы, используя setNames и rbind получившийся список.
subset(df, Conflict %in% c('WATER.START', 'WATER.STOP')) |>
apply(MARGIN=1, \(x) {
mt <- match(tolower(x[2]), tolower(names(df2)))
cbind(t(x[1:2]), df2[df2$study_id == x[1], c(mt, mt + 1)]) |>
setNames(c('study_id', 'Conflict', 'initial', 'verification'))
}) |> do.call(what=rbind)
# study_id Conflict initial verification
# 1 1 WATER.START 1 1
# 2 1 WATER.STOP 33 34
# 5 5 WATER.STOP 8 8
Вы также можете использовать словарь a (который может быть расширен до других уровней, которые вы можете использовать).
a <- c(WATER.START='WATER.start', WATER.STOP='WATER.stop')
subset(df, Conflict %in% c('WATER.START', 'WATER.STOP')) |>
apply(MARGIN=1, \(x) {
mt <- match(a[match(x[2], names(a))], names(df2))
cbind(t(x[1:2]), df2[df2$study_id == x[1], c(mt, mt + 1)]) |>
setNames(c('study_id', 'Conflict', 'initial', 'verification'))
}) |> do.call(what=rbind)
# study_id Conflict initial verification
# 1 1 WATER.START 1 1
# 2 1 WATER.STOP 33 34
# 5 5 WATER.STOP 8 8
Чуть менее элегантным способом было использование fct_recode df <- data.frame(study_id = (c("1","1","4","4","5")), Conflict = (c("fluid_a_on ","fluid_a_off","OIL.START","NA","WATER.STOP")), Результат = (c("ИСТИНА","ИСТИНА","ИСТИНА","NA","ИСТИНА" ))) df <- df %>% mutate(Conflict = fct_recode(Conflict, "WATER.START" = "fluid_a_on", "WATER.STOP" = "fluid_a_off")) df Если есть альтернативный подход, мне было бы интересно знать. Ваше здоровье
@GJW Чтобы предоставить информацию, которую вы можете использовать в словаре, см. Обновление. Мы могли бы сделать здесь много необычных вещей, но, возможно, было бы лучше решить эту проблему заранее в предварительной обработке очистки данных, где соответствующие элементы получают одинаковые метки.
Блестящие указатели. При применении этого кода к моему кадру данных я получаю следующую ошибку «Ошибка в data.frame(..., check.names = FALSE): аргументы подразумевают разное количество строк: 1, 0 Вызывается из: data.frame(... , check.names = FALSE)" Когда я меняю cbind на bind_cols, я перестаю получать повторяющуюся ошибку, однако код не возвращает вывод для всех строк. Мой эквивалент «df» содержит меньше строк, чем мой эквивалент «df2», а df2 содержит много NA. И df, и df2 являются кадрами данных.
Код @GJW у меня работает, не знаю, в чем причина проблемы, не могу воспроизвести. Возможно, у вас есть таблички вместо фреймов данных, попробуйте изменить их на фреймы данных, как показано в OP.
Извините, я не мог скопировать «мои данные» из-за ограничений по количеству символов, поэтому я снова опубликовал — с исходными данными и кодом. Ошибка заключается где-то в том, как представлены мои данные, в отличие от вашего решения, подробно описанного выше.
Ваше здоровье. В этом подходе используется тот факт, что WATER.START также находится во втором кадре данных, все в частичном нижнем регистре, а WATER.truestart находится с помощью mt + 1. Каким был бы подход, если бы WATER.START в первом кадре данных не смог изменить в простом было, изменив на нижний регистр. Например, WATER.START на самом деле назывался Fluid.on.