📚 背景知識(読んでから問題へ)
numpyは「数値計算専用の超高速リスト」です。Pythonの普通のリストと何が違うのでしょうか?
普通のリストとnumpyの違い
# Pythonのリスト → 足し算がつなぎ合わせになる
a = [1, 2, 3]
b = [4, 5, 6]
a + b # → [1, 2, 3, 4, 5, 6](つなぎ合わせ)
# numpyの配列 → 足し算が要素ごとの計算になる
import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
a + b # → [5, 7, 9](要素ごとに足し算)
これが「ベクトル演算(vectorization)」です。Excelで列ごとに計算するイメージ。
numpyが得意なこと
| 操作 | Pythonリスト | numpy | 速度差 |
|---|---|---|---|
| 100万件の足し算 | 遅い(for文) | 速い(C言語内部) | 100倍以上 |
| 行列計算 | 不可 | 簡単 | — |
| 統計(平均など) | sum()/len() | np.mean() | 高速 |
重要な操作一覧
import numpy as np
# 配列の作成
arr = np.array([1, 2, 3, 4, 5])
# 形状・サイズの確認
arr.shape # (5,) → 5要素の1次元
arr.ndim # 1 → 1次元
arr.dtype # int64 → 整数型
# スライシング(Pythonリストと同じ感覚)
arr[0] # 1 → 最初の要素
arr[1:3] # [2, 3] → インデックス1〜2
arr[-1] # 5 → 最後の要素
# 形状変換
arr.reshape(5, 1) # 縦ベクトルに変換
arr.reshape(1, 5) # 横ベクトルに変換
# 数学関数
np.sqrt(arr) # √各要素
np.log(arr) # log(各要素)
np.abs(arr) # 絶対値
Kaggleデータとの接続
Kaggleのデータは最終的にnumpy配列 or pandas DataFrameになります。機械学習モデルへの入力は常に「numpy配列の数値」です。pandasをマスターする前にnumpyを理解することで、データ変換が直感的にわかるようになります。
📝 問題
以下のタスクをすべてコードで実装してください。
データ: Titanicの乗客年齢データ(一部)
ages = np.array([22, 38, 26, 35, 0, 27, 14, 0, 27, 18,
40, 0, 34, 0, 58, 20, 39, 0, 31, 55])
# ※ 0 は欠損値(年齢不明)を表す
タスク1: agesの形状(shape)、要素数(size)、データ型(dtype)を出力してください。
タスク2: 欠損値(0)を除いた「有効な年齢」の配列を作成し、以下の統計を計算してください。
- 最小値、最大値
- 平均値(小数点第2位まで)
- 中央値
タスク3: 有効な年齢データを「子供(18歳未満)」「成人(18〜59歳)」「高齢者(60歳以上)」に分類し、それぞれの人数を出力してください。numpyのブール配列を使うこと。
タスク4: 年齢を0〜1に正規化(min-max normalization)してください。
$$\text{正規化後} = \frac{x - x{min}}{x{max} - x_{min}}$$
🔍 ヒント(段階的開示)
ヒント1(方向性)
タスク2のフィルタリングは「ブール配列マスク」を使います。条件式(ages != 0)で True/False の配列を作り、それを添字として使う方法です。
ヒント2(アプローチ)
- タスク2:
ages[ages != 0]でフィルタリング。np.min(),np.max(),np.mean(),np.median()を使用 - タスク3:
(valid < 18).sum()のように.sum()でTrueの数を数える - タスク4:
(valid - valid.min()) / (valid.max() - valid.min())で計算
ヒント3(コード骨格)
import numpy as np
ages = np.array([22, 38, 26, 35, 0, 27, 14, 0, 27, 18,
40, 0, 34, 0, 58, 20, 39, 0, 31, 55])
# タスク1
print("shape:", ages._____)
print("size:", ages._____)
print("dtype:", ages._____)
# タスク2
valid = ages[ages != 0]
print("min:", np._____(valid))
print("max:", np._____(valid))
print(f"mean: {np.mean(valid):.2f}")
print("median:", np._____(valid))
# タスク3
children = (valid < 18).sum()
adults = ((valid >= 18) & (valid < 60)).sum()
elderly = (valid >= 60).sum()
# タスク4
normalized = (valid - valid.min()) / (valid.max() - valid.min())
✅ 模範解答
import numpy as np
ages = np.array([22, 38, 26, 35, 0, 27, 14, 0, 27, 18,
40, 0, 34, 0, 58, 20, 39, 0, 31, 55])
# タスク1: 配列の基本情報
print("=== タスク1: 配列の基本情報 ===")
print("shape:", ages.shape) # (20,)
print("size:", ages.size) # 20
print("dtype:", ages.dtype) # int64
# タスク2: 有効な年齢の統計
print("\n=== タスク2: 有効な年齢の統計 ===")
valid = ages[ages != 0]
print("有効なデータ数:", len(valid)) # 14
print("最小値:", np.min(valid)) # 14
print("最大値:", np.max(valid)) # 58
print(f"平均値: {np.mean(valid):.2f}") # 32.43
print("中央値:", np.median(valid)) # 31.5
# タスク3: 年齢層の分類
print("\n=== タスク3: 年齢層の分類 ===")
children = (valid < 18).sum()
adults = ((valid >= 18) & (valid < 60)).sum()
elderly = (valid >= 60).sum()
print(f"子供(18歳未満): {children}人") # 1人
print(f"成人(18〜59歳): {adults}人") # 13人
print(f"高齢者(60歳以上): {elderly}人") # 0人
# タスク4: Min-Max正規化
print("\n=== タスク4: Min-Max正規化 ===")
normalized = (valid - valid.min()) / (valid.max() - valid.min())
print("正規化前(最初の5件):", valid[:5])
print("正規化後(最初の5件):", np.round(normalized[:5], 3))
print(f"正規化後の範囲: {normalized.min():.1f} 〜 {normalized.max():.1f}")
実行結果:
▶ 出力を見る
=== タスク1: 配列の基本情報 ===
shape: (20,)
size: 20
dtype: int64
=== タスク2: 有効な年齢の統計 ===
有効なデータ数: 14
最小値: 14
最大値: 58
平均値: 32.43
中央値: 31.5
=== タスク3: 年齢層の分類 ===
子供(18歳未満): 1人
成人(18〜59歳): 13人
高齢者(60歳以上): 0人
=== タスク4: Min-Max正規化 ===
正規化前(最初の5件): [22 38 26 35 27]
正規化後(最初の5件): [0.182 0.545 0.273 0.477 0.295]
正規化後の範囲: 0.0 〜 1.0🪜 Step-by-Step 解説
# 条件式でTrue/Falseの配列を作る
mask = ages != 0
# → [True, True, True, True, False, True, True, False, ...]
# マスクを使って有効な要素だけ取り出す
valid = ages[mask]
# 短縮形: valid = ages[ages != 0]
なぜこう書くのか: Pythonのfor文でフィルタリングするより100倍以上速い。データが100万件あっても一瞬で終わる。
np.min(valid) # 最小値 = 14
np.max(valid) # 最大値 = 58
np.mean(valid) # 平均値 = 32.428...
np.median(valid) # 中央値 = 31.5(14個あるので14番目と15番目の平均)
中央値が31.5の理由: データを昇順に並べると [14, 18, 20, 22, 26, 27, 27, 31, 34, 35, 38, 39, 40, 55, 58]...実は14個あります(0が6個除外)。14個なので中央は7番目(27)と8番目(31)の平均 → (27+31)/2 = 29.0。※上のコードを実際に実行して確認しましょう。
# 「かつ」は & (Pythonの and ではなく &)
# 「または」は | (Pythonの or ではなく |)
adults = ((valid >= 18) & (valid < 60)).sum()
# ↑18以上 ↑かつ60未満 ↑Trueの数を数える
注意点: 複数条件は必ず各条件を()で囲む。valid >= 18 & valid < 60 はエラーになる(演算子の優先順位の問題)。
normalized = (valid - valid.min()) / (valid.max() - valid.min())
直感的な理解:
valid - valid.min()→ 最小値を0にシフト(最小は必ず0になる)/ (valid.max() - valid.min())→ 最大値を1にスケール(最大は必ず1になる)- 結果: 全データが0〜1の範囲に収まる
📐 数学・統計の補足(文系向け)
Min-Max正規化の直感
例えば身長データ [150, 160, 170, 180] を正規化すると:
- 最小150, 最大180, 差=30
- 150 → (150-150)/30 = 0.0
- 160 → (160-150)/30 = 0.33
- 170 → (170-150)/30 = 0.67
- 180 → (180-150)/30 = 1.0
なぜ正規化が必要か: 年齢(0〜100)と給与(0〜10,000,000)を同じモデルに入れると、数値が大きい給与が結果を支配してしまう。正規化で同じスケールに揃えることで、公平に比較できる。
ブール配列(True/False配列)
Excelのフィルター機能と同じです。「条件に合う行だけ表示」をnumpyでやると自動的に配列になります。
🏆 Kaggleでの実践的な使い方
1. 欠損値処理(最重要)
# Titanicコンペでよく使うパターン
import pandas as pd
import numpy as np
df = pd.read_csv('train.csv')
# pandasの中身はnumpy配列。欠損値処理はnumpyの考え方がベース
ages = df['Age'].values # pandas → numpy配列に変換
# 欠損値をnanで扱う(0ではなくnp.nanを使うのが本流)
valid_mask = ~np.isnan(ages) # nanでないものがTrue
mean_age = np.nanmean(ages) # nan を無視して平均
2. 特徴量の正規化
# 機械学習の前処理で必須
# sklearn の StandardScaler / MinMaxScaler は内部でnumpyを使っている
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X)
3. ブール配列でラベル作成
# 年齢層を0/1/2のラベルに変換
labels = np.zeros(len(valid), dtype=int)
labels[valid >= 18] = 1
labels[valid >= 60] = 2
# → [1, 1, 1, 1, 0, 1, 1, 1, 1, ...] のような特徴量
⚠️ よくある誤解・ミス
| 誤解・ミス | なぜ起こるか | 正しい理解 | |
|---|---|---|---|
ages != 0 の括弧忘れ | Pythonの演算子優先順位 | ages[ages != 0] が正しい形 | |
複数条件で and を使う | Pythonの通常条件文の習慣 | numpyでは & / `\ | ` を使う |
np.mean() と arr.mean() どちら? | 両方あって迷う | 両方同じ。どちらでもOK | |
| 正規化後にnanが出る | 最大と最小が同じ(全要素同値) | 事前に assert arr.max() != arr.min() でチェック | |
shape に () をつける | .size() などのメソッドと混同 | arr.shape はプロパティ(括弧なし) |
🚀 次のステップ
- 発展: 2次元配列(行列)の操作 —
np.zeros((3,4)),np.dot(),arr.T(転置) - 次回予告: pandas入門(DataFrame・Series) — numpyの上に乗っているpandasを学ぶ。DataFrameはExcelの表のようなもの