語言分類

  1. 編譯器: C fortran ocaml
  2. 直譯器: python perl ruby basic
  3. 虛擬機: java erlang (python on pypy)

作業系統家族圖

Unix -> BSD/freeBSD-> OSX
     └> Minix -> Linux
     └> Windows NT -> WIndows 10
MS-DOS -> Windows ME

library (函式庫)

把常用的、系統的程式預先寫好供引用

Anaconda

  1. 下載 Anaconda for Windows
  2. 選擇 python 3.4 版本
  3. 讓安裝程式自動設定 PATH (PATH 可讓應用程式找到安裝檔來源)

參考讀物

  1. A Byte of Python
  2. Programming Python
  3. Python Essential Reference

工作環境

  1. 使用 ipython notebook
  2. 啟動後用瀏覽器開啟 localhost:8888
  3. new folder / new python3
  4. 內部操作
    1. Cell
    2. Read Execute Print Loop
    3. Save

下次上課

網路爬蟲 (crawler)

Bud! 參一腳

核心資料結構

曾經設計過仿造 StumbleUpon 的終端機版本,見山寨 StumbleUpon ,學到了一件事情,即 儲存網址資訊的好方式是 hash-map。底下的資料結構是程式內的,不過我想轉換成 SQL 資料庫可以接受的格式應該不難。

