是否有可能在不使用循环的情况下对数据帧的每一行进行线性回归?趋势线的输出(截距+斜率)应作为新列添加到原始数据框中。
为了更清楚地表达我的意图,我准备了一个非常小的数据示例:
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)
输入变量是第1-3天;让我们说这些是连续3天不同商店的销售额。我想要做的是计算3行的线性趋势线,并将输出参数添加到原始表(请参阅output.intercept + output.slope)作为新列。
解决方案在计算时间方面非常有效,因为实际数据帧有100k行。
Best,Christoph
答案 0 :(得分: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
但是,如果您有大量数据,可能需要循环由于内存限制。如果是这种情况,我将使用长格式data.table并使用包的by
语法循环。
答案 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
即。行作为时间点而不是现在拥有的单个系列。这是因为R期望数据的排列方式。请注意,我们必须在dat
调用中转置lm.fit()
,这将需要一个大对象的副本。因此,如果您可以控制这些数据在进入R之前如何排列/提供,那将有助于解决大问题。
lm.fit()
,因为它是lm()
使用的基础精益代码,但我们避免了解析公式和创建模型矩阵的复杂性。如果你想要更高效,你可能不得不亲自去做QR分解(代码在lm.fit()
来做这个)因为lm.fit()
做了一些事情,因为理智检查你可能是如果您确定您的数据不会导致单个矩阵等,则可以取消。
答案 2 :(得分:1)
我和OP有同样的问题。该解决方案将与具有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)
只能获得斜率,但可以轻松添加拦截。我怀疑这是特别有效的,但它在我的情况下是有效的。
答案 3 :(得分: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)