【问题标题】:Correct use of na.approx in data.table and pipe在 data.table 和 pipe 中正确使用 na.approx
【发布时间】:2019-02-23 03:07:30
【问题描述】:

我是data.table 的新手,想试试看它是否能让我的分析更快。我主要使用knitr 编译.rnw 文件(我倾向于每小时编译多次,所以我希望它尽可能快)。

我在下面发布了一个示例,这绝不是与data.tabledata.frame 进行比较的问题。我想知道我下面的代码是否应该是这样的。

我基本上加入了两个data.tables,然后需要使用na.approx 缺少NA 值进行线性近似。我使用了 CRAN 的 Introduction to data.table vignette 和 R-Pubs 的 JOINing data in R using data.table

我在下面使用的代码导致我对 data.table 方法的最佳尝试需要很长时间(通常也是如此,我只添加了其他代码参考)。

另外,如果有人知道是否有办法将na.approx() 输入到一个链中,并且仍然将输出作为data.frame,那将不胜感激。请注意df_merged = as.data.frame(df_merged) 行,如果可能,我想删除它!

非常感谢您的任何意见谢谢!

library(data.table)
library(zoo)
library(dplyr)

dt_function_test = function() {
    set.seed(123)
    # data.table
    dt_random = data.table(vals = runif(1E5, 0, 500))
    dt_na = data.table(vals = c(0, 250, 500),
                       ref1 = c(0.33, 0.45, 0.78),
                       ref2 = c(0.12, 0.79, 1))

    dt_merged = merge(dt_random[],
                      dt_na[],
                      all = TRUE)

    dt_merged = dt_merged[, lapply(.SD,
                                   na.approx),
                          by = vals]
}


df_function_test = function() {
    set.seed(123)
    # data.frame
    df_random = data.frame(vals = runif(1E5, 0, 500))
    df_na = data.frame(vals = c(0, 250, 500),
                       ref1 = c(0.33, 0.45, 0.78),
                       ref2 = c(0.12, 0.79, 1))

    df_merged = full_join(df_random,
                          df_na) %>% 
        na.approx

    df_merged = as.data.frame(df_merged)
}

print(system.time(dt_function_test()))
#  user  system elapsed 
# 11.42    0.00   11.46 

print(system.time(df_function_test()))
# Joining, by = "vals"
#    user  system elapsed  
#    0.05    0.05    0.10 

【问题讨论】:

  • 如果我没记错的话,他们正在计算差异。 dplyr 代码(如果我错了,请有人纠正我)在每一列上执行 na.approx。 data.table 代码在每一行上执行 na.approx (因为 vals 在每一行上几乎总是差异)。只需打印每个输出的几行以检查它们是否相同。
  • 您将by = vals 分组在data.table 代码中,但不在data.frame 代码中?
  • @chinsoon12 好点。结果实际上并不相同,但我打算这样做!所以我的理解是有缺陷的......我会修改,并审查我现在看到的你的答案......
  • @MichaelChirico data.frame 代码自动按列 vals 分组,因为它在两者中都很常见,所以我没有明确指定要加入哪一列。
  • 这不是by 的意思吗? byvals 的每个值中表示apply na.approx`... 指定合并列应该发生在merge 步骤中?

标签: r dplyr data.table na.approx


【解决方案1】:

下面是一些使用data.table 的可能实现,它在ref* 列上执行zoo::na.approx(请注意,还使用了更大的数据集):

library(data.table)
library(zoo)

dt_function_test_0 = function() {
    set.seed(123)
    # data.table
    dt_random = data.table(vals = runif(1e7, 0, 500))
    dt_na = data.table(vals = c(0, 250, 500),
        ref1 = c(0.33, 0.45, 0.78),
        ref2 = c(0.12, 0.79, 1))

    cols <- c("ref1", "ref2")

    ##Version 0
    merge(dt_random, dt_na, all=TRUE)[, lapply(.SD, na.approx)]
}


dt_function_test_1 = function() {
    set.seed(123)
    # data.table
    dt_random = data.table(vals = runif(1e7, 0, 500))
    dt_na = data.table(vals = c(0, 250, 500),
        ref1 = c(0.33, 0.45, 0.78),
        ref2 = c(0.12, 0.79, 1))

    cols <- c("ref1", "ref2")

    ##Version 1: using update by reference
    merge(dt_random, dt_na, all = TRUE)[, 
        (cols) := lapply(.SD, na.approx), .SDcols=cols]
}


dt_function_test_2 = function() {
    set.seed(123)
    # data.table
    dt_random = data.table(vals = runif(1e7, 0, 500))
    dt_na = data.table(vals = c(0, 250, 500),
        ref1 = c(0.33, 0.45, 0.78),
        ref2 = c(0.12, 0.79, 1))

    cols <- c("ref1", "ref2")
    ##Version 2: using set
    dt_merged <- merge(dt_random, dt_na, all = TRUE)
    for (x in cols)
        set(dt_merged, j=x, value=na.approx(dt_merged[[x]]))
    dt_merged
}

定时输出:

> system.time(dt_function_test_0())
   user  system elapsed 
   5.44    1.90    6.96 

> system.time(dt_function_test_1())
   user  system elapsed 
   3.55    1.30    4.41 

> system.time(dt_function_test_2())
   user  system elapsed 
   3.78    1.19    4.52

【讨论】:

  • 效果很好!为什么(cols)必须在括号中?为什么整个j 表达式不必放在括号中?我是否正确解释.SDcols=cols 表示j 计算应该只在那些特定的列上进行?这样就可以避免任何形式的分组?因此,任何时候我想对特定列执行功能而不按任何列分组,我都会使用(colnames):=function(), .SDcols=colnames 争论?
  • 当您阅读:= 上的小插图时,您就会明白为什么需要括号。基本上是通过引用区别于其他类型的更新。 .SDcols 可以在 ?data.table 中找到,它指定要使用的 .SD 的列。您可以查看?.SD 了解什么是.SD。 ?data.table 也是必读的(羞愧地低着头,我可能没有读过里面的每一个字)。是的,在大多数情况下,您可以使用DT[i, j=lapply(.SD, func), by=groupid, .SDcols=colsInDTtoApplyFunc]
  • 感谢您的意见。我会更多地研究data.table 并做一些阅读!
猜你喜欢
  • 2021-09-16
  • 2018-08-01
  • 2018-12-07
  • 2021-12-14
  • 2021-02-22
  • 1970-01-01
  • 2018-12-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多