Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/73.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
R 使用apply函数更新范围外变量_R_Data.table - Fatal编程技术网

R 使用apply函数更新范围外变量

R 使用apply函数更新范围外变量,r,data.table,R,Data.table,我正在尝试循环遍历data.table并对数据执行某些处理: 提供基于每行组合输出的输出 加工 在一个名为 statsTable,在流程的此阶段和其他阶段更新 实际的处理过程更为复杂,每次apply迭代的输出中都包含了记录,并且比下面我为这个问题简化的代码要大 然而,我看不到如何更新statsTable,因为lapply通过设计防止了这种情况的发生,我相信这样函数就不会产生意外的后果——因此处理时间保持在零。有并没有办法做到这一点,并且仍然使用其中一个apply函数?我知道我可以使用for循环,

我正在尝试循环遍历data.table并对数据执行某些处理:

提供基于每行组合输出的输出 加工

在一个名为 statsTable,在流程的此阶段和其他阶段更新

实际的处理过程更为复杂,每次apply迭代的输出中都包含了记录,并且比下面我为这个问题简化的代码要大

然而,我看不到如何更新statsTable,因为lapply通过设计防止了这种情况的发生,我相信这样函数就不会产生意外的后果——因此处理时间保持在零。有并没有办法做到这一点,并且仍然使用其中一个apply函数?我知道我可以使用for循环,但如果可能的话,我宁愿不使用

mainTable <- data.table(year = rep(2016:2020), value = runif(5, min=0, max=50000000))
statsTable <- data.table(year = rep(2016:2020), procTime = 0)
setkey(statsTable, year) 

output <- bind_rows(lapply(mainTable$year, function(fileYear) {
  randomValue = as.integer(mainTable[year == fileYear]$value)
  print(paste0(fileYear, ":", randomValue))
  start <- proc.time()[[3]]
  for(i in 1:randomValue) {}
  elapsed = proc.time()[[3]]- start
  statsTable[year == fileYear]$procTime = elapsed
  print(elapsed)
  data.table(year = fileYear, loopsPerSecond = randomValue / elapsed)
}))
print(output)
print(statsTable)

到达应用函数外部变量的一种方法可以是到达应用函数外部变量的一种方法可以是您正在使用的data.table,但是对一些规范的data.table有一点了解,因此首先我将推荐一些关于data.table essentials的小插曲,请参见此处:

特别是,如果statsTable是data.table,则不应使用=将行分配给statsTable,而应使用data.table分配运算符::=:

这绕过了您原始问题中的问题,因为作业是在没有副本的情况下完成的,因此您使用的是data.table,但对一些规范的data.table有点不了解,因此首先我将推荐一些小案例来复习data.table要点,请参见此处:

特别是,如果statsTable是data.table,则不应使用=将行分配给statsTable,而应使用data.table分配运算符::=:

这回避了你原来问题中的问题,因为作业是在没有副本的情况下完成的,所以也许,lapply不是满足OP期望的最佳选择

OP希望他的手术有两个结果

结果输出和 statsTable的更新版本 不幸的是,根据文档,lappy返回一个与X长度相同的列表,其中的每个元素都是对X的相应元素应用FUN的结果

我建议使用for循环迭代mainTable$year并同时更新这两个结果,而不是扭曲lappy:

out_list <- vector("list", length(mainTable$year))
for (idx in seq_along(mainTable$year)) {
  fileYear <- mainTable$year[idx]
  randomValue = as.integer(mainTable[idx, "value"])
  cat(fileYear, ":", randomValue, "\n")
  start <- proc.time()[[3]]
  for(i in 1:randomValue) {}
  elapsed = proc.time()[[3]]- start
  statsTable[year == fileYear]$procTime = elapsed
  cat(elapsed, "\n")
  out_list[[idx]] <- data.table(year = fileYear, loopsPerSecond = randomValue / elapsed)
}
output <- rbindlist(out_list)
print(output)
也许,lapply不是满足OP期望的最佳选择

OP希望他的手术有两个结果

结果输出和 statsTable的更新版本 不幸的是,根据文档,lappy返回一个与X长度相同的列表,其中的每个元素都是对X的相应元素应用FUN的结果

我建议使用for循环迭代mainTable$year并同时更新这两个结果,而不是扭曲lappy:

