【问题标题】:R how to use mapply with a data table and two lists of column namesR如何将mapply与数据表和两个列名列表一起使用
【发布时间】:2018-10-09 12:19:56
【问题描述】:

我有一个包含 2x 数据列和两个 id 列的数据表。 id 列是带有值(X2010、X2015、X2020 等)和国家(cty1、cty2 等)的年份。对于每个国家/地区,第一组数据列(f1、f2、f3 等)仅在第一行 (X2010) 中具有值,在其余行中具有 NA。第二组列(x.f1、x.f2、x.f3 等)在第一行中具有 NA,而在其余行中具有不同的值。我想将第一组列中的 NA 替换为每个国家/地区的以下递归结构。

f1.X2015 = f1.X2010 * x.f1.X2015
f1.X2020 = f1.X2015 * x.f1.X2020
...

我已经尝试了以下

foods <- c("f1", "f2", "f3")
x.foods <- c("x.f1", "x.f"2, "x.f3")
res <- c("res.f1", "res.f2", "res.f3")
f.cumprod <- function(x,y) {return(first(x) * cumprod(replace(y), 1,1) * NA^(.I= 1))}

这是我认为可以为 res 列生成值的数据表结构。

DT[,(res) := mapply(FUN = f.cumprod, x = .SD, y = list(x.foods)), .SDcols = foods, by = c("cty")]

这是一个仅适用于一个国家/地区的简化版本

set.seed(24)

 dt <- data.table(cty = c(rep("cty1", 5), rep("cty2", 5), rep("cty3", 5)), year = rep(c("X2010", "X2015", "X2020", "X2025", "X2030"), 3), 
             f1 = rep(c(0.9883415, rep(NA, 4)), 3), f2 = rep(c(1.0685221, rep(NA, 4)), 3), f3 = rep(c(1.0664189, rep(NA, 4)), 3), 
           x.f1 = rep(c(NA, rep(rnorm(4))), 3),   x.f2 = rep(c(NA, rep(rnorm(4))), 3),   x.f3 = rep(c(NA, rep(rnorm(4))), 3))

还有一种笨拙而缓慢的方式来获得其中一种食物的结果,f1。

dt.subset <- dt[, c("f1", "x.f1"), with = FALSE]

for (i in 2:nrow(dt.subset)) {
  dt.subset$f1[i] <- dt.subset$f1[i - 1] * dt.subset$x.f1[i]
}

由于我想为大约 170 个国家和 20 种食品(以及 4 个场景)执行此操作,我希望有一个类似于上述 DT 代码的解决方案。

【问题讨论】:

  • 你想申请哪一个。它是第二个功能还是第一个。顺便说一句,您的示例中有一些错字
  • 我想使用 f.cumprod 或它的某个版本(这是你在另一篇文章中给我的)。如果我了解 cumprod 的工作原理,for 循环给出的结果与 f.cumprod 函数针对单个国家和食物的结果相同。我是否理解您关于哪个功能正确的问题?
  • 您的函数似乎有拼写错误,即.I=1。是.I==1 吗?最好有一个使用mapply 的示例数据,因为"cty" 不在dt
  • 除此之外不清楚replace在做什么cumprod(replace(y), 1,1)这里,我认为是括号不匹配
  • 有一个错字。应该是.I==1。 replace xxx 结构来自@Frank 在stackoverflow.com/questions/50032823/… 的评论中的一些代码。

标签: r data.table


【解决方案1】:

如果我们正在寻找递归函数(对于单个“cty”)

dt.subset[, f1 := Reduce(`*`, x.f1[-1], init = f1[1], accumulate = TRUE)]

或与accumulate 来自purrr

library(purrr)
dt.subset[, f1 := accumulate(x.f1[-1], ~ .x * .y, .init = f1[1])]

基于 OP 的数据 'dt',我们可以将melt 转换为 'long' 形式,然后将带有 accumulatedcast 的函数应用回 'wide'

out <- dcast(melt(dt, measure = patterns("^f\\d+", "^x\\.f\\d+"))[, 
  accumulate(value2[-1], ~ .x * .y, .init = value1[1]), .(variable, cty)], 
  cty + rowid(variable) ~ variable, value.var = "V1")
nm1 <- grep("^f\\d+$", names(dt), value = TRUE)
setnames(out, -(1:2), nm1)

然后set 具有新值的感兴趣的列

for(j in nm1) set(dt, i= NULL, j= j, value = out[[j]])
dt
#     cty  year          f1         f2           f3       x.f1       x.f2         x.f3
# 1: cty1 X2010  0.98834150  1.0685221  1.066418900         NA         NA           NA
# 2: cty1 X2015 -0.53951661  0.9055298 -0.904717849 -0.5458808  0.8474600 -0.848370044
# 3: cty1 X2020 -0.28949668  0.2408908 -0.002091656  0.5365853  0.2660220  0.002311942
# 4: cty1 X2025 -0.12147951  0.1070965  0.002754518  0.4196231  0.4445853 -1.316908124
# 5: cty1 X2030  0.07089875 -0.0499600  0.001647943 -0.5836272 -0.4664951  0.598269113
# 6: cty2 X2010  0.98834150  1.0685221  1.066418900         NA         NA           NA
# 7: cty2 X2015 -0.53951661  0.9055298 -0.904717849 -0.5458808  0.8474600 -0.848370044
# 8: cty2 X2020 -0.28949668  0.2408908 -0.002091656  0.5365853  0.2660220  0.002311942
# 9: cty2 X2025 -0.12147951  0.1070965  0.002754518  0.4196231  0.4445853 -1.316908124
#10: cty2 X2030  0.07089875 -0.0499600  0.001647943 -0.5836272 -0.4664951  0.598269113
#11: cty3 X2010  0.98834150  1.0685221  1.066418900         NA         NA           NA
#12: cty3 X2015 -0.53951661  0.9055298 -0.904717849 -0.5458808  0.8474600 -0.848370044
#13: cty3 X2020 -0.28949668  0.2408908 -0.002091656  0.5365853  0.2660220  0.002311942
#14: cty3 X2025 -0.12147951  0.1070965  0.002754518  0.4196231  0.4445853 -1.316908124
#15: cty3 X2030  0.07089875 -0.0499600  0.001647943 -0.5836272 -0.4664951  0.598269113

