GNU Parallel 是一款功能強大的命令列工具,能有效提升資料處理效率,尤其在處理大量資料時,可將任務分散至多台機器或多核心 CPU 進行平行運算。本文將探討如何使用 GNU Parallel 安裝設定、分配資料、處理檔案,並結合平行管線技術,更有效率地完成複雜的資料處理任務。文章也涵蓋資料建模與機器學習實務,以葡萄酒品質資料集為例,示範如何使用命令列工具進行資料清理、降維、視覺化分析,並比較 PCA 和 t-SNE 降維技術的應用與差異,提供讀者更全面的技術理解。
分散式處理:使用 GNU Parallel 加速資料處理
GNU Parallel 是一款強大的命令列工具,能夠幫助使用者在多個 CPU 核心或遠端機器上平行執行任務,大幅提升資料處理的效率。本文將介紹如何使用 GNU Parallel 進行分散式處理,包括在遠端機器上安裝 Parallel、分配本地資料給遠端機器、以及在遠端機器上處理檔案等主題。
在遠端機器上安裝 GNU Parallel
首先,我們需要在多台遠端機器上安裝 GNU Parallel。可以使用以下命令在多台機器上同時安裝:
$ parallel --nonall --slf hostnames "sudo apt-get install -y parallel"
內容解密:
parallel:啟動 GNU Parallel。--nonall:表示命令將在所有列出的主機上執行,但不傳遞任何引數。--slf hostnames:指定包含遠端主機名稱的檔案。sudo apt-get install -y parallel:在遠端主機上安裝 GNU Parallel。
分配本地資料給遠端機器
假設我們有一個龐大的資料集需要處理,可以使用 GNU Parallel 將資料分配到多台遠端機器上進行平行處理。以下範例展示如何將 1 到 1000 的數字分配到多台機器上,並計算總和:
$ seq 1000 | parallel -N100 --pipe --slf hostnames "(hostname; wc -l) | paste -s -d:"
$ seq 1000 | parallel -N100 --pipe --slf hostnames "paste -sd+ | bc" | paste -sd+ | bc
內容解密:
seq 1000:生成 1 到 1000 的數字序列。parallel -N100 --pipe:將輸入資料分成每 100 個一組,並透過管道傳遞給命令。--slf hostnames:指定遠端主機列表檔案。(hostname; wc -l) | paste -s -d::在遠端機器上執行,輸出主機名稱和接收到的輸入行數。paste -sd+ | bc:計算每組數字的總和。- 最後透過
paste -sd+ | bc合計所有遠端計算的結果。
在遠端機器上處理檔案
另一個常見的場景是將檔案傳送到遠端機器進行處理,然後取回結果。以下範例展示如何從 NYC Open Data API 下載資料,並在遠端機器上統計各行政區的服務呼叫次數:
$ seq 0 100 900 | parallel "curl -sL 'http://data.cityofnewyork.us/resource/erm2-nwe9.json?\$limit=100&\$offset={}' | jq -c '.[]' | gzip > nyc-{#}.json.gz"
$ parallel --basefile nyc-process.sh --slf hostnames './nyc-process.sh {}' ::: nyc-*.json.gz
內容解密:
seq 0 100 900:生成用於 API 請求的偏移量序列。parallel:下載 JSON 資料並壓縮儲存為多個檔案。--basefile nyc-process.sh:將處理指令碼上傳到遠端機器。./nyc-process.sh {}:在遠端機器上執行處理指令碼,傳入壓縮的 JSON 檔案。
分散式處理與平行管線
在處理大量資料時,單機的運算能力往往不足。這時,我們可以利用 GNU parallel 工具將任務分散到多台機器或多個 CPU 核心上平行處理,大幅提升處理效率。
使用 parallel 進行分散式處理
以下是一個實際範例,展示如何使用 parallel 將 JSON 檔案處理任務分散到多台遠端機器:
$ ls *.json.gz |
> parallel -v --basefile jq \
> --trc {.}.csv \
> --slf hostnames \
> "zcat {} | ./jq -r '.borough' | tr '[A-Z] ' '[a-z]_' | sort | uniq -c | awk '{
print \$2\",\"\$1}' > {.}.csv"
內容解密:
ls *.json.gz列出當前目錄下的所有.json.gz檔案。parallel命令接收這些檔案列表,並將任務分配到多台機器。--basefile jq將jq二進位制檔案傳輸到每台遠端機器上。--trc {.}.csv表示傳輸輸入檔案到遠端機器,執行後將結果檔案傳回本地,並在遠端清理相關檔案。--slf hostnames指定包含遠端主機名稱的檔案。- 管線命令:
zcat {}解壓縮輸入的 JSON 檔案。./jq -r '.borough'使用傳輸過去的jq工具提取borough欄位。tr '[A-Z] ' '[a-z]_'將提取的內容轉換為小寫並將空格替換為底線。sort | uniq -c統計每個區名出現的次數。awk '{print \$2\",\"\$1}'將輸出格式調整為「區名,次數」。
合併分散式處理結果
將多個 CSV 檔案的結果合併並匯總:
$ cat nyc*csv | header -a borough,count |
> rush run -t 'group_by(df, borough) %>% summarize(count = sum(count))' - |
> csvsort -rc count | csvlook
內容解密:
cat nyc*csv合併所有符合模式的 CSV 檔案。header -a borough,count為輸入資料新增標頭。rush run -t '...'使用rush執行 R 語言的資料處理指令碼:group_by(df, borough)按borough欄位分組。summarize(count = sum(count))對每組的計數求和。
csvsort -rc count按count欄位進行降序排序。csvlook將結果以表格形式顯示。
或者使用 SQL 聚合結果:
$ cat nyc*csv | header -a borough,count |
> csvsql --query 'SELECT borough, SUM(count) AS count FROM stdin GROUP BY borough ORDER BY count DESC' |
> csvlook
內容解密:
csvsql --query '...'使用 SQL 陳述式處理 CSV 資料。SELECT borough, SUM(count) AS count選擇borough欄位並對count求和。GROUP BY borough按borough分組。ORDER BY count DESC按總計數降序排列結果。
建模資料
資料建模是將資料抽象化並提取有價值資訊的過程。本章節將介紹三種常見的資料建模演算法:
- 降維(Dimensionality Reduction)
- 迴歸(Regression)
- 分類別(Classification)
這些演算法來自統計學和機器學習領域。在處理 CSV 資料集時,每一行代表一個資料點,每個資料點具有一個或多個特徵,有時還帶有標籤。
資料集與特徵
以葡萄酒資料集為例,每個資料點代表一瓶葡萄酒,其特徵可能包括化學成分(如酒精含量、酸度等),而標籤可能是葡萄酒的品質評分或類別。
未來探索
GNU parallel 的線上教學提供了更多高階功能,例如輸入規格化、任務日誌記錄、超時控制等。熟練掌握這些功能將使你的命令列操作更高效。接下來的章節將繼續探討 OSEMN 模型的第四步:資料建模。
機器學習實務:以葡萄酒資料為例
本章節將介紹如何使用命令列工具進行機器學習實務,特別是以葡萄酒品質資料集為例。我們將使用 tapkee、vw 和 skll 等工具來進行資料降維、品質預測和分類別。
取得與準備資料
首先,我們需要取得葡萄酒資料集。該資料集分為紅酒和白酒兩個檔案,分別包含1599和4898筆資料。每筆資料包含11個物理化學屬性以及一個品質評分。
$ parallel "curl -sL http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-{}.csv > wine-{}.csv" ::: red white
$ cp /data/.cache/wine-*.csv .
接下來,我們檢查資料的內容和數量:
$ < wine-red.csv nl | fold | trim
$ < wine-white.csv nl | fold | trim
$ wc -l wine-{red,white}.csv
內容解密:
- 使用
parallel命令同時下載紅酒和白酒的資料檔案。 nl命令用於為檔案內容新增行號,fold用於換行處理,而trim則去除多餘的空白。wc -l用於統計檔案的行數。
資料清理與合併
由於原始資料使用分號作為分隔符且含有空格,我們需要對其進行清理和轉換:
$ for COLOR in red white; do
< wine-$COLOR.csv tr '[A-Z]; ' '[a-z],_' | tr -d \" > wine-${COLOR}-clean.csv
done
然後,我們使用 csvstack 將兩個檔案合併,並新增一個名為 type 的欄位來區分紅酒和白酒:
$ csvstack -g red,white -n type wine-{red,white}-clean.csv | xsv select 2-,1 > wine.csv
內容解密:
- 使用
tr命令將大寫字母轉換為小寫,分號替換為逗號,並刪除引號。 csvstack用於合併多個CSV檔案,並新增一個欄位來標示資料來源。xsv select用於重新排列欄位順序,將type欄位移至最後。
檢查缺失值
大多數機器學習演算法無法處理缺失值,因此我們需要檢查資料集中是否存在缺失值:
$ csvstat wine.csv --nulls
內容解密:
csvstat命令用於統計CSV檔案的相關資訊,加上--nulls引數可以檢查是否存在缺失值。
視覺化分析
接下來,我們使用 rush 和 ggplot2 來視覺化葡萄酒品質的分佈和酒精含量與品質之間的關係:
$ rush run -t 'ggplot(df, aes(x = quality, fill = type)) + geom_density(adjust = 3, alpha = 0.5)' wine.csv > wine-quality.png
$ display wine-quality.png
$ rush plot --x alcohol --y quality --color type --geom smooth wine.csv > wine-alcohol-vs-quality.png
$ display wine-alcohol-vs-quality.png
內容解密:
- 使用
rush命令呼叫ggplot2進行資料視覺化,繪製密度圖來比較紅酒和白酒的品質分佈。 - 使用
--x、--y和--color引數來指定X軸、Y軸和顏色變數,繪製酒精含量與品質之間的關係圖。
使用Tapkee進行降維處理
降維的主要目標是將高維度的資料點對映到較低維度的空間,同時盡量保持相似資料點之間的鄰近關係。我們的紅白酒資料集包含13個特徵,為了便於視覺化,我們將採用兩種降維技術:主成分分析(PCA)和t-Distributed Stochastic Neighbor Embedding(t-SNE)。
介紹Tapkee
Tapkee是一個C++範本函式庫,用於實作多種降維演算法,包括:
- 區域性線性嵌入(Locally Linear Embedding)
- 等距對映(Isomap)
- 多維度縮放(Multidimensional Scaling)
- 主成分分析(PCA)
- t-SNE
雖然Tapkee主要作為一個可以被其他應用程式包含的函式庫,但它也提供了一個命令列工具tapkee。我們將使用這個工具對紅白酒資料集進行降維處理。
線性和非線性對映
首先,我們需要對特徵進行標準化處理,以確保每個特徵的重要性相同。這通常能改善機器學習演算法的表現。
$ rush run --tidyverse --output wine-scaled.csv \
> 'select(df, -type) %>%
> scale() %>%
> as_tibble() %>%
> mutate(type = df$type)' wine.csv
$ csvlook wine-scaled.csv
內容解密:
select(df, -type):移除type欄位,因為scale()函式只能對數值型欄位進行操作。scale():對資料進行標準化處理,使每個特徵具有相同的尺度。as_tibble():將處理後的矩陣轉換回資料框架。mutate(type = df$type):將原本的type欄位增加回資料框架中。
接下來,我們使用Tapkee進行降維處理,先採用PCA方法:
$ xsv select '!type' wine-scaled.csv |
> header -d |
> tapkee --method pca |
> tee wine-pca.txt | trim
$ < wine-pca.txt header -a pc1,pc2 |
> paste -d, - <(xsv select type wine-scaled.csv) |
> tee wine-pca.csv | csvlook
內容解密:
xsv select '!type' wine-scaled.csv:選取除type欄位以外的所有欄位。header -d:移除標頭。tapkee --method pca:使用PCA方法進行降維。header -a pc1,pc2:為輸出的資料新增標頭pc1和pc2。paste -d, - <(xsv select type wine-scaled.csv):將原本的type欄位增加回處理後的資料中。
然後,我們使用Rio-scatter繪製散點圖(Figure 9-3):
$ rush plot --x pc1 --y pc2 --color type --shape type wine-pca.csv > wine-pca.png
$ display wine-pca.png
圖示說明:
此圖示展示了使用PCA進行線性降維後的結果,紅白酒樣本在二維空間中的分佈情況。
同樣地,我們使用t-SNE方法進行降維處理:
$ xsv select '!type' wine-scaled.csv |
> header -d |
> tapkee --method t-sne |
> header -a x,y |
> paste -d, - <(xsv select type wine-scaled.csv) |
> rush plot --x x --y y --color type --shape type > wine-tsne.png
$ display wine-tsne.png
圖示說明:
此圖示展示了使用t-SNE進行非線性降維後的結果,紅白酒樣本在二維空間中的分佈情況。相比於PCA,t-SNE更好地分隔了紅白酒樣本,表明資料集具有一定的結構。
結果分析
透過比較PCA和t-SNE的結果,我們發現t-SNE在分隔紅白酒樣本方面表現更好,這意味著資料的特徵與紅白酒的分類別之間存在著非線性的關係。因此,在處理類別似的資料集時,應考慮使用非線性的降維技術以獲得更好的結果。