4

我最近一直在使用 R 在 100 mb csv 文件(900 万行 x 5 列)上运行广义线性模型(GLM)。该文件的内容包括 5 列,称为 depvar、var1、var2、var3、var4,并且都是随机分布的,因此这些列包含的数字是 0,1 或 2。基本上我使用 biglm 包来运行 GLM这个数据文件和 R 在大约 2 分钟内处理了这个。这是在使用 R 版本 2.10(我目前正在更新到 2.14)、4 核和 8 GB RAM 的 linux 机器上。基本上我想在 30 到 60 秒左右更快地运行代码。一种解决方案是添加更多内核和 RAM,但这只是一个临时解决方案,因为我意识到数据集只会变得更大。理想情况下,我想找到一种方法让 bigglm 的代码更快。我在数据集上运行了一些 R 分析代码。

Rprof('method1.out')

然后在输入此命令后,我编写了如下所示的 bigglm 代码:

x<-read.csv('file location of 100mb file')
form<-depvar~var1+var2+var3+var4
a<-bigglm(form, data=x, chunksize=800000, sandwich=FALSE, family=binomial())
summary(a)
AIC(a)
deviance(a)

运行这些代码大约需要 2 到 3 分钟后,我键入以下内容来查看我的分析代码:

Rprofsummary('method1.out')

然后我得到的是 bigglm 过程的细分以及哪些单独的行需要很长时间。在查看此内容后,我惊讶地发现调用 fortran 代码需要很长时间(大约 20 秒)。此代码可以在 Bigglm 的基本文件中找到:

http://cran.r-project.org/web/packages/biglm/index.html

在 bigglm 0.8.tar.gz 文件中

基本上我要问社区的是,这段代码可以做得更快吗?例如通过更改代码来调用 Fortran 代码来进行 QR 分解。此外还有其他函数,如 as.character 和 model.matrix 也需要很长时间。我没有在此处附加分析文件,因为我相信根据我提供的信息可以轻松复制它,但基本上我是在暗示大数据的大问题并在此大数据上处理 GLM。这是 R 社区共享的一个问题,我认为任何反馈或帮助将不胜感激。您可能可以使用不同的数据集轻松复制此示例,并查看 bigglm 代码中花费了这么长时间的内容,看看它们是否与我发现的相同。如果是这样,有人可以帮我弄清楚如何让 bigglm 运行得更快。在 Ben 请求之后,我上传了我拥有的分析代码片段以及我的 csv 文件的前 10 行:

 CSV File:

 var1,var2,var3,var4,depvar
   1,0,2,2,1
   0,0,1,2,0
   1,1,0,0,1
   0,1,1,2,0
   1,0,0,3,0
   0,0,2,2,0
   1,1,0,0,1
   0,1,2,2,0
   0,0,2,2,1

这个 CSV 输出是从我的文本编辑器 UltraEdit 复制的,可以看出 var1 取值 0 或 1,var2 取值 0 和 1,var3 取值 0,1,2,var4 取值 0,1, 2,3 和 depvar 取值 1 或 0。此 csv 可以使用 RAND 函数在 excel 中复制最多约 100 万行,然后可以复制和粘贴多次以在文本编辑器中获得大量行像超编辑。基本上将 RAND() 键入一列以获得 100 万列,然后在 RAND() 列旁边的列中进行舍入(列)以获得 1 和零。同样的想法适用于 0,1,2,3。

分析文件很长,所以我附上了花费最多时间的行:

 summaryRprof('method1.out')



$by.self
                        self.time self.pct total.time total.pct
