Заполните пропущенные значения с помощью линейной регрессии

У меня есть фрейм данных, который содержит 7 столбцов.

 str(df)

'data.frame':   8760 obs. of  7 variables:
 $ G1_d20_2014.SE1_ : num  25.1 25.1 25 25 25.1 ...
 $ G1_d20_2014.SE4_ : num  42.4 42.3 42.3 42.3 42.3 ...
 $ G1_d20_2014.SE7_ : num  34.4 34.4 34.4 34.4 34.4 ...
 $ G1_d20_2014.SE22_: num  42.5 42.4 42.3 42.4 42.3 ...
 $ G1_d20_2014.SE14_: num  52.5 52.5 52.5 52.5 52.4 ...
 $ G1_d20_2014.SE26 : num  40.8 40.8 40.8 40.8 40.8 ...

Каждый столбец представляет уникальный датчик, а столбцы содержат данные измерений от датчиков. Некоторые столбцы содержат пропущенные значения. Я хочу заполнить пробелы в данных в каждом столбце с помощью линейной регрессии. Я уже сделал это вручную, но есть одно очень важное условие, и я ищу функцию, которая делает это самостоятельно, так как это займет слишком много времени для всех столбцов. Вот условие: Допустим, G1_d20_2014_SE1 содержит недостающие данные. Затем я хочу заполнить пробелы в данных от этого датчика полным набором данных от другого датчика с самым высоким коэффициентом корреляции.

Вот как я сделал это вручную:

Я создал функцию, которая создает индикаторную переменную. Переменная-индикатор становится равной 1, если значение не равно NA, и 0, если NA. Затем я добавил эту переменную в качестве столбца в набор данных:

Indvar <- function(t) {

  x <- dim(length(t))
  x[which(!is.na(t))] = 1
  x[which(is.na(t))] = 0 
  return(x)
}

df$I <- Indvar(df$G1_d20_2014.SE1_)

Затем я посмотрел, между каким датчиком и датчиком 1 коэффициент корреляции самый высокий (в этом случае коэффициент корреляции самый высокий между SE1 и SE14). Затем я вычислил линейную регрессию, взял из нее уравнение и поместил его в цикл for, который заполняет значения NA в соответствии с уравнением всякий раз, когда индикаторная переменная равна 0:

lm(df$G1_d20_2014.SE1_ ~ df$G1_d20_2014.SE14_, data = df)

for (i in 1:nrow(df)) {

  if (df$I[i] == 0)

  {

    df$G1_d20_2014.SE1_[i] = 8.037 + 0.315*df$G1_d20_2014.SE14_[i]
  }
}

Это прекрасно работает, но это занимает слишком много времени, потому что у меня много фреймов данных, которые выглядят как тот, что в посте.

Я уже пробовал использовать impute_lm из пакета simputation, но, к сожалению, он, похоже, не заботится о том, где корреляция самая высокая, прежде чем заполнять пробелы в данных. Вот что я написал:

impute_fun <- impute_lm(df, 
    formula = SE1_ + SE4_ ~ SE14_ + SE26)

Как я писал SE14_ + SE26_, я проверил, использует ли он значения из SE14 для вменения значений в SE1, но он этого не делает, так как результат отличается от моего ручного результата.

Есть ли функция, которая делает то, что я хочу? Я очень расстроен, потому что я искал это уже более 2 недель. Я был бы очень признателен за помощь!

ИЗМЕНИТЬ/Ответить на @jay.sf

Итак, я попытался сделать из него функцию (см. Ниже), но есть кое-что, с чем я борюсь:

Я не знаю, как указать в функции, что я хочу сделать это для каждого столбца, и что она удаляет имя того датчика, который я хочу заполнить, из sapply(c("SE1_", "SE2_", . ..) Потому что, очевидно, если я сделаю это для SE1_, а SE1_ все еще находится в коде, корреляция будет равна 1, и ничего не произойдет. Теперь, как вы можете видеть, это также проблематично для остальной части кода, например, в строке cor( df$SE1_, df[, x], use = "complete.obs")), как здесь написано df$SE1_. То же самое для строки df$SE1_imp ‹- .... Конечно, я мог бы просто удалить датчик из кода sapply(...), чтобы не возникало первой проблемы. Мне просто интересно, есть ли более приятный способ сделать это. То же самое для частей df$SE1_, если я хочу присвоить значения для SE2_, тогда мне придется изменить df$SE1_ на df$SE2_ и так далее.