out_list <- vector("list", length(mainTable$year))
for (idx in seq_along(mainTable$year)) {
  fileYear <- mainTable$year[idx]
  randomValue = as.integer(mainTable[idx, "value"])
  cat(fileYear, ":", randomValue, "\n")
  start <- proc.time()[[3]]
  for(i in 1:randomValue) {}
  elapsed = proc.time()[[3]]- start
  statsTable[year == fileYear]$procTime = elapsed
  cat(elapsed, "\n")
  out_list[[idx]] <- data.table(year = fileYear, loopsPerSecond = randomValue / elapsed)
}
output <- rbindlist(out_list)
print(output)

您提到的out_list@Liman实际用例与示例代码不同。请查看并尝试将我的建议改编为您自己的代码,看看您是否受到性能下降的影响。如果是这样的话,我可以建议一个不会成为同一问题受害者的替代方案。我知道@Chris提出的主要问题是data.table statsTable的procTime列没有在lapply内部得到更新。具体来说,问题是是否有一种方法可以做到这一点,并且仍然使用其中一个apply函数?。所以,当你说我的实际用例与我的示例代码不同时,我真的不理解你的意思。@Liman我指的是你Q中的这一段,实际处理更复杂@MichaelChirico@克里斯问的是问题,不是我:@MichaelChirico和Liman,谢谢,这真的很有趣-我已经看了这个小插曲,可以看到DT比我想象的更多。我可以看出,您已经用遍历表的data.table函数替换了apply。我只有几个问题。如果我想按照我的原始版本合并每个迭代结果创建的行,我是否需要在每个迭代中包含一个绑定到另一个data.table的行?在语法中,我看不出.assignment适合于{}。你的意思是说这种方法运行较慢,有办法解决吗?谢谢,克里斯。@Liman您提到的实际用例与示例代码不同。请查看并尝试将我的建议改编为您自己的代码,看看您是否受到性能下降的影响。如果是这样的话,我可以建议一个不会成为同一问题受害者的替代方案。我知道@Chris提出的主要问题是data.table statsTable的procTime列没有在lapply内部得到更新。具体来说,问题是是否有一种方法可以做到这一点,并且仍然使用其中一个apply函数?。所以,当你说我的实际用例与我的示例代码不同时,我并不真正理解你的观点。@Liman我指的是这个
在你的Q中的s段,实际处理更复杂@MichaelChirico@克里斯问的是问题,不是我:@MichaelChirico和Liman,谢谢,这真的很有趣-我已经看了这个小插曲,可以看到DT比我想象的更多。我可以看出,您已经用遍历表的data.table函数替换了apply。我只有几个问题。如果我想按照我的原始版本合并每个迭代结果创建的行,我是否需要在每个迭代中包含一个绑定到另一个data.table的行?在语法中,我看不出.assignment适合于{}。你的意思是说这种方法运行较慢,有办法解决吗?谢谢,克里斯。
# print(statsTable)
#   year procTime
# 1: 2016    1.071
# 2: 2017    0.496
# 3: 2018    0.623
# 4: 2019    0.771
# 5: 2020    0.941
statsTable[ , procTime := elapsed]
mainTable[ , by=year, {
  randomValue = as.integer(value)
  cat(sprintf('%d:%d\n', .BY$year, randomValue))
  start <- proc.time()[[3L]]
  for(i in 1:randomValue) {}
  elapsed = proc.time()[[3L]]- start
  statsTable[.BY, procTime := elapsed]
  print(elapsed)
  .(loopsPerSecond = randomValue / elapsed)
}]
out_list <- vector("list", length(mainTable$year))
for (idx in seq_along(mainTable$year)) {
  fileYear <- mainTable$year[idx]
  randomValue = as.integer(mainTable[idx, "value"])
  cat(fileYear, ":", randomValue, "\n")
  start <- proc.time()[[3]]
  for(i in 1:randomValue) {}
  elapsed = proc.time()[[3]]- start
  statsTable[year == fileYear]$procTime = elapsed
  cat(elapsed, "\n")
  out_list[[idx]] <- data.table(year = fileYear, loopsPerSecond = randomValue / elapsed)
}
output <- rbindlist(out_list)
print(output)
   year loopsPerSecond
1: 2016       71127692
2: 2017       79373691
3: 2018       96125167
4: 2019       90166990
5: 2020       83897274
print(statsTable)
   year procTime
1: 2016     0.24
2: 2017     0.11
3: 2018     0.03
4: 2019     0.29
5: 2020     0.38