Day 026 — numpy入門(配列操作・数値計算)— 理論編

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

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

numpyとは何か?

Pythonで数値計算をするとき、普通のリスト([1, 2, 3])は「電卓を1つずつ押す」イメージです。

numpyの配列(ndarray)は「1000個のボタンを一気に押せる計算機」のイメージです。

たとえば、全員の給料に10%ボーナスを足す処理:

# 普通のPythonリスト(遅い)
salaries = [300, 400, 500]
result = [s * 1.1 for s in salaries]  # 1つずつループ

# numpy(速い・シンプル)
import numpy as np
salaries = np.array([300, 400, 500])
result = salaries * 1.1  # 全部まとめて計算!

numpyの核心:ブロードキャスト

「ブロードキャスト」とは、異なる形の配列を自動的に合わせて計算する機能です。

テレビ放送が1つの電波を全テレビに届けるイメージ → 1つの数値を全要素に適用する。

arr = np.array([1, 2, 3, 4, 5])
arr + 10  # → [11, 12, 13, 14, 15]  ← 10が全要素にブロードキャスト
arr * 2   # → [2, 4, 6, 8, 10]

多次元配列(行列)の考え方

numpyは「表形式のデータ」を扱うのが得意です。

1次元: [1, 2, 3]          ← 数直線(1列のデータ)
2次元: [[1, 2, 3],        ← 表(行と列)
        [4, 5, 6]]
3次元: 表が積み重なったもの ← 画像データなど
属性意味
ndim何次元か2次元なら 2
shape行×列の形(3, 4) = 3行4列
dtypeデータの型float64, int32 など
size要素の総数shape の積

インデックスとスライシング

arr = np.array([10, 20, 30, 40, 50])
arr[0]    # → 10  (最初の要素)
arr[-1]   # → 50  (最後の要素)
arr[1:4]  # → [20, 30, 40]  (1番目〜3番目)
arr[::2]  # → [10, 30, 50]  (1個おき)

2次元の場合は [行, 列] の形でアクセス:

matrix = np.array([[1, 2, 3],
                   [4, 5, 6],
                   [7, 8, 9]])
matrix[1, 2]    # → 6  (2行目、3列目)
matrix[:, 1]    # → [2, 5, 8]  (全行の2列目)
matrix[0, :]    # → [1, 2, 3]  (1行目の全列)

📝 問題

以下の4つの問いに答えなさい。

問1: 配列の属性を理解する

次のコードを見て、各出力値を予測しなさい(実行せずに考える)。

▶ 出力を見る
import numpy as np
data = np.array([[1.0, 2.0, 3.0],
                 [4.0, 5.0, 6.0]])
print(data.ndim)
print(data.shape)
print(data.size)
print(data.dtype)

Q: ndim, shape, size, dtype はそれぞれ何を出力するか?


問2: ブロードキャストの結果を予測する

次のコードの出力を答えなさい。

▶ 出力を見る
import numpy as np
scores = np.array([60, 75, 88, 45, 92])

# 全員の点数に5点のボーナスを加算
result_a = scores + 5

# 70点未満の人を抽出(ブール型インデックス)
result_b = scores[scores < 70]

print(result_a)
print(result_b)

問3: 形状変換(reshape)

1次元配列を行列に変換しなさい。

import numpy as np
arr = np.arange(12)  # [0, 1, 2, ..., 11]

# この配列を 3行4列 の2次元配列に変換せよ
# ヒント: reshape を使う

arr を reshape した後の shape は何になるか?また最後の行(3行目)の要素は何か?


問4: numpy の便利な集計関数

下記のコードの空欄を埋めて、出力を完成させなさい。

▶ 出力を見る
import numpy as np
exam_scores = np.array([72, 85, 91, 63, 78, 88, 55, 94, 67, 80])

# 以下の値を求めよ
total   = ___________   # 合計
average = ___________   # 平均
minimum = ___________   # 最小値
maximum = ___________   # 最大値
std_dev = ___________   # 標準偏差

print(f"合計: {total}")
print(f"平均: {average:.1f}")
print(f"最小: {minimum}, 最大: {maximum}")
print(f"標準偏差: {std_dev:.2f}")

🔍 ヒント(段階的開示)

ヒント1(方向性)
  • 問1: numpyの配列には「次元数」「形」「要素数」「型」という属性がある
  • 問2: scores < 70 は True/False の配列を作り、それでフィルタリングできる
  • 問3: np.arange(n) は0からn-1まで連番を作る。reshape(行, 列) で形を変える
  • 問4: numpy には .sum(), .mean(), .min(), .max(), .std() という集計関数がある
ヒント2(アプローチ)
  • 問1: data は2行3列の浮動小数点配列。ndim=次元数, shape=(行,列), size=行×列の総数
  • 問2: ブール型インデックス arr[arr < 70] は条件を満たす要素だけを取り出す
  • 問3: np.arange(12) → 12個の要素 → 3×4=12 なので reshape(3, 4) が可能
  • 問4: np.sum(arr) または arr.sum() の2通りの書き方がある(どちらでも正解)
ヒント3(コード骨格)
# 問1の答えを確認
import numpy as np
data = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
print(data.ndim)    # 2(2次元)
print(data.shape)   # (2, 3)(2行3列)
print(data.size)    # 6(2×3=6個)
print(data.dtype)   # float64

# 問3のヒント
arr = np.arange(12)
matrix = arr.reshape(3, 4)  # ← ここを埋める
print(matrix[-1])   # 最後の行

# 問4のヒント
exam_scores = np.array([72, 85, 91, 63, 78, 88, 55, 94, 67, 80])
total   = exam_scores.sum()
average = exam_scores.mean()
# ...

