最近我們 Lab 有一個 case,據說會是我們這一屆最後的一個 case。這個 case 其實存在已久,我之前曾經用 PHP + MySQL 寫了一個版本,這個版本後來因為 requirements 改來改去,我一開始也沒做好設計,只求快速結案,於是 bug 滿天飛,最後決定砍掉重練。其實 bug 太多只是砍掉重練的其中一個理由,更大的原因是我希望大家能夠多分擔一點工作,畢竟這是 Lab 的大家都有責任的 case。
重新開始時,我們首先有幾個決定:
- 程式語言、資料庫的選擇?
- 資料庫要不要正規化?正規化到什麼程度?
- 如何分工?
我們的決定是 C# + MySQL,因為 C# 大家都不熟,但是為了論文大家都得用到,可以一起學習———我用 C# 寫了論文實驗的前置處理程式,大家得學會看懂它、修改它。資料庫也下定決心重新正規化,至於分工方面,由於這個 case 環環相扣,我們、或者說我實在不知道怎麼分,最後分得似乎有些不公平,不過這應該是大家第一次、也是最後一次,動員整個 lab 一起進行一個 case,我覺得很感人。
根據這次的經驗,我覺得我不是一個好的 PM 或一個好的 Senior———我早該知道的,但我沒有改進。我不知道如何控制進度,才第一次開工就讓大家一起吃了早餐,當天其實我也很累,不過看大家都沒走,我也不敢走。PM 實在是一個深奧的職業,要怎麼樣保持良好關係又能及時交付,我實在是想不出好方法。
猴子有問題問我時,我的態度有時、或者可能是通常都不是很好———剛開始如此,我後來有特別注意措詞、語氣,希望給人的感覺確實有所改善。猴子的 C# 沒有比其他人更熟,甚至我覺得他可能連最根本的程式基礎都沒有打好,他非常認真,但他還是被我唸最多的。猴子大概兩年來都是扮演受害者的角色,最近我開始感覺他可能只是想要扮演一個深入大家的好同學,所以假裝融入大家,其實沒有人認識真實的他,我們認識的只是一小部份罷了———不過反過來說,誰又是真實的?所謂的社會化,不就是用層層的糖衣武裝起自己?每個人都有必須說謊的理由,我並不覺得有什麼不對。———當我在寫前面這段自作聰明的言論時,就表示我又回到 1st Phase 了 XD
分工的方面,起初我覺得好像給胤太爽了,但後來由於 data 也更新了好幾次,所以他也得重複好幾次人工過濾及轉換成資料庫的流程,並沒有輕鬆到哪裡去。為了避免誤會而附帶一提,我們這個 case 的資料必須是由人工過濾,因為沒有固定的規則可以交給電腦自動過濾,這項工作以及類似的工作我以前也作過,一邊作一邊覺得自己其實是資處科的學生才對 XD 我的分工是寫 UI,可能有人覺得這麼輕鬆的工作我分給自己很不公平,然而這是必然的結果,因為不管給誰寫,最後老闆都會要我重作 UI,但為了彌補我的良心不安,我還是給其餘三個小組都幫了一些忙。
前面提到我們決定採用 MySQL,但猴子發現 MySQL 不能同時開啟多個 Reader,這對於猴子寫程式是個阻力,而且用 MySQL 的話,安裝也會變得困難,因此我建議改用 Embedded Database。在 C# 上的 Embedded Database Solution 最常見的有兩種,其一是 SQL Server Compact、其一是 SQLite。雖然我跟 SQLite 比較熟,但我熱愛官方的毛病又犯了,便努力研究了一陣子 SQL Server Compact,最後結論是 SQLite 方便又夠用。一些評測還指出 SQLite 更快,完全沒有吸引我選用 SQL Server Compact 的理由,於是我們決定改用 SQLite。SQLite 不但不用安裝,還允許同時開啟多個 Reader,但這時我們的程式已經不再需要這個要求了,這是好事 :p
今天是意料之外、相當充實的一天。
昨晚我早早便上床就寢,於是早上四點多就醒了,賴床到六點時,感覺實在清醒得不得了,才只好下床。雖然這陣子太早起床的情形並不少見,但最近我都懶得出門吃早餐,已經對早餐失去了新鮮感。然而今天我突然想再給志學早餐小吃的滷肉飯一個機會,我已經快要整整一個月沒有再點它的滷肉飯了。
除了滷肉飯外,今天我還點了烤總匯,這裡的烤總匯真的彙總了好多東西,因此我不常點。不過烤總匯不是重點,重點是今天的滷肉飯又恢復原來的水準了!只差少了蛋皮,而我並不是很在乎蛋皮 XD 我有點懷疑上次吃到的寒酸滷肉飯是工讀生太年輕所犯的錯,這也是我比較喜歡凌晨就來買早餐,讓老闆娘親自為我服務的原因。
上午看完幾個優先權較高的新番後,我興致一來,去給 Herbivora debug ,這次的 bug 發生在我用的其中一個 Library 裡,它連「=_=」都會被當成 Quoted-printable 來 decode 1。我看了一下原始碼後,覺得用 RegEx 重寫比較精簡,於是也實際如此重寫了,從執行時間上看來似乎有快一點點 :) 不過我很好奇的是,為什麼之前寫這個 Library 的作者不使用 RegEx 呢?甚至有另一個類似的 Library 還用了數十行的程式來判斷 = 後面的文字是不是16進位數字,而不用一行 RegEx 解決…… 難道這樣會比較快嗎? XD
接近中午時,我感覺頭髮已經長到很礙事,因此趁著沒事,去市區剪頭髮。還要買新的鍵盤,我那遭眾人唾棄的舊鍵盤,原本就因為太難按,用過的都討厭,現在更經常發生 s 和 backspace 兩個按鍵失靈的情況,終於讓我下定決心換掉它 XD
我換褲子換到一半,手機響了起來,平常我很少有電話,偏偏在我要出門前打來…… 第一時間我想到會不會是教務處還是堅哥又有什麼事,接起來後才知道原來是村辦公室,要我去領兵種抽籤通知,於是我去市區的目的又多了一項。
我先領了通知單,再去剪頭髮。剪完後則是例行地到隔壁光南隨便看看,在二樓看見了一本簡介相當吸引我的書,不僅簡介看起來很有趣,隨便翻了一下,內容看起來好像也滿不錯的…… 於是我考慮了一下決定買下來,這算對我來說是意義滿重大的一個決定,因為有一就有二,這象徵著我從此踏進了小說這個坑 XD 附帶一提,其實我房間目前還有一本剛看到三分之一的《電影般的風格》,可是它之所以只看到三分之一,也是因為我才看到三分之一就實在忍受不了它的枯燥乏味,我還是不喜歡佐藤友哉的敘事風格啊~
這本吸引我目光的小說書名是《遊戲》,特殊的封面設計也是我注意到它的原因之一,然而這種封面相當不利於保存,它的硬塑膠書腰讓封面容易彎曲變形,而純白無上膠的封面則非常容易弄髒… 光南和瓊林的幾本都保存得很糟,結果我最後特地走到飲冰室書店買,這家書店人煙稀少,所以書況都很好 XD
為了選鍵盤我又跑了光南、順發和燦坤,試過許多鍵盤後,覺得按起來好像都差不多,所以決定就選一個按鍵排列最習慣的鍵盤就好。要找一個完全標準的鍵盤似乎也不是這麼容易,大家都好喜歡在方向鍵上面和 Enter 鍵附近動手腳。從燦坤出來後發現我的車上多了一張藍單,要我去作機車排氣檢查,於是我今天的行程又多了一項,警察在這方面的效率也太高了吧… orz
回房間後,我一口氣讀完了《遊戲》,這的確是一篇非常引人入勝的故事。故事中的劇情相當緊張,不過我這個變態讀者看來的感覺則是「真美麗啊~」 XD 我覺得本書很棒的地方是,它有兩條主線,雖然其中一條剛開始看起來只是支線…… 兩條主線讓閱讀變得非常充實。給線索的步驟也安排得很適當,不會讓我有太久都沒進展的感覺,這兩點也是它在我心中大大擊敗《電影般的風格》原因———我看過的這兩本鏡家系列都在前面鋪陳的地方耗費太多文字,必須苦等到故事後段,才能開始享受劇情。還有,佐藤實在過於愛用註釋,或者也可能是譯者好意加上的,無論如何,我覺得在小說中加入一大堆對於劇情沒有什麼幫助的註釋實在很干擾閱讀。
雖然我非常喜歡《遊戲》,不過同作者的前作《治療》看起來好像不怎麼有趣,所以我並沒有很想補完它 :p
今天又是一個日夜顛倒的日子。
晚上醒來後,猴子說想找人陪吃宵夜,然而線上的同學們意願並不是太高,所以考慮、討論了非常久,久到我都想說我可不可以自己先去吃 XD 最後決定是到惠阿姨吃滷味。這是我到東華以來第一次吃滷味,吃起來的感覺呢,就跟我多年前吃過的滷味差不多 XD 我今天點的好像是花干、凍豆腐和科學麵,性質過於相近,吃起來感覺都一樣,真是選擇錯誤… 囧rz
用完餐後我到 Lab 念 paper ,本來我想把車停在行政大樓旁邊的小停車場,但停那裡的話早上就得再來移位,所以最後決定停在前門。有了一次經驗後才發現,停在這裡比工學院旁邊好很多,從 Lab 到工學院這段路雖然比較短,但是照明不佳;而從前門一直到 Lab 這一段路的夜間照明都非常好,所以以後要來 Lab 值大夜班的話都會停這裡吧!
今天半夜的 Lab 人還不少,平常不會來值大夜的庭任、卓哥都待在這裡,聽卓哥說他是要等著考早上的 ITE ,有必要這麼拼嗎? XD
今天念的是有關網頁文件分類的 paper ,雖然作者是個大頭,但是性質跟目前 Lab 的走向差有點多,讓我唸得不太踏實。途中多次想換另一篇來念,甚至還真的開始畫起另一篇 paper 的心智圖,然而經過這些波折之後,我還是看完了這篇網頁文件分類的 XD 這篇大概是我看得最快的一篇了吧!時間壓力真是恐怖。
由於前面提過的原因,我這篇 paper 唸得滿心虛的,因此就順手找了一些 E-mail corpora 來充實 Lab 的收藏,以彌補我心中的不安 XD 在蒐集這些 corpora 時,我發現其中有個 corpora 包含正常郵件資料,並且沒有經過編碼,適合我們使用,因此我拿出好久沒更新的 Herbivora 來 run ,然後又 run 出了 bug… 囧rz
這又是一個出在 RegEx 上的 bug ,而且還是出在最複雜的 E-mail RegEx 上… 所以我只好再來 debug 。搜尋了一下 “C# RegEx bug” ,發現不只有我發生這個問題,不過微軟說這是因為我的 RegEx 寫得不好,解決方法則是修改 RegEx… 所以我就乖乖地修改了,今天修改以前我還先查了一些 RegEx 教學,我覺得我現在的 RegEx 功力又進步了喔!1今天學會了給 Group 取名字,這樣可以讓 RegEx 容易閱讀2,在取值時也比較方便 :)
我在教學上看到 .NET 的 group 取名後,可以使用 \k<name> 的方式呼叫,這樣就不用 copy-paste 相同的 RegEx ,不過這個功能我還沒測試出來,要再研究看看~
「星期三的 meeting 延到今天。」這件事我在兩天內忘記而又被提醒了好幾次,連並非同 Lab 的同學都記得,我卻忘記了,真是慚愧 XD
雖然已經隔了兩天,但大家似乎都有其他事情要忙,因此今天還是沒有人有東西可以報告,不過剛好堅哥有新的 idea ,所以今天的 meeting 主要是堅哥在談他的 idea 。咪完之後,我因為報告終於都告一段落了,所以到 Lab 去查點論文的相關資料。
我繼續研究了一陣子 multiple pattern matching 演算法,然後覺悟到我實在沒必要把時間浪費在提昇邊際效益上,於是開始認識決策樹。我看了學弟妹的畢專論文對於決策樹的介紹後,實在無法瞭解他們選擇 ID3 的原因,如果要以最適用而論,我覺得 CART 的二分法相當適合他們,而如果要以最準確而論,改良自 ID3 的 C4.5 顯然更好。之後又看了一些其他的決策樹演算法簡介,我想 C4.5 是個不錯的研究目標。
接下來查到 Weka 這個軟體,雖然某人的 blog 上曾經提過,但我一直沒有興趣研究,因為我不會改 Java ,如果有需要對演算法作修改的話,還是用我熟悉的語言比較好。不過今天發現微軟竟然提供了 Java 轉 C# 的工具 ,所以我想或許可以參考一下用 Java 寫成的 Weka… XD
試用後才發現滿好用的,它實作了好多演算法任君選擇,效率也非常好,真是讓我心動。 ARFF 格式的資料也不難產生,只要稍微修改一下 Herbivora 便能使用,現在只差還沒有足夠的 Data 可以讓我玩———只有一種類型的 Data 是沒有辦法跑決策樹的 XD
昨天用 Aho-Corasick 比較慢果然是因為我使用錯誤,而今天重寫後成功了,執行時間幾乎沒有差異1,甚至在郵件量小時, Aho-Corasick 還會輸在它必須先為 Keywords 建立 tree 而花費更多時間,然而我還是很開心地改用 Aho-Corasick———因為我發現我本來使用的 for-loop + String.Contains 就是吃掉記憶體的最大兇手。之前我用 CLR Profiler 檢查時有發現在 Herbivora 中吃記憶體最嚴重的是 System.String 物件,但是我在建立字串時都有記得使用 StringBuilder ,所以一直搞不懂這是為什麼,沒想到今天拿掉 String.Contains ,改用 Aho-Corasick 後,記憶體用量馬上從 300 MB 掉到 60 MB2,所以就算 Aho-Corasick 慢一點點,我還是會用它的啦! XD
雖然根據我的需求, Aho-Corasick 跟 String.Contains 幾乎沒差,但理論上 Aho-Corasick 還是會比 String.Contains 快。今天在我將它套進 Herbivora 前先作了 benchmark ,發現速度是 Aho-Corasick ≈ String.Contains > String.IndexOf ≫ Regex , String.Contains 的速度大約比 Aho-Corasick 慢三倍3, String.IndexOf 由於還需回傳在哪裡找到,當然會比 String.Contains 慢一點, Regex 則又慢更多。
接下來聽說 Dictionary 通常會比 Hashtable 快,所以我想改用 Dictionary 。我本來就偏好使用 type-safe 的 Generic Collections ,這樣要取資料時也可以省下 type cast 的花費 :)
雖然 Dictionary 和 Hashtable 的 Method 都一樣,但行為有些不同,當我要用一個不存在的 key 來取 value 時, Hashtable 會回傳 null ,而 Dictionary 會給我 KeyNotFoundException ,我上次是用 try-catch 來處理這個 Exception ,但我沒想到 try-catch 這麼貴,昨天 Aho-Corasick 的速度會大輸,我想這也是其中一個原因…
下一步想測測看加入 q-Gram 會不會有更好的效果(用記憶體換速度 XD)