如何使 group_by 和 lm 更快?

2024-01-31

这是一个样本。

df <- tibble(
      subject = rep(letters[1:7], c(5, 6, 7, 5, 2, 5, 2)),
      day = c(3:7, 2:7, 1:7, 3:7, 6:7, 3:7, 6:7),
      x1 = runif(32), x2 = rpois(32, 3), x3 = rnorm(32), x4 = rnorm(32, 1, 5))

df %>%
  group_by(subject) %>%
  summarise(
    coef_x1 = lm(x1 ~ day)$coefficients[2],
    coef_x2 = lm(x2 ~ day)$coefficients[2],
    coef_x3 = lm(x3 ~ day)$coefficients[2],
    coef_x4 = lm(x4 ~ day)$coefficients[2])

这个数据很小,所以性能没有问题。

但我的数据太大了,大约有 1,000,000 行和 200,000 个主题,而且这段代码非常慢。

我认为原因不是lm的速度但是很多subject and 子集化.


理论上

首先,您可以拟合具有多个 LHS 的线性模型 https://stackoverflow.com/q/39262534/4891738.

其次,显式数据分割并不是分组回归的唯一方法(或推荐方法)。看R回归分析:分析特定种族的数据 https://stackoverflow.com/q/51407989/4891738 and R:为每个类别建立单独的模型 https://stackoverflow.com/q/43189497/4891738。所以将你的模型构建为cbind(x1, x2, x3, x4) ~ day * subject where subject是因子变量。

最后,由于您有许多因子级别并使用大型数据集,lm是不可行的。考虑使用speedglm::speedlm with sparse = TRUE, or MatrixModels::glm4 with sparse = TRUE.


事实上

Neither speedlm nor glm4正在积极开发中。 (在我看来)它们的功能很原始。

Neither speedlm nor glm4支持多个 LHS 作为lm。所以你需要做 4 个独立的模型x1 ~ day * subject to x4 ~ day * subject反而。

这两个包背后的逻辑不同sparse = TRUE.

  • speedlm首先使用标准构建密集设计矩阵model.matrix.default,然后使用is.sparse调查是否稀疏。如果为 TRUE,则后续计算可以使用稀疏方法。
  • glm4 uses model.Matrix构造设计矩阵,可以直接构造稀疏矩阵。

所以,这并不奇怪speedlm和一样糟糕lm在这个稀疏性问题中,并且glm4是我们真正想要使用的。

glm4没有一套完整、有用的通用函数来分析拟合模型。您可以通过以下方式提取系数、拟合值和残差coef, fitted and residuals,但必须自己计算所有统计数据(标准误差、t 统计量、F 统计量等)。这对于熟悉回归理论的人来说不是什么大事,但仍然相当不方便。

glm4仍然期望你使用最好的模型公式,以便可以构造最稀疏的矩阵。常规的~ day * subject确实不太好。我可能应该稍后就这个问题设立一个问答。基本上,如果你的公式有截距并且因子是对比的,你就会失去稀疏性。这是我们应该使用的:~ 0 + subject + day:subject.


测试与glm4

## use chinsoon12's data in his answer
set.seed(0L)
nSubj <- 200e3
nr <- 1e6
DF <- data.frame(subject = gl(nSubj, 5),
                 day = 3:7,
                 y1 = runif(nr), 
                 y2 = rpois(nr, 3), 
                 y3 = rnorm(nr), 
                 y4 = rnorm(nr, 1, 5))

library(MatrixModels)
fit <- glm4(y1 ~ 0 + subject + day:subject, data = DF, sparse = TRUE)

在我的 1.1GHz Sandy Bridge 笔记本电脑上大约需要 6 ~ 7 秒。让我们提取它的系数:

b <- coef(fit)

head(b)
#  subject1   subject2   subject3   subject4   subject5   subject6 
# 0.4378952  0.3582956 -0.2597528  0.8141229  1.3337102 -0.2168463 

tail(b)
#subject199995:day subject199996:day subject199997:day subject199998:day 
#      -0.09916175       -0.15653402       -0.05435883       -0.02553316 
#subject199999:day subject200000:day 
#       0.02322640       -0.09451542 

