e-Statの家計調査CSVは罠だらけ?Pandas初心者がデータ前処理でハマった話
はじめに
私は熊本で米やクレソンを栽培する農家です。今回は、自身の農産物のマーケティング戦略を考えるため、政府のオープンデータ「家計調査」の分析に挑戦しました。しかし、そのデータは想像以上に手強く…。ということで、今日のブログでは初心者がオープンデータのe-statのデータの前処理にハマってしまった話です。
1. 最初の壁:e-StatのCSVは、そのままでは読めない
政府統計e-Statから家計調査のデータをダウンロードし、Google Colab上のPandasで意気揚々と読み込んだ。しかし、DataFrameは”null"の表示が多いスカスカのデータに。データサイエンス系の本で読むような、きれいなデータとは程遠い現実を突きつけられた。

原因: CSVファイルの上部に、統計名などのメタデータが複数行記載されているため。
対策: df.iloc[]やheaderオプションを使い、メタデータを読み飛ばして、データ本体が始まる行を直接ヘッダーとして指定する必要があった。
import pandas as pd
# 提供されたデータをDataFrameとして読み込むことを想定
df = pd.DataFrame(FEH_All)
# index: 11 の行を新しいヘッダーとして取得
new_header = df.iloc[11]
# DataFrameの列名を新しいヘッダーに設定
df.columns = new_header
# index: 12 以降のデータのみを抽出し、インデックスをリセット
df = df.iloc[12:].reset_index(drop=True)
print("ヘッダー設定後、不要行を削除したデータ:")
print(df.head())
2. 次の壁:ヘッダーが見当たらない & 目的のデータが消える
地域別の支出額を比較するため、データを読み込み、最新年のデータで絞り込んだ。2つのトラブルでうまく読み込めない…。1つは①「ヘッダーがみつからない!」そしてもう1つは、②なぜか「全国」のデータしか残らず、比較したい都市のデータが全て消えてしまった。
原因:
①列名の変更をしたいが、ヘッダーがうまく指定できずエラーが発生。
②当初、「都市別のデータは最新年まで更新されていないのでは?」という仮説を立てたが、これは間違いだった。
真の原因: データの**「都市名の表記の不一致」**。
分析コード上で指定した都市名のリスト(例:'札幌市')と、データ内の都市名(例:'01100 札幌市')の表記が、先頭の市町村コードのせいで一致していなかった。
3. 解決策①:ヘッダーを目視で確認してからヘッダーを指定
- まず、前回同様取り込んだcsvファイルのヘッダーの場所を調整してみた。
import matplotlib.pyplot as plt
import japanize_matplotlib # 日本語表示のためのライブラリ
# --- 1. データの読み込みとヘッダーの同時設定 ---
file_path = '/content/FEH_00200561_251003183302.csv' # あなたがダウンロードしたファイル名に置き換えてください
# header=11 とすることで、12行目をヘッダーとして直接読み込みます
df_raw = pd.read_csv(file_path, encoding='shift_jis', header=None)
- →エラーが発生して列名の変更ができない。
# ファイルの最初の20行を表示します
print("ファイルの最初の20行を表示します。ヘッダー(列名)が何行目にあるか、目で確認してください。")
print(df_raw.head(20))
- -> .head(20)で出力してヘッダーの場所を確認。ヘッダーの位置は"0"!
# ▼▼▼▼▼【あなたの作業】下の XX を、先ほど確認した正しいヘッダー行の番号に書き換える ▼▼▼▼▼
CORRECT_HEADER_ROW = 0
# ▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲
# --- 1. データの読み込み ---
file_path = '/content/FEH_00200561_251003183302.csv'
df = pd.read_csv(file_path, encoding='shift_jis', header=CORRECT_HEADER_ROW)
- 出力
Column Non-Null Count Dtype -----
0 表章項目 1044 non-null object
1 世帯区分(年次−二人以上の世帯) 1044 non-null object
2 地域区分 1044 non-null object
3 時間軸(年次) 1044 non-null object
4 249 他の葉茎菜【円】 1044 non-null object
5 6.2 健康保持用摂取品【円】 1044 non-null object
dtypes: object(6)
memory usage: 49.1+ KB
- ヘッダーを特定したので列名を指定して変更した
# --- 2. 列名の変更と整形 ---
df_renamed = df.rename(columns={
'地域区分': 'city_name',
'時間軸(年次)': 'year',
'249 他の葉茎菜【円】': 'leafy_veg_spend',
'6.2 健康保持用摂取品【円】': 'supplement_spend'
})
# 末尾の不要な行を削除(ファイルによって調整が必要な場合があります)
df_renamed = df_renamed.iloc[:-3]
4. 解決策②:正規表現での文字列置換
対策: Pandasの文字列操作機能を使い、正規表現で都市名の列から先頭の「数字 + スペース」を削除する一行を追加した。
df['city_name'] = df['city_name'].str.replace(r'^\d+\s*', '', regex=True)
これにより、都市名の表記が統一され、ようやく目的のデータを正しく抽出。無事にグラフ化まで辿り着くことができた。
# --- 3. データの抽出と整形(★★最重要修正箇所★★) ---
latest_year = df_renamed['year'].max()
df_latest = df_renamed[df_renamed['year'] == latest_year].copy()
df_analysis = df_latest[['city_name', 'leafy_veg_spend', 'supplement_spend']]
# ▼▼▼▼▼【この一行が全てを解決します】▼▼▼▼▼
# city_name列から、先頭の「数字 + スペース」を正規表現で削除します
df_analysis['city_name'] = df_analysis['city_name'].str.replace(r'^\d+\s*', '', regex=True)
# ▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲
# 金額列を数値に変換
df_analysis['leafy_veg_spend'] = pd.to_numeric(df_analysis['leafy_veg_spend'].str.replace(',', ''), errors='coerce')
df_analysis['supplement_spend'] = pd.to_numeric(df_analysis['supplement_spend'].str.replace(',', ''), errors='coerce')
# グラフ化したい都市をリストアップ(コードなしのシンプルな市名)
target_cities = [
'全国', '札幌市', '仙台市', '東京都区部', '金沢市',
'名古屋市', '大阪市', '広島市', '松山市', '福岡市', '那覇市'
]
df_plot = df_analysis[df_analysis['city_name'].isin(target_cities)].set_index('city_name')
['全国' '01100 札幌市' '02201 青森市' '03201 盛岡市' '04100 仙台市' '05201 秋田市'
'06201 山形市' '07201 福島市' '08201 水戸市' '09201 宇都宮市' '10201 前橋市'
'11100 さいたま市' '12100 千葉市' '13100 東京都区部' '14100 横浜市' '15100 新潟市'
'16201 富山市' '17201 金沢市' '18201 福井市' '19201 甲府市' '20201 長野市' '21201 岐阜市'
'22100 静岡市' '23100 名古屋市' '24201 津市' '25201 大津市' '26100 京都市' '27100 大阪市'
'28100 神戸市' '29201 奈良市' '30201 和歌山市' '31201 鳥取市' '32201 松江市' '33100 岡山市'
'34100 広島市' '35203 山口市' '36201 徳島市' '37201 高松市' '38201 松山市' '39201 高知市'
'40130 福岡市' '41201 佐賀市' '42201 長崎市' '43100 熊本市' '44201 大分市' '45201 宮崎市'
'46201 鹿児島市' '47201 那覇市' '14130 川崎市' '14150 相模原市' '22130 浜松市' '27140 堺市'
'40100 北九州市']
↓正規表現での文字列置換して、余分な数字コードを削除できた!
['全国' '札幌市' '青森市' '盛岡市' '仙台市' '秋田市' '山形市' '福島市' '水戸市' '宇都宮市' '前橋市' 'さいたま市'
'千葉市' '東京都区部' '横浜市' '新潟市' '富山市' '金沢市' '福井市' '甲府市' '長野市' '岐阜市' '静岡市'
'名古屋市' '津市' '大津市' '京都市' '大阪市' '神戸市' '奈良市' '和歌山市' '鳥取市' '松江市' '岡山市' '広島市'
'山口市' '徳島市' '高松市' '松山市' '高知市' '福岡市' '佐賀市' '長崎市' '熊本市' '大分市' '宮崎市' '鹿児島市'
'那覇市' '川崎市' '相模原市' '浜松市' '堺市' '北九州市']
5.今後のための「マイ・テンプレート」
今回の経験から、今後e-Statのデータを扱う際は、以下の手順で進めるのが最も効率的だと分かりました。
まずheader=Noneで読み込み、df.head(20)でヘッダー行を目視で特定する。
特定したヘッダー行番号を使い、header=XXで再読み込みする。
.rename()で列名を英語(あるいは自分が分かりやすい名前)に統一する。
.str.replace()などを使い、データ内の表記の揺れ(今回は市町村コード)を正規化する。
to_numericで数値データを変換する。
6. まとめ:データ分析は「前処理」が9割
データサイエンスの学習では綺麗なデータセットを扱うことが多いが、現実世界のオープンデータは、そのままでは使えない「クセ」の強いものばかりだと痛感した。エラーと向き合い、仮説を立て、一つずつデバッグしていく地道なプロセスこそが、データ分析の核心であると学んだ一連の奮闘だった。
そして、この苦労の末に可視化されたデータを可視化することに成功しました。きっとマーケティング戦略として極めて重要なインサイトを与えてくれることでしょう。畑の土をいじることと、コンピュータのデータをいじること。一見、全く違うこの2つの世界が繋がった瞬間でした。
Discussion