【问题标题】:Vectorizing a loop through lines of data frame R while accessing multiple variables the dataframe在访问数据帧的多个变量时通过数据帧 R 的行对循环进行矢量化
【发布时间】:2014-02-26 18:53:18
【问题描述】:

又一个apply 问题。

我查看了很多关于 R 中 apply 函数系列的文档(并在我的工作中使用了很多)。我已经定义了一个函数myfun,我想在它下面应用到数据帧inc 的每一行。我想我需要一些apply(inc,1,myfun) 的变体,我已经玩了一段时间了,但还是不太明白。我已经包含了一个循环,它完全实现了我想要做的......它对我的真实数据来说超级慢而且效率低下,这比我在这里包含的样本数据要大得多。

我希望这是一个快速修复,但我不能完全确定它...也许有特殊参数 ... 可以应用?

以下代码的英文版:我想查看inc 数据框中的所有提交日期,并为每个日期查找chg 中有多少行chg$Submit.Date 在其中inc$Submit.Date 的一些范围。其中范围由myfun中的fdaysbdays控制

设置一些虚假数据

chgdf <- data.frame(Submit.Date=as.Date(c("2013-09-27", "2013-09-4", "2013-08-01", "2013-06-24", '2013-05-29', '2013-08-20')), ID=c('001', '001', '001', '001', '001', '005'), stringsAsFactors=F)
incdf <- data.frame(Submit.Date=as.Date(c("2013-10-19", "2013-09-14", "2013-08-22", '2013-08-20')), ID=c('001', '001', '002', '006'), stringsAsFactors=F)

我想应用于数据框每一行的函数

myfun <- function(tdate, aid, chg=chgdf, inc=incdf, fdays=30, bdays=30) {
  fdays <- tdate+fdays
  bdays <- tdate-bdays
  chg2 <- chg[chg$ID==aid & chg$Submit.Date<fdays & chg$Submit.Date>bdays, ]
  ret <- nrow(chg2)
  return(ret)
}

适用于一行 inc 数据帧

tdate <- inc[inc$ID==aid, 'Submit.Date'][1]
myfun(tdate, aid='001', bdays=50, fdays=100)

工作但速度慢...使用完整的数据集

inc$chgw <- 0
for(i in 1:nrow(inc)){
  aid <- inc$ID[i]
  tdate <- inc$Submit.Date[i]
  inc$chgw[i] <- myfun(tdate, aid, bdays=50, fdays=100)
}

【问题讨论】:

  • 怀疑该示例是否有效,因为tdate 是一个字符串,您可以像使用myfun 中的数字一样使用它
  • 另见mapply(或等效的Vectorize):Vectorize(myfun)(incdf$Submit.Date, incdf$ID, bdays = 50, fdays = 100)

标签: r date vectorization apply


【解决方案1】:

类似于朱利安的回答:

sapply(
  split(incdf, 1:nrow(incdf)), 
  function(x) do.call(myfun, c(unname(x), bdays=50, fdays=100))
)

这里我不使用apply,因为apply 会将整行强制为同一类型,这可能是不可取的。请注意,我们需要unname(x),因为您的 df 的列名与函数的 args 不同。

【讨论】:

    【解决方案2】:

    首先,当你调用apply时,所有的值都被强制转换为字符串,所以你需要在使用之前转换tdate。否则,您会尝试将天数添加到字符串中:

    tdate <- as.Date(tdate)
    fdays <- tdate+fdays
    bdays <- tdate-bdays
    

    其次,你打电话给apply(inc, 1, myfun)。请注意,在这种情况下,您将单个参数传递给 myfun(整行),而不是 myfun 应该接收的多个参数。

    解决方案 1: 更改您的函数以接收整行数据帧并像您一样调用:

    myfun <- function(row, chg=chgdf, inc=incdf, fdays=30, bdays=30) {
      tdate <- as.Date(row[1])
      fdays <- tdate+fdays
      bdays <- tdate-bdays
      chgdf2 <- chgdf[chgdf$ID==row[2] & chgdf$Submit.Date<fdays & chgdf$Submit.Date>bdays, ]
      ret <- nrow(chgdf2)
      return(ret)
    }
    > apply(inc, 1, myfun)
    [1] 1 2 0 0
    

    解决方案2:使用函数调用中的所有参数调用apply

    myfun <- function(tdate, aid, chg=chgdf, inc=incdf, fdays=30, bdays=30) {
      fdays <- tdate+fdays
      bdays <- tdate-bdays
      chgdf2 <- chgdf[chgdf$ID==aid & chgdf$Submit.Date<fdays & chgdf$Submit.Date>bdays, ]
      ret <- nrow(chgdf2)
      return(ret)
    }
    > apply(inc, 1, function(row) myfun(as.Date(row[1]), row[2]))
    [1] 1 2 0 0
    

    我个人更喜欢第二种解决方案,因为它使您可以更改 myfun 中其他参数的默认值:

    > apply(inc, 1, function(row) myfun(as.Date(row[1]), row[2], bdays=50, fdays=50))
    [1] 2 3 0 0
    

    【讨论】:

      猜你喜欢
      • 2018-01-31
      • 1970-01-01
      • 2019-06-18
      • 1970-01-01
      • 2021-06-25
      • 1970-01-01
      • 2019-11-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多