你可以做B <- matrix(b, ncol = 2),因此第一列是截距,第二列是斜率。


我的想法:我们可能需要更好的包来进行大回归

Using glm4这里并没有提供有吸引力的优势青松12的data.table解决方案 https://stackoverflow.com/a/51940464/4891738因为它基本上也只是告诉你回归系数。它也比慢一点data.table方法,因为它计算拟合值和残差。

简单回归分析不需要适当的模型拟合例程。我有一些关于如何在这种回归上做一些奇特的事情的答案,比如数据框中所有变量之间的快速成对简单线性回归 https://stackoverflow.com/q/51953709/4891738其中还给出了如何计算所有统计数据的详细信息。但当我写这个答案时,我正在思考一些关于大型回归问题的一般问题。我们可能需要更好的包,否则就没有尽头进行案例到案例的编码。


回复OP

speedglm::speedlm(x1 ~ 0 + subject + day:subject, data = df, sparse = TRUE) gives 错误:无法分配大小为 74.5 Gb 的向量

是的,因为它有一个坏处sparse logic.

MatrixModels::glm4(x1 ~ day * subject, data = df, sparse = TRUE)给出错误Cholesky(crossprod(from), LDL = FALSE):internal_chm_factor:Cholesky 分解失败

这是因为某些数据只有一个数据subject。您至少需要两个数据才能拟合一条线。这是一个示例(在密集设置中):

dat <- data.frame(t = c(1:5, 1:9, 1),
                  f = rep(gl(3,1,labels = letters[1:3]), c(5, 9, 1)),
                  y = rnorm(15))

级别“c”f只有一个数据/行。

X <- model.matrix(~ 0 + f + t:f, dat)
XtX <- crossprod(X)
chol(XtX)
#Error in chol.default(XtX) : 
#  the leading minor of order 6 is not positive definite

Cholesky 分解无法解决秩缺陷模型。如果我们使用lm的 QR 分解,我们会看到NA系数。

lm(y ~ 0 + f + t:f, dat)
#Coefficients:
#      fa        fb        fc      fa:t      fb:t      fc:t  
# 0.49893   0.52066  -1.90779  -0.09415  -0.03512        NA  

我们只能估计水平“c”的截距,而不能估计斜率。

请注意,如果您使用data.table解决方案,你最终会得到0 / 0计算该级别的斜率时,最终结果为NaN.


更新:现已提供快速解决方案

查看快速分组简单线性回归和一般配对简单线性回归 https://stackoverflow.com/q/51996021/4891738.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使 group_by 和 lm 更快? 的相关文章

