Re: [问题] 如何快速计算内插多个字段数值

楼主: celestialgod (天)   2023-08-02 12:36:28
※ 引述《studioA (understand?)》之铭言:
: [软件熟悉度]:
: 入门(写过其他程式,只是对语法不熟悉)
: [问题叙述]:
: 我有一组数据如下,因为对方系统给的数据跨日整点 00:00的数据传输有异常
: 如下所示
: 日期 时间 参数A 参数B 参数C 参数D
: 2023-07-02 23:54 25 100 33 99
: 2023-07-02 23:57 25.1 128 40 89
: 2023-07-03 0:00
: 2023-07-03 0:03 25.8 111 52 101
: 2023-07-03 23:54 25.6 120 39 103
: 2023-07-04 23:57 27 157 55 88
: 2023-07-04 0:00
: 2023-07-04 0:03 24.6 155 48 93
: 我想使用内插法,上下数据取平均把各参数内插补资料进去,但因为字段太多,日期也有近2万笔
: 用一般for 循环发现跑很慢 然后我用apply 却跑不出来,求解
: [程式范例]:
: cal <- colnames(data)[-c(1:2)]
: for(i in cal){
: xset <- which(data$时间=="00:00")
: for(j in xset ){
: data[j,i] <- (data[j+1,i]+data[j-1,i])/2
: }
: }
: [环境叙述]:
:
: 请提供 sessionInfo() 的输出结果,
: R version 4.2.3 (2023-03-15 ucrt)
: Platform: x86_64-w64-mingw32/x64 (64-bit)
: Running under: Windows 10 x64 (build 22621)
: Matrix products: default
: locale:
: [1] LC_COLLATE=Chinese (Traditional)_Taiwan.utf8 LC_CTYPE=Chinese
: (Traditional)_Taiwan.utf8
: [3] LC_MONETARY=Chinese (Traditional)_Taiwan.utf8
: LC_NUMERIC=C
: [5] LC_TIME=Chinese (Traditional)_Taiwan.utf8
:
: [关键字]:
:
library(data.table)
# 生成30万笔资料 每小时一笔
# 不失一般性下 生成四个字段 parameter a,b,c,d
n_rows <- 300000
time_count <- 24
time_hour <- seq(0, 1440, length = time_count+1)/60
time_minute <- seq(0, 1440, length = time_count+1)%%60
num_days <- n_rows/time_count
dt <- data.table(
date = rep(as.Date("2023-07-01")+seq_len(num_days)-1, each=time_count),
time = rep(sprintf("%02i:%02i", time_hour[-length(time_hour)],
time_minute[-length(time_minute)]), num_days),
para_a = rnorm(n_rows, 5),
para_b = rnorm(n_rows, 5),
para_c = rnorm(n_rows, 5),
para_d = rnorm(n_rows, 5)
)
para_columns <- c("para_a", "para_b", "para_c", "para_d")
# 挖空00:00的资料
dt[time == "00:00", para_columns] <- NA_real_
df <- as.data.frame(dt)
# 单字段做法范例
dt[ , para_a := ifelse(is.na(para_a),
(shift(para_a, 1L) + shift(para_a, -1L))/2, para_a)]
# 多字段做法范例 with data.table syntax
system.time({
dt[ , (para_columns) := lapply(para_columns, function(col)
ifelse(is.na(get(col)), (shift(get(col), 1L) + shift(get(col), -1L))/2,
get(col)))]
})
# User System Elapsed
# 0.00 0.00 0.04
# 多字段做法范例二 with data.frame syntax + for loop on columns
system.time({
for (col in para_columns) {
# with data.table shift
df[ , col] <- ifelse(is.na(df[[col]]), (shift(df[[col]], 1L) +
shift(df[[col]], -1L))/2, df[[col]])
}
})
# User System Elapsed
# 0.03 0.00 0.06
以上供参考
切记data.frame一步步更新是非常慢的
这样写的话 三十万笔资料也是瞬间就做完了
当然这还有优化空间 可以只抓00:00的资料来更新
但是除非资料超过几亿 不然那样写 花的时间成本超过跑的成本
作者: joshddd (joshddd)   2023-08-02 19:29:00
我觉得他的资料蛮整齐的https://i.imgur.com/dJ1F9en.jpg缺少值刚好夹在中间,我把原po 的程式码改成01:00模拟刚好夹在中间的情况,直接上下平移然后相加取平均就好如果刚好在头尾的话 写个判断式处理头尾 中间就一样,nrow 一亿笔大概都2秒内跑完
作者: hohiyan (海洋)   2023-08-03 00:49:00
楼上的简洁有力

Links booklink

Contact Us: admin [ a t ] ucptt.com