Day 040 — pandas入門(DataFrame・Series)

2026-05-20 白 / Phase 1 理論+コーディング pandas入門

📚 背景知識(読んでから問題へ)

pandasExcel のような表形式データを Python で扱うライブラリです。Kaggle で配布される train.csv の 99% は pandas で読み込みます。numpy が「数値の配列」だったのに対し、pandas は「行ラベル・列ラベル付きの表」を扱えます。

numpy と pandas の違い

ライブラリ主な用途データ単位
numpy 数値計算・行列演算 ndarray 全要素同じ型
pandas 表形式データ操作 DataFrame 列ごとに違う型OK

DataFrame の構造(イメージ)

index Name Age Sex Fare Survived
0Alice22F7.251
1Bob35M71.280
2Carol28F53.101
3Dave45M8.050
4Eve19F13.001

↑ 左端の灰色列が index(行ラベル)、上の青色行が columns(列名)です。

Series と DataFrame の関係

Series(1列だけ)

numpy 配列に「名前と行ラベル」が付いたもの。1次元データ。

df["Age"]
# 0    22
# 1    35
# 2    28
# Name: Age, dtype: int64

DataFrame(表全体)

複数の Series が横に並んだ「表」。Excel シートそのもの。

df
#   Name  Age  Sex  Fare
# 0 Alice  22  F   7.25
# 1 Bob    35  M  71.28
# ...

EDA の典型パイプライン

読込
pd.read_csv()
形状確認
df.shape
型確認
df.dtypes
先頭表示
df.head()
分布確認
value_counts()

🗂️ データスキーマ

架空のタイタニック号風データ(乗客5名分)を使用します。

列名説明値の範囲備考
Name object (str) 乗客名 識別子(モデルには使わない)
Age int64 年齢 19 〜 45 数値特徴量
Sex object (str) 性別 "F" or "M" カテゴリ特徴量
Fare float64 運賃 7.25 〜 71.28 数値特徴量
Survived int64 生存フラグ(0/1) 0 or 1 予測対象(target)

📝 問題

📌
シナリオ: 架空のタイタニック号風データで、pandas の基本操作を実装してください。4つの小問に分かれています。
import pandas as pd
import numpy as np

data = {
    "Name":     ["Alice", "Bob", "Carol", "Dave", "Eve"],
    "Age":      [22, 35, 28, 45, 19],
    "Sex":      ["F", "M", "F", "M", "F"],
    "Fare":     [7.25, 71.28, 53.10, 8.05, 13.00],
    "Survived": [1, 0, 1, 0, 1],
}

問1 — DataFrameの作成

上記の辞書 data から DataFrame df を作成してください。

💡
pd.DataFrame() に辞書をそのまま渡すだけで作れます。

問2 — 基本情報の確認

以下の3つを print() で表示してください:

  • df.shape の結果(行数・列数)
  • df.dtypes の結果(各列の型)
  • df.head(3) の結果(先頭3行)

問3 — 列の選択と統計

  • df["Age"] を取り出し(これが Series)
  • Age平均値・最大値・最小値 を表示
  • df["Sex"].value_counts() で性別ごとの人数を表示
💡
期待される平均: 29.8 / 最大: 45 / 最小: 19

