用于日志转换的循环

时间:2016-08-23 21:26:22

标签: r performance loops readability

我的任务是编写一个函数,该函数旨在通过声明的变量(with ... , new as (select 'i' as src ...), , old as (select 'd' as src ...), , combined as (select * from new union all select * from old) select Id, Col min(case when src = 'i' then Change end) as newVal, min(case when src = 'd' then Change end) as oldVal, from combined group by Id, Col; 的级别计算给定数据集(vars)中给定变量(dset)的对数。 )。如果给定级别byvar的给定变量的最小值大于0,则计算简单的自然对数。否则,给定段的给定变量的新值计算为:

byvar

为了达到这个目的,我编写了这样一个代码(对于一个可重现的例子):

new.value =  log(old.value + 1 + abs(min.value.of.given.var.for.given.level)

然而,它的可读性存在明显的问题。另外,我想知道它的性能是否会得到提升。最后但同样重要的是,目标是保持数据集中观察的顺序。任何形式的帮助/建议将不胜感激

1 个答案:

答案 0 :(得分:2)

将我的评论转到答案:

不要重新发明轮子。有很好的方法可以按照组和#34;在basetapplyave),data.tableplyrdplyr中。您不必提供以下功能:

my_log = function(x) {
    m = min(x)
    if (m > 0) return(log(x))
    return(log1p(x - m))
}

以上实现了您描述的日志。由于您希望在多个列的相同分组上运行此功能,dplyr::mutate_each可以让我们的生活轻松:

library(dplyr)
iris %>% group_by(Species) %>%
    mutate_each(funs = funs(logged = my_log))
# Source: local data frame [150 x 11]
# Groups: Species [3]
# 
#    Sepal.Length Sepal.Width Petal.Length Petal.Width Species       random Sepal.Length_logged
#           <dbl>       <dbl>        <dbl>       <dbl>  <fctr>        <dbl>               <dbl>
# 1           5.1         3.5          1.4         0.2  setosa  0.156703769            1.629241
# 2           4.9         3.0          1.4         0.2  setosa  1.373811191            1.589235
# 3           4.7         3.2          1.3         0.2  setosa  0.730670244            1.547563
# 4           4.6         3.1          1.5         0.2  setosa -1.350800927            1.526056
# 5           5.0         3.6          1.4         0.2  setosa -0.008514961            1.609438
# 6           5.4         3.9          1.7         0.4  setosa  0.320981863            1.686399
# 7           4.6         3.4          1.4         0.3  setosa -1.778148409            1.526056
# 8           5.0         3.4          1.5         0.2  setosa  0.909503835            1.609438
# 9           4.4         2.9          1.4         0.2  setosa -0.919404336            1.481605
# 10          4.9         3.1          1.5         0.1  setosa -0.157714831            1.589235
# # ... with 140 more rows, and 4 more variables: Sepal.Width_logged <dbl>, Petal.Length_logged <dbl>,
# #   Petal.Width_logged <dbl>, random_logged <dbl>

这就是它的全部!这似乎很好,简洁,可读。如果你想&#34;功能化&#34;更重要的是,你可以将它包装成一个函数,如下所示,同样的结果:

log_vars = function(data, vars, byvar) {
    data %>% group_by_(byvar) %>%
        mutate_each_(funs = funs(logged = my_log), vars = vars) %>%
        return
}

log_vars(iris, vars = c("Sepal.Width", "random"), byvar = "Species")

关于你的三个要求:

  1. 可读 - 这似乎更具可读性。如果您愿意,可以在没有%>%管道的情况下重写。
  2. 性能 - 在重要的地方会更快:包含大量组的大量数据。
  3. 订单 - 不会更改行的顺序。