-在应用 OP 函数后检查第一个 'cty' 的 'dt.subset' 的值

dt.subset
#            f1       x.f1
#1:  0.98834150         NA
#2: -0.53951661 -0.5458808
#3: -0.28949668  0.5365853
#4: -0.12147951  0.4196231
#5:  0.07089875 -0.5836272

或者我们可以使用Map 来做到这一点

dt[, (foods) := Map(function(x, y) accumulate(y[-1], `*`, .init = x[1]),
           mget(foods), mget(x.foods)), by = .(cty)]
dt
#     cty  year          f1         f2           f3       x.f1       x.f2         x.f3
# 1: cty1 X2010  0.98834150  1.0685221  1.066418900         NA         NA           NA
# 2: cty1 X2015 -0.53951661  0.9055298 -0.904717849 -0.5458808  0.8474600 -0.848370044
# 3: cty1 X2020 -0.28949668  0.2408908 -0.002091656  0.5365853  0.2660220  0.002311942
# 4: cty1 X2025 -0.12147951  0.1070965  0.002754518  0.4196231  0.4445853 -1.316908124
# 5: cty1 X2030  0.07089875 -0.0499600  0.001647943 -0.5836272 -0.4664951  0.598269113
# 6: cty2 X2010  0.98834150  1.0685221  1.066418900         NA         NA           NA
# 7: cty2 X2015 -0.53951661  0.9055298 -0.904717849 -0.5458808  0.8474600 -0.848370044
# 8: cty2 X2020 -0.28949668  0.2408908 -0.002091656  0.5365853  0.2660220  0.002311942
# 9: cty2 X2025 -0.12147951  0.1070965  0.002754518  0.4196231  0.4445853 -1.316908124
#10: cty2 X2030  0.07089875 -0.0499600  0.001647943 -0.5836272 -0.4664951  0.598269113
#11: cty3 X2010  0.98834150  1.0685221  1.066418900         NA         NA           NA
#12: cty3 X2015 -0.53951661  0.9055298 -0.904717849 -0.5458808  0.8474600 -0.848370044
#13: cty3 X2020 -0.28949668  0.2408908 -0.002091656  0.5365853  0.2660220  0.002311942
#14: cty3 X2025 -0.12147951  0.1070965  0.002754518  0.4196231  0.4445853 -1.316908124
#15: cty3 X2030  0.07089875 -0.0499600  0.001647943 -0.5836272 -0.4664951  0.598269113

或者如果我们使用cumprod(OP 的f.cumprod 函数中有一些错误)。可以改成

f.cumprod <- function(x, y)  cumprod(c(x[1], y[-1]))
dt[, (foods) := Map(f.cumprod,  mget(foods), mget(x.foods)), by = .(cty)]
dt
#     cty  year          f1         f2           f3       x.f1       x.f2         x.f3
# 1: cty1 X2010  0.98834150  1.0685221  1.066418900         NA         NA           NA
# 2: cty1 X2015 -0.53951661  0.9055298 -0.904717849 -0.5458808  0.8474600 -0.848370044
# 3: cty1 X2020 -0.28949668  0.2408908 -0.002091656  0.5365853  0.2660220  0.002311942
# 4: cty1 X2025 -0.12147951  0.1070965  0.002754518  0.4196231  0.4445853 -1.316908124
# 5: cty1 X2030  0.07089875 -0.0499600  0.001647943 -0.5836272 -0.4664951  0.598269113
# 6: cty2 X2010  0.98834150  1.0685221  1.066418900         NA         NA           NA
# 7: cty2 X2015 -0.53951661  0.9055298 -0.904717849 -0.5458808  0.8474600 -0.848370044
# 8: cty2 X2020 -0.28949668  0.2408908 -0.002091656  0.5365853  0.2660220  0.002311942
# 9: cty2 X2025 -0.12147951  0.1070965  0.002754518  0.4196231  0.4445853 -1.316908124
#10: cty2 X2030  0.07089875 -0.0499600  0.001647943 -0.5836272 -0.4664951  0.598269113
#11: cty3 X2010  0.98834150  1.0685221  1.066418900         NA         NA           NA
#12: cty3 X2015 -0.53951661  0.9055298 -0.904717849 -0.5458808  0.8474600 -0.848370044
#13: cty3 X2020 -0.28949668  0.2408908 -0.002091656  0.5365853  0.2660220  0.002311942
#14: cty3 X2025 -0.12147951  0.1070965  0.002754518  0.4196231  0.4445853 -1.316908124
#15: cty3 X2030  0.07089875 -0.0499600  0.001647943 -0.5836272 -0.4664951  0.598269113

注意:每个“cty”的值都相同,因为每个“cty”的示例数据集值都相同

【讨论】:

  • 这是一个很好的答案;详细,多个选项,纠正了我的问题中的错误!尽管有规则,我还是要说 - 非常感谢!
猜你喜欢
  • 1970-01-01
  • 2012-12-29
  • 1970-01-01
  • 2021-05-14
  • 2016-05-12
  • 2019-10-17
  • 1970-01-01
  • 2020-02-24
  • 2019-04-16
相关资源
最近更新 更多