#r #dplyr
Вопрос:
У меня есть кое-какие данные:
данные
structure(list(WBC_BASELINE = c(2.9, NA, NA, 6.9, NA, NA, NA, NA, NA, NA, 7.4, 12.8, NA, NA, NA, NA, NA, 4.2, NA, NA), WBC_FIRST = c(2.4, 14.8, 11, 7.3, 4.5, NA, NA, 6.1, 7.7, 16.2, 5.3, 10.3, 14.5, NA, NA, 12.8, 3.7, 4.7, 16.6, 9.3), neuts_BASELINE = c(2, NA, NA, 5.4, NA, NA, NA, NA, NA, NA, 4.96, 8.9, NA, NA, NA, NA, NA, NA, NA, NA), neuts_FIRST = c(1.5, 13, 5.8, 4.5, 1.6, NA, NA, 1.7, 4.3, 9.3, 3.4, 5.8, 10.1, NA, NA, 9.7, 2.3, 3.5, 5, 8.2)), row.names = c(NA, 20L), class = "data.frame")
В наборе данных у меня есть некоторые результаты анализа крови (в данном случае WBC и neuts взяты в 2 временных точках — исходная и первая). Я хочу выбрать базовое значение, если оно существует, иначе возьмите первое значение.
Я могу сделать это отдельно для WBC и neuts, но я хочу сделать это для 20 различных анализов крови без жесткого кодирования каждый раз…
Жесткий способ кодирования:
data %gt;% mutate(WBC_first_value=ifelse(!is.na(WBC_BASELINE), WBC_BASELINE, WBC_FIRST)) %gt;% mutate(neuts_first_value=ifelse(!is.na(neuts_BASELINE), neuts_BASELINE, neuts_FIRST))
Пожалуйста, обратите внимание, что за каждым анализом крови всегда следует _BASELINE
и _FIRST
Я был бы благодарен за любую помощь, пожалуйста!
Ответ №1:
Мы могли бы автоматизировать этот процесс с помощью некоторой обработки данных с использованием pivot_longer
и pivot_wider
в сочетании:
library(dplyr) library(tidyr) data %gt;% mutate(rn = row_number()) %gt;% pivot_longer(cols = -rn, names_to = c('grp', '.value'), names_sep = "_") %gt;% group_by(grp) %gt;% transmute(rn, new = coalesce(BASELINE, FIRST)) %gt;% pivot_wider(names_from = grp, values_from = new) %gt;% select(-rn) %gt;% bind_cols(data, .)
выход:
WBC_BASELINE WBC_FIRST neuts_BASELINE neuts_FIRST WBC neuts 1 2.9 2.4 2.00 1.5 2.9 2.00 2 NA 14.8 NA 13.0 14.8 13.00 3 NA 11.0 NA 5.8 11.0 5.80 4 6.9 7.3 5.40 4.5 6.9 5.40 5 NA 4.5 NA 1.6 4.5 1.60 6 NA NA NA NA NA NA 7 NA NA NA NA NA NA 8 NA 6.1 NA 1.7 6.1 1.70 9 NA 7.7 NA 4.3 7.7 4.30 10 NA 16.2 NA 9.3 16.2 9.30 11 7.4 5.3 4.96 3.4 7.4 4.96 12 12.8 10.3 8.90 5.8 12.8 8.90 13 NA 14.5 NA 10.1 14.5 10.10 14 NA NA NA NA NA NA 15 NA NA NA NA NA NA 16 NA 12.8 NA 9.7 12.8 9.70 17 NA 3.7 NA 2.3 3.7 2.30 18 4.2 4.7 NA 3.5 4.2 3.50 19 NA 16.6 NA 5.0 16.6 5.00 20 NA 9.3 NA 8.2 9.3 8.20
Комментарии:
1. спасибо, я получаю ошибку — я пробовал
distinct()
, и это не исправляет ее… 1: Ожидается 2 штуки. Дополнительные фигуры отбрасываются в 2 ряда [20, 47]. 2: Значения не идентифицируются однозначно; выходные данные будут содержать столбцы списка. * Используйтеvalues_fn = list
для подавления этого предупреждения. * Используетсяvalues_fn = length
для определения места возникновения дубликатов * Используетсяvalues_fn = {summary_fun}
для обобщения дубликатов2. С предоставленной базой данных он должен работать, как показано здесь. Если ваш исходный набор данных отличается, возможно, вы можете предоставить исходный кадр данных.?
3. Кажется, я все исправил. Я использовал столбец идентификатора, а также, как я думаю, были не уникальные значения. Спасибо за вашу помощь!
Ответ №2:
Вы могли бы сделать это с помощью петли!
vars lt;- c("WBC", "neuts") for(v in vars){ df[,paste0(v, "_new")] lt;- ifelse(!is.na(df[,paste0(v, "_BASELINE")]), df[,paste0(v, "_BASELINE")], df[,paste0(v, "_FIRST")]) }
Или с sapply
:
sapply(vars, function(v) ifelse(!is.na(df[,paste0(v, "_BASELINE")]),df[,paste0(v, "_BASELINE")], df[,paste0(v, "_FIRST")]))
Также можно определить vars программно:
vars lt;- unique(gsub(pattern = "^([A-Za-z] )_[A-Za-z] ", "\1", names(df)))