R 拆分并运行线性回归-使用data.table
我问了前面的一个问题(),使用tidyverse和pipes提供了一个很好的解决方案。我正在为数据中的4000个“键”保存参数的p值,将它们放在单独的数据框中,然后运行一些直方图和其他视觉效果来检查4000个键中每个键的参数的重要性。在我运行它的前几次,这是有效的,但是在不同的参数/预测值上运行完全相同的代码,我不断收到一个错误,说:R 拆分并运行线性回归-使用data.table,r,data.table,regression,R,Data.table,Regression,我问了前面的一个问题(),使用tidyverse和pipes提供了一个很好的解决方案。我正在为数据中的4000个“键”保存参数的p值,将它们放在单独的数据框中,然后运行一些直方图和其他视觉效果来检查4000个键中每个键的参数的重要性。在我运行它的前几次,这是有效的,但是在不同的参数/预测值上运行完全相同的代码,我不断收到一个错误,说: 汇总错误(lm(y1~x1+x2))$系数['x1',:下标超出范围 如果我在该键上运行单个模型并查看摘要,那么pvalue肯定存在于[x1,4]或[2,4]位置
汇总错误(lm(y1~x1+x2))$系数['x1',:下标超出范围
如果我在该键上运行单个模型并查看摘要,那么pvalue肯定存在于[x1,4]
或[2,4]
位置,但它不会返回到模型中。有时它会运行,但随后会在[3,4]
或[4,4]
位置爆炸,等等
有人认为tidyverse正在杀死内存,从而将其炸飞。我知道这不是代码,因为它有时会工作,有时会比其他时间进步得更快,但这似乎很奇怪。因此,data.table
是循环整个数据集的更好解决方案吗?我不熟悉如何将它们链接在一起data.table
,那么如何使用data.table
在我拥有的4000个键中的每一个键上运行一个模型,并使用我拥有的10个以上的参数重新创建以下代码
df
Key y1 x1 x2
A 10 1 3
A 11 2 4
A 12 3 5
B 13 4 6
B 14 5 7
B 15 6 8
C 16 7 9
C 17 8 1
C 18 9 2
df %>% group_by(Key) %>%
summarise(Intercept = lm(y1 ~ x1 + x2)$coefficients[1],
Coeff_x1 = lm(y1 ~ x1 + x2)$coefficients[2],
Coeff_x2 = lm(y1 ~ x1 + x2)$coefficients[3],
R2 = summary(lm(y1 ~ x1 + x2))$r.squared,
pvalue = summary(lm(y1 ~ x1 + x2))$coefficients["x1",4])
# A tibble: 3 x 6
Key Intercept Coeff_x1 Coeff_x2 R2 pvalue
<chr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 A 9. 1.00 NA 1 8.00e-16
2 B 9. 1.00 NA 1 7.00e-16
3 C 9. 1.00 7.86e-16 1 NaN
df
图例y1 x1 x2
A 1013
A 112 4
A 1235
B 13 4 6
B 14 5 7
B 15 6 8
C 16 7 9
C 17 8 1
C 18 9 2
df%%>%分组依据(键)%%>%
总结(截距=lm(y1~x1+x2)$系数[1],
Coeff_x1=lm(y1~x1+x2)$系数[2],
Coeff_x2=lm(y1~x1+x2)$系数[3],
R2=汇总(lm(y1~x1+x2))$r.平方,
pvalue=汇总(lm(y1~x1+x2))$系数[“x1”,4])
#一个tibble:3x6
键截距系数x1系数x2 R2 pvalue
1 A 9.1.00 NA 18.00e-16
2 B 9.1.00 NA 17.00e-16
3 C 9.1.00 7.86e-16 1 NaN
使用开发版本的dplyr
(即将在CRAN上发布为1.0版),您可以执行以下操作:
# devtools::install_github("tidyverse/dplyr")
library(tidyverse)
res = df %>%
nest_by(Key) %>%
mutate(model=list(lm(y1 ~ x1 + x2, data=data)))
res %>%
summarise(broom::tidy(model))
键r.squared p.value`(截距)`x1 x2
1A 18.00e-16 9.1.00NA
2B17.00e-169.1.00NA
3 C 1 NaN 9.1.00 7.86e-16
我在100000行数据帧上运行了上面的代码,其中包含4000个级别的
键
,在2018年的Macbook Pro上没有遇到任何内存问题。我做了一个小测试,将OP的当前方法与Lappy
+data.table方法进行了比较。在1000行数据上执行了1000次操作。table
具有26个唯一键(keycol
):
这两种方法的执行时间有很大的差距,lappy
方法在这个测试中更快
注意:我无法测试tidyverse
的开发版本,该版本具有nest\u by
功能(我的MacOS安装中存在Xcode问题)但是,由于OP的数据集有4000个键,因此也值得在测试中包含这些键。这是一种相对直接的方法,它将中间结果(例如,lm(…)
和summary(lm(…)
分配给临时变量:
dt[, {LM = lm(y1 ~ x1 + x2, data = .SD)
LM.summary = summary(LM)
list(Intercept = LM$coefficients[1],
Coeff_x1 = LM$coefficients[2],
Coeff_x2 = LM$coefficients[3],
R2 = LM.summary$r.squared,
pvalue.x1 = LM.summary$coefficients["x1", 4],
pvalue.x2 = LM.summary$coefficients["x2", 4])
},
by = Key]
{}
允许创建中间对象,然后我们只返回一个实际需要的列表
数据:
library(data.table)
dt = fread('Key y1 x1 x2
A 10 1 3
A 11 2 4
A 12 3 5
A 13 4 5
B 13 4 6
B 14 5 7
B 15 6 8
B 15 5 9
C 16 7 9
C 17 8 1
C 18 9 2
C 18 9 2')
您可以使用lappy
循环key
的唯一值,并让函数返回一个data.frame
和所需的系数,这是前一篇文章中的建议,但我得到一个错误错误:无法分配大小为XX.x Mb的向量
,因此我认为我的机器可能太弱,即使对于t、 …这太疯狂了,因为18个月前它还是相当高端的…好吧,让我测试一下。我在[.tbl_df(dat,{:未使用的参数(by=Key))中得到一个错误error
我需要做些什么来初始化data.table?我假设dt
是您正在引用的数据帧?我使用了fread
直接将您的表作为data.table
读取。您需要添加库(data.table);setDT(dt)
你的代码哇,它运行得非常快。非常感谢你的建议。但是,当我再添加一行来获取x2的pvalue时,它告诉我它超出了范围。即使我尝试说pvalue=LM.summary$coverties[3,4])
它说它超出了范围。但是,如果我运行pvalue=LM.summary$coverties[2,4])
它将正确地创建一个重复的my pValue列(与'x1'相比)。我不明白为什么除了截距和第一个参数之外,我无法从线性模型摘要中提取任何其他的PV值?我认为这与每个分组只有3个记录这一事实有关,并且拟合是完美的。请参见摘要(lm(y1~x1+x2,数据=列表(y1=10:12,x1=1:3,x2=3:5)))$conferences
-它也只提供两个系数。
Key r.squared adj.r.squared sigma statistic p.value df logLik AIC BIC deviance df.residual
<fct> <dbl> <dbl> <dbl> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <dbl> <int>
1 A 1 1 1.78e-15 6.34e29 8.00e-16 2 99.3 -193. -195. 3.16e-30 1
2 B 1 1 1.55e-15 8.28e29 7.00e-16 2 99.7 -193. -196. 2.42e-30 1
3 C 1 NaN NaN NaN NaN 3 Inf -Inf -Inf 0. 0
library(broom)
res %>%
summarise(tidy(model), glance(model)) %>%
select(Key, term, estimate, r.squared, p.value) %>%
pivot_wider(names_from=term, values_from=estimate)
Key r.squared p.value `(Intercept)` x1 x2
<fct> <dbl> <dbl> <dbl> <dbl> <dbl>
1 A 1 8.00e-16 9. 1.00 NA
2 B 1 7.00e-16 9. 1.00 NA
3 C 1 NaN 9. 1.00 7.86e-16
set.seed(28)
dat <- data.table(keycol = sample(x = LETTERS, size = 1000, replace = T),
x = rnorm(n = 1000, mean = 30, sd = 2),
y = rnorm(n = 1000, mean = 20, sd = 2),
z = rnorm(n = 1000, mean = 10, sd = 2))
speed_test <- benchmark(
'data_table' = {
model_list <- lapply(X = 1:26, function(z){ #X could be the unique keys or the 1:length(unique(keys))
m <- lm(data = dat[keycol == LETTERS[z], ], formula = x ~ y + z)
smry <- summary(m)
ret_tbl <- data.table(intercept = smry$coefficients[1],
coef_y = smry$coefficients[2],
coef_z = smry$coefficients[3],
r_squared = smry$adj.r.squared,
pvale = smry$coefficients[2,4],
keycol = z)
return(ret_tbl)
})
desired_tbl <- rbindlist(l = model_list, use.names = T, fill = T)
},
'tidyverse1' = {
dat %>% group_by(keycol) %>%
summarise(Intercept = lm(x ~ y + z)$coefficients[1],
Coeff_y = lm(x ~ y + z)$coefficients[2],
Coeff_z = lm(x ~ y + z)$coefficients[3],
R2 = summary(lm(x ~ y + z))$r.squared,
pvalue = summary(lm(x ~ y + z))$coefficients["y",4])
},
replications = 1000,
columns = c("test", "replications", "elapsed")
)
> speed_test
test replications elapsed
1 data_table 1000 29.477
2 tidyverse1 1000 88.781
dt[, {LM = lm(y1 ~ x1 + x2, data = .SD)
LM.summary = summary(LM)
list(Intercept = LM$coefficients[1],
Coeff_x1 = LM$coefficients[2],
Coeff_x2 = LM$coefficients[3],
R2 = LM.summary$r.squared,
pvalue.x1 = LM.summary$coefficients["x1", 4],
pvalue.x2 = LM.summary$coefficients["x2", 4])
},
by = Key]
library(data.table)
dt = fread('Key y1 x1 x2
A 10 1 3
A 11 2 4
A 12 3 5
A 13 4 5
B 13 4 6
B 14 5 7
B 15 6 8
B 15 5 9
C 16 7 9
C 17 8 1
C 18 9 2
C 18 9 2')