アナリストと開発者のためのCSVデータクリーニングのコツ
CSVファイルは表形式データの普遍的な交換フォーマットです。シンプルで人間が読め、ExcelからPandasまであらゆるツールでサポートされています。しかし実際のCSVファイルは多くの場合乱雑です — 不整合なエンコーディング、欠損値、混在するデータ型、不正な行。このガイドではCSVデータを確実にクリーニングする実践的なテクニックを解説します。
よくあるCSVの問題
1. エンコーディングの問題
最もイライラするCSVの問題はエンコーディングです。WindowsのExcelで作成されたファイルは windows-1252 を使用している場合がありますが、Pythonスクリプトは utf-8 を期待します。
症状:文字化け(mojibake)、例えば é の代わりに é が表示されたり、UnicodeDecodeError 例外が発生します。
検出:
import chardet
with open('data.csv', 'rb') as f:
result = chardet.detect(f.read(10000))
print(result) # {'encoding': 'Windows-1252', 'confidence': 0.73}
修正:検出されたエンコーディングで読み込み、UTF-8として保存:
import pandas as pd
df = pd.read_csv('data.csv', encoding='windows-1252')
df.to_csv('data_clean.csv', encoding='utf-8', index=False)
2. 不整合なデリミター
すべての「CSV」がカンマを使うわけではありません。ヨーロッパのCSVファイルでは、多くのヨーロッパのロケールでカンマが小数点区切りであるため、セミコロンがよく使われます。
# デリミターの自動検出
import csv
with open('data.csv', 'r') as f:
dialect = csv.Sniffer().sniff(f.read(5000))
print(f"Delimiter: {repr(dialect.delimiter)}")
CSVエディターはデリミター検出を自動的に処理します — データを貼り付けるとフォーマットを識別します。
3. 欠損値
欠損データはさまざまな形で表示されます:空のセル、NA、N/A、null、-、または空白だけ。
# すべての欠損値表現を標準化
df = pd.read_csv('data.csv', na_values=['NA', 'N/A', 'null', '-', '', ' '])
# 列ごとの欠損値をチェック
print(df.isnull().sum())
# 戦略1:重要なフィールドが欠損している行を削除
df = df.dropna(subset=['email', 'name'])
# 戦略2:デフォルト値で埋める
df['country'] = df['country'].fillna('Unknown')
# 戦略3:前方補完(時系列)
df['price'] = df['price'].ffill()
4. 重複行
完全な重複は簡単に見つかります。ファジー重複(同じ人物で名前のスペルが少し異なるなど)はより困難です。
# 完全な重複を検出
duplicates = df[df.duplicated(keep=False)]
print(f"Found {len(duplicates)} duplicate rows")
# 最初の出現を残して重複を除去
df = df.drop_duplicates()
# 特定の列に基づいて重複を除去
df = df.drop_duplicates(subset=['email'], keep='last')
5. 不整合なデータフォーマット
混在した日付フォーマット、国コードの有無がある電話番号、不整合な大文字小文字:
# 日付の標準化
df['date'] = pd.to_datetime(df['date'], format='mixed', dayfirst=False)
# テキストフィールドの標準化
df['name'] = df['name'].str.strip().str.title()
df['email'] = df['email'].str.strip().str.lower()
# 電話番号の標準化(基本)
df['phone'] = df['phone'].str.replace(r'[^0-9+]', '', regex=True)
6. データ型の問題
CSVはすべてをテキストとして保存します。先頭ゼロのある数値、郵便番号、電話番号はパース時にフォーマットを失う可能性があります:
# 郵便番号の先頭ゼロを保持
df = pd.read_csv('data.csv', dtype={'zip_code': str, 'phone': str})
# 通貨文字列を数値に変換
df['price'] = df['price'].str.replace('$', '').str.replace(',', '').astype(float)
クリーニング後の検証
クリーニングしたデータは必ず検証しましょう:
# 行数チェック(予期せず行が増減していないか?)
print(f"Rows: {len(df)}")
# データ型チェック
print(df.dtypes)
# 値の範囲チェック
print(df.describe())
# 残っているnullのチェック
print(df.isnull().sum())
# 一意性制約の検証
assert df['email'].is_unique, "Duplicate emails found!"
コマンドラインツール
コードを書かずに素早くクリーニングする場合:
# エンコーディング変換
iconv -f WINDOWS-1252 -t UTF-8 input.csv > output.csv
# ソートして重複行を除去
sort -u input.csv > output.csv
# 特定の列を抽出(cut)
cut -d',' -f1,3,5 input.csv > output.csv
# 行のフィルタリング(awk)
awk -F',' '$3 > 100' input.csv > filtered.csv
より複雑な変換には、csvkit がCSVユーティリティの完全なスイートを提供します:
# インストール
pip install csvkit
# 列名の表示
csvcut -n data.csv
# 行のフィルタリング
csvgrep -c country -m "USA" data.csv > usa_only.csv
# JSONに変換
csvjson data.csv > data.json
CSVとJSON間の変換は、CSV to JSONコンバーターで即座に処理できます。
FAQ
CSV処理の最大ファイルサイズは?
CSVフォーマット自体には固有の制限はありません。実際の制限はツールに依存します:Excelは約100万行を処理でき、Pandasは十分なRAMがあれば数GBまで問題なく動作し、DaskやPolarsなどのツールはメモリ以上のデータセットを処理できます。ブラウザベースのツールについては、当CSVエディターは100MBまでのファイルを処理します。
データ交換にはCSVとJSONのどちらを使うべきですか?
CSVはフラットな表形式データ(スプレッドシート、データベースエクスポート、シンプルなリスト)に最適です。JSONはネストされた階層データ(APIレスポンス、設定、構造が変化するドキュメント)に適しています。詳細な比較についてはCSV vs JSON vs XMLガイドをご覧ください。
関連リソース
- CSVエディター — ブラウザでCSVデータを編集・クリーニング
- CSV to JSON変換ガイド — フォーマット間の変換
- JSONフォーマットのベストプラクティス — JSON出力の扱い方