[英]R: How do you loop an linear model over a list of data frames?
我有一个名为AllFramesCoeff
的数据帧列表。 我想生成一个随机数,让我的数据帧列表引用该数字以引用一个随机数据帧,并对带有lm
模型的两个特定列在列表中的185个数据帧之一上使用for循环。 我希望它执行1000次随机测试。
我还想将lm系数结果放在一个对象中,可能是一个向量。
我的计划是稍后返回并创建直方图,分布,也许还可以插入新的列以重复进行。
我尝试过的
m <- matrix(0, ncol = 2)
CorrResults<- as.data.frame(m)
for (i in length(WaFramesCoeff)) function() {
r <- sample(185, 1)
CorrLM <-lm( WaFramesCoeff[i]$ `Nights_&_Weekends_Min_Used` ~ WaFramesCoeff[i]$ `Taxes,_Surcharges_and_Fees` ,data=WaFramesCoeff[i] )
CorrResults[i,]<- CorrLM$Coeff
}
接着:
m <- matrix(0, ncol = 2)
CorrResults<- as.data.frame(m)
for (i in length(WaFramesCoeff)) {
r <- sample(185, 1)
function(x){
CorrLM <-lm( x$ `Nights_&_Weekends_Min_Used` ~ x$ `Taxes,_Surcharges_and_Fees` ,data=x )
}
CorrResults[i,]<- CorrLM$Coeff
}
我知道这个网站更喜欢可复制的数据,因此我对此表示歉意。 我和一个同伴无法弄清楚。 我敢肯定这很明显,但是我已经用光了我所有的知识。
编辑 :
我走近了。 但是每1000个中只有一个显示出拦截。 另外,绘图仅显示了一个点,因此我显然没有正确执行此操作。
CorrResults <- matrix(0, 1,1000)
for (i in 1:1000) {
d <- sample(WaFramesAll,1)
w <- sapply( d, TestLM )
CorrResults[i]<- w
}
让我们通过一种不同的方式来想象做这种事情。
首先,要知道for
循环是有其for
,正确完成后,它们可以和*apply
函数一样快。 尽管您在语法上对循环的使用是正确的,但是使用循环的其他方式可能更有意义。 您试图在列表的多个元素上运行一系列命令或函数。 想象一下这个简单的计划:对于列表中的每个元素,取第一个元素,然后将其加倍并平方:
invec <- list(c(21,22),c(23,24),c(25,26))
str(invec)
# List of 3
# $ : num [1:2] 21 22
# $ : num [1:2] 23 24
# $ : num [1:2] 25 26
outvec <- replicate(length(invec), NULL) # preallocate same size
for (i in seq_along(invec)) {
outvec[[i]] <- c(2*invec[[i]][1], invec[[i]][1]^2)
}
str(outvec)
# List of 3
# $ : num [1:2] 42 441
# $ : num [1:2] 46 529
# $ : num [1:2] 50 625
似乎很简单。 现在,让我们看看如何使用*apply
函数执行相同的操作:
invec <- list(c(21,22),c(23,24),c(25,26))
outvec <- lapply(invec, function(a) c(2*a[1], a[1]^2))
str(outvec)
# List of 3
# $ : num [1:2] 42 441
# $ : num [1:2] 46 529
# $ : num [1:2] 50 625
读取apply函数的方法是“获取向量invec
,并在每个元素上调用此函数,将结果捕获到列表名称中outvec
” 。 该函数可以是“匿名”(如此处所示),也可以是“命名”函数,例如
lapply(invec, max)
# [[1]]
# [1] 22
#
# [[2]]
# [1] 24
#
# [[3]]
# [1] 26
那么,这如何解决您的抽样问题呢? 让我再发散一下。
您是否知道可以对向量进行索引并任意列出? 例如:
str(invec[c(1,3,2,3,2,3)])
# List of 6
# $ : num [1:2] 21 22
# $ : num [1:2] 25 26
# $ : num [1:2] 23 24
# $ : num [1:2] 25 26
# $ : num [1:2] 23 24
# $ : num [1:2] 25 26
有骗子,好吧。 假设我们要从这个非常短的列表中获取1000个随机样本:
set.seed(3)
ind <- sample(length(invec), size=1000, replace=TRUE)
str(outvec[1:4])
# List of 4
# $ : num 42
# $ : num 46
# $ : num 50
# $ : num 46
outvec <- lapply(invec[ind], function(a) 2*a[1])
str(outvec[1:4])
# List of 4
# $ : num 42
# $ : num 50
# $ : num 46
# $ : num 42
好的,我们已经对原始列表进行了1000次采样并对其进行了处理( 2*a[1]
),并存储了结果。
因此,将其应用于您的方案。 由于您的数据是看不见的,所以我来弥补。
set.seed(2)
n <- 20
lst <- lapply(1:185, function(ign) data.frame(x=sample(100,size=n), y=sample(100,size=n)))
str(lst[1:2])
# List of 2
# $ :'data.frame': 20 obs. of 2 variables:
# ..$ x: int [1:20] 19 70 57 17 91 90 13 78 44 51 ...
# ..$ y: int [1:20] 67 39 83 15 34 47 97 96 89 13 ...
# $ :'data.frame': 20 obs. of 2 variables:
# ..$ x: int [1:20] 99 30 12 16 91 76 92 33 47 74 ...
# ..$ y: int [1:20] 78 88 62 26 83 42 37 43 21 7 ...
现在,我有了185个data.frames的列表,每个都有相同的两个变量x
和y
。 让我们将您的问题应用于此数据。 哦,随机性可能很耗时。 (顺便说一句:一次获得1000个随机数,然后再获得1000次随机数, 则要快得多。)
ind <- sample(185, size=1000, replace=TRUE)
现在, lst[ind]
将是一个列表,长1000个元素,每个元素都是从原始列表中随机选择的。
lms <- lapply(lst[ind], function(a) lm(y~x, data=a))
( lm
部分可以是您需要的任何东西,只要它是应用于所有元素的相同回归即可。函数中的代码可以根据您的需要而定,因此也许可以这样考虑:
lms <- lapply(lst[ind], function(a) {
z <- lm(y~x, data=a)
return(z)
})
这有意义吗?)好的,让我们看一些输出:
summary(lms[[1]])
# Call:
# lm(formula = y ~ x, data = a)
# Residuals:
# Min 1Q Median 3Q Max
# -53.944 -13.463 -1.239 15.473 44.430
# Coefficients:
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) 80.4523 15.3577 5.239 5.56e-05 ***
# x -0.4217 0.2499 -1.687 0.109
# ---
# Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Residual standard error: 25.23 on 18 degrees of freedom
# Multiple R-squared: 0.1366, Adjusted R-squared: 0.0886
# F-statistic: 2.847 on 1 and 18 DF, p-value: 0.1088
summary(lms[[2]])
# Call:
# lm(formula = y ~ x, data = a)
# Residuals:
# Min 1Q Median 3Q Max
# -55.108 -20.653 -0.465 18.827 42.747
# Coefficients:
# Estimate Std. Error t value Pr(>|t|)
# (Intercept) 60.7651 12.2366 4.966 1e-04 ***
# x -0.1898 0.2060 -0.922 0.369
# ---
# Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# Residual standard error: 27.37 on 18 degrees of freedom
# Multiple R-squared: 0.04506, Adjusted R-squared: -0.007996
# F-statistic: 0.8493 on 1 and 18 DF, p-value: 0.3689
“但是我不需要整个模型,我只需要系数!” 当然,您是对的。 当您知道只需要一件事时,您显然可以coef(lm(y~x,data=a))
并直接获取(例如coef(lm(y~x,data=a))
)。 因此,代替我重新运行随机样本的1000个回归,我可以执行另一个lapply
:
coefs <- lapply(lms[1:3], coef)
str(coefs[1:3])
# List of 3
# $ : Named num [1:2] 80.452 -0.422
# ..- attr(*, "names")= chr [1:2] "(Intercept)" "x"
# $ : Named num [1:2] 60.77 -0.19
# ..- attr(*, "names")= chr [1:2] "(Intercept)" "x"
# $ : Named num [1:2] 53.716 -0.189
# ..- attr(*, "names")= chr [1:2] "(Intercept)" "x"
在这种情况下,我实际上有两个选择。 我可以坚持使用,然后将它们“ rbind”(行绑定)在一起,
head(do.call(rbind, coefs))
# (Intercept) x
# [1,] 80.45230 -0.42173749
# [2,] 60.76507 -0.18979726
# [3,] 53.71643 -0.18883933
# [4,] 49.51803 0.01494021
# [5,] 49.51803 0.01494021
# [6,] 68.25463 -0.25840920
或者,我可能早先使用了“简单应用”(可选,但默认是),将结果简化为矩阵或向量。 如果任何返回值的大小与其他值不同,它将始终返回一个列表。 (因此,从程序上讲,不简化它,进行一些健全性检查然后重新整理它们也许是更合理的选择。)
coefs2 <- t(sapply(lms, coef))
head(coefs2)
# (Intercept) x
# [1,] 80.45230 -0.42173749
# [2,] 60.76507 -0.18979726
# [3,] 53.71643 -0.18883933
# [4,] 49.51803 0.01494021
# [5,] 49.51803 0.01494021
# [6,] 68.25463 -0.25840920
请注意,我不得不t
ranspose输出:这是一个有点古怪和反直觉的,输出(无t(...)
将有2 排 (每个回归系数)和1000 列 。 因此我们将其转置,因为我自然将其视为每模型行。 如果可以将其作为每个模型的列进行处理,则不需要这样做。
因此,最重要的是, for
循环本质上在语法上并不是错误的,但是如果您考虑以这种方式对一个向量/许多事物列表执行一件事情,那么您将获得显着的速度改进(在这种情况下),并且可以说一次您了解它,可读性强得多的代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.