📚 背景知識(読んでから問題へ)
Kaggleコンペでデータが与えられたとき、いきなりモデルを作るのは厳禁です。まず「データの全体像を把握する」ことから始めます。これをEDA(探索的データ分析)の第一歩と呼びます。
行数・列数を確認
例: (891, 12) → 891行12列
各列のデータ型を確認
int64 / float64 / object
数値列の統計量まとめ
mean / std / min / max …
型・欠損数・メモリを一覧
Non-Null Count に注目
データ型(dtypes)の種類
| dtypes | 意味 | 代表例 |
|---|---|---|
int64 | 整数 | 年齢(欠損なし)、チケットクラス |
float64 | 小数 or 欠損を含む整数 | 運賃、欠損ありの年齢 |
object | 文字列(カテゴリ変数も含む) | 名前、性別 |
float64 なのはこのためです。🗂️ データスキーマ
今回使用する架空のタイタニック号データ(10行9列)のスキーマです。
| 列名 | 型 | 列番号 | 説明 | 欠損 |
|---|---|---|---|---|
PassengerId | int64 | 0 | 乗客ID | なし |
Survived | int64 | 1 | 生存フラグ (0/1) | なし |
Pclass | int64 | 2 | チケットクラス (1/2/3) | なし |
Name | object | 3 | 乗客名 | なし |
Sex | object | 4 | 性別 (male/female) | なし |
Age | float64 | 5 | 年齢 | 2件あり(行5・6) |
SibSp | int64 | 6 | 兄弟・配偶者数 | なし |
Parch | int64 | 7 | 親・子供数 | なし |
Fare | float64 | 8 | 運賃 | なし |
📊 describe() の読み方
Age列の describe() 出力例です。各行の意味を確認してください。
| 統計量 | Age の値 | 意味 |
|---|---|---|
| count | 8.0 | 欠損を除いた有効行数 → 10行中8行有効 = 2件欠損 |
| mean | 30.56 | 平均値 |
| std | 15.31 | 標準偏差(バラつき具合) |
| min | 2.0 | 最小値 |
| 25% | 19.75 | 第1四分位(下から25%の値) |
| 50% | 26.50 | 中央値(メジアン) |
| 75% | 37.25 | 第3四分位(上から25%の値) |
| max | 54.0 | 最大値 |
🔎 info() — Non-Null Count で欠損を見る
各列の Non-Null Count(欠損ゼロ行数)を棒グラフで表現しています。全10行中、赤い列に欠損があります。
緑 = 欠損なし(10/10) | 赤 = 欠損あり(8/10)
📝 問題
import pandas as pd
import io
csv_data = """PassengerId,Survived,Pclass,Name,Sex,Age,SibSp,Parch,Fare
1,0,3,Braund Mr. Owen Harris,male,22.0,1,0,7.25
2,1,1,Cumings Mrs. John Bradley,female,38.0,1,0,71.28
3,1,3,Heikkinen Miss. Laina,female,26.0,0,0,7.92
4,1,1,Futrelle Mrs. Jacques Heath,female,35.0,1,0,53.1
5,0,3,Allen Mr. William Henry,male,,0,0,8.05
6,0,3,Moran Mr. James,male,,0,0,8.46
7,0,1,McCarthy Mr. Timothy J,male,54.0,0,0,51.86
8,0,3,Palsson Master. Gosta Leonard,male,2.0,3,1,21.07
9,1,3,Johnson Mrs. Oscar W,female,27.0,0,2,11.13
10,1,2,Nasser Mrs. Nicholas,female,14.0,1,0,30.07
"""
df = pd.read_csv(io.StringIO(csv_data))
タスク1 — shape で行数・列数を取得
df.shape を使って「行数と列数」を表示し、変数 n_rows, n_cols に格納してください。
行数=10, 列数=9タスク2 — dtypes で文字列列を抽出
df.dtypes を使って「文字列型(object)の列名」をリスト str_cols に格納してください。
['Name', 'Sex']タスク3 — describe() で Age の統計を取り出す
df.describe() を使い、以下の2つを変数に格納してください。
age_mean: Age 列の平均age_missing: Age 列の欠損数(総行数 - count)
タスク4 — info() を実行して欠損列を確認
df.info() を実行し、Non-Null Count が全行数より少ない列(= 欠損あり)を目視で確認してください。
df.info() の1行だけでOKです。出力の読み方を確認しましょう。🔍 ヒント(段階的開示)
ヒント1 — 方向性
- タスク1:
df.shapeはタプル。n_rows, n_cols = df.shapeでアンパック - タスク2:
df.dtypesは Series。df.dtypes == "object"で True/False 絞り込み - タスク3:
df.describe()は DataFrame。.loc["mean", "Age"]で特定値を取得 - タスク4:
df.info()を呼ぶだけ。Non-Null Count が 10 未満の行に注目
ヒント2 — アプローチ
# タスク1
n_rows, n_cols = df.shape
# タスク2
str_cols = df.dtypes[df.dtypes == "object"].index.tolist()
# タスク3
stats = df.describe()
age_mean = stats.loc["mean", "Age"]
age_missing = df.shape[0] - int(stats.loc["count", "Age"])
# タスク4
df.info()
ヒント3 — コード骨格(ほぼ答え)
# タスク1
n_rows, n_cols = df.___
print(f"行数: {n_rows}, 列数: {n_cols}")
# タスク2
str_cols = df.___[df.___ == ___].index.tolist()
# タスク3
stats = df.___()
age_mean = stats.loc[___, ___]
age_missing = df.shape[0] - int(stats.loc[___, ___])
# タスク4
df.___()
✅ 模範解答
import pandas as pd
import io
csv_data = """PassengerId,Survived,Pclass,Name,Sex,Age,SibSp,Parch,Fare
1,0,3,Braund Mr. Owen Harris,male,22.0,1,0,7.25
2,1,1,Cumings Mrs. John Bradley,female,38.0,1,0,71.28
3,1,3,Heikkinen Miss. Laina,female,26.0,0,0,7.92
4,1,1,Futrelle Mrs. Jacques Heath,female,35.0,1,0,53.1
5,0,3,Allen Mr. William Henry,male,,0,0,8.05
6,0,3,Moran Mr. James,male,,0,0,8.46
7,0,1,McCarthy Mr. Timothy J,male,54.0,0,0,51.86
8,0,3,Palsson Master. Gosta Leonard,male,2.0,3,1,21.07
9,1,3,Johnson Mrs. Oscar W,female,27.0,0,2,11.13
10,1,2,Nasser Mrs. Nicholas,female,14.0,1,0,30.07
"""
df = pd.read_csv(io.StringIO(csv_data))
# タスク1: shape
n_rows, n_cols = df.shape
print(f"タスク1: 行数={n_rows}, 列数={n_cols}")
# → タスク1: 行数=10, 列数=9
# タスク2: 文字列列の抽出
str_cols = df.dtypes[df.dtypes == "object"].index.tolist()
print(f"タスク2: 文字列型の列 → {str_cols}")
# → タスク2: 文字列型の列 → ['Name', 'Sex']
# タスク3: describe() から Age の統計
stats = df.describe()
age_mean = stats.loc["mean", "Age"]
age_missing = df.shape[0] - int(stats.loc["count", "Age"])
print(f"タスク3: Age 平均={age_mean:.2f}, Age 欠損数={age_missing}")
# → タスク3: Age 平均=30.56, Age 欠損数=2
# タスク4: info()
df.info()
# Data columns (total 9 columns):
# # Column Non-Null Count Dtype
# 5 Age 8 non-null float64 ← 欠損あり!
🪜 Step-by-Step 解説
1 pd.read_csv() でデータを読み込む
実際のKaggleでは pd.read_csv("train.csv") とファイルパスを渡します。io.StringIO() は文字列をファイルのように扱うPython標準ライブラリです(練習環境用)。
2 shape はタプル — アンパックで一発格納
n_rows, n_cols = df.shape # (10, 9) をアンパック
df.shape は (行数, 列数) のタプルを返します。Pythonのアンパック構文で2変数に一行で代入できます。括弧は不要(属性)です。
3 dtypes から "object" 列を絞り込む
str_cols = df.dtypes[df.dtypes == "object"].index.tolist()
df.dtypes → 各列の型が値の Series
df.dtypes == "object" → True/False の Series
[True/False Series] → True の行だけ取り出す(ブールインデックス)
.index.tolist() → 列名のリストに変換
4 describe() の結果は DataFrame — .loc で値を取り出す
stats = df.describe()
age_mean = stats.loc["mean", "Age"]
age_missing = df.shape[0] - int(stats.loc["count", "Age"])
describe() の出力は「行ラベル = 統計量名、列 = 元の列名」のDataFrameです。count は欠損を除いた有効行数なので、総行数との差が欠損数になります。
5 info() の読み方 — Non-Null Count に注目
df.info()
# ...
# 5 Age 8 non-null float64 ← 10行中8行のみ有効 = 2件欠損
全列のうち「Non-Null Count が総行数より少ない列」が欠損ありです。describe() の count よりも一覧で確認しやすいため、EDAの最初に必ず実行します。
🔢 数学・統計の補足(文系向け)
describe() の8行は「5数要約+α」
統計学には「5数要約」という概念があり、データの分布を5つの数字で表します。
最小値(min) → 25%点 → 中央値(50%) → 75%点 → 最大値(max)
describe() はこれに count(有効数)・mean(平均)・std(標準偏差)を加えた8行を返します。
平均と中央値がずれる理由
Age の平均(30.56)は中央値(26.5)より高いです。これは54歳という大きな値が平均を引き上げているためです。このような「外れ値のある分布」では中央値のほうが代表値として適切な場合があります。
shape の (10, 9) はエクセルの「行列数を数える」感覚
スプレッドシートでデータを開いたとき「10行9列のデータだ」と確認するのと全く同じです。Kaggleでは数万〜数百万行が当たり前なので、まず shape で規模感を把握します。
🏆 Kaggleでの実践的な使い方
Kaggleコンペの「最初の3分」のルーティンとして、そのまま使えるテンプレートです。
import pandas as pd
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
# ① 規模確認
print("Train shape:", train.shape)
print("Test shape: ", test.shape)
print()
# ② 型確認
print(train.dtypes)
print()
# ③ 統計量確認(欠損・外れ値の有無)
print(train.describe())
print()
# ④ 欠損の全体像
train.info()
| 確認項目 | 意図 |
|---|---|
shape | データ規模を把握(特徴量エンジニアリングの方針に影響) |
dtypes | 数値列・カテゴリ列を分類(エンコーディング計画) |
describe() | 外れ値・欠損の有無を一目で把握 |
info() | 欠損がある列を全列まとめて確認 |
⚠️ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 |
|---|---|---|
df.shape() と括弧をつける |
メソッドと混同 | shape は属性(プロパティ)なので括弧不要。df.describe() のような呼び出しとは異なる |
describe() に文字列列が含まれない |
仕様を知らない | デフォルトで数値列のみ。df.describe(include="all") で全列表示できる |
dtypes == str と書く |
Pythonの型とpandasの型を混同 | pandasの文字列型は "object" という文字列で比較する。str ではない |
describe() の count を全行数と思い込む |
欠損の概念を知らない | count は「欠損を除いた有効行数」。総行数より少なければ欠損あり。全行数は shape[0] |
整数列なのに float64 で驚く |
欠損とデータ型の関係を知らない | pandasは整数に欠損(NaN)を格納できないため、欠損を含む整数列は自動で float64 になる |
🚀 次のステップ
- 発展:
df.isnull().sum()で欠損数を列ごとに一覧取得 → 欠損可視化(ヒートマップ) - 次回予告: 欠損値の確認と対処(
isna,fillna,dropna)