R中有条件的滚动计算

标签 r

我有一个数据表,例如:

 CurrOdo        Lat            NextLat       PrevODO        NextOdo
 2.62           30.01115868   30.01115868           
 5.19           30.01116407   30.01116407       
 7.61           30.01116919   30.01116919       
18.82                         30.01119282     7.61        19.06
19.06           30.01119282   30.01119282       
19.35           30.01119339   30.01119339       
20.54                         30.01122998     19.35       81.5
20.81                         30.01122998     20.54       81.5
37.38                         30.01122998     20.81       81.5
81.5            30.01132238   30.01132238   

atable<-data.table(odo = c(2.62,5.19,7.61,18.82,19.06,19.35,20.54,20.81, 37.38,81.5 ), 
Lat = c(30.01115868,30.01116407,30.01116919,NA,30.01119282,30.01119339,NA,NA, NA, 30.01132238),
NextLat=c(30.01115868,30.01116407,30.01116919, 30.01119282, 30.01119282,30.01119339, 
30.01122998,30.01122998,30.01122998,30.01122998 ),
PrevLat=c(NA,NA,NA, NA, NA,NA, NA,NA,NA,NA ),
PrevODO=c(NA,NA,NA, 7.61, NA,NA, 19.35,20.54,20.81,NA ),
NextOdo=c(NA,NA,NA, 19.06, NA,NA, 81.5,81.5,81.5,NA )) 

Lat 值是基于此公式的滚动计算:

纬度:(NextLat- PrevLat) * ((CurrODO - PrevODO)/(NextODO - PrevODO)) + PrevLat

如何计算 Lat 的示例

Row CurrODO 18.82:   (30.01119282- 30.01116919) * (( 18.82 - 7.61) / (19.06 - 7.61)) + 30.01116919
Row CurrODO 20.54:  (30.01122998- 30.01119339) * ((  20.54 - 19.35) / (81.5 - 19.35)) + 30.01119339
Row CurrODO 20.81:   (30.01122998- Lat calc result from 20.54 row) * ((20.81 - 20.54) / (81.5 - 20.54)) + Lat calc result from 20.54 row
Row CurrODO 37.38:   (30.01122998- Lat calc result from 20.81 row) * (( 37.38 - 20.81) / (81.5 - 20.81)) + Lat calc result from 20.81 row

最终结果是:

CurrOdo     Lat             NextLat         PrevODO     NextOdo
2.62        30.01115868     30.01115868             
5.19        30.01116407     30.01116407             
7.61        30.01116919     30.01116919             
18.82       30.0111923247   30.01119282      7.61        19.06  
19.06       30.01119282     30.01119282             
19.35       30.01119339     30.01119339             
20.54       30.0111940906   30.01122998      19.35       81.5   
20.81       30.0111942496   30.01122998      20.54       81.5   
37.38       30.0112040049   30.01122998      20.81       81.5   
81.5        30.01132238     30.01132238             

我目前正在 SQL Server 中循环运行它,但这需要很长时间。我也可以将它与 R 放在一个循环中,但是它在大型数据集上表现不佳。我已经坚持了好几天了,所以感谢您的帮助!

最佳答案

我的回答涉及一个重复循环,虽然你说“没有循环”,但我没有看到任何其他方式(当然可能有,这是 R ;-))。< br/> 虽然循环应该执行得非常快,但在我的系统上,它需要大约一秒钟的时间来填充 1000 万行的 NA(参见基准测试)。

Lat 的输出与问题中所需的输出匹配。

旁注:
如果您的第一个 Lat 值为 NA,您可能会遇到问题。
因为 PrevLat 在第一行总是 NA,所以 Lat 的第一行 NA 永远不会被重新计算,循环也永远不会中断。
您(当然)可以在循环中构建逃生路线/中断以防止这种情况发生。我保留了这一点,以保持示例的可读性和简短性。

repeat{
  #until there are no more NA in Lat
  if( sum( is.na( atable$Lat ) ) == 0 ){
    break
  }
  #(re)calculate PrevLat
  atable[, PrevLat := shift( Lat, 1, type = "lag" ) ]
  #calculate Lat when PrevLat is known, but Lat is not
  atable[ is.na( Lat ) & !is.na( PrevLat ),
          Lat := (NextLat-PrevLat)*((odo-PrevODO)/(NextOdo-PrevODO))+PrevLat ]
}

#       odo           Lat     NextLat       PrevLat PrevODO NextOdo
# 1:   2.62 30.0111586800 30.01115868            NA      NA      NA
# 2:   5.19 30.0111640700 30.01116407 30.0111586800      NA      NA
# 3:   7.61 30.0111691900 30.01116919 30.0111640700      NA      NA
# 4:  18.82 30.0111923247 30.01119282 30.0111691900    7.61   19.06
# 5:  19.06 30.0111928200 30.01119282 30.0111923247      NA      NA
# 6:  19.35 30.0111933900 30.01119339 30.0111928200      NA      NA
# 7:  20.54 30.0111940906 30.01122998 30.0111933900   19.35   81.50
# 8:  20.81 30.0111942496 30.01122998 30.0111940906   20.54   81.50
# 9:  37.38 30.0112040049 30.01122998 30.0111942496   20.81   81.50
# 10: 81.50 30.0113223800 30.01122998            NA      NA      NA

基准

在 10M 行的 data.table 上(您的 atable 重复了 1M 次);
在我的系统上(+/- 6 岁的 i5,内存为 16Gb),循环大约需要一秒钟来计算每个纬度的值。

dt <- atable[rep(atable[, .I], 1000000)]

system.time(
  repeat{
    #until there are no more NA in Lat
    if( sum( is.na( dt$Lat ) ) == 0 ){
      break
    }
    #(re)calculate PrevLat
    dt[, PrevLat := shift( Lat, 1, type = "lag" ) ]
    #calculate Lat when PrevLat is known
    dt[ is.na( Lat ) & !is.na( PrevLat ),
            Lat := (NextLat- PrevLat ) * ((odo - PrevODO) / (NextOdo - PrevODO)) + PrevLat ]
  }
)

# user  system elapsed 
# 0.90    0.35    1.08

session 信息

R version 3.6.1 (2019-07-05)   
Platform: x86_64-w64-mingw32/x64 (64-bit)    
Running under: Windows 10 x64 (build 18362)      

other attached packages:    [1] data.table_1.12.4

update::代码解释

代码的作用:

  1. 它用上一行的 Lat 值填充 Prevlat
  2. 它标识所有 LatNA PrevLat 具有值(即 不适用)
  3. 对于在第 2 步中识别的所有行,根据您提供的函数计算 Lat 的值

重复步骤1到3,直到校验is.na(atable$Lat)的和等于0,当满足这个条件时,就不再有NA-Lat 列中的值...因此我们可以使用 break 退出 repeat 循环。

关于R中有条件的滚动计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58562719/

相关文章:

r - 如何在 R 中显示两个日期之间发生的事件

使用 cut() 添加十分位数列时接收 NA

python - 使用带有 g-recaptcha-response 参数的 POST 提交表单

r - devtools::document vs roxygen2::roxygenize

r - ompr 目标 : minimize variance of rowsums

r - 在 r 中显示 80% 线箱线图

python - R/python 向量中的 "grouped/clustered"区域

r - 如何改进 R 中 for 循环中的简单减法?

r - 使用 R 绘图在 R 中绘制点图

r - 如何在Shiny中自动“调整大小” ggplot?