在資料科學領域,資料處理和分析往往涉及多種程式語言和工具。善用命令列介面 (CLI) 能有效簡化工作流程,提升效率。本文將介紹如何在 Jupyter Notebook、Python、R 和 Spark 等環境中整合命令列工具,讓讀者能更靈活地處理資料。
Jupyter 提供便捷的 ! 運算子,讓使用者可以直接在 Notebook 中執行 shell 命令,例如檔案管理、程式安裝等。Python 的 subprocess 模組則提供更進階的命令列工具控制,能捕捉輸出、處理輸入,並與 Python 程式碼無縫銜接。R 語言則可使用 system2() 或 pipe() 函式執行外部命令,並透過管道操作串接多個命令,實作更複雜的資料處理流程。此外,RStudio IDE 內建的終端機功能也方便使用者直接操作 shell 環境。在大資料處理方面,Spark 的 pipe() 轉換操作允許將資料集傳遞給外部命令列工具,結合 Spark 的分散式運算能力,大幅提升資料處理效率。
多語言資料科學
資料科學家如同語言通才,需要使用多種程式語言、工具和技術來取得、清理、探索和建模資料。命令列介面(CLI)促進了這種多語言方法,因為它不限制工具的程式語言,只要符合Unix哲學。本章將展示如何在不同的程式語言和環境中利用命令列介面。
概述
本章將學習以下內容:
- 在JupyterLab和RStudio IDE中執行終端
- 在Python和R中與任意命令列工具互動
- 在Apache Spark中使用shell命令轉換資料
本章從以下檔案開始:
$ cd /data/ch10
$ l
total 176K
-rw-r--r-- 1 dst dst 164K Jun 29 14:36 alice.txt
-rwxr-xr-x 1 dst dst 408 Jun 29 14:36 count.py*
-rw-r--r-- 1 dst dst 460 Jun 29 14:36 count.R
-rw-r--r-- 1 dst dst 1.7K Jun 29 14:36 Untitled1337.ipynb
取得這些檔案的說明在第2章中。其他檔案要麼被下載,要麼使用命令列工具生成。
Jupyter
Project Jupyter是一個開源專案,誕生於IPython專案在2014年的發展,旨在支援跨所有程式語言的互動式資料科學和科學計算。Jupyter支援超過40種程式語言,包括Python、R、Julia和Scala。本文將重點介紹Python。
Jupyter Console
Jupyter Console是與Python互動的最基本選項。以下是Jupyter Console會話,展示了利用命令列介面的幾種方法:
$ jupyter console
Jupyter console 6.4.0
Python 3.9.4 (default, Apr 4 2021, 19:38:44)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.23.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: ! date
Sun May 2 01:45:06 PM CEST 2021
In [2]: ! pip install --upgrade requests
Requirement already satisfied: requests in /home/dst/.local/lib/python3.9/site-packages (2.25.1)
Collecting requests
Using cached requests-2.25.1-py2.py3-none-any.whl (61 kB)
命令列操作
在Jupyter Console中,可以使用!符號執行命令列操作。例如:
In [3]: ! head alice.txt
Project Gutenberg's Alice's Adventures in Wonderland, by Lewis Carroll
This eBook is for the use of anyone anywhere at no cost and with
almost no restrictions whatsoever. You may copy it, give it away or
re-use it under the terms of the Project Gutenberg License included
with this eBook or online at www.gutenberg.org
Title: Alice's Adventures in Wonderland
In [4]: len(open("alice.txt").read().strip().split("\n"))
Out[4]: 3735
In [5]: total_lines = ! < alice.txt wc -l
In [6]: total_lines
Out[6]: ['3735']
In [7]: int(total_lines[0])
Out[7]: 3735
使用requests下載檔案
可以使用requests函式庫下載檔案:
In [8]: url = "https://www.gutenberg.org/files/11/old/11.txt"
In [9]: import requests
In [10]: with open("alice2.txt", "wb") as f:
...: response = requests.get(url)
...: f.write(response.content)
...
使用curl下載檔案
也可以使用curl命令下載檔案:
In [11]: ! curl '{url}' > alice3.txt
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 163k 100 163k 0 0 211k 0 --:--:-- --:--:-- --:--:-- 211k
In [12]: ! ls alice*txt
alice2.txt alice3.txt alice.txt
In [13]: ! rm -v alice{2,3}.txt
程式碼解析
在上述範例中,我們展示瞭如何在Jupyter Console中使用命令列操作和Python程式碼來完成各種任務,包括下載檔案、檢查檔案內容和刪除檔案。
使用!符號執行命令列操作
在Jupyter Console中,!符號用於執行命令列操作。這使得使用者可以在Python環境中直接使用命令列工具。
使用requests函式庫下載檔案
requests函式庫是一個流行的Python函式庫,用於傳送HTTP請求。在上述範例中,我們使用requests函式庫下載了一個檔案並儲存到本地。
使用curl命令下載檔案
curl是一個命令列工具,用於傳輸資料。在上述範例中,我們使用curl命令下載了一個檔案並儲存到本地。
檔案操作
在上述範例中,我們展示瞭如何使用Python程式碼和命令列操作來檢查檔案內容、刪除檔案等。
在多語言資料科學中運用命令列工具
在資料科學領域,能夠有效地運用命令列工具是提升工作效率的關鍵。無論是使用 Jupyter Notebook、Python 或 R,都有多種方法可以與命令列工具進行互動。
在 Jupyter Notebook 中使用命令列工具
Jupyter Notebook 提供了一種瀏覽器為基礎的介面,讓使用者能夠以互動的方式執行程式碼、撰寫檔案和視覺化資料。在 Jupyter Notebook 中,可以透過驚嘆號(!)來執行 shell 命令。例如:
!rm -v alice{{2,3}}.txt
上述命令會刪除 alice2.txt 和 alice3.txt 檔案。
內容解密:
!符號告訴 Jupyter Notebook 這是一條 shell 命令。rm是刪除檔案的命令。-v選項讓rm命令顯示詳細的刪除資訊。alice{{2,3}}.txt是一種 Bash 的擴充套件語法,等同於alice2.txt alice3.txt。
在 Python 中使用命令列工具
Python 的 subprocess 模組提供了一種推薦的方式來執行命令列工具並與其進行輸入輸出的連線。以下是一個範例:
from subprocess import run
lower = ["foo", "bar", "baz"]
upper = run(["echo", "\n".join(lower)], capture_output=True, text=True, shell=True)
print(upper.stdout.strip().split("\n"))
內容解密:
subprocess.run()函式用於執行命令列工具。["echo", "\n".join(lower)]定義了要執行的命令和引數。capture_output=True確保命令的輸出被捕捉。text=True表示輸出以字串形式傳回,而不是位元組。shell=True允許使用 shell 語法,但需謹慎使用以避免安全性問題。
在 R 中使用命令列工具
在 R 中,可以使用 system2() 函式來執行命令列工具。以下是一個範例:
lines <- readLines("alice.txt")
words <- unlist(strsplit(lines, " "))
alice <- system2("grep", c("-i", "alice"), input = words, stdout = TRUE)
length(alice)
內容解密:
readLines("alice.txt")讀取檔案alice.txt的內容。strsplit(lines, " ")將文字分割成單詞。system2("grep", c("-i", "alice"), input = words, stdout = TRUE)使用grep命令過濾包含 “alice” 的單詞。length(alice)統計過濾結果的數量。
多語言資料科學的實務應用
在資料科學的領域中,命令列工具的運用不僅限於特定的程式語言或環境。透過結合不同的工具和技術,可以更有效地完成資料處理和分析的工作。本篇文章將探討如何在不同的程式語言和環境中使用命令列工具,並介紹相關的技術和最佳實踐。
R 語言中的命令列工具整合
在 R 語言中,可以透過 pipe() 函式來執行 shell 命令並讀取其輸出結果。下面是一個簡單的例子,展示如何使用 grep 命令來篩選資料:
in_con <- pipe("grep b > out")
writeLines(c("foo", "bar"), in_con)
close(in_con)
readLines("out")
內容解密:
pipe("grep b > out"):建立一個管道,將grep b的輸出結果寫入檔案out中。writeLines(c("foo", "bar"), in_con):將字串 “foo” 和 “bar” 寫入管道的輸入端。close(in_con):關閉輸入管道。readLines("out"):讀取檔案out的內容,輸出包含字元 “b” 的行。
為了簡化這個過程,可以建立一個輔助函式 sh(),如下所示:
library(magrittr)
sh <- function(.data, command) {
temp_file <- tempfile()
out_con <- fifo(temp_file, "w+")
in_con <- pipe(paste0(command, " > ", temp_file))
writeLines(as.character(.data), in_con)
result <- readLines(out_con)
close(out_con)
close(in_con)
unlink(temp_file)
result
}
lines <- readLines("alice.txt")
words <- unlist(strsplit(lines, " "))
sh(words, "grep -i alice") %>%
sh("wc -l") %>%
sh("cowsay") %>%
cli::cat_boxx()
內容解密:
sh()函式接受資料和命令列指令,將資料寫入管道並執行指令,最後讀取輸出結果。- 使用
magrittr的管道運算子 (%>%) 將多個命令列指令串聯起來,對 “alice.txt” 中的單詞進行篩選、計數,並使用cowsay命令產生一個有趣的輸出。
RStudio 中的終端機標籤
RStudio 提供了一個完整的終端機環境,可以在其中執行 shell 命令。這個終端機環境與 R 控制檯是分開的,可以用來執行獨立的 shell 命令。
Apache Spark 中的命令列工具整合
Apache Spark 是一個叢集計算框架,可以處理大規模的資料集。Spark 提供了 pipe() 轉換操作,可以將資料集透過 shell 命令進行處理。下面是一個使用 Spark Shell 的例子:
val lines = sc.textFile("alice.txt")
val words = lines.flatMap(line => line.split(" "))
val alice = words.pipe("grep -i alice")
val counts = alice.pipe("wc -l")
counts.map(x => x.toInt).reduce(_ + _)
內容解密:
sc.textFile("alice.txt"):讀取 “alice.txt” 檔案,每行作為一個元素。flatMap(line => line.split(" ")):將每行分割成單詞。pipe("grep -i alice"):將資料集透過grep命令篩選出包含 “alice” 的單詞。pipe("wc -l"):對篩選出的單詞進行計數。map(x => x.toInt).reduce(_ + _):將計數結果轉換為整數並求和,得到最終的計數結果。
回顧
本文探討了使用命令列進行資料科學的強大功能。令人感興趣的是,這個相對年輕的領域所面臨的挑戰,可以透過這種經過時間考驗的技術來解決。希望讀者現在能夠理解命令列的能力。許多命令列工具提供了各種可能性,非常適合涵蓋資料科學的多種任務。
資料科學有許多不同的定義。在第一章中,介紹了由Hilary Mason和Chris Wiggins定義的五步驟OSEMN模型,因為它非常實用,可以轉化為非常具體的任務。OSEMN這個縮寫代表了取得、清理、探索、建模和解釋資料。第一章還解釋了為什麼命令列非常適合執行這些資料科學任務。
第二章解釋瞭如何取得本文中使用的所有工具,並介紹了命令列的基本工具和概念。
四個OSEMN模型章節重點介紹了使用命令列執行這些實際任務。並沒有專門為第五步——解釋資料——寫一章,因為坦白說,電腦,甚至命令列,在這方面用處不大。不過,還是提供了一些進一步閱讀的參考資料。
在四個插曲章節中,探討了一些更廣泛的與在命令列上進行資料科學相關的主題,這些主題並不特定於某個步驟。在第四章中,解釋瞭如何將單行命令和現有程式碼轉換為可重複使用的命令列工具。在第六章中,描述瞭如何使用名為make的工具來管理資料工作流程。在第八章中,示範瞭如何使用GNU Parallel平行執行普通的命令列工具和管道。在第十章中,展示了命令列並不是孤立存在的,它可以從其他程式語言和環境中被利用。這些插曲章節中討論的主題可以在資料工作流程中的任何時候應用。
無法展示所有可用於資料科學的命令列工具。新的工具每天都在被創造出來。正如讀者現在可能已經理解的那樣,本文更關注的是使用命令列的理念,而不是提供一個詳盡的工具清單。
三點建議
讀者可能花了很多時間閱讀這些章節,也許還跟著程式碼範例一起練習。為了最大限度地提高這種投資的回報,並增加讀者繼續將命令列納入資料科學工作流程的機率,提出三點建議:(1)要有耐心,(2)要富有創意,(3)要務實。在接下來的三個小節中,將對每點建議進行詳細闡述。
要有耐心
第一點建議是要有耐心。在命令列上處理資料與使用程式語言不同,因此需要不同的思維方式。
此外,命令列工具本身並非毫無癖好和不一致性。這部分是因為它們是由許多不同的人在幾十年間開發出來的。如果讀者對它們令人眼花繚亂的選項感到困惑,請不要忘記使用--help、man、tldr或您喜歡的搜尋引擎來瞭解更多。
儘管如此,尤其是在剛開始的時候,在命令列上工作可能會是一種令人沮喪的體驗。相信我,隨著您練習使用命令列及其工具,您將變得更加熟練。命令列已經存在了幾十年,並且將繼續存在下去。這是一項值得投資的技能。
要富有創意
第二點相關的建議是要富有創意。命令列非常靈活。透過組合命令列工具,您可以完成超出您想像的事情。
鼓勵讀者不要立即回到程式語言上。當您確實需要使用程式語言時,請思考是否可以將程式碼以某種方式概括或重複使用;如果是這樣,請考慮使用第四章中討論的步驟,使用該程式碼建立自己的命令列工具。如果您認為您的工具可能對其他人有益,您甚至可以更進一步,將其開源。也許有一個步驟您知道如何在命令列上執行,但您寧願不離開您正在使用的主要程式語言或環境的舒適圈。也許您可以嘗試第十章中列出的其中一種方法。
要務實
第三點建議是要務實。務實與富有創意有關,但值得單獨說明。在前面的小節中,曾提到不要立即迴歸到程式語言。當然,命令列有其侷限性。在整本文中,一直強調命令列應該被視為進行資料科學的一種輔助方法。
討論了在命令列上進行資料科學的四個步驟。在實踐中,命令列的適用性對於步驟1比對於步驟4更高。應該使用最適合當前任務的方法。在工作流程中的任何時候混合和匹配方法都是完全可以的。正如第十章所示,命令列非常適合與其他方法、程式語言和統計環境整合。每種方法都有某種權衡,而成為命令列高手的一部分就是學習何時使用哪種方法。
總之,當您有耐心、富有創意且務實時,命令列將使您成為更高效、更有生產力的資料科學家。
未來探索方向
由於本文處於命令列和資料科學的交叉點,因此許多相關主題僅被觸及。現在輪到讀者進一步探索這些主題了。以下的小節提供了一些主題和建議的資源供參考。
探索更多主題
- 資料科學的其他應用
- 命令列的高階用法
- 與其他程式語言和環境的整合
進一步閱讀資源
- 相關書籍
- 線上課程
- 專業論壇和社群
透過遵循這些建議並繼續探索相關主題,讀者可以充分利用本文所學,並在資料科學領域取得更大的進步。