Day 028 — numpy入門(配列操作・数値計算)

2026-05-07 白 / Phase 1 分析 numpy入門(配列操作・数値計算)

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

numpyは「数値計算の専門ライブラリ」で、Pythonのリストより圧倒的に速く大量のデータを処理できます。

なぜKaggleでnumpyが重要か?

  • 大量のデータ(数万〜数百万行)を瞬時に集計・変換できる
  • pandasの内部もnumpyで動いており、理解することでデータ操作が速くなる
  • モデルの入力データは最終的にnumpy配列(ndarray)として渡すことが多い

今日のポイント:配列の「形状」と「変換」

numpyの配列には形状(shape)という概念があります。

[1, 2, 3, 4, 5, 6]  →  shape: (6,)   1次元(横1列)
[[1, 2, 3],
 [4, 5, 6]]         →  shape: (2, 3)  2次元(2行3列)

行列の変換・集計は実際のKaggleデータ分析でよく使います。

よく使う操作のイメージ

操作意味
reshape形を変える(総要素数は同じ)(6,) → (2,3)
mean(axis=0)列ごとの平均各特徴量の平均
mean(axis=1)行ごとの平均各サンプルの平均
np.where条件分岐で値を置き換える欠損値の補完

📝 問題

以下のシナリオを読み、コードを完成させてください。

シナリオ: Titanicコンペで年齢データを前処理しています。

12人の乗客の年齢データが1次元配列で与えられています。

このデータを分析・変換して情報を取り出してください。

import numpy as np

# 12人の乗客の年齢(-1は欠損値を意味する)
ages = np.array([22, 38, 26, 35, -1, 27, 14, 4, 27, 14, 40, -1])

タスク1: 欠損値(-1)を除いた有効な年齢データのみ取り出し、valid_ages に格納してください。

タスク2: valid_ages の平均年齢・最大年齢・最小年齢を計算してください。

タスク3: 欠損値(-1)を validages の平均年齢(小数点以下切り捨て)で補完した新しい配列 filledages を作ってください。

タスク4: filledages(4, 3) の2次元配列 agesmatrix に変換し、「各行の平均年齢」を計算してください(4グループ×3人の構成と考える)。

期待する出力例:

▶ 出力を見る
有効なデータ数: 10
平均年齢: 24.7
最大年齢: 40
最小年齢: 4

欠損補完後: [22 38 26 35 24 27 14  4 27 14 40 24]

各行(グループ)の平均年齢: [28.33 28.33 15.  26.  ]

🔍 ヒント(段階的開示)

ヒント1(方向性)

欠損値の抽出はnumpyのブールインデックスが使えます。「-1ではないもの」という条件で配列を絞り込みましょう。

ヒント2(アプローチ)
  • タスク1: ages[ages != -1] のようにブールインデックスで絞り込む
  • タスク2: np.mean(), np.max(), np.min() を使う
  • タスク3: np.where(条件, 真の値, 偽の値) または ages.copy() + インデックス代入
  • タスク4: .reshape(4, 3) で形状変換、mean(axis=1) で行ごとの平均
ヒント3(コード骨格)
# タスク1
valid_ages = ages[___]

# タスク2
mean_age = int(np.mean(valid_ages))  # 小数点以下切り捨て用
print(f"平均年齢: {np.mean(valid_ages):.1f}")

# タスク3
filled_ages = np.where(ages == -1, ___, ages)

# タスク4
ages_matrix = filled_ages.reshape(___, ___)
row_means = ages_matrix.mean(axis=___)

模範解答

import numpy as np

# 12人の乗客の年齢(-1は欠損値を意味する)
ages = np.array([22, 38, 26, 35, -1, 27, 14, 4, 27, 14, 40, -1])

# タスク1: 有効な年齢データのみ取り出す
valid_ages = ages[ages != -1]
print(f"有効なデータ数: {len(valid_ages)}")

# タスク2: 基本統計量の計算
mean_age = np.mean(valid_ages)
max_age = np.max(valid_ages)
min_age = np.min(valid_ages)
print(f"平均年齢: {mean_age:.1f}")
print(f"最大年齢: {max_age}")
print(f"最小年齢: {min_age}")

# タスク3: 欠損値を平均で補完(小数点以下切り捨て)
fill_value = int(mean_age)  # 24
filled_ages = np.where(ages == -1, fill_value, ages)
print(f"\n欠損補完後: {filled_ages}")

