Проблема
Я работаю над таблицей данных, где каждая строка представляет собой медицинское наблюдение. Проблема в том, что в моих данных есть некоторые ошибки, и мне нужно исправить их, прежде чем приступить к анализу. Например, пациент мужского пола может иметь наблюдение, где он закодирован как женщина.
Решение
Мое решение заключается в выборе пациентом режима (наиболее частого значения) переменной. Если у пациента 10 наблюдений в качестве мужчины и одно в качестве женщины, можно с уверенностью предположить, что он является мужчиной.
Я нашел этот умный способ сделать это с помощью data.table.
DATA[j = .N,
by = .(ID, SEX)][i = base::order(-N),
j = .(SEX = SEX[1L]),
keyby = ID]
Проблема в том, что когда у пациента несколько режимов, он просто сохраняет один. Таким образом, пациент, который на 50% является мужчиной и 50% женщин, будет считаться мужчиной, что в итоге приведет к смещению. Я хотел бы закодировать их как NA.
Единственный способ исправить это, которое я основал, это использовать dplyr
DATA[j = .N,
by = .(ID, SEX)] %>%
group_by(ID) %>%
filter(N == max(N))
, а затем заменить значение SEX на NA при дублировании. Но это занимает намного больше времени, чем data.table, он не очень оптимизирован, и у меня есть большой набор данных с большим количеством переменных, которые также необходимо исправить.
Resume
Как взять режим переменной у пациента и заменить его на NA, если он не уникален?
Пример
ID <- c(rep(x = "1", 6), rep(x = "2", 6))
SEX <- c("M","M","M","M","F","M","M","F","M","F","F","M")
require(data.table)
DATA <- data.table(ID, SEX)
# First method (doesn't work)
DATA[j = .N,
by = .(ID, SEX)][i = base::order(-N),
j = .(SEX = SEX[1L]),
keyby = ID]
# Second method (work with dplyr)
require(dplyr)
DATA[j = .N,
by = .(ID, SEX)] %>%
group_by(ID) %>%
filter(N == max(N)) %>%
mutate(SEX = if_else(condition = duplicated(ID) == TRUE,
true = "NA",
false = SEX)) %>%
filter(row_number() == n())
# Applied to my data it took 84.288 seconds
Обновление
Решение, предложенное @Cole basedпо идее @Sindri_baldur:
DATA <- data.table(
ID = c(rep(x = "1", 6), rep(x = "2", 6)),
SEX = c("M","M","M","M","F","M","M","F","M","F","F",NA),
V1 = c("a", NA, "a", "a", "b", "a", "b", "b", "b", "c", "b", "c")
)
our_mode_fac <- function(x) {
freq <- tabulate(x)
if (length(freq) == 0 || sum(freq == max(freq)) > 1 ) {NA}
else {levels(x)[which.max(freq)]}
}
vars <- c("SEX", "V1")
DATA[j = paste0(vars) := lapply(.SD, as.factor),
.SDcols = vars][j = vars := lapply(.SD, our_mode_fac),
.SDcols = vars,
by = ID]
Работает отлично. Он взял режим, даже когда имеется больше NA, чем факторов, и заменил значения на NA, когда существует более 1 режима.
Теперь он также очень быстрый: 11 секунд для наблюдений 3M + и пациентов 1M + (117секунд с ответом @Sindri_baldur). Большое спасибо вам обоим, я очень благодарен!