問4 — 条件抽出と新列追加

  • Age30 以上の乗客だけを抽出した DataFrame df_senior を作成
  • 新しい列 IsAdult を追加(Age >= 20 なら 1、それ未満なら 0
  • 生存者(Survived == 1)の Fare の平均値を計算
💡
期待される df_senior: Bob, Dave の2行
生存者の平均運賃: 24.45

🔍 ヒント(段階的開示)

ヒント1 — 方向性
  • 問1: 辞書を pd.DataFrame() に渡すだけ
  • 問2: df.shape df.dtypes df.head(n) はそれぞれ別の方法でアクセス(属性 or メソッド)
  • 問3: 列の取り出しは df["列名"]、Series には .mean() .max() .min() が使える
  • 問4: 条件式 df["Age"] >= 30df[...] の中に入れる
ヒント2 — アプローチ
  • 作成: df = pd.DataFrame(data)
  • 平均: df["Age"].mean()
  • カウント: df["Sex"].value_counts()
  • 条件抽出: df_senior = df[df["Age"] >= 30]
  • 新列追加: df["IsAdult"] = (df["Age"] >= 20).astype(int)
ヒント3 — コード骨格(ほぼ答え)
import pandas as pd
import numpy as np

# 問1
df = pd.DataFrame(___)

# 問2
print("shape:", df.___)
print("dtypes:\n", df.___)
print(df.___(3))

# 問3
ages = df[___]
print("mean:", ages.___())
print(df["Sex"].___())

# 問4
df_senior = df[df["Age"] ___ 30]
df["IsAdult"] = (df["Age"] >= ___).astype(int)
mean_fare_survived = df[df["Survived"] == ___]["Fare"].mean()

模範解答

import pandas as pd
import numpy as np

# 問1: DataFrameの作成
data = {
    "Name":     ["Alice", "Bob", "Carol", "Dave", "Eve"],
    "Age":      [22, 35, 28, 45, 19],
    "Sex":      ["F", "M", "F", "M", "F"],
    "Fare":     [7.25, 71.28, 53.10, 8.05, 13.00],
    "Survived": [1, 0, 1, 0, 1],
}
df = pd.DataFrame(data)

# 問2: 基本情報
print("shape:", df.shape)
# → shape: (5, 5)
print("dtypes:\n", df.dtypes)
# → Name object / Age int64 / Sex object / Fare float64 / Survived int64
print(df.head(3))

# 問3: 列の選択と統計
ages = df["Age"]
print("type:", type(ages))   # 
print(f"mean: {ages.mean():.1f}")  # 29.8
print(f"max:  {ages.max()}")        # 45
print(f"min:  {ages.min()}")        # 19
print(df["Sex"].value_counts())
# F  3
# M  2

# 問4: 条件抽出と新列追加
df_senior = df[df["Age"] >= 30]
print(df_senior)
# Bob (35), Dave (45)

df["IsAdult"] = (df["Age"] >= 20).astype(int)

mean_fare_survived = df[df["Survived"] == 1]["Fare"].mean()
print(f"生存者の平均運賃: {mean_fare_survived:.2f}")  # 24.45
29.8
平均年齢
3
生存者数
60%
生存率
24.45
生存者の平均運賃
2
30歳以上の乗客

🪜 Step-by-Step 解説

Step 1: 辞書 → DataFrame の変換

df = pd.DataFrame(data)

辞書のキーが列名、値(リスト)が列データになります。Kaggle では pd.read_csv("train.csv") で CSV から直接読み込みますが、原理はこれと同じです。

Step 2: shape / dtypes / head — EDA 3点セット

df.shape    # (5, 5)
df.dtypes   # 各列の型
df.head(3)  # 先頭3行

なぜこの順番か? まず shape で「どのくらいの規模か」、次に dtypes で「列ごとの型」、最後に head で「実データ」を確認するのが Kaggle EDA の定番です。

⚠️
shapedtypes属性(括弧なし)、head()メソッド(括弧あり)。この区別は最初の落とし穴です。

Step 3: 列の選択は df["列名"] で Series 化

ages = df["Age"]   # Series(1列だけ)
ages.mean()        # 29.8

Series は numpy 配列に「インデックス」が付いたもの。なので mean() max() min() がそのまま使えます。

Step 4: value_counts() でカテゴリ分布を見る

df["Sex"].value_counts()
# F    3
# M    2

カテゴリ列(性別・地域など)の出現回数を降順で返します。Kaggle の分類問題で「target 列のクラス分布」を確認する時に必ず使います。

Step 5: 条件抽出 — ブールマスクで行を絞る

df_senior = df[df["Age"] >= 30]

内側の df["Age"] >= 30[F, T, F, T, F] のようなブール Series を返します。これを df[...] の中に入れると、True の行だけが残ります。

indexNameAgeSexFareSurvived
1Bob35M71.280
3Dave45M8.050

↑ df_senior(Age >= 30 の2行)。index は元の番号がそのまま保持される点に注目。

Step 6: 新列追加と .astype(int)

df["IsAdult"] = (df["Age"] >= 20).astype(int)

df["IsAdult"] = ... で新しい列を追加できます。(df["Age"] >= 20) はブール Series、.astype(int) で True→1, False→0 に変換。Kaggle 特徴量エンジニアリングの最も基本的なパターンです。

📊 集計可視化(生存率・性別分布)

DataFrame から集計した結果を可視化します。

性別ごとの生存率(架空データ) 100% 50% 0% 100% Female (3名) 生存:3 / 死亡:0 0% Male (2名) 生存:0 / 死亡:2 高生存率 低生存率
💡
本物の Titanic コンペでもこのパターン(女性の生存率が高い)は再現されます。df.groupby("Sex")["Survived"].mean() で1行で出せます(次回以降詳しく扱います)。

🔢 数学・統計の補足(文系向け)

Series と DataFrame を Excel で例える

  • Series = Excel の1つの列(A列だけ)
  • DataFrame = Excel シート全体

df["Age"] で A 列だけ取り出すイメージです。Series には Excel の「行番号」に相当する インデックス が必ず付いています。

「条件抽出」の数学的な意味

df[df["Age"] >= 30]

これは集合論で言う「条件Pを満たす要素の部分集合」の取り出し。

  • 全体集合: 全乗客(5名)
  • 部分集合: 年齢30歳以上の乗客(2名)

中学数学の「集合と部分集合」の概念そのものです。

平均年齢 29.8 の計算

(22 + 35 + 28 + 45 + 19) / 5 = 149 / 5 = 29.8

numpy で学んだ np.mean() と完全に同じ計算を、pandas では series.mean() で実行できます。

🏆 Kaggleでの実践的な使い方

操作Kaggle場面具体例
pd.read_csv() コンペデータ読込 train = pd.read_csv("train.csv")
df.head() / df.shape EDA の第一歩 データ構造の確認
df.dtypes 型チェック object 列は要前処理(label encoding 等)
df["target"].value_counts() クラス分布確認 不均衡データか判定(>9:1なら要対策)
条件抽出 サブセット分析 男性のみ・特定地域のみ等
新列追加 特徴量生成 df["FamilySize"] = df["SibSp"] + df["Parch"]

Titanic コンペでの典型例

train = pd.read_csv("train.csv")
print(train.shape)              # (891, 12)
print(train["Survived"].mean()) # 0.384 → 全体の生存率
train["IsChild"] = (train["Age"] < 12).astype(int)  # 子供フラグ

⚠️ よくある誤解・ミス

誤解・ミスなぜ起こるか正しい理解
df["Age"]df[["Age"]] の違い不明 括弧の数の意味が曖昧 1重→Series、2重→DataFrame(1列だけの表)
df.shape() と書く 関数だと思い込む shape属性(括弧不要)
df["Age" >= 30] と書く 比較を内側でしてしまう 正解は df[df["Age"] >= 30](外側に df が必要)
ブール Series を int に変換する方法を忘れる numpy 感覚 (bool_series).astype(int) で True→1, False→0
新列追加で df.NewCol = ... を使う 属性アクセスの誤用 必ず df["NewCol"] = ... の角括弧形式

🚀 次のステップ

  • 発展1: df.loc[] df.iloc[] を使った位置・ラベルベースのアクセス
  • 発展2: df.groupby("Sex")["Survived"].mean() で性別ごとの生存率を集計
  • 次回予告: pandas 入門 続編 — CSVファイル読み込みと info() / describe() を使った EDA 基礎

📋 自己評価(解いた後に記入)

自分の回答・気づき・メモ: