數據科學家的命令行技巧
對於許多數據科學家來說,數據操作從始至終就是 Pandas 或 Tidyverse。從理論上講,這樣做沒有任何問題。畢竟,這就是這些工具存在的原因。然而,對於像分隔符轉換這樣的簡單任務,這些工具是大材小用了。
立志掌握命令行應該在每個開發人員的學習清單上,特別是數據科學家。學習 shell 的來龍去脈將無可否認地提高你的生產力。除此之外,命令行還是計算領域的一個重要歷史課程。例如,awk —— 一種數據驅動的腳本語言。1977 年,在 Brain Kernighan(即傳奇的 K&R 書中 K)的幫助下,awk 首次出現。今天,大約五十年過去了,awk 仍然活躍在每年新出版的書裡面。因此,可以安全地假設對命令行魔法的付出不會很快貶值。
我們將涵蓋什麼
- ICONV
- HEAD
- TR
- WC
- SPLIT
- SORT & UNIQ
- CUT
- PASTE
- JOIN
- GREP
- SED
- AWK
ICONV
文件編碼可能會很棘手。現在大部分文件都是 UTF-8 編碼的。要了解 UTF-8 背後的一些魔力,請查看這個出色的視頻。儘管如此,有時我們收到的文件不是這種編碼。這可能引起對改變編碼模式的一些胡亂嘗試。這裡,iconv
是一個拯救者。iconv
是一個簡單的程序,它將獲取採用一種編碼的文本並輸出採用另一種編碼的文本。
# Converting -f (from) latin1 (ISO-8859-1)
# -t (to) standard UTF_8
iconv -f ISO-8859-1 -t UTF-8 < input.txt > output.txt
實用選項:
iconv -l
列出所有已知編碼iconv -c
默默丟棄無法轉換的字元
HEAD
如果你是一個 Pandas 重度用戶,那麼會很熟悉 head
。通常在處理新數據時,我們想做的第一件事就是了解其內容。這就得啟動 Pandas,讀取數據然後調用 df.head()
—— 要說這有點費勁。沒有任何選項的 head
將列印出文件的前 10 行。head
的真正力量在於乾淨利落的測試操作。例如,如果我們想將文件的分隔符從逗號更改為管道。一個快速測試將是:head mydata.csv | sed 's/,/|/g'
。
# Prints out first 10 lines
head filename.csv
# Print first 3 lines
head -n 3 filename.csv
實用選項:
head -n
列印特定行數head -c
列印特定位元組數
TR
tr
類似於翻譯。這個功能強大的實用程序是文件基礎清理的主力。理想的用例是替換文件中的分隔符。
# Converting a tab delimited file into commas
cat tab_delimited.txt | tr "t" "," comma_delimited.csv
tr
另一個功能是你可以用內建 [:class:]
變數(POSIX 字元類)發揮威力。這些包括了:
[:alnum:]
所有字母和數字[:alpha:]
所有字母[:blank:]
所有水平空白[:cntrl:]
所有控制字元[:digit:]
所有數字[:graph:]
所有可列印字元,但不包括空格[:lower:]
所有小寫字母[:print:]
所有可列印字元,包括空格[:punct:]
所有標點符號[:space:]
所有水平或垂直空白[:upper:]
所有大寫字母[:xdigit:]
所有 16 進位數字
你可以將這些連接在一起以組成強大的程序。以下是一個基本的字數統計程序,可用於檢查 README 是否被濫用。
cat README.md | tr "[:punct:][:space:]" "n" | tr "[:upper:]" "[:lower:]" | grep . | sort | uniq -c | sort -nr
另一個使用基本正則表達式的例子:
# Converting all upper case letters to lower case
cat filename.csv | tr '[A-Z]' '[a-z]'
實用選項:
tr -d
刪除字元tr -s
壓縮字元b
退格f
換頁v
垂直製表符NNN
八進位字元
WC
單詞計數。它的價值主要來自其 -l
選項,它會給你提供行數。
# Will return number of lines in CSV
wc -l gigantic_comma.csv
這個工具可以方便地確認各種命令的輸出。所以,如果我們在轉換文件中的分隔符之後運行 wc -l
,我們會期待總行數是一樣的,如果不一致,我們就知道有地方出錯了。
實用選項:
wc -c
列印位元組數wc -m
列印字元數wc -L
列印最長行的長度wc -w
列印單詞數量
SPLIT
文件大小的範圍可以很廣。對於有的任務,拆分文件或許是有好處的,所以使用 split
吧。split
的基本語法是:
# We will split our CSV into new_filename every 500 lines
split -l 500 filename.csv new_filename_
# filename.csv
# ls output
# new_filename_aaa
# new_filename_aab
# new_filename_aa
它有兩個奇怪的地方是命名約定和缺少文件擴展名。後綴約定可以通過 -d
標誌變為數字。要添加文件擴展名,你需要運行以下 find
命令。它將通過附加 .csv
擴展名來更改當前目錄中所有文件的名稱,所以小心了。
find . -type f -exec mv '{}' '{}'.csv ;
# ls output
# filename.csv.csv
# new_filename_aaa.csv
# new_filename_aab.csv
# new_filename_aac.csv
實用選項:
split -b N
按特定位元組大小分割split -a N
生成長度為 N 的後綴split -x
使用十六進位後綴
SORT & UNIQ
上面兩個命令很明顯:它們的作用就是字面意思。這兩者結合起來可以提供最強大的衝擊 (例如,唯一單詞的數量)。這是由於 uniq
只作用於重複的相鄰行。這也是在輸出前進行 sort
的原因。一個有趣的事情是 sort -u
會達到和典型的 sort file.txt | uniq
模式一樣的結果。
sort
對數據科學家來說確實具有潛在的有用能力:能夠根據特定列對整個 CSV 進行排序。
# Sorting a CSV file by the second column alphabetically
sort -t"," -k2,2 filename.csv
# Numerically
sort -t"," -k2n,2 filename.csv
# Reverse order
sort -t"," -k2nr,2 filename.csv
這裡的 -t
選項將逗號指定為分隔符,通常假設分隔符是空格或製表符。此外,-k
選項是為了確定我們的鍵。這裡的語法是 -km,n
,m
作為開始列,n
作為結束列。
實用選項:
sort -f
忽略大小寫sort -r
反向排序sort -R
亂序uniq -c
統計出現次數uniq -d
只列印重複行
CUT
cut
用於刪除列。作為演示,如果我們只想刪除第一和第三列。
cut -d, -f 1,3 filename.csv
要選擇除了第一行外的所有行。
cut -d, -f 2- filename.csv
結合其他命令,將 cut
用作過濾器。
# Print first 10 lines of column 1 and 3, where "some_string_value" is present
head filename.csv | grep "some_string_value" | cut -d, -f 1,3
查出第二列中唯一值的數量。
cat filename.csv | cut -d, -f 2 | sort | uniq | wc -l
# Count occurences of unique values, limiting to first 10 results
cat filename.csv | cut -d, -f 2 | sort | uniq -c | head
PASTE
paste
是一個帶有趣味性功能的特定命令。如果你有兩個需要合併的文件,並且它們已經排序好了,paste
幫你解決了接下來的步驟。
# names.txt
adam
john
zach
# jobs.txt
lawyer
youtuber
developer
# Join the two into a CSV
paste -d ',' names.txt jobs.txt > person_data.txt
# Output
adam,lawyer
john,youtuber
zach,developer
更多 SQL 式變種,見下文。
JOIN
join
是一個簡單的、 准切向的 SQL。最大的區別是 join
將返回所有列以及只能在一個欄位上匹配。默認情況下,join
將嘗試使用第一列作為匹配鍵。為了獲得不同結果,必須使用以下語法:
# Join the first file (-1) by the second column
# and the second file (-2) by the first
join -t "," -1 2 -2 1 first_file.txt second_file.txt
標準的 join
是內連接。然而,外連接通過 -a
選項也是可行的。另一個值得一提的技巧是 -q
標誌,如果發現有缺失的欄位,可用於替換值。
# Outer join, replace blanks with NULL in columns 1 and 2
# -o which fields to substitute - 0 is key, 1.1 is first column, etc...
join -t"," -1 2 -a 1 -a2 -e ' NULL' -o '0,1.1,2.2' first_file.txt second_file.txt
它不是最用戶友好的命令,而是絕望時刻的絕望措施。
實用選項:
join -a
列印不可配對的行join -e
替換丟失的輸入欄位join -j
相當於-1 FIELD -2 FIELD
GREP
grep
即 用正則表達式全局搜索並且列印 ,可能是最有名的命令,並且名副其實。grep
很強大,特別適合在大型代碼庫中查找。在數據科學的王國里,它充當其他命令的提煉機制。雖然它的標準用途也很有價值。
# Recursively search and list all files in directory containing 'word'
grep -lr 'word' .
# List number of files containing word
grep -lr 'word' . | wc -l
計算包含單詞或模式的總行數。
grep -c 'some_value' filename.csv
# Same thing, but in all files in current directory by file name
grep -c 'some_value' *
對多個值使用「或」運算符: |
。
grep "first_value|second_value" filename.csv
實用選項:
alias grep="grep --color=auto"
使 grep 色彩豐富grep -E
使用擴展正則表達式grep -w
只匹配整個單詞grep -l
列印匹配的文件名grep -v
非匹配
大人物們
sed
和 awk
是本文中最強大的兩個命令。為簡潔起見,我不打算詳細討論這兩個命令。相反,我將介紹各種能證明其令人印象深刻的力量的命令。如果你想了解更多,這兒就有一本書是關於它們的。
SED
sed
本質上是一個流編輯器。它擅長替換,但也可以用於所有輸出重構。
最基本的 sed
命令由 s/old/new/g
組成。它的意思是搜索 old
,全局替換為 new
。 如果沒有 /g
,我們的命令將在 old
第一次出現後終止。
為了快速了解它的功能,我們可以深入了解一個例子。 在以下情景中,你已有以下文件:
balance,name
$1,000,john
$2,000,jack
我們可能想要做的第一件事是刪除美元符號。-i
標誌表示原位。''
表示零長度文件擴展名,從而覆蓋我們的初始文件。理想情況下,你可以單獨測試,然後輸出到新文件。
sed -i '' 's/$//g' data.txt
# balance,name
# 1,000,john
# 2,000,jack
接下來,去除 blance
列的逗號。
sed -i '' 's/([0-9]),([0-9])/12/g' data.txt
# balance,name
# 1000,john
# 2000,jack
最後 jack 有一天決定辭職。所以,再見了,我的朋友。
sed -i '' '/jack/d' data.txt
# balance,name
# 1000,john
正如你所看到的,sed
有很多強大的功能,但樂趣並不止於此。
AWK
最好的留在最後。awk
不僅僅是一個簡單的命令:它是一個成熟的語言。在本文中涉及的所有內容中,awk
是目前為止最酷的。如果你感興趣,這裡有很多很棒的資源 —— 看 這裡、這裡 和 這裡。
awk
的常見用例包括:
- 文字處理
- 格式化文本報告
- 執行算術運算
- 執行字元串操作
awk
可以以最原生的形式並行 grep
。
awk '/word/' filename.csv
或者更加神奇:將 grep
和 cut
組合起來。在這裡,對於所有帶我們指定單詞 word
的行,awk
列印第三和第四列,用 tab
分隔。-F,
用於指定切分時的列分隔符為逗號。
awk -F, '/word/ { print $3 "t" $4 }' filename.csv
awk
內置了許多精巧的變數。比如,NF
—— 欄位數,和 NR
—— 記錄數。要獲取文件中的第 53 條記錄:
awk -F, 'NR == 53' filename.csv
更多的花招是其基於一個或多個值進行過濾的能力。下面的第一個示例將列印第一列等於給定字元串的行的行號和列。
awk -F, ' $1 == "string" { print NR, $0 } ' filename.csv
# Filter based off of numerical value in second column
awk -F, ' $2 == 1000 { print NR, $0 } ' filename.csv
多個數值表達式:
# Print line number and columns where column three greater
# than 2005 and column five less than one thousand
awk -F, ' $3 >= 2005 && $5 <= 1000 { print NR, $0 } ' filename.csv
求出第三列的總和:
awk -F, '{ x+=$3 } END { print x }' filename.csv
在第一列等於 something
的那些行,求出第三列值的總和。
awk -F, '$1 == "something" { x+=$3 } END { print x }' filename.csv
獲取文件的行列數:
awk -F, 'END { print NF, NR }' filename.csv
# Prettier version
awk -F, 'BEGIN { print "COLUMNS", "ROWS" }; END { print NF, NR }' filename.csv
列印出現了兩次的行:
awk -F, '++seen[$0] == 2' filename.csv
刪除重複的行:
# Consecutive lines
awk 'a !~ $0; {a=$0}']
# Nonconsecutive lines
awk '! a[$0]++' filename.csv
# More efficient
awk '!($0 in a) {a[$0];print}
使用內置函數 gsub()
替換多個值。
awk '{gsub(/scarlet|ruby|puce/, "red"); print}'
這個 awk
命令將組合多個 CSV 文件,忽略標題,然後在最後附加它。
awk 'FNR==1 && NR!=1{next;}{print}' *.csv > final_file.csv
需要縮小一個龐大的文件? awk
可以在 sed
的幫助下處理它。具體來說,該命令根據行數將一個大文件分成多個較小的文件。這個一行腳本將增加一個擴展名。
sed '1d;$d' filename.csv | awk 'NR%NUMBER_OF_LINES==1{x="filename-"++i".csv";}{print > x}'
# Example: splitting big_data.csv into data_(n).csv every 100,000 lines
sed '1d;$d' big_data.csv | awk 'NR%100000==1{x="data_"++i".csv";}{print > x}'
結語
命令行擁有無窮無盡的力量。本文中介紹的命令足以將你從一無所知提升到英雄人物。除了涵蓋的內容之外,還有許多實用程序可以考慮用於日常數據操作。Csvkit、xsv 還有 q 是需要記住的三個。如果你希望更深入地了解命令行數據科學,查看這本書。它也可以免費在線獲得!
via: http://kadekillary.work/post/cli-4-ds/
作者:Kade Killary 選題:lujun9972 譯者:GraveAccent 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive