📚 背景知識(読んでから問題へ)
pandas は Excel のような表形式データを Python で扱うライブラリです。Kaggle で配布される train.csv の 99% は pandas で読み込みます。numpy が「数値の配列」だったのに対し、pandas は「行ラベル・列ラベル付きの表」を扱えます。
numpy と pandas の違い
| ライブラリ | 主な用途 | データ単位 | 型 |
|---|---|---|---|
numpy |
数値計算・行列演算 | ndarray |
全要素同じ型 |
pandas |
表形式データ操作 | DataFrame |
列ごとに違う型OK |
DataFrame の構造(イメージ)
| index | Name | Age | Sex | Fare | Survived |
|---|---|---|---|---|---|
| 0 | Alice | 22 | F | 7.25 | 1 |
| 1 | Bob | 35 | M | 71.28 | 0 |
| 2 | Carol | 28 | F | 53.10 | 1 |
| 3 | Dave | 45 | M | 8.05 | 0 |
| 4 | Eve | 19 | F | 13.00 | 1 |
↑ 左端の灰色列が 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 の典型パイプライン
🗂️ データスキーマ
架空のタイタニック号風データ(乗客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) |
📝 問題
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 — 条件抽出と新列追加
Ageが 30 以上の乗客だけを抽出した DataFramedf_seniorを作成- 新しい列
IsAdultを追加(Age >= 20なら1、それ未満なら0) - 生存者(
Survived == 1)のFareの平均値を計算
Bob, Dave の2行生存者の平均運賃:
24.45🔍 ヒント(段階的開示)
ヒント1 — 方向性
- 問1: 辞書を
pd.DataFrame()に渡すだけ - 問2:
df.shapedf.dtypesdf.head(n)はそれぞれ別の方法でアクセス(属性 or メソッド) - 問3: 列の取り出しは
df["列名"]、Series には.mean().max().min()が使える - 問4: 条件式
df["Age"] >= 30をdf[...]の中に入れる
ヒント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
🪜 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 の定番です。
shape と dtypes は 属性(括弧なし)、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 の行だけが残ります。
| index | Name | Age | Sex | Fare | Survived |
|---|---|---|---|---|---|
| 1 | Bob | 35 | M | 71.28 | 0 |
| 3 | Dave | 45 | M | 8.05 | 0 |
↑ 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 から集計した結果を可視化します。
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 基礎