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 ;-))。
该循环应该执行得非常快,在我的系统上,在 10M 行中填充 NA 大约需要一秒钟(请参阅基准)。
Lat 的输出与问题中所需的输出相匹配。
旁注:如果你的第一个有 value
,你可能会遇到问题。
因为第一行总是 NA,所以永远不会重新计算 Lat 的第一行 NA,并且循环永远不会中断。
您(当然)可以在循环中构建一个逃生路线/中断来防止这种情况发生。我保留了这一点,以保持示例的可读性和简短性。Lat
NA
PrevLat
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
会话信息
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:: 代码说明
代码的作用:
Prevlat
它用上一行的Lat
-value填充列- 它标识了所有行在哪里
Lat
是NA 并且哪里PrevLat
有一个值(即不是NA) - 对于步骤 2中标识的所有行
Lat
,根据您提供的函数计算 的值
重复步骤 1 到 3,直到检查的总和is.na(atable$Lat)
等于 0。当满足此条件时,列中不再有NA值Lat
。所以我们可以使用 . 退出repeat
-loop break
。
推荐阅读
- scilab - xcos中如何使用exp(x)?
- mysql - Mysql v5.1/RHEL6 转储到 MariaDB v10.3/RHEL7 恢复过程
- javascript - 未将图像数据发送到用于 base64 图像 javascript 的 Imgur API
- ubuntu - 如何解决在 Ubuntu 上从源代码安装 GridDb 的错误?
- javascript - 在 foreach 循环中单击时禁用选定的锚按钮
- android - DialogFragment 在全屏对话框上设置黑色状态栏
- pine-script - TradingView Pine 编辑器获取标签的实际价格
- vue.js - nuxt ssr false 设置代理 javascript
- mongodb - 将对象数组转换为该对象的值数组
- scipy - 最小化标量的应用