我有一个数据表,例如:
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::代码解释
代码的作用:
- 它用上一行的
Lat
值填充Prevlat
列 - 它标识所有
Lat
为 NA 和PrevLat
具有值(即 不不适用) - 对于在第 2 步中识别的所有行,根据您提供的函数计算
Lat
的值
重复步骤1到3,直到校验is.na(atable$Lat)
的和等于0,当满足这个条件时,就不再有NA-Lat
列中的值...因此我们可以使用 break
退出 repeat
循环。
关于R中有条件的滚动计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58562719/