2014-02-14 5 views
2

возможно ли провести линейную регрессию для каждой отдельной строки кадра без использования цикла? Результат (перехват + наклон) линии тренда должен быть добавлен в исходный кадр данных в виде новых столбцов.Вычисление линейной линии тренда для каждой строки таблицы в R

Чтобы сделать свое намерение более четко, я подготовил очень небольшой пример данных:

day1 <- c(1,3,1) 
day2 <- c(2,2,1) 
day3 <- c(3,1,5) 
output.intercept <- c(0,4,-1.66667) 
output.slope <- c(1,-1,2) 
data <- data.frame(day1,day2,day3,output.intercept,output.slope) 

входные переменные day1-3; скажем, это продажи для разных магазинов в течение 3 дней подряд. То, что я хочу сделать, - вычислить линейную линию тренда для трех строк и добавить выходные параметры в таблицу начала (см. Output.intercept + output.slope) в качестве новых столбцов.

Решение должно быть очень эффективным с точки зрения времени вычисления, так как реальный кадр данных имеет много строк в 100 тыс. Строк.

Бест, Christoph

+0

Какова переменная ответа? –

+0

@SvenHohenstein. Ответы показывают, что ковариат подразумевается как '1: 3' (в данном случае),' seq_len (nrow (dat)) 'в более общем случае. –

ответ

3
design.mat <- cbind(1,1:3) 
response.mat <- t(data[,1:3]) 

reg <- lm.fit(design.mat, response.mat)$coefficients 
data <- cbind(data, t(reg)) 
# day1 day2 day3 output.intercept output.slope  x1 x2 
#1 1 2 3   0.00000   1 0.000000 1 
#2 3 2 1   4.00000   -1 4.000000 -1 
#3 1 1 5   -1.66667   2 -1.666667 2 

Однако, если у вас есть большие массивы данных, может возникнуть необходимость в цикле из-за ограничений памяти. Если это так, я бы использовал таблицу данных long format.table и использовал синтаксис by пакета для цикла.

+0

Woow, работает отлично. Thx много! Я попробую позже с большим набором данных. Что такое exaccty «design.mat» для? Чтобы имитировать значения x? – user2635656

+0

Если вы не знаете, что такое матрица дизайна, вы должны изучить учебник по регрессии. – Roland

+0

+1 - Я должен перестать быть таким длинным :-) –

1

Используя данные,

day1 <- c(1,3,1) 
day2 <- c(2,2,1) 
day3 <- c(3,1,5) 
output.intercept <- c(0,4,-1.66667) 
output.slope <- c(1,-1,2) 
dat <- data.frame(day1,day2,day3) 

Я думаю, что вы хотите что-то вроде этого:

fits <- lm.fit(cbind(1, seq_len(nrow(dat))), t(dat)) 
t(coef(fits)) 

Который дает

R> t(coef(fits)) 
     x1 x2 
[1,] 0.000 1 
[2,] 4.000 -1 
[3,] -1.667 2 

Они могут быть добавлены к dat как так

dat <- cbind(dat, t(coef(fits))) 
names(dat)[-(1:3)] <- c("Intercept","Slope") 

R> dat 
    day1 day2 day3 Intercept Slope 
1 1 2 3  0.000  1 
2 3 2 1  4.000 -1 
3 1 1 5 -1.667  2 

Возможно, было бы проще хранить данные другим способом, причем столбцы как временные ряды, а не строки, если у вас есть какой-либо контроль над тем, как данные сначала упорядочиваются, поскольку это позволит избежать переноса большой матрицы при установке через lm.fit(). В идеале вы хотите, чтобы данные были расположены так, как это первоначально:

 [,1] [,2] [,3] 
day1 1 3 1 
day2 2 2 1 
day3 3 1 5 

I.e. строки как временные точки, а не отдельные серии, как вы их сейчас. Это связано с тем, как R ожидает, что данные будут организованы. Обратите внимание, что мы должны транспонировать ваш dat в вызове lm.fit(), который повлечет за собой копию большого объекта. Следовательно, если вы можете контролировать, как эти данные упорядочены/поставлены до того, как они попадут в R, это поможет решить большую проблему.

lm.fit() Используется как точный код, используемый lm(), но мы избегаем сложностей разбора формулы и создания матриц модели. Если вам нужна более эффективная работа, вам, возможно, придется попробовать сделать QR-декомпозицию самостоятельно (код находится в lm.fit(), чтобы сделать это), поскольку есть несколько вещей, которые lm.fit() делает как проверки на работоспособность, с которыми вы могли бы справиться, если вы определенные ваши данные не приведут к сингулярным матрицам и т. д.

+0

спасибо. Я понимаю, что я все еще очень люблю учиться в R, даже в основных вещах. И благодарю вас за намек на структуру данных. У меня есть контроль над компоновкой данных, поскольку я заранее подготовил предварительную подготовку данных в R. Я думал, что я буду более эффективным таким образом, так как мой настоящий файл данных содержит 600 тыс. Строк и всего 100 столбцов. – user2635656

+0

Одно замечание: Я предполагаю, что выражение «fits <- lm.fit (cbind (1, seq_len (nrow (dat))), t (dat))« должно быть отрегулировано на «fits <- lm.fit (cbind (1) , seq_len (ncol (dat))), t (dat)) ". Или я ошибаюсь? Он работал в примере, потому что ncol (dat) = nrow (dat). – user2635656

0

Или вот так?

day1 <- c(1,3,1) 
day2 <- c(2,2,1) 
day3 <- c(3,1,5) 
data <- data.frame(day1,day2,day3) 
y<-1:3 

reg<-apply(data,1,function(x) lm(as.numeric(x)~y)) 
data[,c("intercept","slope")]<-rbind(reg[[1]]$coef,reg[[2]]$coef,reg[[3]]$coef) 
+0

Это правильно, но не эффективно. Обратите внимание, что 'lm()' должен анализировать формулу 'nrow (dat)' раз, что быстро, если вы делаете 3 раза, медленно, если вы делаете это в 100K раз. Кроме того, это пропускает функцию 'lm()' в том смысле, что принимает матричный ответ. Поэтому вам вообще не нужен 'apply()' или loop здесь; вы можете поместить все серии в один вызов 'lm()': lm (t (data [, 1: 3]) ~ I (1: 3)). Однако вы не хотите анализировать формулу и генерировать model.frame и model.matrix плюс все дополнительные guff 'lm()' дает вам, если вы хотите быть эффективными. Используйте 'lm.fit()' для этого для улучшения. –

1

У меня была такая же проблема, как и у ОП.Это решение будет работать с данными с NA. Все предыдущие ответы генерируют ошибку для меня в этом случае:

slp = function(x) { 
    y = t(x) 
    y = y[!is.na(y)] 
    len = length(y):1 
    b = cov(y,len)/var(len) 
    return(b)} 

reg_slp <- apply(data,1,slp) 

только получает по склону, но перехватывать может быть легко добавлены. Я сомневаюсь, что это особенно эффективно, но это было эффективно в моем случае.