{"http://lib.cmu.edu.tw/"
 {:title "中國醫藥大學 圖書館 China Medical University Library, Taiwan"
  :date #(java.util.Date)
  :from #({:url "http://www.cmu.edu.tw"
           :date #(java.util.Date)})
  :to #({:url "http://etds-lib.cmu.edu.tw/main/index"
         :date #(java.util.Date)}
        {:url "http://lib.cmu.edu.tw/download.html"
         :date #(java.util.Date)})}

這個資料格式記錄了哪些項目呢?

  1. 網址與 title
  2. 開啟這個網址的最新日期
    1. java.util.Date 是一個日期物件,以物件為載入方式會比較方便
    2. #() 是 clojure 的不重複、非有序性串列,數學上稱為「集合(set)」
  3. :to 跟 :from
    1. 點開超聯結的時候會自動更新當前頁面的「:to」與新頁面的 「:from」
    2. 建立歷史樹狀圖用

資料庫、搜尋模式

資料以純文字儲存於 SQLite3 的資料庫中。另外搜尋的時候可能會採用遞增搜尋。考慮到 豆泥可能會想要把所有看過的網頁都快取下來方便搜尋 ,因此這裡要強調搜尋除非電腦容量跟速度與 Google 的伺服器一樣快,否則暫時是基於網頁標題 title 以及網址來做搜尋的動作。遞增式搜尋,允許動態搜尋,邊打邊找。

介面引擎

考慮到 豆泥各種不正常、詭異、會讓駭客感到呵呵的審美觀 ,決定採用 node-webkit 作為 desktop application rendering 的引擎。雖然我本人對 javascript 完全不熟,不過多虧了強大而且變態的 clojurescript,我們也能分一杯雲端時代產物 nodejs 的羹。

Reference

  1. StrongLoop | Creating Desktop Applications With node-webkit

學了某個語言,不知道拿來幹嘛? 提供幾個練習目標,由「基本模型」的實現難度淺到難排列。當然,不是說前面的就都很簡單,而是看你要實現到多難的程度。(所列練習階段非全部,可以嘗試更多的東西)

Parser 網路爬蟲

顧名思義,即是代替人工把網路資料抓下來的程式。可以訓練你下列技巧:

  1. 初階練習:
    • 網路連線
    • 長字串處理
    • 基本 HTML 語法
  2. 中階練習:
    • Xpath 處理 HTML 結點
    • User Agent 僞造
    • 程式模組化
    • 多線程 thread 或 多進程 process
  3. 高階練習:
    • 反反爬蟲(Tor 化)
    • 使用資料庫存放資料
    • robots.txt

IRC bot 聊天室機器人

自動掛在 IRC 頻道上的機器人,可以做很自動化項目

  1. 初階練習:
    • Socket 基礎知識
    • Event-driven 的程式架構
    • 學習 IRC 協議
  2. 中階練習
    • 物件導向的多頻道機器人
    • 正則表達式,關鍵字捕捉
  3. 高階練習:
    • 服務模組化
    • 自動化頻道管理員

RESTful API Server

有關 RESTful 的知識可上 阮一峰的部落格 查看。
括號後面是 clojure 的相關原件,讀者可略過。

  1. 初階練習:
    • 路由導向 (ring / compojure)
    • http 協議格式
    • 相關測試工具,如 curl
  2. 中階練習:
    • 網頁模板(將 RESTful 當成webapp server)(enlive / hiccup)
    • SQL 資料庫 (jdbc)
    • NoSQL 資料庫 (clutch)
  3. 高階練習:
    • API 設計
    • 身分認證機制 (friend)
    • 處理併發,研究諸如阻塞式線程等技術

最近在跟好友搞 Evidence-based Investment。因爲有需要弄 crawler 爬一些資訊,幾次被牆的教訓後,覺得應該把資料存下來以利重複應用,故開始研究資料庫。

建立每隻股票的基本資訊,將作爲其他資料表的 foreign key 的參照來源

CREATE TABLE Profile (
  MarketNo TEXT PRIMARY KEY,
  MarketName TEXT
);

接著是個股每天的收盤價格。我們先收集 2009 - 2013 每個月每日的收盤價。

CREATE TABLE DatePrice (
  No  TEXT,
  Date  DATE,
  Price  REAL,
  FOREIGN KEY(No) REFERENCES Profile(MarketNo) ON UPDATE CASCADE
);

個股每年的配息等資訊

CREATE TABLE StockInfo (
  No TEXT,
  SurplusYear    INTEGER,
  DividendYear   INTEGER,
  ShareholdersMeeting    DATE,
  ExDividendDate DATE,
  ExDividendPrice    REAL,
  ExRightsDate   DATE,
  ExRightsPrice  REAL,
  PriceStaticsticsHighest    REAL,
  PriceStaticsticsMinium REAL,
  PriceStaticsticsAverage    REAL,
  CashDividendSurplus    REAL,
  CashDividendProvident  REAL,
  CashDividendTotal  REAL,
  StockDividendSurplus   REAL,
  StockDividendProvident REAL,
  StockDividendTotal REAL,
  TotalDividend  REAL,
  AnnualYield    REAL,
  FOREIGN KEY(No) REFERENCES Profile(MarketNo) ON UPDATE CASCADE
);

出處: 一行代码完成并行任务

核心結構:(媽的,這麼短,那以前搞 multithread 是搞心酸的嗎 QAQ)

from multiprocessing.dummy import Pool as ThreadPool
from libyour import function # functions or objects

pool = ThreadPool(4)
results = pool.map(function, objects)

result 裏面可能是物件指標或資料,端看 function 的返回是什麼。

原出處:

  1. Python Tutorial 第二堂(1)數值與字串型態 這裏我省略以及懂了的部分。
  2. Python Tutorial 第二堂(2)容器、流程、for 包含式

可以使用 [] 指定索引來取得字串中的某個字元,索引從 0 開始,可以是正數或負數,負數表示從尾端開始計數,例如 -1 就是最後一個字元, -2 就是倒數第二個字元,依此類推。
[] 也可以用來切割字串;還可以指定間距(Gap),例如取索引 0 至 6,每 2 個間距的方式取子字串:

>>> lang[0:6:2]
'Pto'

'Python' 的 'P' 至 'y' 算一個間距,'y' 與 't' 之間也是一個間距,依此類推 'Python'[0:6:2] 取得的就是 'Pto',將以上對 [] 的運算方式組合在一起,可以得到一個有趣的反轉字串方式 [::-1]:

>>> lang[::-1]
'nohtyP'

如果要進行字串格式化,以下是舊式寫法:

>>> '%d %.2f %s' % (1, 99.3, 'Justin')
'1 99.30 Justin'
>>> '%(real)s is %(nick)s' % {'real' : 'Justin', 'nick' : 'caterpillar'}
'Justin is caterpillar'
>>>

技術上來說,字串物件將 % 定義為格式化操作,可以接受 tuple 與 dict 型態,不過這種寫法可讀性不好,從 Python 2.6 之後,建議使用字串的 format 方法來取代 % 操作:

>>> '{0} is {1}'.format('Justin', 'caterpillar')
'Justin is caterpillar'
>>> '{real} is {nick}'.format(real = 'Justin', nick = 'caterpillar')
'Justin is caterpillar'
>>> '{0} is {nick}'.format('Justin', nick = 'caterpillar')
'Justin is caterpillar'
>>> import sys
>>> 'My platform is {pc.platform}'.format(pc = sys)
'My platform is linux2'

set 型態是無序群集,管理的元素不會重複而且 hashable。以下是 set 的幾個功能示範:

>>> admins = {'Justin', 'caterpillar'}  # 建立 set
>>> users = {'momor', 'hamini', 'Justin'}
>>> 'Justin' in admins  # 是否在站長群?
True
>>> admins & users      # 同時是站長群也是使用者群的?
{'Justin'}
>>> admins | users      # 是站長群或是使用者群的?
{'hamini', 'caterpillar', 'Justin', 'momor'}
>>> admins - users      # 站長群但不使用者群的?
{'caterpillar'}
>>> admins ^ users      # XOR
{'hamini', 'caterpillar', 'momor'}
>>> admins > users      # ∈
False
>>> admins < users
False

Python 中的 if..else 也有運算式(Expression)形式,使用上就像是 C 或 Java 的三元運算子 ?:。if 條件式成立的話,會傳回 if 左邊的值,否則傳回 else 右邊的值。例如上面的程式也可以寫為:

from sys import argv
print 'Hello, ' + (argv[1]) if len(argv) > 1 else 'Guest')

for 包含式(comprehension)也可以形式巢狀結構,例如有個元素都為 list 的 list,想將其中的 list 元素串起來,也就是將之平坦化,可以如下:

lts = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print [ele for lt in lts for ele in lt]

當你使用 [] 包圍住 for 包含式(comprehension) 時,會建立 list 實例,如果使用 {} 的話,可以建立 set 實例,重複的元素會自動去除。例如:

>>> {name for name in ['caterpillar', 'Justin', 'caterpillar', 'openhome']}
set(['caterpillar', 'Justin', 'openhome'])

也可以建立 dict 實例。例如:

>>> {name : passwd for name, passwd in zip(names, passwds)}
{'caterpillar': 123456, 'Justin': 13579, 'openhome': 987654}

上例中的 zip 函式,就如名稱意義,會將兩個 list 像拉鏈一樣,兩兩相扣在一起為 tuple,這些 tuple 元素組成一個新的 list,對於 tuple 元素組成的這個 list,每個 tuple 中的一對元素再指定給 name 與 passwd,最後這對 name 與 passwd 組成 dict 的一對鍵值。

報告主題

雖然說是兩學分的課,不過每週都是不一樣的主題,由學校各系所不同的老師輪流上課,除了教導相關的基本知識,如影像處理原理、熱治療的計算、奈米尺度材料外,也告訴了我們其實驗室正在進行那些研究、該領域的熱門主題又有那些。

從大二下開始即聽到學校有工程學程,對相關主題萌生了極大的興趣,一上大三便迫不及待的選修。我覺得,受到近十年來以驚人速度演變的資訊科技影響,加上各研究機構其處理技術被大量轉移到民用階段,未來的醫療環境或許會大有不同,應該要對此有所瞭解才能夠走在時代的尖端。

底下報告的主題,是關於新興的「硬件」健康產業、其與醫學工程的關係,還有就是未來的醫事人員如何在這樣的環境下以更少的力氣對病人提供更好的照顧。

醫療與健康的差別

雖然常看到這兩個詞並用,但其是從產業的觀點來看,這兩個詞略有差異,可用一個簡易表格大略表示如下(以高血壓爲例):

隨著生活水平、經濟能力提升及亞健康狀況蔓延,人們普遍需要知道如何調整飲食、運動、起居、心理等才能實現健康目標,於是有了龐大的健康產業。不是說醫事人員不適任於健康產業,而是醫事人員的價值在於處理人體無法自行修復的狀況,有其分工的需要。於是,健康產業應運而生,蓬勃發展。

健康產業,如同醫療行業一樣,有四個主要的運作流程

  1. 訊息蒐集:取得使用者自身或環境的量化數據
  2. 分析評估:講數據轉化爲判斷,瞭解身體正處於怎樣的狀態
  3. 解決方案:根據狀態,給出解決方案,如何調整等
  4. 方案執行:確定使用者有確實執行;此方面尚無確切有效的運作模式

技術轉移

那麼,健康產業有什麼特質?與生醫工程的關聯又如何?

  1. 在 11/26 號上課的時候,教學的老師提到了《藥事法》,其中法條 13 規定了什麼叫「醫療器材」。因此,健康產業的器材應該也屬於該規範(「預防」人類疾病)之內。
  2. 健康產業可能單次花費較小(如抗癌標靶藥物可能價格昂貴,但奈米化的檢測晶片可能相對便宜很多),且特異性更低,使用者基數大。
  3. 生醫工程研究出的嶄新技術,如更快的影像判讀、更精確的分析或不會引起排斥的材料,都能提升產業水平。這些硬件技術是學術研究技轉的好目標。另外,因為這些硬件對於精密度及複雜功能要求不高,容易進入量產階段。
  4. 可以累積大量公共衛生及流行病學數據甚至是基因資訊(隱私及法律授權是另一個重點),這對於國家衛生政策、藥廠開發藥物以及學術研究等具有指導性的意義。

底下舉幾個目前已經投入市面的例子:

  1. 孕婦:胎兒生理監測
    • 通過以超音波為探測手段,對胎兒心電圖的變化曲線做分析,能夠了解胎兒是否有缺氧。如果偵測到異常狀況可以立刻通知孕婦接受治療。
    • 由於產檢之間通常間隔數周時間,無法即時檢測胎兒變化。
    • 這類型的產品只有在懷孕期間才有需求,或許可能採取租賃的營利模式或作為某種工具的子集合。
  2. 環境檢測:
    • 模塊化的組合,能夠監測室內 PM2.5 的濃度、二氧化碳、甲醛、常見家庭汙染、溫度溼度及亮度等。
    • 除了身體狀況外,生活工作環境的實際狀況也很重要。環境檢測再中國是非常熱門的投資項目,未來有機會為智能化的環境凈化器(如:空氣清淨機)等健康產業項目試水溫。
  3. 智能藥罐
    • 俱備自檢測能力,可以探測病患何時吃了多少藥物。
    • 或許具有設定定時才可開啟(避免因忘記而又吃一次)、提醒及通知能力,必要時也會告知醫師病患的用藥狀況。
    • 檢測器夾在藥罐的內層與外層間,不接觸藥物,保證了藥物不受汙染。

未來趨勢

健康產業的蓬勃發展來自嘗試遠離亞健康的龐大人群,在這個基礎上,可以預見未來這個產業的發展:

  1. 移動的醫院訊息系統(HIS):醫療人員透過平板或智慧型手機等與醫院訊息系統連線,即時察看由監測器提供的病人生理數據。病人也可以獲得自己身體狀況的歷史數據。健康產業可能是醫院訊息系統的互補端,讓病人出了醫院後能夠持續的追蹤自己的身體狀況。同時,這些對於現代醫療環境來說「消失的數據」也能夠提供更好的判斷一句。
  2. 慢性病的移動管理:慢性病的監測是龐大的市場。諸如高血壓、糖尿病與神經方面的疾病等。個人化的服務、參考資料的提供及及諮詢等。
  3. 數據化的人體:許多本來沒辦法量測的身體狀況(例如心律不整的長期監測)隨著硬件的進步而能夠有量化數據的產出。有可能造成醫療人員的訊息爆炸,但或許也是精確、個人化治療的基本條件。
  4. 不同疾病會需要整合不一樣的技術,包括:檢測晶片、訊號分析與傳輸、資料庫意義判讀以及整合進入醫療體系;這方面將會有更多專業人才的需求。

修課心得

有時候同學會不解的問我說為什麼要花費這麼大的力氣去選修這 16 個醫學工程的學分。我的看法是這樣:隨著資訊量不斷的累積,醫學正受到來自資訊產業帶來的影響。雖然說可能學術領域依然有著保守的傳統,但是在醫病互動、醫療團隊合作、全人照顧方面,變化會相當快速。了解醫學工程的相關知識,不啻於是拓展了一片新的視野,可以看到在病理玻片與大體老師構造外的一片風景。另外,由於中國醫大多數科系畢業後都有執照,獲得工作比起其他外校科系相對容易許多,會往這方面摸索的同學,或許以後是事業上的合作夥伴也說不定,可以利用修課機會增進交流。

反正也關了,放上來以資紀念。只是一個嘗試,不過因爲有圖片,不知道怎麼抓,失敗,放棄。

#!/usr/bin/env python

# Filename: noname.py


from sgmllib import SGMLParser
from urllib.request import Request
from urllib.request import urlopen
import re

account = 'arbodino'
url = 'http://www.wretch.cc/blog/'+account+'&list=1'

hdr = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64)',
       'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
       'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
       'Accept-Encoding': 'none',
       'Accept-Language': 'en-US,en;q=0.8',
       'Connection': 'keep-alive'}