模範解答

import numpy as np

# ===============================
# 問1: 配列の属性
# ===============================
data = np.array([[1.0, 2.0, 3.0],
                 [4.0, 5.0, 6.0]])

print("=== 問1 ===")
print(data.ndim)    # 2
print(data.shape)   # (2, 3)
print(data.size)    # 6
print(data.dtype)   # float64

# ===============================
# 問2: ブロードキャスト&ブールインデックス
# ===============================
print("\n=== 問2 ===")
scores = np.array([60, 75, 88, 45, 92])

result_a = scores + 5
result_b = scores[scores < 70]

print(result_a)   # [65 80 93 50 97]
print(result_b)   # [60 45]

# ===============================
# 問3: reshape
# ===============================
print("\n=== 問3 ===")
arr = np.arange(12)
matrix = arr.reshape(3, 4)

print(matrix.shape)   # (3, 4)
print(matrix)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]
print("3行目:", matrix[-1])   # [ 8  9 10 11]

# ===============================
# 問4: 集計関数
# ===============================
print("\n=== 問4 ===")
exam_scores = np.array([72, 85, 91, 63, 78, 88, 55, 94, 67, 80])

total   = exam_scores.sum()
average = exam_scores.mean()
minimum = exam_scores.min()
maximum = exam_scores.max()
std_dev = exam_scores.std()

print(f"合計: {total}")           # 合計: 773
print(f"平均: {average:.1f}")     # 平均: 77.3
print(f"最小: {minimum}, 最大: {maximum}")  # 最小: 55, 最大: 94
print(f"標準偏差: {std_dev:.2f}") # 標準偏差: 12.26

🪜 Step-by-Step 解説

1
配列属性の読み方(問1)

np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]) は「2行3列の表」。

属性理由
ndim2「行と列」の2軸がある
shape(2, 3)2行、3列
size62 × 3 = 6要素
dtypefloat64小数点あり → 浮動小数点型
2
ブロードキャストとブールインデックス(問2)

ブロードキャスト (scores + 5):

[60, 75, 88, 45, 92] + 5
= [65, 80, 93, 50, 97]  ← 全要素に+5

ブールインデックス (scores[scores < 70]):

scores < 70 → [True, False, False, True, False]
scores[[True, False, False, True, False]] → [60, 45]

条件式が True の位置にある要素だけが選ばれる仕組み。

3
reshape の仕組み(問3)

np.arange(12) = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

これを reshape(3, 4) すると:

行0: [ 0,  1,  2,  3]
行1: [ 4,  5,  6,  7]
行2: [ 8,  9, 10, 11]  ← matrix[-1] はこれ

ポイント: reshape 前後で要素数が変わってはいけない(12 = 3×4 ✓)。

4
集計関数(問4)
データ: [72, 85, 91, 63, 78, 88, 55, 94, 67, 80]
合計:   72+85+91+63+78+88+55+94+67+80 = 773
平均:   773 ÷ 10 = 77.3
最小:   55
最大:   94
標準偏差: 約12.26(ばらつきの大きさ)

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

ndim / shape / size の違いを「建物」で例えると

  • ndim = 何階建てか(1階建て=1次元、2階建て=2次元)
  • shape = 各フロアの間取り(3部屋×4列のオフィス)
  • size = 部屋の総数(3×4=12部屋)

dtype の意味

numpyはデータ型を自動判定する:

  • 整数だけ → int64(整数型)
  • 小数点あり → float64(浮動小数点型)
  • 文字列 → (文字列型)

Kaggleではほとんど float64int64 を使う。


🏆 Kaggleでの実践的な使い方

ブールインデックスは特徴量選択・フィルタリングの基本

import numpy as np
import pandas as pd

# 例: Titanicデータで年齢が30歳以上の乗客のみ抽出
df = pd.read_csv('titanic.csv')
ages = df['Age'].values  # numpy配列に変換

# 30歳以上をフィルタリング
over_30 = ages[ages >= 30]
print(f"30歳以上の人数: {len(over_30)}")

reshapeは画像・時系列データで必須

# 画像データ (28×28ピクセル) をニューラルネットに入力する際
image = np.random.rand(28, 28)        # 2次元: 28×28
flat  = image.reshape(1, 784)         # 1次元に変換: 1×784
# または
flat  = image.reshape(-1)             # -1は「残りは自動計算」

集計関数は EDA(探索的データ分析)の基礎

コンペ開始時に必ずやる作業:

data = df.select_dtypes(include='number').values
print(f"平均: {data.mean(axis=0)}")   # 列ごとの平均
print(f"最大: {data.max(axis=0)}")    # 列ごとの最大
print(f"欠損: {np.isnan(data).sum(axis=0)}")  # 列ごとの欠損数

⚠️ よくある誤解・ミス

誤解・ミスなぜ起こるか正しい理解
shape(6) と答える1次元と混同(2, 3) のようにタプルで表す
reshape(3, 4)reshape(4, 3) を混同行と列の順序を忘れる第1引数=行数、第2引数=列数
arr + 5 でエラーが出ると思うPythonリストでは +5 が意味をなさないnumpyはブロードキャストで一括処理できる
arr.mean()np.mean(arr) が違うと思う見た目が違う結果は同じ。どちらでも正解
dtype=int なのに .mean() が小数を返す整数配列の平均が小数になると思わないnumpyは自動的に float64 に変換して返す

🚀 次のステップ

  • 発展: axis パラメータを使った行・列方向の集計(arr.sum(axis=0) vs arr.sum(axis=1)
  • 次回予告: pandas入門(DataFrame・Series) — numpyを「名前付き列」で使えるようにするライブラリ

🎯 自己評価

自分の回答

気づき・メモ