# タスク4: (4, 3)に変換して各行の平均を計算
ages_matrix = filled_ages.reshape(4, 3)
row_means = ages_matrix.mean(axis=1)
print(f"\n各行(グループ)の平均年齢: {row_means.round(2)}")

実行結果:

▶ 出力を見る
有効なデータ数: 10
平均年齢: 24.7
最大年齢: 40
最小年齢: 4

欠損補完後: [22 38 26 35 24 27 14  4 27 14 40 24]

各行(グループ)の平均年齢: [28.67 28.67 15.    26.  ]

🪜 Step-by-Step 解説

1
ブールインデックスで有効データを抽出する
valid_ages = ages[ages != -1]

ages != -1 は「各要素が-1でないか」を判定して [True, True, True, ..., False] のような真偽値の配列を返します。それを ages[...] に入れると、Trueの位置の値だけ取り出せます。

これはKaggleで最もよく使うテクニックの一つです。特定の条件のデータだけ取り出す操作を「フィルタリング」と呼びます。

2
基本統計量の計算
mean_age = np.mean(valid_ages)  # 平均
max_age = np.max(valid_ages)    # 最大値
min_age = np.min(valid_ages)    # 最小値

Pythonの sum()max() でも計算できますが、numpy版は数百万件でも瞬時に計算できるため、大規模データでは必須です。

3
np.whereで欠損値を補完する
filled_ages = np.where(ages == -1, fill_value, ages)

np.where(条件, 真のとき, 偽のとき) はExcelの IF関数 と同じ仕組みです。

  • 条件が True(-1のとき)→ fill_value(24)を入れる
  • 条件が False(正常値のとき)→ 元の ages の値をそのまま使う
4
reshapeで形状を変換する
ages_matrix = filled_ages.reshape(4, 3)

reshape は要素の総数(12)を変えずに形を変えます。12 = 4×3 なので (4, 3) に変換できます。

row_means = ages_matrix.mean(axis=1)

axis=1 は「横方向(行方向)に計算する」という意味です。覚え方:

  • axis=0 → 縦方向(列ごと)に計算 → 結果は列数分の配列
  • axis=1 → 横方向(行ごと)に計算 → 結果は行数分の配列

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

reshapeのイメージ

12個の卵が1列に並んでいる状態を、4段×3列の卵パックに入れ直すイメージです。卵の数は変わらず、並べ方だけ変わります。

axis(軸)の覚え方

表(テーブル)をイメージしてください:

  • axis=0:上から下に向かって計算(列の集計)→ 各列の平均など
  • axis=1:左から右に向かって計算(行の集計)→ 各行の平均など

Kaggleのデータは「行=サンプル(乗客1人)、列=特徴量(年齢・性別など)」なので:

  • axis=0 = 全乗客の特徴量ごとの集計
  • axis=1 = 1人の乗客の全特徴量を横断した集計

🏆 Kaggleでの実践的な使い方

欠損値補完はほぼ全コンペで必須

実際のKaggleコンペでは、年齢・料金・客室番号などに欠損値(NaN)が頻出します。np.where や pandas の fillna で平均・中央値・最頻値を補完することが基本前処理になります。

Titanicコンペでの例

# 実際のTitanicデータでの欠損値補完(pandas版)
import pandas as pd
df = pd.read_csv('train.csv')
median_age = df['Age'].median()
df['Age'] = df['Age'].fillna(median_age)

numpyで学んだブールインデックスと条件置換の考え方は、pandasでもそのまま応用できます。


⚠️ よくある誤解・ミス

誤解・ミスなぜ起こるか正しい理解
reshape(3, 4)reshape(4, 3) が同じだと思う総要素数が同じだから行と列が入れ替わるため、axis=1 の結果が変わる
axis=0axis=1 を逆に使う直感に反する番号付けaxis=0が縦方向(列集計)、axis=1が横方向(行集計)と覚える
int(meanage)round(meanage) を混同する「切り捨て」の表現が曖昧int() は常に0方向に切り捨て。24.7 → 24
ブールインデックスで元の配列が変わると思う副作用への誤解ages[ages != -1] は新しい配列を返す。元の ages は変わらない

🚀 次のステップ

  • 発展: np.where の多重条件(np.select)、fancy indexing、ベクトル化演算(ufunc)
  • 次回予告: pandas入門(DataFrame・Series) — numpyで学んだ概念をpandasに応用します

🎯 自己評価

自分の回答

気づき・メモ