用 CuPc(銅酞菁 / PB15)與亮藍 FCF(三芳基甲烷)兩種藍色料的拉曼光譜當教材,把「基線 → 找峰 → 比對 → 分類」這條分析鏈,分別用 Python、R、Orange Data Mining 走一次——讓學生看到同一個概念在三種介面下的樣子。
關鍵差異一眼可見:CuPc 有 pyrrole/isoindole 四峰組(748 / 1337 / 1450 / 1526),FCF 沒有,改以芳香環伸縮叢集(1534 / 1587 / 1619)為主。這張圖由下方 Python 腳本的峰位表合成。
讀 CSV:波數 + 強度
ModPoly 去螢光背景
區域極大 + 門檻
與參考庫算相關係數
PCA + kNN / 類心
下面三個分頁是同一條流程的三種實作。完整可執行檔在最後的檔案清單,這裡只列核心。
# 1. 載入 + 3. 找峰 + 4. 比對(核心) import numpy as np def modpoly(x, y, order=5, it=24): # 2. ModPoly 基線 yw = y.copy() for _ in range(it): c = np.polyfit(x, yw, order) yw = np.minimum(yw, np.polyval(c, x)) return np.polyval(np.polyfit(x, yw, order), x) def pick_peaks(x, y, min_h=0.05, min_dist=9): # 3. 找峰 idx = np.where((y[1:-1]>=y[:-2]) & (y[1:-1]>y[2:]) & (y[1:-1]>=min_h))[0]+1 idx = idx[np.argsort(-y[idx])]; keep=[] for i in idx: if all(abs(x[i]-x[j])>=min_dist for j in keep): keep.append(i) return sorted(keep) # 4. 與參考光譜比對(皮爾森相關) corr = {name: np.corrcoef(sample, r)[0,1] for name,r in refs.items()} verdict = max(corr, key=corr.get) # -> 'CuPc' # 5. 監督式分類(PCA + kNN,交叉驗證) from sklearn.pipeline import make_pipeline from sklearn.decomposition import PCA from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import cross_val_score clf = make_pipeline(PCA(5), KNeighborsClassifier(3)) acc = cross_val_score(clf, X, y, cv=5).mean() # -> 1.00
# 1. 載入 ref <- read.csv("raman_reference_spectra.csv", check.names=FALSE) wn <- ref[["wavenumber_cm-1"]]; cupc <- ref$CuPc; fcf <- ref$FCF modpoly <- function(x, y, order=5, it=24) { # 2. ModPoly 基線 yw <- y; xc <- scale(x) for (i in seq_len(it)) yw <- pmin(yw, predict(lm(yw ~ poly(xc, order)))) predict(lm(yw ~ poly(xc, order))) } pick_peaks <- function(x, y, min_h=0.05, min_dist=9) { # 3. 找峰 n <- length(y) is_max <- c(FALSE, y[2:(n-1)]>=y[1:(n-2)] & y[2:(n-1)]>y[3:n], FALSE) cand <- which(is_max & y>=min_h); cand <- cand[order(-y[cand])] keep <- integer(0) for (i in cand) if (all(abs(x[i]-x[keep])>=min_dist)) keep <- c(keep,i) sort(keep) } # 4. 比對(相關係數) scores <- sapply(list(CuPc=cupc, FCF=fcf), function(r) cor(sample, r)) verdict <- names(which.max(scores)) # -> "CuPc" # 5. PCA + 最近類心(base R;進階可用 class::knn + caret 交叉驗證) pca <- prcomp(Xlib, center=TRUE); sc <- pca$x[, 1:5] cent <- aggregate(sc, list(cls), mean)
先安裝 Spectroscopy 外掛(Options → Add-ons → Spectroscopy),然後拉出這條工作流程:
raman_spectral_library.csv。開 domain editor 把 class 設為 target、其餘波數欄設為 feature(連續)。Baseline (Polynomial) 去背景、Normalize (Vector / Area) 正規化;相當於 Python 的步驟 2。cross_val_score。流程圖:File → Preprocess Spectra → PCA → Test and Score(kNN),並從 Preprocess 分岔到 Spectra viewer 做視覺檢查。
先讓學生「看」出四峰組有/無的差別,建立指紋概念,不碰程式。
把基線、找峰、相關比對拆成看得懂的函式,理解每步在做什麼。
用拉元件的方式跑同一條流程,專注在方法選擇與結果判讀,不寫程式。