"model.matrix.default"      25.40     20.5      26.76      21.6
".Call"                     20.24     16.3      20.24      16.3
"as.character"              17.22     13.9      17.22      13.9
"[.data.frame"              14.80     11.9      22.12      17.8
"update.bigqr"               5.72      4.6      14.38      11.6
"-"                          4.36      3.5       4.36       3.5
"anyDuplicated.default"      4.18      3.4       4.18       3.4
"|"                          3.98      3.2       3.98       3.2
"*"                          3.44      2.8       3.44       2.8
"/"                          3.18      2.6       3.18       2.6
"unclass"                    2.28      1.8       2.28       1.8
"sum"                        2.26      1.8       2.26       1.8
"attr"                       2.12      1.7       2.12       1.7
"na.omit"                    2.02      1.6      20.00      16.1
"%*%"                        1.74      1.4       1.74       1.4
"^"                          1.56      1.3       1.56       1.3
"bigglm.function"            1.42      1.1     122.52      98.8
"+"                          1.30      1.0       1.30       1.0
"is.na"                      1.28      1.0       1.28       1.0
"model.frame.default"        1.20      1.0      22.68      18.3
">"                          0.84      0.7       0.84       0.7
"strsplit"                   0.62      0.5       0.62       0.5

$by.total
                        total.time total.pct self.time self.pct
"standardGeneric"           122.54      98.8      0.00      0.0
"bigglm.function"           122.52      98.8      1.42      1.1
"bigglm"                    122.52      98.8      0.00      0.0
"bigglm.data.frame"         122.52      98.8      0.00      0.0
"model.matrix.default"       26.76      21.6     25.40     20.5
"model.matrix"               26.76      21.6      0.00      0.0
"model.frame.default"        22.68      18.3      1.20      1.0
"model.frame"                22.68      18.3      0.00      0.0
"["                          22.14      17.9      0.02      0.0
"[.data.frame"               22.12      17.8     14.80     11.9
".Call"                      20.24      16.3     20.24     16.3
"na.omit"                    20.00      16.1      2.02      1.6
"na.omit.data.frame"         17.98      14.5      0.02      0.0
"model.response"             17.44      14.1      0.10      0.1
"as.character"               17.22      13.9     17.22     13.9
"names<-"                    17.22      13.9      0.00      0.0
"<Anonymous>"                15.10      12.2      0.00      0.0
"update.bigqr"               14.38      11.6      5.72      4.6
"update"                     14.38      11.6      0.00      0.0
"data"                       10.26       8.3      0.00      0.0
"-"                           4.36       3.5      4.36      3.5
"anyDuplicated.default"       4.18       3.4      4.18      3.4
"anyDuplicated"               4.18       3.4      0.00      0.0
"|"                           3.98       3.2      3.98      3.2
"*"                           3.44       2.8      3.44      2.8
"/"                           3.18       2.6      3.18      2.6
"lapply"                      3.04       2.5      0.04      0.0
"sapply"                      2.44       2.0      0.00      0.0
"as.list.data.frame"          2.30       1.9      0.02      0.0
"as.list"                     2.30       1.9      0.00      0.0
"unclass"                     2.28       1.8      2.28      1.8
"sum"                         2.26       1.8      2.26      1.8
"attr"                        2.12       1.7      2.12      1.7
"etafun"                      1.88       1.5      0.14      0.1
"%*%"                         1.74       1.4      1.74      1.4
"^"                           1.56       1.3      1.56      1.3
"summaryRprof"                1.48       1.2      0.02      0.0
"+"                           1.30       1.0      1.30      1.0
"is.na"                       1.28       1.0      1.28      1.0
">"                           0.84       0.7      0.84      0.7
"FUN"                         0.70       0.6      0.36      0.3
"strsplit"                    0.62       0.5      0.62      0.5

我主要对调用 Fortran 的 .Call 函数感到惊讶。可能我没看懂。一旦使用此功能,似乎所有计算都已完成。我认为这就像一个用于提取 Fortran 代码的链接函数。此外,如果 Fortran 正在完成所有工作以及所有迭代加权最小二乘/QR,那么为什么其余代码要花这么长时间。

4

1 回答 1

4

我的外行理解是 biglm 正在将数据分解成块并按顺序运行它们。

  • 因此,您可以通过优化块的大小来加快速度,使其与内存允许的一样大。
  • 这也只是使用您的一个核心。这不是多线程代码。你需要做一些魔法才能让它发挥作用。
于 2012-11-26T09:44:51.490 回答