# establish webpage connection and get page html source

def getsource(url):
    req = Request(url, headers=hdr)
    return str(urlopen(req).read())

# class code comes from diveintopython.net 

class URLLister(SGMLParser):
    def reset(self):
        SGMLParser.reset(self)
        self.urls = []

    def start_a(self, attrs):                     
        href = [v for k, v in attrs if k=='href'] 
        if href:
            self.urls.extend(href)
            
parser = URLLister()
parser.feed(getsource(url))
parser.close()
for url in parser.urls:
    if url[0:27+len(account)] == 'http://www.wretch.cc/blog/'+account+'/':   
        print(url)

21:59 < hashcat> letoh: 我對lisp想法是, 他是直接在語法樹編程, 當然就沒啥麼限制
21:59 < letoh> 是啊
22:00 * letoh 其實直接寫 asm 大概也沒什麼限制 (誤
22:03 < hashcat> 靈活到讓他很難形成一個穩定的模式, 可重用可維護可擴展性都不太行
22:04 < hashcat> 沒辦法大量生產具有同一思考模式的程序員
22:04 < letoh> 這倒是沒錯 不過我不覺得「可重用可維護可擴展性都不太行」只是範圍有限吧
22:04 < hashcat> 不符合蘇維埃政權的行事準則
22:05 < letoh> 例如只限 common lisp 的話 還是做得到一些吧?
22:05 < letoh> 其他各家方言當然就很難放在一起討論
22:06 < letoh> 或者限 elisp 的話,其實也還可以接受
22:07 < hashcat> 現在語言的reflection, 一方面可以有那種彈性, 也可以形成穩定的思考模式
22:08 < hashcat> 不過lisp樸素的反映出來語法樹, 教學用途沒法抹滅
22:09 < hashcat> 不過怎麼好像也沒什麼人在教 lisp
22:09 < letoh> 學店當然不教 lisp XD
22:10 < letoh> 不過以前在機械系有學一點 因為 autocad 的關係 只是就真的只有一點點
22:10 < hashcat> 那三個特性都不太行的原因是, 每個lisper都可以有自己的方式
22:10 < hashcat> 可能根本沒有共通語言, 雖說表面上看來都是lisp
22:11 < letoh> 也許要看你說的 lisper 是不是都寫同一種 lisp ?
22:12 < hashcat> clojure就或多或少改良了這劣勢, 給了一些東西特別的符號,一個編程模型, 就順利地引導不同程序員有不會差太多的模式
22:13 < letoh> 唔 意思是你覺得 common lisp 做不到 clojure 做的這些嗎?
22:14 < hashcat> 原始lisp不同意義的東西看起來一樣, 社群也沒有形成啥模式準則, 也可能是因為看起來一樣而很難形成模式
22:15 < hashcat> 我的觀察是沒有相同的模式, 社群就很難形成很大的力量
22:15 < letoh> 因為 common lisp 有 ansi standard,所以一般在講 lisp 應該會盡量講 common lisp
22:15 < letoh> 其他的 lisp 因為很難統一,說真的也很難討論XD
22:16 < hashcat> 總之那是種能讓不認識的人合作的力量
22:16 < letoh> 那可以說一下為什麼你覺得 common lisp 有標準卻不如 clojure 的原因嗎?
22:17 < hashcat> 一些東西特別的符號, 一個編程模型, 引導不同程序員有不會差太多的模式
22:18 < letoh> 嗯 想了一下大概知道你在講哪方面的東西 我不確定 common lisp 有沒有同樣的文化,只有很粗淺的看過一些需要的部份而已
22:19 < letoh> 不過如果你講的是像 concurrency 這些東西,我覺得差別大概就是 clojure 是官方在引導一些特殊編程應用的方向?
22:20 < letoh> 我只知道 clojure 很強調這方面的優勢XD
22:20 < hashcat> 嗯嗯
22:21 < hashcat> clojure還有幾個模式
22:21 < hashcat> 引用自haskell跟java的模式都是可選的
22:22 < letoh> 如果是要引導或統一編程模型的話 我覺得就是語言限制多一點比較容易做到吧 不然很容易就跑出不同做法
22:23 < hashcat> 用了這模式可維護啥麼的都很神奇的提昇了
22:23 < hashcat> 引導模式這其實沒說起來的那麼簡單
22:24 < hashcat> 總不能訂出一個手冊然後強迫要求每個人都遵守
22:25 < hashcat> clojure的語法和模型, 是能自然而然牽引的那種
22:28 < hashcat> 某些大公司貌似也有對C 搞出個編程準則手冊, 但都是那種每個人都說很厲害, 但實務上也沒啥人理他
22:28 < letoh> python 的 pep8? XD
22:30 < hashcat> 我是覺得就算沒pep8, python也夠簡單一致了
22:31 < hashcat> 沒理過pep8 1
22:31 < letoh> 沒理過pep8 1
22:32 < hashcat> clojure有一些好玩的東西
22:33 < hashcat> http://clojurewerkz.org/
22:34 < letoh> 唔 類似 cpan 的東西
22:35 < hashcat>
http://incanter.org/
https://github.com/liebke/zookeeper-clj
http://puniverse.github.io/pulsar/
http://avout.io/
https://github.com/clojure-numerics/expresso

22:36 < hashcat> 那不算是類似 cpan 的東西吧, 因為不是完全分散的社群支持
22:39 < hashcat> 類似cpan的是這個 https://clojars.org/

這是一個質因數分解的程式。比目前你網路上能找到的 python 例子簡短很多。這是跟同學慢慢討論、一邊研究數論出來的。

def getPrime(number):
    result = []
    # 先將質數2去除

    while number % 2 == 0:
        number = number / 2
        result.append(2)
    current = 3
    while number != 1:
        while number % current == 0:
                number  = number / current
                result.append(current)
        current = current + 2
    return result