基准和处理时间结果的差异

2024-04-15

我一直在尝试对替换数据框中的 NA 的最有效方法进行一些测试。

我首先在 100 万行、12 列的数据集上比较 NA 与 0 的替换解决方案。 把所有有管道能力的都扔进去microbenchmark我得到以下结果。

问题一:有没有办法测试子集左赋值语句(例如:df1[is.na(df1)] benchmark功能?

library(dplyr)
library(tidyr)
library(microbenchmark)

set.seed(24)
df1 <- as.data.frame(matrix(sample(c(NA, 1:5), 1e6 *12, replace=TRUE),
                            dimnames = list(NULL, paste0("var", 1:12)), ncol=12))

op <- microbenchmark(
    mut_all_ifelse   = df1 %>% mutate_all(funs(ifelse(is.na(.), 0, .))),
    mut_at_ifelse    = df1 %>% mutate_at(funs(ifelse(is.na(.), 0, .)), .cols = c(1:12)),
    # df1[is.na(df1)] <- 0 would sit here, but I can't make it work inside this function
    replace          = df1 %>% replace(., is.na(.), 0),
    mut_all_replace  = df1 %>% mutate_all(funs(replace(., is.na(.), 0))),
    mut_at_replace   = df1 %>% mutate_at(funs(replace(., is.na(.), 0)), .cols = c(1:12)),
    replace_na       = df1 %>% replace_na(list(var1 = 0, var2 = 0, var3 = 0, var4 = 0, var5 = 0, var6 = 0, var7 = 0, var8 = 0, var9 = 0, var10 = 0, var11 = 0, var12 = 0)),
    times = 1000L
)

print(op) #standard data frame of the output
    Unit: milliseconds
            expr       min       lq     mean   median       uq       max neval
  mut_all_ifelse 769.87848 844.5565 871.2476 856.0941 895.4545 1274.5610  1000
   mut_at_ifelse 713.48399 847.0322 875.9433 861.3224 899.7102 1006.6767  1000
         replace 258.85697 311.9708 334.2291 317.3889 360.6112  455.7596  1000
 mut_all_replace  96.81479 164.1745 160.6151 167.5426 170.5497  219.5013  1000
  mut_at_replace  96.23975 166.0804 161.9302 169.3984 172.7442  219.0359  1000
      replace_na 103.04600 161.2746 156.7804 165.1649 168.3683  210.9531  1000
boxplot(op) #boxplot of output
library(ggplot2) #nice log plot of the output
qplot(y=time, data=op, colour=expr) + scale_y_log10()

为了测试子集赋值运算符,我最初运行了这些测试。

set.seed(24) 
> Book1 <- as.data.frame(matrix(sample(c(NA, 1:5), 1e8 *12, replace=TRUE),
+ dimnames = list(NULL, paste0("var", 1:12)), ncol=12))
> system.time({ 
+     Book1 %>% mutate_all(funs(ifelse(is.na(.), 0, .))) })
   user  system elapsed 
  52.79   24.66   77.45 
> 
> system.time({ 
+     Book1 %>% mutate_at(funs(ifelse(is.na(.), 0, .)), .cols = c(1:12)) })
   user  system elapsed 
  52.74   25.16   77.91 
> 
> system.time({ 
+     Book1[is.na(Book1)] <- 0 })
   user  system elapsed 
  16.65    7.86   24.51 
> 
> system.time({ 
+     Book1 %>% replace_na(list(var1 = 0, var2 = 0, var3 = 0, var4 = 0, var5 = 0, var6 = 0, var7 = 0, var8 = 0, var9 = 0,var10 = 0, var11 = 0, var12 = 0)) })
   user  system elapsed 
   3.54    2.13    5.68 
> 
> system.time({ 
+     Book1 %>% mutate_at(funs(replace(., is.na(.), 0)), .cols = c(1:12)) })
   user  system elapsed 
   3.37    2.26    5.63 
> 
> system.time({ 
+     Book1 %>% mutate_all(funs(replace(., is.na(.), 0))) })
   user  system elapsed 
   3.33    2.26    5.58 
> 
> system.time({ 
+     Book1 %>% replace(., is.na(.), 0) })
   user  system elapsed 
   3.42    1.09    4.51 

在这些测试中,基replace()首先出现。 在基准测试中,replace排名进一步落后,而tidyr replace_na()获胜(以微弱优势) 在不同形状和大小的数据帧上重复运行奇异测试总能找到基础replace()处于领先。

问题2:它的基准性能怎么可能是唯一与简单测试结果不一致的结果呢?

更令人费解的是——问题3:怎样才能全部mutate_all/_at(replace())比简单的工作更快replace()? 很多人反映这样的情况:http://datascience.la/dplyr-and-a-very-basic-benchmark/ http://datascience.la/dplyr-and-a-very-basic-benchmark/(以及该文章中的所有链接)但我仍然没有找到为什么使用除此之外的哈希和 C++ 的解释。)

特别感谢 Tyler Rinker:https://www.r-bloggers.com/microbenchmarking-with-r/ https://www.r-bloggers.com/microbenchmarking-with-r/和阿克伦:https://stackoverflow.com/a/41530071/5088194 https://stackoverflow.com/a/41530071/5088194


您可以在其中包含复杂/多语句microbenchmark通过包裹它{}基本上,它转换为单个表达式:

microbenchmark(expr1 = { df1[is.na(df1)] = 0 }, 
               exp2 = { tmp = 1:10; tmp[3] = 0L; tmp2 = tmp + 12L; tmp2 ^ 2 }, 
               times = 10)
#Unit: microseconds
#  expr        min         lq       mean     median         uq        max neval cld
# expr1 124953.716 137244.114 158576.030 142405.685 156744.076 284779.353    10   b
#  exp2      2.784      3.132     17.748     23.142     24.012     38.976    10  a 

值得注意的是这样做的副作用:

tmp
#[1]  1  2  0  4  5  6  7  8  9 10

相比之下,比如说:

rm(tmp)
microbenchmark(expr1 = { df1[is.na(df1)] = 0 },  
               exp2 = local({ tmp = 1:10; tmp[3] = 0L; tmp2 = tmp + 12L; tmp2 ^ 2 }), 
               times = 10)
#Unit: microseconds
#  expr       min         lq        mean     median         uq        max neval cld
# expr1 127250.18 132935.149 165296.3030 154509.553 169917.705 314820.306    10   b
#  exp2     10.44     12.181     42.5956     54.636     57.072     97.789    10  a 
tmp
#Error: object 'tmp' not found

注意到基准测试的副作用,我们看到第一个删除的操作NAValues 为以下替代方案留下了相当轻松的工作:

# re-assign because we changed it before
set.seed(24)
df1 = as.data.frame(matrix(sample(c(NA, 1:5), 1e6 * 12, TRUE), 
                           dimnames = list(NULL, paste0("var", 1:12)), ncol = 12))
unique(sapply(df1, typeof))
#[1] "integer"
any(sapply(df1, anyNA))
#[1] TRUE
system.time({ df1[is.na(df1)] <- 0 })
# user  system elapsed 
# 0.39    0.14    0.53 

之前的基准给我们留下了:

unique(sapply(df1, typeof))
#[1] "double"
any(sapply(df1, anyNA))
#[1] FALSE

并更换NA,当没有时,应该考虑对输入不执行任何操作。

除此之外,请注意,在所有替代方案中,您都分配了一个“双”(typeof(0))到“整数”列向量(sapply(df1, typeof))。虽然,我认为没有任何情况(在上述替代方案中)df1就地修改(因为在创建“data.frame”之后,存储了信息以在修改时复制其向量列),在强制转换为“double”时仍然存在较小但可以避免的开销,并且存储为“双”。 R 在替换“整数”向量中的元素之前将分配和复制(在“整​​数”替换的情况下)或分配和强制(在“双”替换的情况下)。此外,在第一次强制转换(来自基准的副作用,如上所述)之后,R 将在“double”上运行,并且包含比“integer”上更慢的操作。我找不到直接的 R 方法来研究这种差异,但简而言之(有不完全准确的危险),我们可以通过以下方式模拟这些操作:

# simulate R's copying of int to int
# allocate a new int and copy
int2int = inline::cfunction(sig = c(x = "integer"), body = '
    SEXP ans = PROTECT(allocVector(INTSXP, LENGTH(x)));
    memcpy(INTEGER(ans), INTEGER(x), LENGTH(x) * sizeof(int));
    UNPROTECT(1);
    return(ans);
')
# R's coercing of int to double
# 'coerceVector', internally, allocates a double and coerces to populate it
int2dbl = inline::cfunction(sig = c(x = "integer"), body = '
    SEXP ans = PROTECT(coerceVector(x, REALSXP));
    UNPROTECT(1);
    return(ans);
')
# simulate R's copying form double to double
dbl2dbl = inline::cfunction(sig = c(x = "double"), body = '
    SEXP ans = PROTECT(allocVector(REALSXP, LENGTH(x)));
    memcpy(REAL(ans), REAL(x), LENGTH(x) * sizeof(double));
    UNPROTECT(1);
    return(ans);
')

并在基准上:

x.int = 1:1e7; x.dbl = as.numeric(x.int)
microbenchmark(int2int(x.int), int2dbl(x.int), dbl2dbl(x.dbl), times = 50)
#Unit: milliseconds
#           expr      min       lq     mean   median       uq      max neval cld
# int2int(x.int) 16.42710 16.91048 21.93023 17.42709 19.38547 54.36562    50  a 
# int2dbl(x.int) 35.94064 36.61367 47.15685 37.40329 63.61169 78.70038    50   b
# dbl2dbl(x.dbl) 33.51193 34.18427 45.30098 35.33685 63.45788 75.46987    50   b

总结(!)整个之前的注释,替换0 with 0L将节省一些时间...

最后,为了以更公平的方式复制基准,我们可以使用:

library(dplyr)
library(tidyr)
library(microbenchmark) 
set.seed(24)
df1 = as.data.frame(matrix(sample(c(NA, 1:5), 1e6 * 12, TRUE), 
                            dimnames = list(NULL, paste0("var", 1:12)), ncol = 12))

包裹在函数中:

stopifnot(ncol(df1) == 12)  #some of the alternatives are hardcoded to 12 columns
mut_all_ifelse = function(x, val) x %>% mutate_all(funs(ifelse(is.na(.), val, .)))
mut_at_ifelse = function(x, val) x %>% mutate_at(funs(ifelse(is.na(.), val, .)), .cols = c(1:12))
baseAssign = function(x, val) { x[is.na(x)] <- val; x }
baseFor = function(x, val) { for(j in 1:ncol(x)) x[[j]][is.na(x[[j]])] = val; x }
base_replace = function(x, val) x %>% replace(., is.na(.), val)
mut_all_replace = function(x, val) x %>% mutate_all(funs(replace(., is.na(.), val)))
mut_at_replace = function(x, val) x %>% mutate_at(funs(replace(., is.na(.), val)), .cols = c(1:12))
myreplace_na = function(x, val) x %>% replace_na(list(var1 = val, var2 = val, var3 = val, var4 = val, var5 = val, var6 = val, var7 = val, var8 = val, var9 = val, var10 = val, var11 = val, var12 = val))

测试基准之前的结果是否相等:

identical(mut_all_ifelse(df1, 0), mut_at_ifelse(df1, 0))
#[1] TRUE
identical(mut_at_ifelse(df1, 0), baseAssign(df1, 0))
#[1] TRUE
identical(baseAssign(df1, 0), baseFor(df1, 0))
#[1] TRUE
identical(baseFor(df1, 0), base_replace(df1, 0))
#[1] TRUE
identical(base_replace(df1, 0), mut_all_replace(df1, 0))
#[1] TRUE
identical(mut_all_replace(df1, 0), mut_at_replace(df1, 0))
#[1] TRUE
identical(mut_at_replace(df1, 0), myreplace_na(df1, 0))
#[1] TRUE

强制“双重”测试:

benchnum = microbenchmark(mut_all_ifelse(df1, 0), 
                          mut_at_ifelse(df1, 0), 
                          baseAssign(df1, 0), 
                          baseFor(df1, 0),
                          base_replace(df1, 0), 
                          mut_all_replace(df1, 0),
                          mut_at_replace(df1, 0), 
                          myreplace_na(df1, 0),
                          times = 10)
benchnum
#Unit: milliseconds
#                    expr       min        lq      mean    median        uq       max neval cld
#  mut_all_ifelse(df1, 0) 1368.5091 1441.9939 1497.5236 1509.2233 1550.1416 1629.6959    10   c
#   mut_at_ifelse(df1, 0) 1366.1674 1389.2256 1458.1723 1464.5962 1503.4337 1553.7110    10   c
#      baseAssign(df1, 0)  532.4975  548.9444  586.8198  564.3940  655.8083  667.8634    10  b 
#         baseFor(df1, 0)  169.6048  175.9395  206.7038  189.5428  197.6472  308.6965    10 a  
#    base_replace(df1, 0)  518.7733  547.8381  597.8842  601.1544  643.4970  666.6872    10  b 
# mut_all_replace(df1, 0)  169.1970  183.5514  227.1978  194.0903  291.6625  346.4649    10 a  
#  mut_at_replace(df1, 0)  176.7904  186.4471  227.3599  202.9000  303.4643  309.2279    10 a  
#    myreplace_na(df1, 0)  172.4926  177.8518  199.1469  186.3645  192.1728  297.0419    10 a

测试时不强制“双倍”:

benchint = microbenchmark(mut_all_ifelse(df1, 0L), 
                          mut_at_ifelse(df1, 0L), 
                          baseAssign(df1, 0L), 
                          baseFor(df1, 0L),
                          base_replace(df1, 0L), 
                          mut_all_replace(df1, 0L),
                          mut_at_replace(df1, 0L),
                          myreplace_na(df1, 0L),
                          times = 10)
benchint
#Unit: milliseconds
#                     expr        min        lq      mean    median        uq       max neval cld
#  mut_all_ifelse(df1, 0L) 1291.17494 1313.1910 1377.9265 1353.2812 1417.4389 1554.6110    10   c
#   mut_at_ifelse(df1, 0L) 1295.34053 1315.0308 1372.0728 1353.0445 1431.3687 1478.8613    10   c
#      baseAssign(df1, 0L)  451.13038  461.9731  477.3161  471.0833  484.9318  528.4976    10  b 
#         baseFor(df1, 0L)   98.15092  102.4996  115.7392  107.9778  136.2227  139.7473    10 a  
#    base_replace(df1, 0L)  428.54747  451.3924  471.5011  470.0568  497.7088  516.1852    10  b 
# mut_all_replace(df1, 0L)  101.66505  102.2316  137.8128  130.5731  161.2096  243.7495    10 a  
#  mut_at_replace(df1, 0L)  103.79796  107.2533  119.1180  112.1164  127.7959  166.9113    10 a  
#    myreplace_na(df1, 0L)  100.03431  101.6999  120.4402  121.5248  137.1710  141.3913    10 a

以及一个简单的可视化方法:

boxplot(benchnum, ylim = range(min(summary(benchint)$min, summary(benchnum)$min),
                               max(summary(benchint)$max, summary(benchnum)$max)))
boxplot(benchint, add = TRUE, border = "red", axes = FALSE) 
legend("topright", c("coerce", "not coerce"), fill = c("black", "red"))                       

注意df1毕竟这一切都没有改变(str(df1)).

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

基准和处理时间结果的差异 的相关文章

  • 使用 readHTMLTable 从 https 网页读取表格

    我安装了 R 3 3 1 并使用 RStudio 0 99 903 我正在尝试从以下 URL 将表格读入 R https www fantasypros com nfl rankings consensus cheatsheets php
  • 将不同的 grViz 组合成一个图

    我想结合不同的DiagrammeR绘制成一个图形 生成的图如下例所示 library DiagrammeR pDia lt grViz digraph boxes and circles a graph statement graph ov
  • R闪亮主面板显示样式和字体

    我正在学习闪亮的应用程序 并且有一些关于调整布局的基本问题 特别是样式和字体 希望得到指点或明确的答案 谢谢 考虑一个基本的输入输出应用程序 用户在 sidebarPanel 中输入数据 然后在 mainPanel 中反应性地输出结果 如何
  • 如何使用 R 中的函数 sqlSave() 将数据附加到具有 IDENTITY 主键的 SQL Server 表?

    我在SQL Server中创建了一个表 如下所示 CREATE TABLE testPK ID INT NOT NULL IDENTITY 1 1 PRIMARY KEY NumVal NUMERIC 18 4 现在我想使用 RODBC 函
  • 如何有效地将多个光栅 (.tif) 文件导入 R

    我是 R 新手 尤其是在空间数据方面 我正在尝试找到一种方法来有效地将多个 600 单波段栅格 tif 文件导入到 R 中 所有文件都存储在同一文件夹中 不确定这是否重要 但请注意 在我的 Mac 和 Windows 并行 VM 上的文件夹
  • R data.table 连接不等式条件

    我想使用 data table 包根据多个不等式条件对数据进行子集化 data table 手册中的示例展示了如何使用字符变量执行此操作 但不显示数字不等式 我还了解了如何使用子集函数来执行此操作 但我真的很想利用 data table 二
  • 改进R中从google获取股票新闻数据的功能

    我已经编写了一个函数来从 Google 获取和解析给定股票代码的新闻数据 但我确信有一些方法可以改进它 对于初学者来说 我的函数返回一个 GMT 时区的对象 而不是用户当前的时区 如果传递的数字大于 299 它就会失败 可能是因为 goog
  • 在 R 中导入 csv 文件时如何保留前导零?

    当我写一个 csv来自 R 的文件 其中我的组名称以前导零值开头 前导零被保留 但是当我导入 csv前导零被删除 组名称被转换为整数 当我导入一个组时 如何保留组名称中的前导零 csvR 中的文件 Example df lt data fr
  • 如何读取 R 中的每个 .csv 文件并将其导出到单个大文件中

    你好 我有以下格式的数据 101 20130826T155649 3 1 round 0 10552 180 yellow 12002 1 round 1 19502 150 yellow 22452 1 round 2 28957 130
  • 在 Lavaan 生长曲线模型中提取个体轨迹

    我已经使用 R 的 Lavaan 包中的 Growth 函数成功地对一项研究的纵向数据进行了建模 我找不到任何关于如何提取每个参与者的预测轨迹的记录 我只能找到整个组的预测轨迹 在摘要输出的 拦截 部分下给出 使用 lavPredict m
  • 通过 Shiny 中的串扰将 Plotly 与 DT 结合使用

    我正在编写一个应用程序来将 csv 文件读取为闪亮的并将散点图与 DT 表链接起来 我几乎遵循了 Plotly 网站上 DT 数据表上的示例 https plot ly r datatable https plot ly r datatab
  • 如果条目出现次数少于 x 则删除数据框中的行

    我有以下数据框 称之为 df 它是由三个向量组成的数据框 姓名 年龄 和 邮政编码 df Name Age ZipCode 1 Joe 16 60559 2 Jim 20 60637 3 Bob 64 94127 4 Joe 23 9412
  • 如何返回包含最大值标签的向量

    我有一个 4 列数组 我想获得一个向量 其中每行包含包含该行最大值的列的标签 我可以在循环中执行此操作 但我想使用矩阵函数来提高速度 我怎样才能在不编写自己的库函数的情况下做到这一点 有一个函数可以做到这一点 如果x是你的矩阵 尝试max
  • 按不规则时间间隔对数据进行分组求和(R语言)

    我正在看这里的 stackoverflow 帖子 R 计算一组内的观察次数 https stackoverflow com questions 65366412 r count number of observations within a
  • 使用 RDCOMClient 搜索 Outlook 收件箱

    我尝试使用 RDCOMClient 在 Outlook 收件箱中搜索电子邮件中的特定主题 然后获取附件 我在一封电子邮件上进行了这项工作 但由于主题包含日期元素 我需要搜索成为一个类似的子句 但不太清楚这适合我的下面的查询 outlook
  • 如何将同一行中以逗号分隔的值拆分到R中的不同行

    我有一些数据来自谷歌表格 https forms gle rGQQL3tvA1PrE4dD8我想拆分以逗号分隔的答案 and 复制参与者的 ID 数据如下 gt head data names Q2 Q3 Q4 1 PART 1 fruit
  • R中整数类和数字类有什么区别

    我想先说我是一个绝对的编程初学者 所以请原谅这个问题是多么基本 我试图更好地理解 R 中的 原子 类 也许这适用于一般编程中的类 我理解字符 逻辑和复杂数据类之间的区别 但我正在努力寻找数字类和整数类之间的根本区别 假设我有一个简单的向量x
  • 排序因素与水平

    有人能解释一下 R 中 ordered 参数的用途吗 R says ordered逻辑标志来确定级别是否应被视为有序 按给定的顺序 所以如果我有一个名为名称的因素并设置ordered TRUE names lt factor c fred
  • 如何自动启动我的 ec2 实例、运行命令然后将其关闭?

    我想每周对 redshift postgres 数据库中的数据运行一次机器学习模型 我使用以下命令将 R 脚本设置为休息 apiplumbr然后我将其设置为一项任务来管理pm2 我有它 所以任务会在ec2实例启动然后继续运行 要让 R 脚本
  • 无法部署 ShinyApp:readTableHeader 在“raw”上发现不完整的最后一行(使用默认值:en_US)

    我已经拼命尝试部署我的闪亮应用程序大约一周了 但不幸的是我无法停止收到以下消息 Warning message Error detecting locale Error in read table file file header head

随机推荐