데이터 정리를 위한 Bash 사용법: 개발자를 위한 핸드북

오늘은 데이터 작업을 하는 모든 사람에게 필수적인 기술인 Bash를 사용한 데이터 정리에 대해 알아보겠습니다. 많은 사람들이 데이터 작업에 Python이나 R을 사용하지만, 명령줄에서 바로 빠르고 효율적인 데이터 조작을 위해 Bash를 활용할 수 있습니다.
이 글에서는 명령어를 보여주는 것뿐만 아니라 각 단계의 사고 과정을 안내하며, 특정 명령어를 사용하는 이유와 일반적인 데이터 정리 문제를 해결하기 위해 어떻게 함께 작동하는지 설명하겠습니다.
바로 시작해 보겠습니다!
데이터 정리 프로세스 이해하기
코드로 바로 들어가기 전에, 데이터 정리가 실제로 무엇을 포함하는지 이해해 봅시다. 데이터 정리는 원시 및 지저분한 데이터에서 정확하고 완전하며 분석 준비가 된 데이터로 변환하는 과정입니다. 여기에는 다음이 포함됩니다:
- 누락된 값 처리
- 형식 문제 수정
- 중복 제거
- 일관성 없는 데이터 표준화
따라서 깨끗한 데이터는 정확한 분석과 신뢰할 수 있는 결과를 위해 필요합니다. "쓰레기 입력, 쓰레기 출력" 원칙은 데이터 과학에 강하게 적용됩니다.
데이터 이해하기
어떤 변경을 하기 전에 작업할 데이터를 이해하는 것이 중요합니다. 몇 가지 기본 검사 명령어를 살펴보겠습니다.
파일 내용을 보려면 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줄을 표시합니다. 데이터의 구조와 헤더를 빠르게 확인하는 데 유용합니다.
$ head users.csv
-n 옵션으로 다른 줄 수를 지정할 수 있습니다.
$ head -n 5 users.csv
결과:
id,firstname,lastname,email,signupdate,lastlogin,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줄을 보여줍니다. 이는 로그 파일이나 시계열 데이터의 최신 항목을 확인하는 데 유용합니다.
$ tail users.csv
wc(word count) 명령어에 -l 플래그를 사용하면 파일의 줄 수를 계산합니다. 이는 데이터셋 크기를 빠르게 이해하는 데 도움이 됩니다.
$ wc -l users.csv
출력:
11 users.csv
다음 명령으로 파일 구조를 볼 수 있습니다:
$ column -t -s, users.csv | less -S
이 명령어는 특히 CSV 파일에 유용합니다. 분석해 보면:
- column은 출력을 열로 형식화합니다
- -t는 테이블을 만들도록 지시합니다
- -s,는 쉼표를 구분자로 지정합니다
- less -S는 줄 바꿈 없이 출력을 스크롤할 수 있게 해줍니다
이를 통해 데이터를 보기 좋게 형식화하여 불일치를 훨씬 쉽게 발견할 수 있습니다.
데이터의 문제점 찾기 및 분석
이제 데이터에 대한 기본적인 이해가 생겼으니, 특정 문제를 식별해 보겠습니다.
이 명령어는 grep을 사용하여 연속된 쉼표(빈 필드를 나타냄)를 검색하고 -c로 발생 횟수를 계산합니다.
$ grep -c ",," users.csv
이는 누락된 값이 있는 행을 빠르게 계산하는 방법을 제공합니다.
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
다음 명령어는 샘플 데이터에서 특히 "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
부정적인 구매 금액이 있는 레코드를 찾아보겠습니다:
$ 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
데이터 정리 기술로 문제 해결하기
이제 문제를 식별했으니, 하나씩 수정해 보겠습니다.
누락된 값 처리
먼저, 빈 필드를 "NULL"로 바꿉니다.
$ sed 's/,,/,NULL,/g; s/,$/,NULL/g' users.csv > users_cleaned.csv
이 sed 명령어:
- 연속된 쉼표(,,)를 ,NULL,로 대체하여 누락된 값을 명시적으로 만듭니다
- s/,$/,NULL/g로 라인 끝의 후행 쉼표를 처리합니다
> 연산자는 화면 대신 새 파일로 출력을 리디렉션합니다.
누락된 이름을 "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/invaliddate/2023-01-20/g' users.csv > userscleaned.csv
실제로는 맥락에 맞는 날짜를 사용하거나 이러한 항목을 추가 검토를 위해 표시하고 싶을 수 있습니다.
음수 값 처리
음수 값을 0으로 바꿀 수 있습니다.
$ awk -F, 'BEGIN {OFS=","} {if ($7 < 0) $7 = 0; print}' users.csv > users_cleaned.csv
이 명령어:
- 7번째 필드(purchase_amount)가 0보다 작은지 확인합니다
- 음수 값을 0으로 설정합니다
여러 데이터 정리 단계 결합하기
실제로는 데이터에 여러 수정 사항을 적용해야 하는 경우가 많습니다. 다음은 이를 단일 명령어로 결합하는 방법입니다:
$ 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
이 명령어의 작동 방식:
- 각 필드를 특정 유효성 검사 규칙에 따라 처리합니다
- 데이터를 한 번 통과하면서 여러 문제를 처리합니다
이 접근 방식은 특히 대규모 데이터셋의 경우 각 문제에 대해 별도의 명령어를 실행하는 것보다 더 효율적입니다.
데이터 정리 단계 검증
데이터를 정리한 후에는 모든 문제가 해결되었는지 확인하는 것이 중요합니다.
빈 필드가 더 이상 없는지 확인하세요:
$ grep -c ",," users_cleaned.csv
모든 빈 필드가 올바르게 채워졌다면 0을 반환해야 합니다.
다음으로, 모든 날짜가 올바른 형식인지 확인하세요:
$ grep -v -E '[0-9]{4}-[0-9]{2}-[0-9]{2}' userscleaned.csv | grep -v "signupdate"
모든 날짜가 올바른 형식이라면 결과가 나오지 않아야 합니다.
모든 구매 금액이 음수가 아닌지 확인하세요:
$ awk -F, '$7 < 0 {print $0}' users_cleaned.csv
모든 구매 금액이 음수가 아니라면 결과가 나오지 않아야 합니다.
데이터 변환
데이터가 깨끗해지면 특정 필드를 다른 형식으로 변환하거나 분석을 위해 특정 정보를 추출해야 할 수 있습니다.
특정 열 추출
이름과 이메일(연락처 정보)만 추출해 보겠습니다:
$ cut -d, -f2,3,4 userscleaned.csv > userscontact_info.csv
cut 명령어:
- -d,를 사용하여 쉼표를 구분자로 지정합니다
- -f2,3,4를 사용하여 2번째, 3번째, 4번째 필드(firstname, lastname, email)를 추출합니다
이는 특정 분석을 위해 특정 정보만 필요할 때 유용합니다.
다음으로, 구매 금액이 $100 이상인 사용자를 추출해 보겠습니다
$ awk -F, '$7 > 100 {print $0}' userscleaned.csv > usershigh_value.csv
이 awk 명령어는 조건에 따라 행을 필터링하여 특정 기준을 충족하는 데이터의 하위 집합을 만듭니다.
데이터 정렬
헤더 행을 건너뛰고 성으로 레코드를 정렬해 보겠습니다.
$ (head -n 1 userscleaned.csv && tail -n +2 userscleaned.csv | sort -t, -k3) > userssortedby_name.csv
이 명령어:
- head -n 1로 헤더 행을 보존합니다
- tail -n +2로 헤더를 제외한 모든 행을 가져옵니다
- sort -t, -k3를 사용하여 세 번째 필드(last_name)로 데이터를 정렬합니다
- 헤더와 정렬된 데이터를 새 파일로 결합합니다
구매 금액을 기준으로 내림차순 정렬
(head -n 1 userscleaned.csv && tail -n +2 userscleaned.csv | sort -t, -k7 -n -r) > userssortedby_purchase.csv
이 명령어는 구매 금액을 기준으로 내림차순으로 데이터를 정렬합니다:
- -t,는 쉼표를 구분자로 지정합니다
- -k7은 7번째 필드(purchase_amount)로 정렬합니다
- -n은 알파벳이 아닌 숫자 정렬을 보장합니다
- -r은 역순(내림차순)으로 정렬합니다
데이터 집계 및 분석
Bash는 기본 데이터 분석에도 사용할 수 있습니다. 총 구매 금액을 계산해 보겠습니다
$ awk -F, 'NR>1 {sum += $7} END {print "Total purchases: $" sum}' users_cleaned.csv
이 awk 명령어:
- NR>1로 헤더 행을 건너뜁니다
- 7번째 필드(purchase_amount)의 모든 값을 더합니다
Total purchases: $1282.49
이제 평균 구매 금액을 계산해 보겠습니다:
$ awk -F, 'NR>1 {sum += $7; count++} END {print "Average purchase: $" sum/count}' users_cleaned.csv
이 명령어는 다음과 같이 평균을 계산합니다:
- 모든 구매 금액을 합산
- 레코드 수를 계산
Average purchase: $128.249
다음으로, 가입 월별 사용자 수를 계산해 보겠습니다:
$ 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 명령어:
- 가입 날짜에서 월을 추출합니다
- 연관 배열(months)을 사용하여 발생 횟수를 계산합니다
Month 01: 10 users
데이터 정리를 위한 Bash 스크립트 만들기
종종 데이터 정리를 위한 재사용 가능한 Bash 스크립트를 만드는 것이 편리합니다. 방법은 다음과 같습니다:
- 데이터 정리 명령어를 cleanuserdata.sh라는 파일에 저장합니다 (스크립트에는 몇 가지 추가 데이터 정리 단계가 포함됩니다)
- chmod +x cleanuserdata.sh로 실행 가능하게 만듭니다
스크립트:
- 각 정리 단계를 개별적으로 처리하지만 모든 변경 사항을 동일한 출력 파일에 씁니다
- 실행을 추적하기 위한 진행 메시지를 포함합니다
- 정리 후 유효성 검사 확인을 수행합니다
- 더 많은 정리 단계를 추가하거나 기존 단계를 변경하기 쉽습니다
명령어를 한 번에 하나씩 실행하는 것과 스크립트를 실행하는 것 모두 동일한 목표를 달성하지만, 스크립트는 정리 프로세스에 대한 더 나은 가시성을 제공하고 문제 해결을 더 쉽게 만듭니다.
마무리
이 튜토리얼이 데이터 정리를 위한 Bash 사용에 대한 탄탄한 기초를 제공했기를 바랍니다.
주요 요점:
- Bash는 소규모에서 중간 규모 데이터셋의 빠르고 효율적인 데이터 정리에 이상적입니다
- grep, awk, sed, sort와 같은 명령어의 조합은 유연한 도구 키트를 제공합니다
Bash가 강력하지만, 데이터 도구 상자의 도구 중 하나일 뿐임을 기억하세요. 매우 큰 데이터셋이나 더 복잡한 변환의 경우 Python, R 또는 전용 ETL 도구를 고려해 볼 수 있습니다. 그러나 많은 일상적인 데이터 정리 작업에서 Bash는 놀라울 정도로 효과적이고 효율적일 수 있습니다!
즐거운 정리되세요!