譯者 | 布加迪
審校 | 重樓
你是否已厭倦了使用臃腫的工具來處理雜亂的數(shù)據(jù)?本文介紹了如何使用Bash 清理和轉換數(shù)據(jù)集。
今天,我們將學習如何使用Bash清理數(shù)據(jù),這是處理數(shù)據(jù)的任何人必備的一項技能。雖然我們許多人在處理數(shù)據(jù)時會使用Python或R,但你也可以使用Bash快速高效地處理數(shù)據(jù),可直接從命令行進行處理。
本文不僅會介紹相關命令,還逐步介紹了每個步驟背后的思考過程,解釋了我們?yōu)槭裁词褂锰囟钜约八鼈內(nèi)绾螀f(xié)同工作以解決常見的數(shù)據(jù)清理問題。
讓我們開始吧!
了解數(shù)據(jù)清理過程
在深入探討代碼之前,不妨先了解一下數(shù)據(jù)清理的實際含義。數(shù)據(jù)清理指將雜亂的原始數(shù)據(jù)轉化成準確、完整、隨時可供分析的數(shù)據(jù)。這包括:
- 處理缺失值
- 修復格式問題
- 刪除重復數(shù)據(jù)
- 標準化不一致的數(shù)據(jù)
- 依據(jù)業(yè)務規(guī)則驗證數(shù)據(jù)
因此,干凈的數(shù)據(jù)對于準確的分析和可靠的結果至關重要。“垃圾進、垃圾出”這個原則非常適用于數(shù)據(jù)科學(這并不奇怪!)。
我們在本教程中將使用一個示例數(shù)據(jù)集:users.csv 文件。
了解你的數(shù)據(jù)
在進行任何更改之前,了解你在處理的數(shù)據(jù)很重要。不妨探究一些基本的檢查命令。
要查看文件的內(nèi)容,你可以使用cat 命令。
$ cat users.csv
輸出:
1,John,Smith,john.smith@example.com,2023-01-15,2023-03-20,125.99
2,Jane,Doe,jane.doe@example.com,2023-01-16,2023-03-21,210.50
3,Bob,Johnson,bob@example.com,2023-01-17,2023-03-22,0
4,Alice,Williams,alice.williams@example.com,2023-01-18,,75.25
5,,Brown,mike.brown@example.com,2023-01-19,2023-03-24,150.75
6,Sarah,Miller,sarah.miller@example.com,invalid_date,2023-03-25,95.00
7,David,Jones,david.jones@example.com,2023-01-21,2023-03-26,300.00
8,Lisa,Garcia,lisa.garcia@example.com,2023-01-22,2023-03-27,-50.00
9,James,Martinez,mymail@example.com,2023-01-23,2023-03-28,125.00
對于大型文件,這可能不切實際,于是我們有其他選擇。
head 命令默認顯示文件的前10 行。這對于快速檢查數(shù)據(jù)的結構和標題非常有用。
$ head users.csv
你可以使用-n選項指定不同的行數(shù)。
$ head -n 5 users.csv
結果如下:
id,first_name,last_name,email,signup_date,last_login,purchase_amount
1,John,Smith,john.smith@example.com,2023-01-15,2023-03-20,125.99
2,Jane,Doe,jane.doe@example.com,2023-01-16,2023-03-21,210.50
3,Bob,Johnson,bob@example.com,2023-01-17,2023-03-22,0
4,Alice,Williams,alice.williams@example.com,2023-01-18,,75.25
同樣,tail默認顯示文件的最后10行。這有助于檢查日志文件或時間序列數(shù)據(jù)中的最新條目。
帶有-l標志的wc(字數(shù)統(tǒng)計)命令可以統(tǒng)計文件中的行數(shù)。這可以讓你快速了解數(shù)據(jù)集的大小。
$ wc -l users.csv
輸出結果:
11 users.csv
你可以使用以下命令查看文件結構:
$ column -t -s, users.csv | less -S
該命令對于CSV文件尤其有用。下面不妨細述一下:
- column 將輸出格式化為列。
- -t 指示它創(chuàng)建表格。
- -s 指定逗號為分隔符。
- less -S允許滾動瀏覽輸出而不換行。
這為你提供了格式良好的數(shù)據(jù)視圖,從而極容易發(fā)現(xiàn)不一致的地方。
查找和分析數(shù)據(jù)中的問題
我們對數(shù)據(jù)已有了一番基本的了解,不妨識別具體的問題。
該命令使用grep搜索連續(xù)的逗號(表示空字段),并使用-c來計數(shù)出現(xiàn)的次數(shù)。
$ grep -c ",," users.csv
這為我們提供了一種快速統(tǒng)計缺失值的行的方法。
2
為grep添加-n 標志可以顯示行號以及匹配項,幫助我們精確定位缺失值的位置。
$ grep -n ",," users.csv
輸出:
5:4,Alice,Williams,alice.williams@example.com,2023-01-18,,75.25
6:5,,Brown,mike.brown@example.com,2023-01-19,2023-03-24,150.75
以下命令識別日期格式無效的行,具體來說在示例數(shù)據(jù)中查找文本“invalid_date”。
$ grep -v -E '^[0-9]{4}-[0-9]{2}-[0-9]{2}$' users.csv | grep "invalid_date"
輸出:
6,Sarah,Miller,sarah.miller@example.com,invalid_date,2023-03-25,95.00
不妨查找購買金額為負數(shù)的記錄:
$ awk -F, '$7 < 0 {print $0}' users.csv
該awk 命令可以:
- 使用-F指定逗號為字段分隔符。
- 檢查第7個字段(purchase_amount)是否小于 0。
- 如果條件成立,打印輸出整行。
輸出:
8,Lisa,Garcia,lisa.garcia@example.com,2023-01-22,2023-03-27,-50.00
使用數(shù)據(jù)清理技術解決問題
我們已確定了問題所在,現(xiàn)在不妨逐一解決。
處理缺失值
首先,我們將空字段替換為“NULL”。
$ sed 's/,,/,NULL,/g; s/,$/,NULL/g' users.csv > users_cleaned.csv
該sed 命令:
- 將連續(xù)的逗號(,,)替換為,NULL,,使缺失值顯式顯示。
- 使用s/,$/,NULL/g 處理行尾的尾隨逗號。
- 將結果寫入到名為users_cleaned.csv 的新文件。
> 運算符將輸出重定向到新文件而不是屏幕。
我們可以用“Unknown”填充缺失的名字。
$ awk -F, 'BEGIN {OFS=","} {if ($2 == "") $2 = "Unknown"; print}' users.csv > users_cleaned.csv
該awk 命令可以:
- 使用-F將輸入字段分隔符設置為逗號。
- 使用BEGIN {OFS=","} 將輸出字段分隔符也設置為逗號。
- 檢查第二個字段(first_name)是否為空。
- 將空值替換為“Unknown”。
- 打印輸出每一行(無論是否修改)。
更正日期格式
該sed 命令將文本“invalid_date”替換為格式正確的日期。
$ sed 's/invalid_date/2023-01-20/g' users.csv > users_cleaned.csv
實際上,你可能需要使用上下文中適用的日期,或者標記這些條目供進一步查看。
處理負值
你可以將負值替換為零。
$ awk -F, 'BEGIN {OFS=","} {if ($7 < 0) $7 = 0; print}' users.csv > users_cleaned.csv
該命令可以:
- 檢查第七個字段(purchase_amount)是否小于 0。
- 將負值設置為 0。
- 如果原始值不是負數(shù),則保留原始值。
組合多個數(shù)據(jù)清理步驟
實際上,你常需要對數(shù)據(jù)進行多重處理。以下是將它們組合成單個命令的方法: $ awk -F, 'BEGIN {OFS=","} {
# Fix missing first names
if ($2 == "") $2 = "Unknown";
# Fix invalid dates
if ($5 == "invalid_date" || $5 == "") $5 = "2023-01-20";
if ($6 == "") $6 = "2023-03-23";
# Fix negative values
if ($7 < 0) $7 = 0;
print
}' users.csv > users_cleaned.csv
該命令的工作原理如下:
- 根據(jù)每個字段的特定驗證規(guī)則處理它們。
- 在一次數(shù)據(jù)傳遞中處理多個問題。
這種方法比為每個問題運行單獨的命令來得更高效,尤其對于大型數(shù)據(jù)集而言。
驗證數(shù)據(jù)清理步驟
清理數(shù)據(jù)后,務必驗證所有問題是否已解決。
檢查是否沒有空字段:
$ grep -c ",," users_cleaned.csv
如果所有空字段都已正確填寫,則返回 0。
接下來,確保所有日期格式正確:
$ grep -v -E '[0-9]{4}-[0-9]{2}-[0-9]{2}' users_cleaned.csv | grep -v "signup_date"
如果所有日期格式正確,則返回結果為空。
檢查所有購買金額是否為非負數(shù):
$ awk -F, '$7 < 0 {print $0}' users_cleaned.csv
如果所有購買金額都為非負數(shù),則返回結果為空。
轉換數(shù)據(jù)
數(shù)據(jù)清理完成后,你可能需要將某些字段轉換成不同的格式,或提取特定信息進行分析。
提取特定列
不妨僅提取姓名和郵箱地址(聯(lián)系信息):
$ cut -d, -f2,3,4 users_cleaned.csv > users_contact_info.csv
cut命令:
- 使用-d,指定逗號為分隔符。
- 使用-f2,3,4 提取第 2個、第3個和第4個字段(first_name、last_name、email)。
- 創(chuàng)建一個僅包含這些列的新文件。
當你只需要特定信息進行特定分析時,這非常有用。
接下來,我們嘗試提取購買金額超過100 美元的用戶。
$ awk -F, '$7 > 100 {print $0}' users_cleaned.csv > users_high_value.csv
該awk命令根據(jù)條件過濾行,創(chuàng)建符合特定條件的數(shù)據(jù)子集。
數(shù)據(jù)排序
我們跳過標題行,按姓氏對記錄進行排序。
$ (head -n 1 users_cleaned.csv && tail -n +2 users_cleaned.csv | sort -t, -k3) > users_sorted_by_name.csv
該命令:
- 使用head -n 1 保留標題行。
- 使用tail -n +2 獲取除標題之外的所有行。
- 使用sort -t, -k3 按第三個字段(last_name)對數(shù)據(jù)進行排序。
- 將標題和排序后的數(shù)據(jù)合并到一個新文件中。
#按購買金額降序排序
(head -n 1 users_cleaned.csv && tail -n +2 users_cleaned.csv | sort -t, -k7 -n -r) > users_sorted_by_purchase.csv
該命令按購買金額降序排序數(shù)據(jù):
- -t,指定逗號為分隔符。
- -k7 按第七個字段(purchase_amount)排序。
- -n 確保按數(shù)字排序(非字母順序)。
- -r 按反向(降序)排序。
聚合和分析數(shù)據(jù)
Bash也可用于基本的數(shù)據(jù)分析。不妨計算一下總購買金額。
$ awk -F, 'NR>1 {sum += $7} END {print "Total purchases: $" sum}' users_cleaned.csv
該awk 命令:
- 跳過NR>1 的標題行。
- 將第7個字段(purchase_amount)中的所有值相加。
- 在末尾打印輸出總購買金額。
Total purchases: $1282.49
現(xiàn)在不妨計算一下平均購買金額:
$ awk -F, 'NR>1 {sum += $7; count++} END {print "Average purchase: $" sum/count}' users_cleaned.csv
該命令按以下方式計算平均值:
- 將所有購買金額相加。
- 計算記錄數(shù)。
- 將總購買金額除以末尾的計數(shù)。
Average purchase: $128.249
接下來,不妨按注冊月份統(tǒng)計用戶數(shù)量:
$ awk -F, 'NR>1 {
split($5, date, "-");
months[date[2]]++;
}
END {
for (month in months) {
print "Month " month ": " months[month] " users"
}
}' users_cleaned.csv
這個更復雜的awk 命令可以:
- 從注冊日期中提取月份。
- 使用關聯(lián)數(shù)組(months)統(tǒng)計出現(xiàn)次數(shù)。
- 按月份打印輸出用戶摘要。
Month 01: 10 users
創(chuàng)建用于清理數(shù)據(jù)的 Bash 腳本
創(chuàng)建可重用的Bash腳本以清理數(shù)據(jù)通常很方便。具體操作方法如下:
- 將數(shù)據(jù)清理命令保存到文件中,比如clean_user_data.sh(該腳本包含幾個額外的數(shù)據(jù)清理步驟)。
- 使用chmod +x clean_user_data.sh 使其可執(zhí)行。
- 使用./clean_user_data.sh 運行該腳本。
clean_user_data.sh 腳本:
- 分別處理每個清理步驟,但將所有更改寫入到同一個輸出文件。
- 包含進度消息以跟蹤執(zhí)行情況。
- 清理后執(zhí)行驗證檢查。
- 可以輕松修改,以添加更多清理步驟或更改現(xiàn)有清理步驟。
- 如果存在臨時文件,末尾刪除臨時文件。
逐個運行命令和運行腳本都可以實現(xiàn)相同的目標,但腳本便于更清楚地了解清理過程,并簡化故障排除。
結語
但愿本教程能為你使用Bash清理數(shù)據(jù)提供了堅實的基礎。
關鍵要點:
- Bash非常適合快速高效地清理中小型數(shù)據(jù)集。
- grep、awk、sed 和sort 等命令的組合提供了一套靈活的工具包。
- 你可以使用Bash 腳本清理數(shù)據(jù)以及將清理過程記入文檔。
請記住,雖然Bash功能強大,但它只是你數(shù)據(jù)工具箱中的一種工具。對于非常大的數(shù)據(jù)集或更復雜的轉換,你可能需要考慮使用Python、R或專用的ETL工具。然而對于許多日常數(shù)據(jù)清理任務而言,Bash 的效率和效果都出奇地好!
祝清理愉快!
原文標題:Data Cleaning with Bash: A Handbook for Developers,作者:Bala Priya C