Linux中國

數據科學家的命令行技巧

對於許多數據科學家來說,數據操作從始至終就是 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 &apos;s/,/|/g&apos;

# 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 &apos;[A-Z]&apos; &apos;[a-z]&apos;

實用選項:

  • 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 &apos;{}&apos; &apos;{}&apos;.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,nm 作為開始列,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 &apos;,&apos; names.txt jobs.txt > person_data.txt

# Output
adam,lawyer
john,youtuber
zach,developer

更多 SQL 式變種,見下文。

JOIN

join 是一個簡單的、 准切向的 quasi-tangential 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 &apos; NULL&apos; -o &apos;0,1.1,2.2&apos; first_file.txt second_file.txt

它不是最用戶友好的命令,而是絕望時刻的絕望措施。

實用選項:

  • join -a 列印不可配對的行
  • join -e 替換丟失的輸入欄位
  • join -j 相當於 -1 FIELD -2 FIELD

GREP

grep 用正則表達式全局搜索並且列印 Global search for a Regular Expression and Print ,可能是最有名的命令,並且名副其實。grep 很強大,特別適合在大型代碼庫中查找。在數據科學的王國里,它充當其他命令的提煉機制。雖然它的標準用途也很有價值。

# Recursively search and list all files in directory containing &apos;word&apos;

grep -lr &apos;word&apos; .

# List number of files containing word

grep -lr &apos;word&apos; . | wc -l

計算包含單詞或模式的總行數。

grep -c &apos;some_value&apos; filename.csv

# Same thing, but in all files in current directory by file name

grep -c &apos;some_value&apos; *

對多個值使用「或」運算符: |

grep "first_value|second_value" filename.csv

實用選項:

  • alias grep="grep --color=auto" 使 grep 色彩豐富
  • grep -E 使用擴展正則表達式
  • grep -w 只匹配整個單詞
  • grep -l 列印匹配的文件名
  • grep -v 非匹配

大人物們

sedawk 是本文中最強大的兩個命令。為簡潔起見,我不打算詳細討論這兩個命令。相反,我將介紹各種能證明其令人印象深刻的力量的命令。如果你想了解更多,這兒就有一本書是關於它們的。

SED

sed 本質上是一個流編輯器。它擅長替換,但也可以用於所有輸出重構。

最基本的 sed 命令由 s/old/new/g 組成。它的意思是搜索 old,全局替換為 new。 如果沒有 /g,我們的命令將在 old 第一次出現後終止。

為了快速了解它的功能,我們可以深入了解一個例子。 在以下情景中,你已有以下文件:

balance,name
$1,000,john
$2,000,jack

我們可能想要做的第一件事是刪除美元符號。-i 標誌表示原位。&apos;&apos; 表示零長度文件擴展名,從而覆蓋我們的初始文件。理想情況下,你可以單獨測試,然後輸出到新文件。

sed -i &apos;&apos; &apos;s/$//g&apos; data.txt
# balance,name
# 1,000,john
# 2,000,jack

接下來,去除 blance 列的逗號。

sed -i &apos;&apos; &apos;s/([0-9]),([0-9])/12/g&apos; data.txt
# balance,name
# 1000,john
# 2000,jack

最後 jack 有一天決定辭職。所以,再見了,我的朋友。

sed -i &apos;&apos; &apos;/jack/d&apos; data.txt
# balance,name
# 1000,john

正如你所看到的,sed 有很多強大的功能,但樂趣並不止於此。

AWK

最好的留在最後。awk 不僅僅是一個簡單的命令:它是一個成熟的語言。在本文中涉及的所有內容中,awk 是目前為止最酷的。如果你感興趣,這裡有很多很棒的資源 —— 看 這裡這裡這裡

awk 的常見用例包括:

  • 文字處理
  • 格式化文本報告
  • 執行算術運算
  • 執行字元串操作

awk 可以以最原生的形式並行 grep

awk &apos;/word/&apos; filename.csv

或者更加神奇:將 grepcut 組合起來。在這裡,對於所有帶我們指定單詞 word 的行,awk 列印第三和第四列,用 tab 分隔。-F, 用於指定切分時的列分隔符為逗號。

awk -F, &apos;/word/ { print $3 "t" $4 }&apos; filename.csv

awk 內置了許多精巧的變數。比如,NF —— 欄位數,和 NR —— 記錄數。要獲取文件中的第 53 條記錄:

awk -F, &apos;NR == 53&apos; filename.csv

更多的花招是其基於一個或多個值進行過濾的能力。下面的第一個示例將列印第一列等於給定字元串的行的行號和列。

awk -F, &apos; $1 == "string" { print NR, $0 } &apos; filename.csv

# Filter based off of numerical value in second column
awk -F, &apos; $2 == 1000 { print NR, $0 } &apos; filename.csv

多個數值表達式:

# Print line number and columns where column three greater
# than 2005 and column five less than one thousand

awk -F, &apos; $3 >= 2005 && $5 <= 1000 { print NR, $0 } &apos; filename.csv

求出第三列的總和:

awk -F, &apos;{ x+=$3 } END { print x }&apos; filename.csv

在第一列等於 something 的那些行,求出第三列值的總和。

awk -F, &apos;$1 == "something" { x+=$3 } END { print x }&apos; filename.csv

獲取文件的行列數:

awk -F, &apos;END { print NF, NR }&apos; filename.csv

# Prettier version
awk -F, &apos;BEGIN { print "COLUMNS", "ROWS" }; END { print NF, NR }&apos; filename.csv

列印出現了兩次的行:

awk -F, &apos;++seen[$0] == 2&apos; filename.csv

刪除重複的行:

# Consecutive lines
awk &apos;a !~ $0; {a=$0}&apos;]

# Nonconsecutive lines
awk &apos;! a[$0]++&apos; filename.csv

# More efficient
awk &apos;!($0 in a) {a[$0];print}

使用內置函數 gsub() 替換多個值。

awk &apos;{gsub(/scarlet|ruby|puce/, "red"); print}&apos;

這個 awk 命令將組合多個 CSV 文件,忽略標題,然後在最後附加它。

awk &apos;FNR==1 && NR!=1{next;}{print}&apos; *.csv > final_file.csv

需要縮小一個龐大的文件? awk 可以在 sed 的幫助下處理它。具體來說,該命令根據行數將一個大文件分成多個較小的文件。這個一行腳本將增加一個擴展名。

sed &apos;1d;$d&apos; filename.csv | awk &apos;NR%NUMBER_OF_LINES==1{x="filename-"++i".csv";}{print > x}&apos;

# Example: splitting big_data.csv into data_(n).csv every 100,000 lines
sed &apos;1d;$d&apos; big_data.csv | awk &apos;NR%100000==1{x="data_"++i".csv";}{print > x}&apos;

結語

命令行擁有無窮無盡的力量。本文中介紹的命令足以將你從一無所知提升到英雄人物。除了涵蓋的內容之外,還有許多實用程序可以考慮用於日常數據操作。Csvkitxsv 還有 q 是需要記住的三個。如果你希望更深入地了解命令行數據科學,查看這本書。它也可以免費在線獲得!

via: http://kadekillary.work/post/cli-4-ds/

作者:Kade Killary 選題:lujun9972 譯者:GraveAccent 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國