Я попытался запустить такой код (но без SE1_ в sapply(...) конечно) и получил ошибку: Ошибка в df[, x] : неправильное количество измерений. Любые идеи, как решить эти проблемы?

      impFUN <- function(df) {

      corr <- sapply(c("SE1_", "SE2_", "SE4_", "SE5_","SE6_",                      
                      "SE7_", "SE12_", "SE13_","SE14_", "SE15_",
                      "SE16_", "SE22_","SE23", "SE24", "SE25",
                      "SE26",  "SE33", "SE34", "SE35", "SE36",
                      "SE37", "SE46", "SE51", "SE52", "SE53",
                      "SE54", "SE59", "SE60", "SE61", "SE62", 
                      "SE68", "SE69", "SE70", "SE71", "SE72", 
                      "SE73","SE74", "SE82", "SE83", "SE84", 
                      "SE85", "SE86", "SE87", "SE99","SE100", 
                      "SE101", "SE102", "SE103","SE104", 
                      "SE106", "SE107","SE121"),  function(x)
                  cor(df$SE1_, df[, x], use = "complete.obs")) 

      imp.use <- names(which.max(corr)) 

      regr.model <- lm(reformulate(imp.use, "SE1_"))

      df$SE1_imp <- 
          ifelse(is.na(df$SE1_), lm.cf[1] + df[[imp.use]]*lm.cf[2], df$SE1_)

    }

person Phil    schedule 12.05.2020    source источник
comment
Если я правильно понимаю, вы хотите сделать линейную модель для отсутствующих значений в df$G1_d20_2014_ на основе df$G1_d20_2014.SE14, чтобы заполнить отсутствующие значения для df$G1_d20_2014.SE1. Вместо того, чтобы предсказывать каждую отсутствующую точку данных отдельно, почему бы не векторизовать ее? Например, mod <- lm(df$G1_d20_2014.SE1_[df$I==1] ~ df$G1_d20,2014.SE14_[df$I==1]); df$G1_d20_2014.SE1[df$I==0] <- predict(mod, df$G1_d20_2014.SE14[df$I==0])   -  person koenniem    schedule 12.05.2020


Ответы (1)


Как насчет этого? Сначала проверьте, какой датчик больше всего коррелирует с датчиком 1.

corr <- sapply(c("sensor.2", "sensor.3", "sensor.4"), function(x) 
  cor(dat$sensor.1, dat[,x], use="complete.obs"))
#   sensor.2    sensor.3    sensor.4 
# 0.04397132  0.26880412 -0.06487781 

imp.use <- names(which.max(corr))
# [1] "sensor.3"

Рассчитать регрессионную модель,

lm.cf <- lm(reformulate(imp.use, "sensor.1"), dat)$coef

и для импутации датчика 1 используйте коэффициенты в ifelse следующим образом:

dat$sensor.1.imp <- 
  ifelse(is.na(dat$sensor.1), lm.cf[1] + dat[[imp.use]]*lm.cf[2], dat$sensor.1)

Результат

head(dat)
#     sensor.1   sensor.2   sensor.3    sensor.4 sensor.1.imp
# 1  2.0348728 -0.6374294  2.0005714  0.03403394    2.0348728
# 2 -0.8830567 -0.8779942  0.7914632 -0.66143678   -0.8830567
# 3         NA  1.2481243 -0.9897785 -0.36361831   -0.1943438
# 4         NA -0.1162450  0.6672969 -2.84821295    0.2312968
# 5  1.0407590  0.1906306  0.3327787  1.16064011    1.0407590
# 6  0.5817020 -0.6133034  0.5689318  0.71543751    0.5817020

Данные игрушек:

library('MASS')
set.seed(42)
M <- mvrnorm(n=1e2, mu=c(0, 0, 0, 0), 
             Sigma=matrix(c(1, .2, .3, .1,
                            .2, 1, 0, 0, 
                            .3, 0, 1, 0,
                            .1, 0, 0, 1), nrow=4),
             empirical=TRUE)
dat <- as.data.frame(`colnames<-`(M, paste0("sensor.", 1:4)))
dat[sample(1:nrow(dat), 30), "sensor.1"] <- NA  ## generate 30% missings
person jay.sf    schedule 12.05.2020
comment
Это мило. Однако проблема остается в том, что я должен проверить самую высокую корреляцию для каждого отдельного датчика. Как я уже сказал, это не проблема для одного фрейма данных, но у меня есть 74 других фрейма данных, и некоторые из них содержат данные для 48 датчиков, и это занимает слишком много времени, чтобы делать это вручную, как здесь. Интересно, есть ли возможность написать функцию, которая автоматически принимает самую высокую корреляцию для каждого датчика, а затем делает вышеперечисленное самостоятельно. - person Phil; 12.05.2020
comment
Просто оберните его в функцию impFUN <- function(dat) {corr <- ... imp.use <- ...lm.cf <- ... ifelse(...)}, а затем используйте lapply(list(dat1, dat2, ... dat48), impFUN). - person jay.sf; 12.05.2020
comment
Я знаю, что это было некоторое время назад, однако у меня возникла проблема. Поскольку ваше решение использует только датчик с самой высокой корреляцией, чтобы заполнить пробел, проблематично, если у другого датчика есть пробел в данных в том же месте, что и датчик, который я хочу заполнить. Вы знаете, как сделать условие в коде, чтобы он брал датчик со второй по величине корреляцией, если первый не работает, чтобы заполнить пробел, затем третий и так далее...? - person Phil; 22.06.2020
comment
Я знаю, как вычислить второй максимум (см. код ниже), но я не знаю, как реализовать это в коде. Было бы очень приятно, если бы вы могли мне помочь! l = length(corr) и secondmax <- sort(corr, partial = l-1)[l-1] - person Phil; 22.06.2020