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