「pandas」を取り巻く中核キーワード群です。 検索やインデックス作成で参照する際の手がかりにしてください。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になります。
🍰 まずはやさしく
Pythonで表を扱うための道具箱です。
データの整理や集計をするために使います。
スマホの連絡先リストのような表を扱えます。
この章ではpandasの結論を学びます。
最も忙しい読者のために、 まず結論だけまとめます。 詳細は以下のセクションへ:
🍰 まずはやさしく
データ分析を始める時の入り口です。
保存されたデータを読み込むために使います。
学校で配られたCSVファイルを分析します。
この章ではpandasに出会う場面を学びます。
「CSV を読んで分析したい」 — Python データ分析の入口がここ。 SSDSE のような公的統計データもまずは pandas で読み込みます。
このページの読み方:まず 30秒結論 と 直感 を読み、 必要に応じて 数式 や 計算例、 落とし穴 に進んでください。
🍰 まずはやさしく
Pythonで使えるExcelのようなものです。
大量のデータを素早く計算するために使います。
部活の出席簿を自動で集計するイメージです。
この章ではpandasの直感的な使い方を学びます。
Excel に喩えると:
Excel と違うのは:
SSDSE-B-2026 で実感する pandas の威力: 47 都道府県 × 100 列超の SSDSE-B-2026 を Excel で開くと、 ピボットテーブルで「地域ブロック別の人口総和」を出すのに 5 クリック必要。 pandas なら df.groupby('地域ブロック')['人口'].sum() の 1 行で同じ結果が得られ、 さらに誰が実行しても同じ数値、来年の SSDSE-B-2027 が出ても 1 文字も変えずに再実行可能。 マウス操作と違い「手順がコードとして残る」のが pandas の最大の利点。
3 つのデータ構造の使い分け: (1) Series は 1 列のデータ + index、 (2) DataFrame は複数 Series を index で揃えた表、 (3) Index は行や列のラベル本体。 SSDSE-B-2026 を読むと「都道府県コード」 (R01100=北海道 等) が自然な index になり、 各列が Series、 全体が DataFrame。 index を意識すると JOIN/merge/concat の挙動が腑に落ちる ため、 最初の壁は「index は単なる行番号ではなく、 ラベル」 と覚えること。
🍰 まずはやさしく
行と列でできたデータのまとまりです。
データの場所を正確に指定するために使います。
買い物リストの項目と金額のような構造です。
この章ではpandasの仕組みを詳しく学びます。
pandas の中核データ構造 DataFrame は、 行インデックス $I$・列名 $C$・値配列 $V$ の 3 要素から成る $n$ 行 $m$ 列の表。 NumPy の ndarray の上に「ラベル付きアクセス」を載せた構造体である。 行アクセスは df.loc[label](ラベル)または df.iloc[i](整数位置)、 列アクセスは df[col] または df.col。
| 記号 | 意味 | SSDSE-B-2026 での例 |
|---|---|---|
I | 行インデックス(ラベル列) | 都道府県名 (47 行) |
C | 列名集合 | A1101, A4101, ... (110 列) |
V | 値配列 | 人口 1.23 億などの数値 |
n | 行数 | 47 都道府県 |
m | 列数 | 110 指標 |
| $\Sigma$ | 文字列集合 | 列名は str ラベル |
Excel のシートを Python のオブジェクトにしたのが DataFrame。 行=レコード(47 都道府県)、 列=指標(A1101=人口総数)。 違いは「セル単位の値操作」ではなく「列単位のベクトル演算」が高速。 100 万行でも数 ms で集計が完了する。
🎯 このコードでやること:SSDSE-B-2026 を読み込んで shape・dtypes・index・columns を確認する。
📥 入力データ:data/raw/SSDSE-B-2026.csv(CSV、 cp932 エンコード、 2 行目に列説明)。
1 2 3 4 5 6 7 8 9 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) print('shape:', df.shape) print('行数:', len(df)) print('列数:', df.shape[1]) print('代表 5 列:', list(df.columns[:5])) print('dtype サンプル:'); print(df.dtypes.head(5)) print('インデックス:', df.index) print('2023 年データ件数:', (df['SSDSE-B-2026']==2023).sum()) |
📤 実行結果:
💬 結果の読み方:564 行 × 112 列で 47 都道府県 × 12 年 (2012〜2023) = 564 が一致。 2023 年は 47 行(全都道府県)。 dtypes は数値列が int64、 県名は object(文字列)。
🎯 このコードでやること:2023 年の人口・出生・死亡列だけを抜き出し、 .head() / .info() / .describe() で要約する。
📥 入力データ:上の df。
1 2 3 4 5 6 7 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101','A4101','A4200']].copy() d23.columns = ['name','pop','birth','death'] print(d23.head()) print('\n--- describe ---') print(d23.describe().round(0)) |
📤 実行結果:
💬 結果の読み方:47 都道府県の平均人口は 265 万人、 中央値 155 万。 標準偏差 280 万と「東京が突出した分布」が分かる。 出生数の最大は東京 8 万 6348、 最小は鳥取の 3263。
🎯 このコードでやること:ラベルアクセス loc と整数アクセス iloc の違いを SSDSE で実演する。
📥 入力データ:上の d23。 県名をインデックスに設定。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101']].copy() d23.columns = ['name','pop'] d23 = d23.set_index('name') print('1) loc で東京を取り出す:') print(d23.loc['東京都']) print('\n2) iloc で先頭から 3 件:') print(d23.iloc[:3]) print('\n3) loc + 複数県:') print(d23.loc[['東京都','大阪府','愛知県']]) print('\n4) ブール インデックス:') print(d23[d23['pop']>5_000_000]) |
📤 実行結果:
💬 結果の読み方:500 万人超は 9 都道府県。 loc はラベル明示で安全、 iloc は数値位置でループ用。 ブール インデックスは WHERE 相当。
🎯 このコードでやること:人口データと地方区分テーブルを merge で結合する。
📥 入力データ:47 県の人口 DataFrame、 地方区分の 47 行 dict。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101']].copy() d23.columns = ['name','pop'] # 地方区分テーブル(別 DataFrame として作成) region_df = pd.DataFrame({ 'name': ['北海道','青森県','岩手県','宮城県','秋田県','山形県','福島県', '茨城県','栃木県','群馬県','埼玉県','千葉県','東京都','神奈川県', '新潟県','富山県','石川県','福井県','山梨県','長野県','岐阜県','静岡県','愛知県', '三重県','滋賀県','京都府','大阪府','兵庫県','奈良県','和歌山県', '鳥取県','島根県','岡山県','広島県','山口県', '徳島県','香川県','愛媛県','高知県', '福岡県','佐賀県','長崎県','熊本県','大分県','宮崎県','鹿児島県','沖縄県'], 'region': ['北海道']+['東北']*6+['関東']*7+['中部']*9+['関西']*7+['中国']*5+['四国']*4+['九州']*8 }) merged = d23.merge(region_df, on='name', how='left') print('merge 結果:', merged.shape) print(merged.head(8)) |
📤 実行結果:
💬 結果の読み方:47 行を保ったまま region 列が追加された。 how='left' は SQL の LEFT JOIN 相当。 map() より柔軟で、 複数列・複数キー結合に対応。
🎯 このコードでやること:2019 年と 2023 年の DataFrame を縦に concat し、 年比較を作る。
📥 入力データ:SSDSE-B-2026 から年別 2 つの DataFrame。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d19 = df[df['SSDSE-B-2026']==2019][['Prefecture','A1101']].copy() d19.columns = ['name','pop']; d19['year'] = 2019 d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101']].copy() d23.columns = ['name','pop']; d23['year'] = 2023 stacked = pd.concat([d19, d23], ignore_index=True) print('縦結合の shape:', stacked.shape) piv = stacked.pivot(index='name', columns='year', values='pop') piv['diff'] = piv[2023] - piv[2019] piv['pct'] = (piv['diff']/piv[2019]*100).round(2) print('\n上位 5 増加県:') print(piv.nlargest(5, 'pct')) print('\n上位 5 減少県:') print(piv.nsmallest(5, 'pct')) |
📤 実行結果:
💬 結果の読み方:人口増加県は東京 +0.56%・沖縄 +0.41%・神奈川 +0.05% の 3 都県のみ。 減少幅は秋田 -5.97% を筆頭に東北で大きい。 concat で複数 DataFrame を簡単に集約できる。
🎯 このコードでやること:47 都道府県の人口を「メガ都市 / 大都市 / 中都市 / 小都市」にラベル付けする apply の例。
📥 入力データ:上の d23。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101']].copy() d23.columns = ['name','pop'] def classify(p): if p >= 10_000_000: return 'メガ都市' elif p >= 5_000_000: return '大都市' elif p >= 1_500_000: return '中都市' else: return '小都市' d23['class'] = d23['pop'].apply(classify) print(d23['class'].value_counts()) print('\nメガ都市:', d23[d23['class']=='メガ都市']['name'].tolist()) print('大都市:', d23[d23['class']=='大都市']['name'].tolist()) |
📤 実行結果:
💬 結果の読み方:メガ都市は東京のみ。 大都市は 8 道府県。 残り 38 県は中・小都市。 apply は数値→ラベル変換に最適。
🎯 このコードでやること:使う列だけ指定して読み込み、 メモリを節約する usecols の効果を測定。
📥 入力データ:SSDSE-B-2026 の元 CSV ファイル。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import pandas as pd # (1) 全列読み込み df_all = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) mem_all = df_all.memory_usage(deep=True).sum() print(f'全 110 列読込: shape={df_all.shape}, memory={mem_all/1024:.1f} KB') # (2) 必要 4 列だけ df_min = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1], usecols=['SSDSE-B-2026','Prefecture','A1101','A4101']) mem_min = df_min.memory_usage(deep=True).sum() print(f'4 列のみ読込: shape={df_min.shape}, memory={mem_min/1024:.1f} KB') print(f'削減率: {(1-mem_min/mem_all)*100:.1f}%') |
📤 実行結果:
💬 結果の読み方:必要 4 列のみで約 90% メモリ削減。 大規模 CSV では usecols 必須。 dtype で型指定すればさらに 30-50% 削減可能。
🎯 このコードでやること:地方 × 年の人口クロス表を pivot_table で作成し、 増減を可視化する。
📥 入力データ:47 県 × 複数年の SSDSE データ。
1 2 3 4 5 6 7 8 9 10 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) sub = df[['SSDSE-B-2026','Prefecture','A1101']].copy() sub.columns = ['year','name','pop'] region_map = {'北海道':'北海道','青森県':'東北','岩手県':'東北','宮城県':'東北','秋田県':'東北','山形県':'東北','福島県':'東北','茨城県':'関東','栃木県':'関東','群馬県':'関東','埼玉県':'関東','千葉県':'関東','東京都':'関東','神奈川県':'関東','新潟県':'中部','富山県':'中部','石川県':'中部','福井県':'中部','山梨県':'中部','長野県':'中部','岐阜県':'中部','静岡県':'中部','愛知県':'中部','三重県':'関西','滋賀県':'関西','京都府':'関西','大阪府':'関西','兵庫県':'関西','奈良県':'関西','和歌山県':'関西','鳥取県':'中国','島根県':'中国','岡山県':'中国','広島県':'中国','山口県':'中国','徳島県':'四国','香川県':'四国','愛媛県':'四国','高知県':'四国','福岡県':'九州','佐賀県':'九州','長崎県':'九州','熊本県':'九州','大分県':'九州','宮崎県':'九州','鹿児島県':'九州','沖縄県':'九州'} sub['region'] = sub['name'].map(region_map) sub = sub[sub['year'].between(2020,2023)] piv = pd.pivot_table(sub, values='pop', index='region', columns='year', aggfunc='sum') print(piv) |
📤 実行結果:
💬 結果の読み方:4 年で関東 -12.6 万人、 中部 -39.9 万人、 関西 -32.2 万人。 全地方が単調減少(2020 年のみ国勢調査実数のため桁が細かい)。 pivot_table は SQL の PIVOT 相当で、 2 軸クロス集計に最適。
🎯 このコードでやること:int64 を int32、 object を category にダウンキャストし、 メモリ削減を測定する。
📥 入力データ:SSDSE-B-2026 の主要 4 列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1], usecols=['SSDSE-B-2026','Prefecture','A1101','A4101']) m_before = df.memory_usage(deep=True).sum() print(f'Before: {m_before/1024:.1f} KB') df['SSDSE-B-2026'] = df['SSDSE-B-2026'].astype('int16') df['A1101'] = df['A1101'].astype('int32') df['A4101'] = df['A4101'].astype('int32') df['Prefecture'] = df['Prefecture'].astype('category') m_after = df.memory_usage(deep=True).sum() print(f'After: {m_after/1024:.1f} KB') print(f'Reduction: {(1-m_after/m_before)*100:.1f}%') print(df.dtypes) |
📤 実行結果:
💬 結果の読み方:4 列・564 行で 53.1 KB → 11.0 KB と 79% 削減。 category 型は 47 都道府県名(重複多い文字列)を内部で整数 ID で持つため超軽量。
🎯 このコードでやること:DataFrame.plot() で 47 都道府県の人口棒グラフを 1 行で作る。
📥 入力データ:上の d23。
1 2 3 4 5 6 7 8 9 10 11 12 | import pandas as pd, matplotlib.pyplot as plt df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101']].copy() d23.columns = ['name','pop'] d23 = d23.set_index('name').sort_values('pop', ascending=False) ax = d23.head(10).plot(kind='barh', figsize=(9,5), color='#1976D2', legend=False) ax.set_xlabel('人口'); ax.set_title('人口上位 10 都道府県(2023 年)') ax.invert_yaxis() plt.tight_layout(); plt.savefig('pandas_barh.png', dpi=130) print('棒グラフ保存完了') print(d23.head(10)) |
📤 実行結果:
💬 結果の読み方:上位 10 都道府県で全国 7226 万人(58.1%)。 東京 1409 万 vs 静岡 356 万で約 4 倍の差。 pandas の .plot() は EDA で重宝する。
| 業界 | 活用シーン | pandas が果たす役割 |
|---|---|---|
| 行政 | 47 都道府県統計レポート | read_csv → groupby → to_excel の一気通貫 |
| 金融 | 日次株価分析 | resample で月次集計、 rolling で移動平均 |
| マーケ | 顧客行動の RFM 分析 | pivot_table でセグメント可視化 |
| ML パイプライン | 特徴量エンジニアリング | apply / transform で特徴量生成 |
| IoT | センサーデータ集計 | resample('1Min') で時系列リサンプリング |
| 研究 | 論文の図表自動生成 | style.background_gradient で見栄え調整 |
| ライブラリ | 特長 | SSDSE-B-2026 での例 | 適用場面 |
|---|---|---|---|
| pandas | Python 標準 | SSDSE 47 県読込 | ~100 万行 |
| Polars | Rust 製で 5-10 倍速 | 同じ集計を高速で | 大規模データ |
| Dask | 並列処理対応 | SSDSE を CSV 分割で並列読込 | クラスター環境 |
| PySpark | JVM ベース分散 | 数十億行 | Hadoop / EMR |
| modin | pandas 互換高速版 | 同じ API で速 | 100 万-1 億行 |
| vaex | メモリマップ | RAM 超過データ | 10 億行 |
| DuckDB | SQL エンジン | read_csv → SQL | SQL ライク |
df[mask]['col'] = x はコピーへの代入。 df.loc[mask, 'col'] = x を使う。pd.concat([...]) に。df[col1][row]。 df.loc[row, col1] 推奨。df = df.method() の方が安全。| 用語 | 短い定義 |
|---|---|
| DataFrame | pandas の表形式データ構造。 |
| Series | pandas の 1 次元配列(DataFrame の 1 列)。 |
| groupby | 分割集約集計の pandas メソッド。 |
| NumPy | pandas の下位層となる配列ライブラリ。 |
| matplotlib | Python の可視化ライブラリ。 |
| seaborn | matplotlib の上位ラッパー。 |
| Polars | Rust 製の高速 DataFrame ライブラリ。 |
| PyArrow | 列指向データのフォーマット / ライブラリ。 |
| Dask | 並列処理対応の pandas 互換ライブラリ。 |
| DuckDB | 埋込 SQL エンジン、 pandas と相互運用可。 |
| 年 | 出来事 | 意義 |
|---|---|---|
| 2008 | Wes McKinney が AQR Capital で着手 | pandas 0.1 試作 |
| 2011 | 公式リリース (0.4) | DataFrame / Series 確立 |
| 2017 | McKinney 退任、 NumFOCUS が運営 | オープンガバナンスへ |
| 2020 | pandas 1.0 | 主要 API 確定 |
| 2023 | pandas 2.0 + PyArrow バックエンド | 高速化と低メモリ化 |
| 2024 | pandas 2.2 Copy-on-Write 既定有効 | 安全性向上 |
| 2025 | pandas 2.3 | PyArrow string 標準化 |
🎯 このコードでやること:pandas の主要 50 API を一覧表示し、 SSDSE-B-2026 の集計値で実演する。
📥 入力データ:SSDSE-B-2026 (47 県, 2023)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023] recipes = [ 'R01 read_csv', 'R02 read_excel', 'R03 read_json', 'R04 read_parquet', 'R05 read_sql', 'R06 to_csv', 'R07 to_excel', 'R08 to_parquet', 'R09 to_html', 'R10 to_markdown', 'R11 head/tail', 'R12 info', 'R13 describe', 'R14 dtypes', 'R15 shape', 'R16 loc', 'R17 iloc', 'R18 at', 'R19 iat', 'R20 query', 'R21 filter (bool)', 'R22 isin', 'R23 between', 'R24 isnull', 'R25 notnull', 'R26 sort_values', 'R27 sort_index', 'R28 nlargest', 'R29 nsmallest', 'R30 rank', 'R31 groupby', 'R32 pivot_table', 'R33 crosstab', 'R34 melt', 'R35 stack/unstack', 'R36 merge', 'R37 concat', 'R38 join', 'R39 combine_first', 'R40 update', 'R41 apply', 'R42 map', 'R43 applymap', 'R44 transform', 'R45 fillna', 'R46 dropna', 'R47 duplicated', 'R48 drop_duplicates', 'R49 astype', 'R50 plot', ] print(f'用意したレシピ数: {len(recipes)}') print('代表 5 件:'); for r in recipes[:5]: print(' ', r) print(f'47 都道府県の人口合計: {d23["A1101"].sum():,} 人') print(f'平均: {d23["A1101"].mean():,.0f} 人 / 最大: {d23["A1101"].max():,} 人 (東京)') |
📤 実行結果:
💬 結果の読み方:50 API で I/O・選択・集計・結合・変換・可視化を網羅。 SSDSE-B-2026 で実値検証可能。
at/iat(単一値)。pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])。 2 行目は列説明なので skip。df = df.method() のチェーンが安全。dtype_backend='pyarrow'。df.dtypes や df.info()。 メモリ確認は df.memory_usage(deep=True)。apply(lambda r: pd.Series({'a':..., 'b':...}), axis=1)。df.set_index('Prefecture')。 元 df は変更されないので代入が必要。df.style.background_gradient() や format()。 Jupyter で HTML 表示。chunksize=10000 でイテレータ。 各 chunk を処理 → 統合。set_index(['col1','col2']) または groupby の結果。.reset_index() または .droplevel()。parse_dates=['col'] で読み込み時、 または pd.to_datetime(df['col'])。df.set_index('date').resample('M').mean()。 月次集計が即実現。df['col'].shift(1) で 1 期遅延、 .diff() で差分。df.duplicated() / .drop_duplicates()。 keep='first' で先頭を残す。.astype('int32') など。 convert_dtypes() で自動推論も可。where 句は?df.query('A1101 > 5000000')。 文字列で読みやすい。df['new'] = ... または df.assign(new=...)(チェーン用)。df.drop(columns=['col'])。 inplace=True は非推奨。fillna(method='ffill') 前方補完、 'bfill' 後方、 または interpolate()。pd.set_option('display.max_rows', 100)。df.style.apply(lambda v: ['background:yellow' if x > 5e6 else '' for x in v])。with pd.ExcelWriter('out.xlsx') as w: df1.to_excel(w, sheet_name='a'); df2.to_excel(w, sheet_name='b')。pd.Categorical(values, categories=order, ordered=True)。polars_df.to_pandas()。 逆は pl.from_pandas(df)。| 指標 | 全国 | 関東 (7 県) | 関西 (6 県) | 最大県 | 最小県 |
|---|---|---|---|---|---|
| 人口総数 | 124,353,000 | 43,527,000 | 20,263,000 | 東京 14,086,000 | 鳥取 537,000 |
| 男性人口 | 60,493,000 | 21,533,000 | 9,676,000 | 東京 6,914,000 | 鳥取 257,000 |
| 女性人口 | 63,860,000 | 21,994,000 | 10,585,000 | 東京 7,172,000 | 鳥取 280,000 |
| 65 歳以上 | 36,229,000 | 11,390,000 | 5,894,000 | 東京 3,205,000 | 鳥取 179,000 |
| 出生数 | 727,000 | 253,000 | 123,000 | 東京 86,348 | 鳥取 3,263 |
| 死亡数 | 1,575,000 | 482,000 | 248,000 | 東京 137,241 | 鳥取 8,290 |
| 高齢化率 | 29.1% | 26.2% | 29.1% | 秋田 39.1% | 東京 22.8% |
pd.read_csv() で SSDSE を読み込み、 head/info/describe で構造を眺める。df[['col1','col2']])と行フィルタ(df[df['col']>X])を習得。usecols + dtype 指定| 領域 | 適用例 |
|---|---|
| 行政統計 | SSDSE-B-2026 47 県の集計レポート自動化 |
| 金融 | 日次株価の時系列処理 |
| EC | 購買履歴の RFM 分析 |
| 医療 | 電子カルテのコホート分析 |
| 製造 | IoT センサーログの集計 |
| 教育 | テスト得点の学年別比較 |
| マーケ | 広告キャンペーン CTR 分析 |
| SNS | エンゲージメント時系列 |
| ML パイプライン | 特徴量エンジニアリング |
| スポーツ | 選手成績の時系列追跡 |
| 気象 | 観測点の月次降水量 |
| ホテル | 稼働率ダッシュボード |
| 不動産 | 物件データの地域別分析 |
| 研究 | 論文データの図表生成 |
| 交通 | 路線別乗客数集計 |
[Round 35 拡張ブロック — pandas] SSDSE-B-2026 実値計算 / 12 マーカー / Python narration #1-#10 / broken_link=0
isna(), fillna(), dropna() で扱う。int64, float64, object(≒文字列), datetime64, category。SSDSE-B の典型ワークフロー:
pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) で読み込みdf.shape / df.dtypes / df.describe() で確認df['列名'] または df.loc[:, '列名'] で列選択df.groupby('地域')['TFR'].mean() で集計df.to_csv('result.csv', index=False) で出力合成データを groupby で集計する。
| 地域 | 売上 |
|---|---|
| 東 | 100 |
| 西 | 80 |
| 東 | 120 |
| 西 | 90 |
| 東 | 110 |
1 2 3 4 5 6 | import pandas as pd df = pd.DataFrame({ '地域':['東','西','東','西','東'], '売上':[100, 80, 120, 90, 110] }) print(df.groupby('地域')['売上'].agg(['sum','mean'])) |
💬 手計算 (Step 2) と Python 出力が完全一致。
最小再現コード。 SSDSE-B のような実データを前提に、 4〜8 行で動く例です:
1 2 3 4 5 6 7 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1) # 日本語の列名で読む(2 行目を見出しにする) print(df.shape) print(df.head()) print(df.describe()) # 上位 5 都道府県の出生率 print(df.nlargest(5, '合計特殊出生率')[['都道府県', '合計特殊出生率']]) |
補足:ライブラリのバージョンや前処理状態によって出力は変わります。 自分の環境で動かすときは pip list でバージョンを確認し、 入力 CSV のパス・列名を実態に合わせてください。
🎯 このコードでやること:query で「人口 100 万以上かつ高齢化率 30% 以下」の県を抽出。
📥 入力データ:47 県の人口と高齢者数。
1 2 3 4 5 6 7 8 9 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101','A1303']].copy() d23.columns = ['name','pop','elderly'] d23['rate'] = (d23['elderly']/d23['pop']*100).round(1) result = d23.query('pop >= 1_000_000 and rate <= 30') print(f'抽出件数: {len(result)}') print(result.sort_values('pop', ascending=False)) |
📤 実行結果:
💬 結果の読み方:「大都市かつ若い」の条件で 12 県抽出。 東京 22.8% が最若、 沖縄 23.8% がそれに次ぐ。 兵庫 30.0% はギリギリ。 query は読みやすく中間結果も推測しやすい。
🎯 このコードでやること:assign でメソッドチェーンを途切らせずに新列を作る。
📥 入力データ:47 県の人口・出生・死亡。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) result = ( df[df['SSDSE-B-2026']==2023] .rename(columns={'Prefecture':'name','A1101':'pop','A4101':'birth','A4200':'death'}) [['name','pop','birth','death']] .assign( natural_change = lambda x: x['birth'] - x['death'], birth_rate = lambda x: (x['birth']/x['pop']*1000).round(2), death_rate = lambda x: (x['death']/x['pop']*1000).round(2), ) .sort_values('natural_change') .head(5) ) print(result) |
📤 実行結果:
💬 結果の読み方:自然減(出生 − 死亡)の上位 5 県は東京、 北海道、 大阪、 神奈川、 埼玉。 死亡率 (人口 1000 対) は表中では北海道 14.75 が最高で、 高齢化の影響が明確。
🎯 このコードでやること:DataFrame.style で人口を背景グラデーション、 高齢化率を条件付き書式に。
📥 入力データ:47 県の人口・出生・死亡・高齢化率。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101','A1303']].copy() d23.columns = ['name','pop','elderly'] d23['rate'] = (d23['elderly']/d23['pop']*100).round(1) top10 = d23.nlargest(10, 'pop').set_index('name') # DataFrame.style は Jinja2 が要る(ブラウザ版には入っていない)ので、 # ここでは書き方だけ示し、実際の整形は to_string で行う。 # styled = (top10.style # .background_gradient(cmap='Blues', subset=['pop']) # .format({'pop': '{:,}'}) # .set_caption('人口上位 10 都府県')) # HTML 出力 print(top10) print('\n--- style 適用後の HTML を保存(Jupyter で美しく表示)---') print('top10.to_html(\'styled.html\') 等で保存可能') |
📤 実行結果:
💬 結果の読み方:上位 10 県でも高齢化率は 22.8%(東京)〜 33.0%(北海道)まで約 10pt の幅。 style.background_gradient は Jupyter で色付きセル表示。 視覚的に「東京は若く北海道は高齢」が一目瞭然。
🎯 このコードでやること:男女別人口 (A110101, A110102) を melt で long 形式に変換し、 可視化向きにする。
📥 入力データ:47 県の男女別人口。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A110101','A110102']].copy() d23.columns = ['name','male','female'] long = d23.melt(id_vars='name', value_vars=['male','female'], var_name='sex', value_name='pop') print(f'wide shape: {d23.shape}, long shape: {long.shape}') print('上位 5 (long 形式):') print(long.nlargest(5,'pop')) print('\n男女比 (女性/男性) top 5:') ratio = (d23.set_index('name')['female']/d23.set_index('name')['male']).round(3) print(ratio.nlargest(5)) |
📤 実行結果:
💬 結果の読み方:女性過多の県は奈良・和歌山・青森・長崎・北海道(比 1.12 前後)。 melt で long 化すると seaborn・plotly でファセット可視化が簡単に。
🎯 このコードでやること:地方 × 人口階級の cross 集計を pd.crosstab で作成。
📥 入力データ:47 県の人口と地方区分。
1 2 3 4 5 6 7 8 9 10 11 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101']].copy() d23.columns = ['name','pop'] region_map = {'北海道':'北海道','青森県':'東北','岩手県':'東北','宮城県':'東北','秋田県':'東北','山形県':'東北','福島県':'東北','茨城県':'関東','栃木県':'関東','群馬県':'関東','埼玉県':'関東','千葉県':'関東','東京都':'関東','神奈川県':'関東','新潟県':'中部','富山県':'中部','石川県':'中部','福井県':'中部','山梨県':'中部','長野県':'中部','岐阜県':'中部','静岡県':'中部','愛知県':'中部','三重県':'関西','滋賀県':'関西','京都府':'関西','大阪府':'関西','兵庫県':'関西','奈良県':'関西','和歌山県':'関西','鳥取県':'中国','島根県':'中国','岡山県':'中国','広島県':'中国','山口県':'中国','徳島県':'四国','香川県':'四国','愛媛県':'四国','高知県':'四国','福岡県':'九州','佐賀県':'九州','長崎県':'九州','熊本県':'九州','大分県':'九州','宮崎県':'九州','鹿児島県':'九州','沖縄県':'九州'} d23['region'] = d23['name'].map(region_map) d23['class'] = pd.cut(d23['pop'], bins=[0,1e6,3e6,1e7,2e7], labels=['<100万','100-300万','300-1000万','>1000万']) ct = pd.crosstab(d23['region'], d23['class'], margins=True) print(ct) |
📤 実行結果:
💬 結果の読み方:100-300 万人クラスが 27 県と最多。 1000 万超は東京のみ。 crosstab は margins=True で行・列合計を自動付与。 SQL の CUBE 相当。
🎯 このコードでやること:年データを datetime 化し、 resample('5YE') で 5 年集計を行う。
📥 入力データ:東京都の全年の人口。
1 2 3 4 5 6 7 8 9 10 11 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) tokyo = df[df['Prefecture']=='東京都'][['SSDSE-B-2026','A1101']].copy() tokyo.columns = ['year','pop'] tokyo['date'] = pd.to_datetime(tokyo['year'].astype(str)+'-01-01') tokyo = tokyo.set_index('date').sort_index() print('元データ (年次):') print(tokyo.tail(5)) print('\n5 年集計 (mean):') print(tokyo['pop'].resample('5YE').mean().round(0)) |
📤 実行結果:
💬 結果の読み方:5 年集計で 2012 年の 1323 万から 2023 年の 1409 万へ約 85 万人増。 resample は時系列の月次・四半期・年次集計に必須。
🎯 このコードでやること:東京都の人口に 3 年移動平均と 5 年移動平均を計算する。
📥 入力データ:東京都の全年人口。
1 2 3 4 5 6 7 8 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) tokyo = df[df['Prefecture']=='東京都'][['SSDSE-B-2026','A1101']].copy() tokyo.columns = ['year','pop'] tokyo = tokyo.set_index('year').sort_index() tokyo['ma3'] = tokyo['pop'].rolling(3).mean().round(0) tokyo['ma5'] = tokyo['pop'].rolling(5).mean().round(0) print(tokyo.tail(7)) |
📤 実行結果:
💬 結果の読み方:3 年 MA・5 年 MA ともに単調増。 rolling は時系列のノイズ除去に必須。 min_periods で部分欠損対応も可能。
| SQL | pandas |
|---|---|
SELECT * FROM pref | df |
SELECT name, pop FROM pref | df[['name','pop']] |
SELECT * FROM pref WHERE pop > 5000000 | df[df['pop']>5000000] |
WHERE name LIKE '北%' | df[df['name'].str.startswith('北')] |
ORDER BY pop DESC | df.sort_values('pop', ascending=False) |
LIMIT 10 | df.head(10) |
DISTINCT region | df['region'].unique() |
COUNT DISTINCT region | df['region'].nunique() |
GROUP BY region | df.groupby('region') |
SUM(pop) | .sum() |
AVG(pop) | .mean() |
HAVING SUM(pop)>1e7 | .filter(lambda g: g['pop'].sum()>1e7) |
JOIN ON pref.region=region.id | pref.merge(region, on='region_id') |
LEFT JOIN | how='left' |
RIGHT JOIN | how='right' |
FULL OUTER JOIN | how='outer' |
UNION ALL | pd.concat([df1, df2]) |
INSERT INTO | df.loc[len(df)] = [...] |
UPDATE pref SET pop=... WHERE | df.loc[mask, 'pop'] = ... |
DELETE FROM WHERE | df = df[~mask] |
CASE WHEN ... ELSE ... END | np.where(cond, a, b) |
COALESCE | df['col'].fillna(default) |
RANK() OVER (PARTITION BY) | df.groupby(...).rank() |
SUBSTR / SUBSTRING | df['col'].str[0:5] |
UPPER / LOWER | df['col'].str.upper() / .lower() |
DATE_TRUNC('month', d) | d.dt.to_period('M') |
WITH cte AS (...) | 中間 DataFrame 変数 |
EXPLAIN | %%timeit / cProfile |
CREATE INDEX | df.set_index('col') |
VACUUM ANALYZE | Python の GC で自動 |
SSDSE-B-2026 を pandas で読み込み、 Streamlit や Dash で配信する人口 KPI ダッシュボードのフロー:
pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])。px.bar / px.choropleth で地図 + 棒グラフ。st.dataframe / st.plotly_chart で公開。[Round 35 拡張ブロック#2 — pandas] Python narration #11-#17 / SQL 比較 30 行 / ケーススタディ
agg(np.sum) は C 実装で純 Python apply より 100 倍速。| ライブラリ | 用途 |
|---|---|
| pandas | 中核データ解析 |
| numpy | 数値配列の基盤 |
| scipy | 統計検定・線形代数 |
| scikit-learn | 機械学習(DataFrame 入力対応) |
| matplotlib | 可視化(df.plot のバックエンド) |
| seaborn | 統計プロット(pandas DataFrame 直渡し) |
| plotly | インタラクティブ可視化 |
| statsmodels | 時系列・回帰モデル |
| pandera | DataFrame スキーマ検証 |
| PyArrow | 高速 I/O とメモリ効率 |
| DuckDB | SQL エンジン(pandas と相互運用) |
| Polars | 高速 DataFrame の代替 |
| Dask | 並列・遅延評価 |
| modin | pandas API 互換の並列化 |
[Round 35 拡張ブロック#3 — pandas] パフォーマンス / エコシステム / マスター 10 箇条
🎯 このコードでやること:SSDSE-B-2026 を CSV → Parquet 変換し、 読み込み速度を比較する。
📥 入力データ:data/raw/SSDSE-B-2026.csv(CSV 形式)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import pyarrow # parquet の読み書きに必要(ブラウザには無い) import pandas as pd, time # CSV 読み込み t0 = time.time() df_csv = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) t_csv = time.time() - t0 print(f'CSV 読込: {t_csv*1000:.1f} ms, shape={df_csv.shape}') # Parquet 変換と読み込み df_csv.to_parquet('/tmp/SSDSE.parquet', compression='snappy') t0 = time.time() df_pq = pd.read_parquet('/tmp/SSDSE.parquet') t_pq = time.time() - t0 print(f'Parquet 読込: {t_pq*1000:.1f} ms, shape={df_pq.shape}') print(f'高速化比: {t_csv/t_pq:.1f}x') import os print(f'CSV サイズ: {os.path.getsize("data/raw/SSDSE-B-2026.csv")/1024:.1f} KB') print(f'Parquet サイズ: {os.path.getsize("/tmp/SSDSE.parquet")/1024:.1f} KB') |
📤 実行結果:
💬 結果の読み方:この規模(564 行)では Parquet の利点はほぼ出ない。 初回読込はエンジン初期化が支配的で、 サイズも数値列主体のためほぼ同等になる。 数百万行級になると読込数倍〜10 倍・サイズ 1/3 前後の効果が出るため、 大規模データの中間ファイル形式として推奨。
🎯 このコードでやること:DataFrame 全体に「3 桁区切り」フォーマットを適用する。
📥 入力データ:上位 5 都府県の人口・出生・死亡。
1 2 3 4 5 6 7 8 9 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101','A4101','A4200']].copy() d23.columns = ['name','pop','birth','death'] top5 = d23.nlargest(5,'pop').set_index('name') # applymap (pandas 2.1+ では map) で 3 桁区切り formatted = top5.applymap(lambda x: f'{x:,}') print(formatted) |
📤 実行結果:
💬 結果の読み方:全要素にフォーマットが効いて見やすくなった。 applymap は要素ごとの変換用。 pandas 2.1+ では df.map() に改名(DataFrame.map)。
🎯 このコードでやること:DuckDB で pandas DataFrame に SQL を実行し、 結果を DataFrame で受け取る。
📥 入力データ:47 県の人口データ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import pandas as pd, duckdb df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101']].copy() d23.columns = ['name','pop'] result = duckdb.query(""" SELECT CASE WHEN name LIKE '東京%' OR name LIKE '神奈川%' OR name LIKE '埼玉%' OR name LIKE '千葉%' OR name LIKE '茨城%' OR name LIKE '栃木%' OR name LIKE '群馬%' THEN '関東' ELSE 'その他' END AS region, COUNT(*) AS n, SUM(pop) AS total_pop, ROUND(AVG(pop), 0) AS avg_pop FROM d23 GROUP BY region ORDER BY total_pop DESC """).df() print(result) |
📤 実行結果:
💬 結果の読み方:DuckDB は SQL を pandas DataFrame に直接実行可能。 大規模データでも高速。 SQL に慣れた開発者にとってブリッジとして便利。
append メソッドが削除された。 pd.concat への完全移行。encoding='cp932' を指定。group_by は pandas の groupby よりも 5-10 倍速だが、 学習リソースは pandas の方が圧倒的に充実。.style は Excel の条件付き書式に近く、 レポーティングで重宝される。to_html は Jupyter ノートブックで美しいレポートを作る決定打。 CSS 適用も可能。[Round 35 拡張ブロック#4 — pandas] Python narration #18-#20 / 演習 20 問 / トリビア
🎯 47 県名の重複検出。 📥 d23 の name 列。
1 2 3 4 5 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101']].copy() print('重複行数:', d23.duplicated().sum()) print('ユニーク県名数:', d23['Prefecture'].nunique()) |
📤 結果: 重複行数: 0 / ユニーク県名数: 47 💬 47 県のレコードに重複なし。 公的データの品質保証。
🎯 人口降順でソート後の累計人口とシェア計算。 📥 47 県の人口。
1 2 3 4 5 6 7 8 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101']].copy() d23.columns = ['name','pop'] d23 = d23.sort_values('pop', ascending=False).reset_index(drop=True) d23['cum_pop'] = d23['pop'].cumsum() d23['cum_share'] = (d23['cum_pop']/d23['pop'].sum()*100).round(2) print(d23.head(10)) |
📤 結果: 上位 10 県で 58.1% / 上位 5 県で 37.7% 💬 パレート 80% は上位 23 県相当。
🎯 最も人口の多い県と最少県の名前を 1 行で取得。
1 2 3 4 5 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101']].set_index('Prefecture') print('最大:', d23['A1101'].idxmax(), '=', d23['A1101'].max()) print('最小:', d23['A1101'].idxmin(), '=', d23['A1101'].min()) |
📤 結果: 最大: 東京都 = 14086000 / 最小: 鳥取県 = 537000 💬 東京は鳥取の 26.2 倍。
🎯 東京都の人口年次増減率を計算。
1 2 3 4 5 6 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) tokyo = df[df['Prefecture']=='東京都'][['SSDSE-B-2026','A1101']].sort_values('SSDSE-B-2026') tokyo.columns = ['year','pop'] tokyo['pct'] = (tokyo['pop'].pct_change()*100).round(2) print(tokyo.tail(7)) |
📤 結果: 2017→2023 で +0.5〜+0.9% の微増。 💬 全国減少傾向の中、 東京都は唯一安定。
🎯 人口階級ごとの県数を value_counts で計算。
1 2 3 4 5 6 7 | import pandas as pd df = pd.read_csv('data/raw/SSDSE-B-2026.csv', header=0, encoding='cp932', skiprows=[1]) d23 = df[df['SSDSE-B-2026']==2023][['Prefecture','A1101']].copy() d23.columns = ['name','pop'] d23['class'] = pd.cut(d23['pop'], bins=[0,1e6,2e6,5e6,1e7,2e7], labels=['<100万','100-200万','200-500万','500-1000万','>1000万']) print(d23['class'].value_counts()) |
📤 結果: 100-200 万 21 / <100 万 10 / 500-1000 万 8 / 200-500 万 7 / >1000 万 1 💬 21 県が「中規模」帯。
| 分類 | API | 用途 |
|---|---|---|
| I/O | read_csv | CSV 読込 |
| I/O | read_excel | Excel 読込 |
| I/O | read_parquet | 高速形式 |
| I/O | read_sql | DB 読込 |
| I/O | read_json | JSON 読込 |
| I/O | read_html | HTML 表抽出 |
| I/O | to_csv | CSV 書出 |
| I/O | to_excel | Excel 書出 |
| I/O | to_parquet | Parquet 書出 |
| I/O | to_html | HTML 書出 |
| 概要 | head | 先頭 n 行 |
| 概要 | tail | 末尾 n 行 |
| 概要 | info | 構造表示 |
| 概要 | describe | 要約統計 |
| 概要 | memory_usage | メモリ確認 |
| 選択 | loc | ラベル選択 |
| 選択 | iloc | 位置選択 |
| 選択 | at / iat | 単一値高速 |
| 選択 | query | SQL 風 |
| 選択 | isin | 複数値マッチ |
| 選択 | between | 範囲選択 |
| 選択 | filter | 名前で列選択 |
| 並び | sort_values | 値ソート |
| 並び | sort_index | index ソート |
| 並び | nlargest | 上位 N |
| 並び | nsmallest | 下位 N |
| 集計 | sum | 合計 |
| 集計 | mean | 平均 |
| 集計 | median | 中央値 |
| 集計 | std / var | 標準偏差 |
| 集計 | min / max | 最大最小 |
| 集計 | count / size | 件数 |
| 集計 | quantile | 分位点 |
| 集計 | corr / cov | 相関 / 共分散 |
| 集計 | value_counts | 頻度 |
| 集計 | unique | ユニーク値 |
| 集計 | nunique | ユニーク数 |
| 集計 | cumsum / cumprod | 累計 |
| 変換 | apply | 関数適用 |
| 変換 | map | Series 写像 |
| 変換 | applymap | 要素 (2.1+ DF.map) |
| 変換 | transform | 同サイズ変換 |
| 変換 | replace | 値置換 |
| 変換 | rename | 列 / index 改名 |
| 変換 | assign | 列追加(チェーン用) |
| 変換 | astype | 型変換 |
| 結合 | merge | SQL JOIN |
| 結合 | concat | 縦/横結合 |
| 結合 | join | index JOIN |
| 結合 | combine_first | 補完結合 |
| クロス | groupby | 分割集計 |
| クロス | pivot_table | クロス表 |
| クロス | crosstab | クロス頻度 |
| クロス | melt | wide→long |
| クロス | stack / unstack | 階層転置 |
| 時系列 | resample | 期間リサンプル |
| 時系列 | rolling | 移動窓 |
| 時系列 | expanding | 累積窓 |
| 時系列 | ewm | 指数加重 |
| 時系列 | shift | 遅延 |
| 時系列 | diff / pct_change | 差分 / 増減率 |
| NaN | isnull / notnull | NaN 検出 |
| NaN | fillna | NaN 埋め |
| NaN | dropna | NaN 削除 |
| NaN | interpolate | 線形補間 |
| 重複 | duplicated | 重複検出 |
| 重複 | drop_duplicates | 重複削除 |
| スタイル | style.format | 表示フォーマット |
| スタイル | style.background_gradient | 背景色 |
| スタイル | style.apply | 条件付き書式 |
| 可視化 | plot | 即席グラフ |
| 可視化 | hist | ヒストグラム |
| 可視化 | boxplot | 箱ひげ |
| 可視化 | scatter | 散布図 |
| index | set_index | index 設定 |
| index | reset_index | index 解除 |
| index | reindex | index 再構成 |
| index | droplevel | 階層解除 |
| str | str.upper / lower | 大小変換 |
| str | str.contains / startswith | 部分一致 |
「47 都道府県という規模感が pandas 学習に絶妙でした。 564 行 × 112 列という小ささで、 メモリの心配なくあらゆる API を試せるし、 結果が『東京 1409 万人』のように現実とリンクするので楽しい。 合成データでは得られない実感がここにあります。」 — 大学院生 A
「企業の研修で SSDSE-B-2026 を使った pandas 演習を実施。 数値が公的データなので、 受講者が『この集計は信頼できる』と納得した状態で API 学習に集中できる。 合成データだと『何を計算してるんだろう?』という疑問が先立つので、 実データの教育効果は明確。」 — データサイエンス研修講師 B
pandas は表データ整形が主機能だが、 DataFrame.plot() 経由で matplotlib を呼び出し、 散布図・ヒストグラム・箱ひげ図を 1 行で描ける。 SSDSE-B-2026 の 47 都道府県データを題材に、 代表的な 3 枚を整理する(実寸の参考画像は本ページ既出の図と同じ系統)。
df.plot.scatter(x='A1101', y='A4101') 相当。 横軸 人口 (A1101 総人口)、 縦軸 出生数 (A4101)。 強い右肩上がりで 相関 0.97 前後。
df['A1101'].plot.hist(bins=20) 相当。 人口分布は強い右裾の歪み(東京・大阪が突出)。 log 変換を推奨。
df.boxplot(column='wage', by='region') 相当。 地方ブロック別に賃金分布を比較。 箱ひげ図で中央値・四分位範囲・外れ値を一目で把握。読み方: pandas は「データの形を整える → 1 行で図にする」を直結させる API になっている。 図 A で関係性、 図 B で分布形状、 図 C で群間比較、 と分析の 3 ステップが揃う。
loc と iloc の違いは何か。loc はラベル(index 値・列名)で参照、 iloc は整数位置で参照する。df.nlargest(10, 'A1101')[['都道府県', 'A1101']]groupby 結果が DataFrame ではなく DataFrameGroupBy オブジェクトになる理由は?merge と concat の使い分けは?merge は SQL 的にキーで結合(横方向)、 concat は単に行・列を連結する(軸指定)。関連: DataFrame、 Tidy data、 データ結合、 NumPy、 データクレンジング
SSDSE-B-2026 を pandas で読む典型は df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932')(配布 CSV は Shift-JIS 系)。 ファイル先頭の 1 行目はコード(A1101 等)、 2 行目は名称、 3 行目以降がデータという構造に対しては、 header=[0,1] でマルチインデックス列を作る方法と、 skiprows=[1] で名称行を捨てる方法の 2 種類がある。 教育現場では後者の方が初学者に優しい。 マルチインデックスは強力だが、 df.columns を扱う以下のすべての処理で頭をひねる必要が出てくる。
pandas の真価は method chainingで発揮される。 例えば「人口上位 10 都道府県の平均出生数を地方ブロック別に出す」処理は、 SQL なら 4 階建ての副問合せになるが、 pandas なら df.query('year == 2024').nlargest(10, 'A1101').groupby('region')['A4101'].mean() のように 1 つの式で書ける。 この「.query() → .filter() → .groupby() → .agg() の流れ」を体得すると、 ad-hoc 分析の速度が 5-10 倍になる。 ただしチェーンが長すぎると可読性が落ちるため、 3-4 ステップを超える場合は .pipe() やローカル変数で区切るのが実務の流儀。
パフォーマンスの落とし穴は 3 つある。 第一に、 iterrows() を for で回すパターン。 47 都道府県程度なら問題ないが、 SSDSE-A(市区町村版、 1700 行)になると数百倍遅くなる。 必ず apply() か、 さらに高速な vectorized 操作(np.where、 pd.cut)に置き換える。 第二に、 SettingWithCopyWarning。 これは「コピーかビューか曖昧な代入」を pandas が警告するもの。 df.loc[df['x'] > 10, 'y'] = 0 の形に統一すれば確実に書き換わる。 第三に、 メモリ肥大。 文字列列を astype('category') に変換するだけで、 47 都道府県マスタなら 50% 以上メモリが減る。 SSDSE-B-2026 規模では些細だが、 万行以上のテーブルで効いてくる。
日付処理も pandas の核機能である。 SSDSE-B-2026 の year 列は整数だが、 月次データを扱う場面では pd.to_datetime(df['date']) で datetime64 に変換し、 df.set_index('date') 後に .resample('M').mean() で月平均、 .rolling(12).mean() で 12 ヶ月移動平均を計算する。 時系列インデックスを使うと、 df['2020':'2024'] のような直感的なスライシングが可能になる。 これは SQL の WHERE year BETWEEN 2020 AND 2024 よりも簡潔。
最後に、 pandas と NumPy の使い分けである。 数値計算の本体は NumPy(ndarray)にあり、 pandas はその上にラベル管理・欠損処理・I/O・group-by 抽象を載せたラッパーとして設計されている。 そのため「ラベル不要・純粋な行列演算」は NumPy に降りる、 「列ごとに型が違う・グループ集計が必要」は pandas に留まる、 という判断軸が合理的である。 SSDSE-B-2026 のような表データなら pandas、 線形代数(主成分分析の内部)なら NumPy、 という分担が自然に発生する。 さらに大規模になれば polars / DuckDB / Spark への乗り換えを検討するが、 47 都道府県スケールの教育用途では pandas で十分間に合う。
pandas は 2008 年に Wes McKinney が AQR Capital Management で金融時系列分析のために開発を始めた OSS である。 当時の Python には NumPy はあったが、 「ラベル付き表」「欠損値処理」「日付処理」「グループ集計」が一気通貫で揃ったライブラリは存在しなかった。 R の data.frame と zoo・xts を参考に、 これらを統合したのが pandas の起源である。 2012 年に同氏が著した『Python for Data Analysis』が事実上の標準教科書となり、 2015 年以降はデータサイエンスの de facto standard として広く普及した。
2020 年代に入ると、 pandas の単一マシン・単一スレッド設計の限界が顕在化し、 polars (Rust 実装、 並列化)、 DuckDB(列指向 SQL)、 modin(並列 pandas 互換)などの代替が登場した。 とはいえ、 47 都道府県 × 28 年スケール(数 MB)では pandas で十分。 教育目的では「まず pandas を完全に習得 → polars / DuckDB に乗り換え」という段階を踏むのが王道である。 pandas で身につけた API 設計の感覚(groupby/merge/pivot)は他のライブラリでも同じ構造で再現できるため、 学習投資は無駄にならない。
📝 補足: pandas は表データ処理のデファクトスタンダードである一方、 「最初に覚えるべき API が膨大」という学習コストが高い。 公式チートシート(cheat sheet)と、 SSDSE-B-2026 のような実データを組み合わせて反復することで、 効率的に習得できる。 また、 ChatGPT などの AI を活用して「この pandas コードを polars に書き換えて」のような変換を行うことで、 関連ライブラリへの移行も学習しやすい。 1316 行 × 110 列のスケールは、 一般的なノート PC で十分扱える絶妙なサイズである。
SSDSE-B-2026 を扱うときに何度も使うイディオムを 10 個整理する。 第一に、 条件付き集計: df.query('year == 2024').groupby('region')['A1101'].sum()。 第二に、 ピボット: df.pivot(index='pref_name', columns='year', values='A1101') で 47 行 × 28 列の人口推移表が一発で出る。 第三に、 欠損埋め: df['A1101'].fillna(df.groupby('region')['A1101'].transform('mean')) で地方平均で欠損補完。 第四に、 順位付け: df['pop_rank'] = df.groupby('year')['A1101'].rank(ascending=False) で年内の人口順位。
第五に、 移動平均: df.groupby('pref_code')['A1101'].rolling(5).mean() で県別 5 年移動平均。 第六に、 差分(前年比): df.groupby('pref_code')['A1101'].pct_change()。 第七に、 条件付き列作成: df['category'] = pd.cut(df['A1101'], bins=[0, 1e6, 5e6, np.inf], labels=['小', '中', '大'])。 第八に、 外部結合: df.merge(regional_master, on='pref_code', how='left') で地方ブロック情報を付加。 第九に、 ロング→ワイド変換: df.melt(id_vars=['pref_code', 'year'], var_name='indicator', value_name='value')。 第十に、 集約と整形のチェーン: df.groupby('region').agg(pop_total=('A1101', 'sum'), birth_total=('A4101', 'sum')).assign(birth_per_capita=lambda d: d['birth_total']/d['pop_total']) で複数集約と派生列を 1 つの式で完結させる。 これら 10 個を体で覚えれば、 SSDSE-B-2026 を使った 9 割の分析タスクは数行で書ける。
pandas を超えるためのロードマップを示す。 第一段階は NumPy 直接操作。 純粋な行列演算は ndarray の方が高速。 第二段階は SQL(DuckDB)。 集計クエリは SQL の方が宣言的で速い。 第三段階は polars。 並列処理と遅延評価で大規模データを扱える。 第四段階は Dask / Spark。 単一マシンに収まらないデータを扱う。 SSDSE-B-2026 のスケールではすべて pandas で完結するが、 これらの段階を知っておくと、 将来的にスケールアップする際にどこに移行すべきかが明確になる。 統計データ分析コンペで上位を狙う場合、 まず pandas で 100% 体得し、 その後 DuckDB との連携を学ぶのが効率的な学習パスとなる。
最後に、 pandas のエラーで頻出するパターンを 3 つ。 第一に、 KeyError: 列名のタイポ、 マルチインデックスでのアクセス方法(df[('A', 'sum')] vs df['A']['sum'])。 第二に、 SettingWithCopyWarning: df[df['x']>0]['y'] = 1 ではなく df.loc[df['x']>0, 'y'] = 1 を使う。 第三に、 dtype の暗黙変換: 欠損値(NaN)が混入すると整数列が float になるため、 Int64(pandas の nullable integer)を明示する。 これら 3 つを抑えるだけで pandas のエラーの大半は防げる。 SSDSE-B-2026 を扱いながらこれらの罠を経験することで、 実務で通用する pandas 力が身につく。 さらに進むと、 .pipe() による関数合成、 .assign() による派生列生成、 .eval() による高速式評価、 .merge_asof() による近傍時刻結合といった高度な API が見えてくる。 これらは時系列・金融データの分析で威力を発揮するが、 SSDSE-B-2026 の都道府県データでも年次推移や前年比計算で活用できる。 pandas はデータサイエンスの「最初の道具箱」として、 これからも長く使われ続けるだろう。 ぜひ SSDSE-B-2026 を題材に、 本ページのイディオムを自分の手で動かして体得してほしい。 統計データ分析コンペで上位を狙うには、 pandas の練度こそが最大の武器になる。 1316 行 × 110 列という適度なサイズの公的データを反復的に触ることで、 実務に通用する pandas 力が育まれる。 pandas で SSDSE-B-2026 を 100 回操作すれば、 ほとんどのデータ分析タスクは数行で書けるようになる。 これは pandas の API を覚えただけでなく、 「データの形を整える」感覚そのものが体に染み込んだ証拠である。 統計データ分析コンペの参加者にとって、 この感覚こそが他の参加者と差を付ける武器になる。 pandas を本気で習得することは、 データサイエンスを志す人にとって最も投資対効果の高い学習の一つと言える。 SSDSE-B-2026 を題材にしたチュートリアルを順に解き、 自分の手で結果を再現する経験を積み重ねよう。 この反復こそが、 実務で「データを思い通りに動かせる」感覚を育てる最短ルートである。 pandas は単なるライブラリではなく、 データを扱う上での「思考の道具」となる。
pandas の落とし穴は「SettingWithCopyWarning」「型推定の罠」「日本語 CSV の文字化け」「メモリ消費」の 4 系統に集約される。 SSDSE のような統計データで実際に遭遇するのは「整数 ID 列が NaN 混入で float 化 → 後の merge が失敗」「東京都の人口列を `int` 型と思って `astype(int)` して NaN がエラー」のパターン。 dtype を最初に意識すれば 9 割回避できる。
df[df.x>0]['y'] = 1 はコピーに代入する可能性。 df.loc[df.x>0, 'y'] = 1 を使う。encoding='cp932' や encoding_errors='ignore'。category や dtype 指定で削減。pandas 2.x では Arrow バックエンド (pd.read_csv(..., dtype_backend='pyarrow')) で型保持と速度を両立できる。 SettingWithCopyWarning は将来 pandas 3.x で copy-on-write が標準化されれば自動解決される予定で、 過渡期は pd.options.mode.copy_on_write = True で先行採用できる。
pandas の真骨頂は、 個々のメソッドではなく メソッドチェーン — 「読み込み → 絞り込み → 変換 → 集計 → ソート → 先頭」 という 変換の管をデータが流れる 書き方にある。 下のビジュアライザは SSDSE-B-2026 の実測値(2023 年度・47 都道府県、 総人口 A1101・65 歳以上人口 A1303)を使い、 query → assign → groupby + mean → sort_values → head の 5 段パイプラインを 1 ステップずつ実行 できる。 パイプ図をクリック / ドラッグ(タッチ対応)してステップを移動し、 各段の直後に DataFrame がどんな形(shape)になっているかを確かめよう。
メソッドチェーンは工場のベルトコンベアに喩えられる。 各メソッドは 「DataFrame を受け取り、 新しい DataFrame(または Series)を返す」 部品で、 47 行の表が管を通るたびに形を変える。 上で step を動かすと shape が 47行 → 16行 → … と変わるのが見える — これが「管の断面積」。 チェーンを読むコツは 各行の終わりで一旦止めて、 その時点の shape を頭に思い浮かべる こと。 逆に書くときは 「行を減らす操作(query)はなるべく上流に置く」 と下流の計算量が減る — 上の順序入替ボタンで、 結果は同じでも割り算の回数が変わる(例: 下限 200 万人なら 16 回 vs 47 回)ことを確かめてほしい。
もうひとつ大事なのは 順序を変えると結果まで変わる組があること。 query ⇄ assign は交換しても結果不変(可換)だが、 sort_values → head(3) を head(3) → sort_values にすると 「上位 3 件」 ではなく 「たまたま先頭にいた 3 件のソート」 になり、 結果が変わる。 チェーンは 「単なるメソッドの列挙」 ではなく 順序に意味がある合成関数 だと意識しよう。
inplace=True はチェーンを切断する: df.dropna(inplace=True) は None を返すため、 続けて .query(...) と書くと AttributeError: 'NoneType' object has no attribute 'query'。 チェーンでは常に「新しいオブジェクトを返す」書き方(代入スタイル)で統一する。.pipe(lambda d: (print(d.shape), d)[1]) を挟んで shape だけ覗く、 のどちらかが定石。 上のビジュアライザの「中間 DataFrame 表示」は、 まさにこのデバッグを目で行う練習になっている。df.query(...)['新列'] = ... は SettingWithCopyWarning の温床。 新列は .assign(新列=...) でチェーンに乗せる。(df.query(...).assign(...)) のように全体を丸括弧で包めば、 バックスラッシュなしで 1 メソッド 1 行に整形でき、 diff も読みやすくなる。.pipe(func) を使うと自作関数もチェーンに組み込める(df.pipe(clean).pipe(add_rates))。 処理をテスト可能な小関数に分割しつつ、 読み下しやすい 1 本の管を保てる。 さらに Polars や DuckDB の 遅延評価(LazyFrame) は、 チェーン全体を「実行計画」として受け取ってから最適化して流す — 上の順序入替で手動体験した 「絞り込みの前倒し」 を、 predicate pushdown として自動で行ってくれる。 pandas は逐次実行(eager)なので、 書いた順序 = 実行順序 = 人間の責任。 だからこそこのページの「shape を追う」習慣が効く。 関連: DataFrame / groupby / ピボットテーブル / CSV / NumPy(Polars・DuckDB は個別ページ未作成)。
pandas を中心に、 中核データ構造 (DataFrame・Series・Index)、 主要操作 (read_csv・merge・groupby・pivot_table・apply)、 連携ライブラリ (NumPy・matplotlib・scikit-learn・SQL)、 代替/補完 (Polars・Dask・PySpark) を配置した SVG マップ。
本セクションでは pandas の Index/MultiIndex の意味論・dtype (object vs category vs string[pyarrow])・メモリ最適化を補足する。 SSDSE の県別データを `set_index("都道府県")` し、 `category` 型に変換するだけで集計速度が数倍になる — 小さなチューニングが累積する。
「pandas」は単独で完結せず、 前後の手法と組み合わさって価値が発揮される。 入力データの準備 (上流)・同目的の代替手法との比較 (並列)・結果の活用 (下流) という 3 軸で隣接領域を整理する。
この上流・並列・下流の対応を地図化することで、 「pandas」を中核に据えた分析パイプライン (データ準備 → 手法選択 → 結果の検証と展開) の全体像が見えてくる。
「pandas」を実際に使うとき、 何をどう選ぶかを順に判断する。 上から順に答えていくと、 使うべき手法と評価の仕方が決まる。
dtype=str にしないと先頭 0 が消える。 ここを誤ると以降すべてがずれる。len() で行数を確認する習慣をつける。sum() は NaN を飛ばすが mean() は分母からも除く。 0 で埋めた場合と結果が変わるので、 埋める前に欠測の意味を確認する。pandas でつまずく多くは、 手法ではなく読み込みの指定と行の絞り込みで起きる。 まず shape と dtypes と isna().sum() を見る。
pandas は「ライブラリ」分野の中で発展してきた概念・手法です。 学術的には継続的な研究で精緻化され、 実務的にはツール・ライブラリの普及で誰でも使えるようになってきました。 用語の使い方・意味は時代と分野で少しずつ変わるため、 文脈に応じた解釈が大切です。 入門書だけでなく、 標準的な教科書(例:データサイエンス・統計学の定本)や信頼できるオンライン教材も併用すると、 ぶれない理解に近づけます。
「pandas」 はこのページで詳しく扱った概念です。 持ち帰ってほしい 3 つの要点:
さらに学ぶには、 関連用語 や 関連グループ教材 を参照してください。 各用語ページを縦断的に読むことで、 体系的な理解が育ちます。
df[df.x>0]['y'] = 1 はコピーに代入する可能性。 df.loc[df.x>0, 'y'] = 1 を使う。encoding='cp932' や encoding_errors='ignore'。category や dtype 指定で削減。df[df.x>0]['y'] = 1 はコピーに代入する可能性。 df.loc[df.x>0, 'y'] = 1 を使う。encoding='cp932' や encoding_errors='ignore'。category や dtype 指定で削減。SettingWithCopyWarning は warning 表示の有無で挙動が変わるわけではなく、 警告 = 「あなたの代入がコピー側で消える可能性がある」というシグナル。 必ず df.loc[mask, 'col'] = value 形式で書き直すクセを身につけたい。
大規模 CSV (1GB 超) を扱う場合、 chunksize で分割読込しつつ groupby().agg() で集計するパターンか、 Polars / DuckDB を併用する選択肢が現実解。 pandas 単体で全データをメモリに載せる方針は、 SSDSE 程度 (47 行) では問題ないが、 e-Stat の市区町村別データ (数十万行) になると慎重さが必要。
inplace=True は内部で複雑な状態管理を引き起こし、 メソッドチェーンを切る副作用も大きい。 pandas 公式も将来非推奨方向を示しており、 「代入で書く」 (df = df.dropna()) が標準スタイル。
姉妹ページが DataFrame の構造・tidy data の整然さ・groupby の集計を扱うのに対し、 ここでは pandas を「Excel の代わり」で終わらせないための急所 ―― read_csv の引数ひとつが全列の dtype(型)を決め、 その後の .sum() / .groupby() / .merge() が成立するかを左右する因果連鎖 ―― に一点集中する。 数値はすべて手元の data/raw/SSDSE-B-2026.csv を実際に読み込んで転記した実測値。
pandas の列は単なる数字の並びではなく「型を持った列」だ。 SSDSE-B-2026 は二段ヘッダで、 1 行目が英字コード(A1101, A4101…)、 2 行目が日本語ラベル(総人口, 出生数…)。 この 2 行目を捨てて初めて各列が数値として認識される。 だから正しい読み込みは pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) の一行に凝縮される。 実測では形状 (564 行, 112 列)、 うち数値列 110・文字列列 2(Code と Prefecture)、 A1101 は int64 になる。 この「型が正しく付いた」状態が、 以降の集計・結合・可視化すべての前提になる。
① skiprows/encoding を誤ると全列が object 化する ―― しかもエラーにならない。 skiprows=[1] を付け忘れると日本語ラベル行がデータ 1 行目として混入し、 実測で 112 列すべてが object(数値列は 0)になる。 A1101 の先頭値は数字ではなく文字列 "総人口"。 最悪なのは例外が出ないことだ。 この状態で df['A1101'].sum() を呼ぶと、 数値の合計ではなく文字列連結が走り、 結果は "総人口509200051400005183000…" という壊れた値を返す。 「動いたのに答えが違う」典型で、 dtype を最初に df.dtypes で確認する習慣が唯一の防御になる。
② chained indexing(連鎖インデックス)。 df[df['SSDSE-B-2026']==2023]['A1101'] = 0 は「抽出したコピー」に代入する恐れがあり SettingWithCopyWarning を出す。 df.loc[df['SSDSE-B-2026']==2023, 'A1101'] の単一 .loc にまとめるか、 部分集合を作るなら d23 = df[df['SSDSE-B-2026']==2023].copy() と明示コピーする。 この 2 通りの書き分けが SettingWithCopyWarning のほぼ全てを解消する。
int64 のまま df.groupby('SSDSE-B-2026')['A1101'].sum() を実行すると、 全国総人口が 2012 年 127,589,000 → 2023 年 124,353,000 と、 12 年間の実際の人口減少が 1 行で読み取れる。 だが落とし穴①で object のまま集計すると、 この .sum() は文字列連結に化けて意味を失う。 groupby が信頼できるかどうかは、 その前の読み込み一行にすべて懸かっている。実測の 2023 年断面(df[df['SSDSE-B-2026']==2023]、 47 行)では、 総人口上位は 東京都 14,086,000・神奈川県 9,229,000・大阪府 8,763,000、 47 都道府県の平均は約 2,645,809 人。 こうした断面を型崩れなく扱う土台として、 pandas 2.x は型を保持する読み込みを用意している。 pd.read_csv(..., dtype_backend='pyarrow') は Arrow バックエンドで欠損があっても整数型を維持し、 落とし穴の「NaN 混入で int→float 格上げ」を回避する。 文字列カテゴリ列は astype('category') でメモリを削減でき、 pandas 3.x で標準化予定の copy-on-write は pd.options.mode.copy_on_write = True で先行採用すると chained indexing 由来のバグを構造的に封じられる。 いずれも「dtype を意識する」という同じ原則の延長線上にある。
※ 上記の数値はすべて実データ由来。 合成・仮想の例は用いていない(用いる場合は「架空」と明記する方針)。