Подгонка линейной модели с несколькими LHS

Я новичок в R и хочу улучшить следующий скрипт с *apply функция (я читал о apply, но я не смог его использовать). Я хочу использовать lm функция на нескольких независимых переменных (которые являются столбцами в кадре данных). я использовал

for (i in (1:3) {
  assign(paste0('lm.',names(data[i])), lm(formula=formula(i),data=data))
  } 

Formula(i) определяется как

formula=function(x)
{
  as.formula ( paste(names(data[x]),'~', paste0(names(data[-1:-3]), collapse = '+')), env=parent.frame() )
}

Спасибо.

1 ответ

Решение

Если я не ошибаюсь, вы работаете с таким набором данных:

set.seed(0)
dat <- data.frame(y1 = rnorm(30), y2 = rnorm(30), y3 = rnorm(30),
                  x1 = rnorm(30), x2 = rnorm(30), x3 = rnorm(30))

x1, x2 а также x3 являются ковариатами, и y1, y2, y3 три независимых ответа. Вы пытаетесь подогнать три линейные модели:

y1 ~ x1 + x2 + x3
y2 ~ x1 + x2 + x3
y3 ~ x1 + x2 + x3

В настоящее время вы используете цикл y1, y2, y3примерка одной модели за раз. Вы надеетесь ускорить процесс, заменив for цикл с lapply,

Вы на неправильном пути. lm() это дорогая операция. Пока ваш набор данных не мал, затраты на for Цикл незначительный. Замена for цикл с lapply не дает прироста производительности.

Так как у вас есть тот же RHS (правая сторона ~) для всех трех моделей матрица модели одинакова для трех моделей. Следовательно, QR-факторинг для всех моделей необходимо выполнить только один раз. lm позволяет это, и вы можете использовать:

fit <- lm(cbind(y1, y2, y3) ~ x1 + x2 + x3, data = dat)
#Coefficients:
#             y1         y2         y3       
#(Intercept)  -0.081155   0.042049   0.007261
#x1           -0.037556   0.181407  -0.070109
#x2           -0.334067   0.223742   0.015100
#x3            0.057861  -0.075975  -0.099762

Если вы проверите str(fit)вы увидите, что это не список из трех линейных моделей; вместо этого, это одна линейная модель с одним $qr объект, но с несколькими LHS. Так $coefficients, $residuals а также $fitted.values являются матрицами. Полученная линейная модель имеет дополнительный класс "mlm" помимо обычного класса "lm". Я создал специальный тэг mlm, собрав несколько вопросов по теме, которые обобщены тегом wiki.

Если у вас гораздо больше ковариат, вы можете избежать ввода или вставки формулы, используя .:

fit <- lm(cbind(y1, y2, y3) ~ ., data = dat)
#Coefficients:
#             y1         y2         y3       
#(Intercept)  -0.081155   0.042049   0.007261
#x1           -0.037556   0.181407  -0.070109
#x2           -0.334067   0.223742   0.015100
#x3            0.057861  -0.075975  -0.099762

Внимание: не пишите

y1 + y2 + y3 ~ x1 + x2 + x3

Это будет относиться y = y1 + y2 + y3 в качестве одного ответа. использование cbind(),


Следовать за:

Я заинтересован в обобщении. У меня есть фрейм данных dfгде первый n столбцы являются зависимыми переменными (y1,y2,y3,....) и следующий m столбцы являются независимыми переменными (x1+x2+x3+....), За n = 3 а также m = 3 это fit <- lm(cbind(y1, y2, y3) ~ ., data = dat)), Но как сделать это автоматически, используя структуру df, Я имею в виду что-то вроде (for i in (1:n)) fit <- lm(cbind(df[something] ~ df[something], data = dat)), Это "что-то" я создал это с paste а также paste0, Спасибо.

Таким образом, вы программируете свою формулу или хотите динамически генерировать / создавать формулы модели в цикле. Есть много способов сделать это, и многие вопросы переполнения стека об этом. Обычно есть два подхода:

  1. использованиеreformulate;
  2. использование paste / paste0 а также formula / as.formula,

я предпочитаю reformulate однако из-за аккуратности он не поддерживает несколько формул LHS в формуле. Это также требует особого отношения, если вы хотите трансформировать LHS. Так что в следующем я бы использовал paste решение.

Для вас фрейм данных df, вы можете сделать

paste0("cbind(", paste(names(df)[1:n], collapse = ", "), ")", " ~ .")

Более привлекательный способ - использовать sprintf а также toString построить LHS:

sprintf("cbind(%s) ~ .", toString(names(df)[1:n]))

Вот пример использования iris Набор данных:

string_formula <- sprintf("cbind(%s) ~ .", toString(names(iris)[1:2]))
# "cbind(Sepal.Length, Sepal.Width) ~ ."

Вы можете передать эту формулу строки lm, как lm автоматически приведёт его в класс формулы. Или вы можете сделать принуждение самостоятельно, используя formula (или же as.formula):

formula(string_formula)
# cbind(Sepal.Length, Sepal.Width) ~ .

Примечание:

Эта множественная формула LHS также поддерживается в другом месте в ядре R:

Другие вопросы по тегам