今天為一個用 R 畫畫的小腳本第一次到傳說中的萬事屋 StackOverflow 去發問了,謹為文記念。
在我一拐一拐學著 R 的過程中,帶我前進的拉力的成分幾乎全是 StackOverflow (至於推力嘛,當然就是在實驗室生活中越養越肥美的懶病),如果沒有它,我想寫出來偷懶的腳本十個有十一個會寫到 library(stringr)
就結束囉。
今天的問題來自之前為了把電位測定的紀錄畫成圖而寫的腳本,是個裡面充滿巢狀的 for - loop 迴圈的恐怖玩意,它雖然會動但因為難以讀懂所以也不太可能再加功能進去。無奈我發下豪語說「啊,這個反正用 R 弄很快」的那個心血來潮只生出個別樣本的電位圖,至於總結的摘要圖當時就沒做了。
不過說到底,最重要的根本就是總結圖……
動手改的過程當中對於執行速度之緩慢感到不耐煩,想起之前看過的讀取速度比較文,我決定歸咎給最開始的 read.table()
跑太慢,目前讀一個原始檔大概要花十秒。
開開心心的戴入 data.table 套件,我理想的流程是這樣的:把讀取的部分用 fread()
重寫一次,然後進到後面的迴圈海整理出可讀的版本再往下做。事實上……
Error in fread("test.txt", fill = TRUE, sep = "\t", quote = "", header = FALSE) :
Expecting 3 cols, but line 258088 contains text after processing all cols. Try again with fill=TRUE. Another reason could be that fread's logic in distinguishing one or more fields having embedded sep=' ' and/or (unescaped) '\n' characters within unbalanced unescaped quotes has failed. If quote='' doesn't help, please file an issue to figure out if the logic could be improved.
好吧(´・ω・`)
我進到原始檔,發現第 258088 列在實驗時做了註記,顯然 fread()
讀取到這裡發現多了一行感到無法接受了。
可是一般來說這個問題應該要被 fill = TRUE
(如果每列行數不同的話則填入 NA
)解決才對呀?fread()
的說明上寫說它會自動偵測前幾列的格式來決定讀取的方式,所以我進一步試試讓它從錯誤的附近開始讀。
fread("test.txt", fill = TRUE, header = FALSE, sep = "\t", skip = 250000)
一樣的錯誤訊息(´・ω・`)
fread("test.txt", fill = TRUE, header = FALSE, sep = "\t", skip = 258080)
問題就解決了……嗯不對,其實沒有,大半的檔案根本都被放棄掉了。
於是我就上了 StackOverflow,這邊網友回文的速度真的是有夠快,難怪能夠累積出我不管碰到什麼怪異問題都能在這找出答案的資訊量。
得到的答案包括:
何不用
read.table()
在標頭的地方強行新開一行讓註解有地方放就不會跳錯誤囉
先強行把原檔沒註解的部分都填個 tab 上去讓 R 知道要多分一行出來
你可以先不分列讀(用readLines()
),然後再用tstrsplit()
之類的方法把它拆開
雖然先把原檔的格式修正是概念上最正確的作法,無奈儀器吐出來的格式就是這樣子,而另外修正它會比用 read.table()
讀花上更多時間,所以大部分的回答最後都以長知識的效果為主。
最後一個想法倒是勾起我的興趣,如果使用 fread()
先讀再切會不會還是比較快呢?
microbenchmark(
tstrsplit(unlist(fread("test.txt", sep = "\n", data.table = F)), "\t", type.convert = T, names = T, keep = 1:4),
read.table("test.txt", header = F, sep = "\t", fill = T),
times = 1)
結果手動拆開就比直接用 read.table()
讀慢了:
Unit: seconds
expr
tstrsplit(unlist(fread("test.txt", sep = "\\n", data.table = F)), "\\t", type.convert = T, names = T, keep = 1:4)
read.table("test.txt", header = F, sep = "\\t", fill = T)
min lq mean median uq max neval
2.185109 2.185109 2.185109 2.185109 2.185109 2.185109 1
1.611715 1.611715 1.611715 1.611715 1.611715 1.611715 1
哎呀哎呀。
留言
張貼留言