随机推荐

  • Java - TestNG:为什么我的断言在 try-catch 块中写入时总是通过

    我正在尝试使用一个简单的代码org testng Assert断言 2 个用例 在第一个用例中 我断言 2 个不相等的值Fail正确 但在第二个用例中 当我在 try catch 块中断言 2 个不相等的值时 结果始终返回为Pass 我的代
  • Arduino:字符串到整数得到奇怪的值

    我想转换一个String to an int 我所能找到的就是你必须将 String 转换为 char 数组 然后将该数组转换为int 但我的代码产生奇怪的值 我无法弄清楚问题是什么 void ledDimm String command
  • 如何在 Mac OS X 上将按钮连接到方法

    我已经习惯了在 iPhone 上编程 在那里 我将一个按钮连接到一个操作 然后通过创建如下方法来连接一个方法 IBAction DoStuff 然后我会为按钮创建一个出口 然后在 Interface Builder 中创建实际的按钮 然后
  • 快速长按自定义键盘的删除键

    我正在制作一个定制键盘 键盘上的删除键单击即可正常工作 但它不适用于长按 我想实现长按删除键 以便当用户按住删除按钮时 键盘会像标准ios键盘一样连续删除 我在 Stackoverflow 上提到了几个解决方案 例如 https stack
  • 从仅系统托盘的应用程序创建工具提示

    所以我试图在屏幕上的某个时刻创建一个工具提示 ToolTip tip new ToolTip tip Show foobar IWin32Window window new Point 100 100 问题是我不知道要插入什么window上
  • 如何从 AWS::Serverless::Function (SAM) 输出 api 资源 arns?

    我需要访问已使用 Cloudformation SAM 模板创建并订阅的网关的 arn 当我尝试以下操作时 出现错误 输出块中未解决的资源依赖项 GetResource AWSTemplateFormatVersion 2010 09 09
  • p:selectOneRadio 未使用 p:ajax 在事件“更改”中更新模型

    我正在使用一个p selectOneRadio with p ajax和另一个组件的值 p inputText 不将其值绑定到我的 bean 中 如果我使用p selectBooleanCheckbox相反 行为正是我所需要的 在调用 aj
  • 我们如何设置 kubernetes 在推送新容器时自动更改容器?

    我正在使用谷歌云来存储我的Docker图像和托管我的库伯内特斯簇 我想知道我怎样才能拥有库伯内特斯下拉图像latest每次推送新的标签时 我想图像拉取策略是要走的路 但它似乎没有完成这项工作 我可能错过了一些东西 这是我的容器规格 name
  • 如何包装交互式命令

    我正在构建一个 ftp 包装器 它在生成之前执行一些操作 我可以轻松地在 shell 脚本中执行此操作 但想知道如何在 go 中执行此操作 而 exec Command 适用于简单命令 out err exec Command ls Out
  • Google Cloud Compute 上的多个 IP 地址

    我正在尝试使用多个内部 IP 地址设置基于 CentOS 7 的虚拟机 但它似乎并不像 Amazon AWS 那样简单 您可以使用路由为虚拟机添加内部 IP https cloud google com compute docs refer
  • 如何根据分隔符将字符串分成两部分?

    我在 SQL Server 数据库中有一个表 其中包含以下列 Field1 Field2 Field3 Field1是带有 的字符串类型列作为分隔符 它具有以下形式 Part1 Part2 我想编写一个返回以下列的 SQL 查询 Part1
  • ArrayIndexOutOfBoundsException 未被捕获和忽略

    我想捕获并忽略 ArrayIndexOutOfBoundsException 错误 基本上这不是我可以控制的 所以我需要我的程序继续运行 但是我的 try catch 对似乎没有捕获异常并忽略它 希望你能指出我做错了什么 异常发生在这一行
  • Oracle:合并两个具有不同列的表

    这是表1 col 1 col 2 date 1 1 3 2016 2 4 2015 这是表 2 col 3 col 4 date 2 5 8 2014 6 9 2012 我想要这样的结果 col 1 col 2 col 3 col 4 da
  • Java类关键字

    几天前我发现了一段Java代码 它使用了class上下文中的关键字 例如 MyConcreteClass class AMethod 我尝试在 JFrame 中执行此操作 例如 JFrame class getName 这是可行的 但是 我
  • OpenShift :: POD 不会从部署配置继承“名称标签”

    我从 git repo 基于 Docker 的应用程序 创建了一个构建配置 oc new build
  • Highcharts 热图 - 禁用不同颜色的图例结果

    我正在使用 Highcharts 热图 如果我通过设置禁用图例 legend enabled false 图表中使用的颜色不同 我还提供了一些 colorAxis 信息 例如最小值 最大值和停止点 这里有一个fiddle http jsfi
  • “会话”从哪里来?

    我正在我的 Rails 应用程序中构建一个会话控制器 我只是不确定为什么有些东西在这里工作 在创建和销毁动作中 session index 被分配给 nil 或用户 ID 但这个会话哈希没有在任何地方定义 据我所知 为什么这有效 谁能帮我澄
  • 这个 cronjob 能工作吗?

    我正在尝试设置一个 cronjob 来运行 PHP 文件 我只是想知道我这样做是否正确 假设 php 位于http mysite com myscript cronjob php http mysite com myscript cronj
  • Maven 构建失败 - 找不到插件

    我已经使用 m2 eclipse 工具创建了一个项目 并选择了 Web 应用程序原型 如果我尝试打包这个空应用程序 我会收到构建失败消息 ERROR Plugin org apache maven plugins maven war plu
  • 如何使 group_by 和 lm 更快?

    这是一个样本 df lt tibble subject rep letters 1 7 c 5 6 7 5 2 5 2 day c 3 7 2 7 1 7 3 7 6 7 3 7 6 7 x1 runif 32 x2 rpois 32 3