【问题标题】:R: run function over same dataframe multiple timesR:在同一数据帧上多次运行函数
【发布时间】:2017-12-21 10:19:16
【问题描述】:

我希望在初始数据帧上多次应用一个函数。举个简单的例子,拿这个数据:

library(dplyr)
thisdata <-  data.frame(vara = seq(from = 1, to = 20, by = 1)
                        ,varb = seq(from = 1, to = 20, by = 1))

这是一个我想运行的简单函数:

simplefunc <- function(data) {datasetfinal2 <- data %>% mutate(varb = varb+1)
return(datasetfinal2)}
thisdata2 <- simplefunc(thisdata)

thisdata3 <- simplefunc(thisdata2)

那么,我将如何运行这个函数,比如说 10 次,而不必继续调用该函数(即 thisdata3)?我最感兴趣的是复制后的最终数据帧,但最好有一个生成的所有数据帧的列表,这样我就可以运行一些诊断。感谢您的帮助!

【问题讨论】:

    标签: r function loops reduce


    【解决方案1】:

    单独处理多个结构相同的 data.frame 是一种难以管理的方法,尤其是在迭代次数多于几次的情况下。一种流行的“最佳实践”是处理“data.frames 列表”,例如:

    n <- 10 # number of times you need to repeat the process
    out <- vector("list", n)
    out[[1]] <- thisdata
    for (i in 2:n) out[[i]] <- simplefunc(out[[i-1]])
    

    您可以查看任何中间值

    str(out[[10]])
    # 'data.frame': 20 obs. of  2 variables:
    #  $ vara: num  1 2 3 4 5 6 7 8 9 10 ...
    #  $ varb: num  10 11 12 13 14 15 16 17 18 19 ...
    

    如您所料,最终结果在out[[n]]

    这可以使用Reduce 稍微简化,并向simplefunc 添加一个可丢弃的第二个参数:

    simplefunc <- function(data, ...) {
      datasetfinal2 <- data %>% mutate(varb = varb+1)
      return(datasetfinal2)
    }
    out <- Reduce(simplefunc, 1:10, init = thisdata, accumulate = TRUE)
    

    这确实有效:

    tmp <- simplefunc(thisdata, 1)
    tmp <- simplefunc(tmp, 2)
    tmp <- simplefunc(tmp, 3)
    # ...
    

    (事实上,如果您查看Reduce 的来源,它实际上是在执行我上面的第一个建议。)

    请注意,如果simplefunc 有其他不能删除的参数,也许:

    simplefunc <- function(data, ..., otherarg, anotherarg) {
      datasetfinal2 <- data %>% mutate(varb = varb+1)
      return(datasetfinal2)
    }
    

    尽管您必须将所有其他调用更改为 simplefunc 以“按名称”而不是按位置传递参数(这是一种常见/默认方式)。

    编辑:如果您不能(或不想)编辑simplefunc,您始终可以使用匿名函数来忽略迭代器/计数器:

    Reduce(function(x, ign) simplefunc(x), 1:10, init = thisdata, accumulate = TRUE)
    

    【讨论】:

    • 这可能需要设置一个新问题,但是如何将两个数据帧输入到 reduce 函数中? (例如,在初始点)。
    • 我不清楚您打算做什么:如果您的意思是对两个数据帧分别执行此操作,则只需运行两次(没有简单的健壮/弹性其他方式);如果您的意思是两个数据帧的组合,那么这取决于您是指rbind 还是cbind-like 组合。
    • 抱歉,有点难以描述。我在这里更详细地概述了这个问题:stackoverflow.com/questions/45242969/… 所以主要是在寻找更多的灵活性,将函数的输出提供给后续迭代。无论如何,上面的答案太棒了。
    【解决方案2】:

    我们可以使用for 循环

    thisdata1 <- thisdata
    for(i in 2:3){
       assign(paste0('thisdata', i), value = simplefunc(get(paste0('thisdata', i-1))))
     }
    

    注意1:最好不要在可以在list 内轻松完成操作的全局环境中创建单个对象。

    注意2:之前忘记添加免责声明

    【讨论】:

    • 你知道最好有一个数据框列表而不是使用assign ...
    猜你喜欢
    • 2013-11-01
    • 1970-01-01
    • 2021-03-09
    • 2016-05-15
    • 1970-01-01
    • 1970-01-01
    • 2021-11-02
    • 2021-12-03
    • 2020-02-10
    相关资源
    最近更新 更多