跳到主要內容

第一次的 StackOverflow

今天為一個用 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

哎呀哎呀。

留言

這個網誌中的熱門文章

尿管水球考

Photo credit: Crystal Explosion via photopin (license)   那約莫是intern到一半的時候。記得那天我放尿管就要大功告成,隨手拿起換藥車上的空針想把固定用的水球打起來結束這回合的時候,碰巧路過的護理師一個飛身順手抄起空針: 「且住!你這針筒裡面裝的是……生理食鹽水吧!」   我定睛一看,啊呀,落在換藥車桌面上的空罐子果然是生理食鹽水,顯然是在抽的時候沒有專心。 「多謝女俠提醒,不過……那可以幫我抽一管純水嗎?我得扶著尿管,不太方便。」

ImageJ (1.51f) 在Mac OS 10.12 (Sierra)中會因為權限管理而無法使用Plugin

問題描述: 在將下載後的ImageJ資料夾搬到應用程式資料夾中後,程式可以使用但Plugin功能表下的項目消失。 系統資訊: OS Version: Mac OS 10.12 ImageJ: 1.51f  JAVA Version: 1.6.0_65 according to About ImageJ 1.8.0_111-b14 according to Control Panel Memory Assigned: 2854k of 7000MB ( No error message 原因: Mac OS 10.12為了解決使用者權限管理的漏洞,在執行應用程式時會建立一個隨機路徑的唯讀資料夾並把.app複製過去在其中執行(Gatekeeper Path Randomization)。這個作法會讓某些需要呼叫其他檔案的程式無法正常作用。   在ImageJ上,如果在Image>Show Info功能表(或Command + I)中的「ImageJ Home:」後面的路徑的開頭是"/private",那就可能是Gatekeeper Path Randomization在作怪。   將執行檔從應用程式資料夾中複製到桌面(Option+拖曳)後刪掉原檔再把執行檔複製回去可以修正這個權限問題。 參考資料: Sierra and Gatekeeper Path Randomization Kind and timely support from Wayne Rasband (NIH/NIMH)

使用β-lactam類藥物時是否需要先做Penicillin skin test?:從醫學與法律探討

View image | gettyimages.com 這個問題應該困擾很多人很久,尤其是實習醫生們被雜事追著跑之餘還要記十五分鐘後要看結果,這根本是剛好會忘記的時間長度嘛! 所以說,除了各院的內規之外,從醫學上來看到底什麼時候應該要做Penicillin skin test?而從法律的觀點來看,每天Penicillin skin test真的能讓訴訟遠離我嗎?