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

2026-05-10 白 / Phase 1 コーディング numpy入門(配列操作・数値計算)

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

numpyとは?

numpyは「数値計算のためのPythonライブラリ」です。Pythonの普通のリストと比べると、以下の点が優れています:

  • 速い: 内部でC言語を使っているため、リストの10〜100倍速い
  • 便利: 数学的な操作(足し算・掛け算・統計)を一度に全要素に適用できる
  • 標準: pandas・scikit-learn・TensorFlowなど全てのデータサイエンスライブラリの基盤

直感的なイメージ

普通のリストで「全ての要素を2倍にする」とき:

data = [1, 2, 3, 4, 5]
result = [x * 2 for x in data]  # ループが必要

numpyなら:

import numpy as np
data = np.array([1, 2, 3, 4, 5])
result = data * 2  # そのまま掛けるだけ!

重要な概念

用語意味
ndarraynumpyの配列np.array([1,2,3])
shape配列の形(行×列)(3, 4) = 3行4列
dtypeデータの型int64, float64
axis操作の方向axis=0→列方向, axis=1→行方向
ブロードキャスト異なる形の配列を自動的に合わせる機能array + 10

よく使う操作

import numpy as np

# 配列作成
a = np.array([1, 2, 3, 4, 5])
zeros = np.zeros(5)          # [0, 0, 0, 0, 0]
ones = np.ones((2, 3))       # 2行3列の1の配列
arange = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]

# 統計
a.mean()  # 平均
a.std()   # 標準偏差
a.min()   # 最小値
a.max()   # 最大値
a.sum()   # 合計

📝 問題

あなたはEコマース会社のデータアナリストです。先月の売上データが以下のようにあります。

データ: 30日分の日次売上(万円)

import numpy as np

np.random.seed(42)
sales = np.random.randint(50, 200, size=30)  # 50〜200万円の間でランダム生成

以下の分析タスクを全てnumpyのみで実装してください(pandasは使用しない):

タスク1: 基本統計の計算

  • 月間合計売上
  • 日次平均売上
  • 最高売上額と最低売上額
  • 売上の標準偏差(日々のばらつき)

タスク2: 条件フィルタリング

  • 平均売上を上回った日数を計算
  • 平均売上を上回った日のデータのみ抽出

タスク3: 正規化(Normalization)

  • 売上データを0〜1の範囲に正規化する
  • 正規化の公式: (値 - 最小値) / (最大値 - 最小値)
  • 正規化後の最小値が0、最大値が1になることを確認

タスク4: 週次集計

  • 30日を4週(各7日)と残り2日に分けて考える
  • 最初の28日を (4, 7) の形に reshape する
  • 各週の合計売上を計算する(axis=1 を使う)

最終的に、以下の形式で結果を出力してください:

▶ 出力を見る
=== 月次売上分析レポート ===
合計売上: XXX万円
平均売上: XX.X万円/日
最高売上: XXX万円
最低売上: XX万円
標準偏差: XX.X万円

平均超え日数: XX日 / 30日

🔍 ヒント(段階的開示)

ヒント1(方向性)

numpyの配列に対して統計関数(.mean(), .sum()など)を使うと、全要素を一度に計算できます。条件フィルタリングは「ブール配列」を使います。

ヒント2(アプローチ)
  • タスク1: sales.sum(), sales.mean(), sales.max(), sales.min(), sales.std()
  • タスク2: sales > sales.mean() でTrue/Falseの配列が作れる。sum()でTrueの数を数えられる
  • タスク3: (sales - sales.min()) / (sales.max() - sales.min())
  • タスク4: sales[:28].reshape(4, 7) で形を変換。.sum(axis=1) で各行の合計
ヒント3(コード骨格)
import numpy as np

np.random.seed(42)
sales = np.random.randint(50, 200, size=30)

# タスク1: 基本統計
total = sales.___()
avg = sales.___()
max_sales = sales.___()
min_sales = sales.___()
std_sales = sales.___()

# タスク2: 条件フィルタリング
above_avg_mask = sales > ___  # ブール配列
above_avg_count = above_avg_mask.___()  # Trueの数
above_avg_days = sales[above_avg_mask]  # フィルタリング

# タスク3: 正規化
normalized = (sales - ___) / (___ - ___)

# タスク4: 週次集計
weekly = sales[:28].reshape(___, ___)
weekly_totals = weekly.sum(axis=___)

print(f"=== 月次売上分析レポート ===")
print(f"合計売上: {total}万円")
print(f"平均売上: {avg:.1f}万円/日")
print(f"最高売上: {max_sales}万円")
print(f"最低売上: {min_sales}万円")
print(f"標準偏差: {std_sales:.1f}万円")
print(f"\n平均超え日数: {above_avg_count}日 / 30日")

模範解答

import numpy as np

# データ生成
np.random.seed(42)
sales = np.random.randint(50, 200, size=30)

print("生成された売上データ(万円):")
print(sales)

# ============================
# タスク1: 基本統計の計算
# ============================
total = sales.sum()
avg = sales.mean()
max_sales = sales.max()
min_sales = sales.min()
std_sales = sales.std()

print("\n=== 月次売上分析レポート ===")
print(f"合計売上: {total}万円")
print(f"平均売上: {avg:.1f}万円/日")
print(f"最高売上: {max_sales}万円")
print(f"最低売上: {min_sales}万円")
print(f"標準偏差: {std_sales:.1f}万円")

# ============================
# タスク2: 条件フィルタリング
# ============================
above_avg_mask = sales > avg          # True/Falseの配列
above_avg_count = above_avg_mask.sum()  # Trueの数 = 平均超えの日数
above_avg_days = sales[above_avg_mask]  # 平均超えの日の売上のみ

print(f"\n平均超え日数: {above_avg_count}日 / 30日")
print(f"平均超えの日の売上: {above_avg_days}")

# ============================
# タスク3: 正規化
# ============================
normalized = (sales - sales.min()) / (sales.max() - sales.min())

print(f"\n正規化後のデータ(先頭5件): {normalized[:5].round(3)}")
print(f"正規化後の最小値: {normalized.min():.1f}")  # 0.0
print(f"正規化後の最大値: {normalized.max():.1f}")  # 1.0

# ============================
# タスク4: 週次集計
# ============================
weekly = sales[:28].reshape(4, 7)  # 28日を4週×7日に変換
weekly_totals = weekly.sum(axis=1)  # axis=1: 各行(各週)の合計

print(f"\n週次売上合計:")
for week, total_w in enumerate(weekly_totals, 1):
    print(f"  第{week}週: {total_w}万円")

🪜 Step-by-Step 解説

1
データ生成とseedの意味
np.random.seed(42)
sales = np.random.randint(50, 200, size=30)

np.random.seed(42) は「ランダムの種」を固定します。同じseedを使えば、何度実行しても同じ「ランダムな」数が生成されます。これはデータサイエンスで「再現性」を保つために非常に重要です。

np.random.randint(50, 200, size=30) は「50以上200未満の整数を30個ランダムに生成」という意味です。

2
基本統計(メソッドチェーン)
total = sales.sum()    # 全て足す
avg = sales.mean()     # 合計÷個数
max_sales = sales.max()  # 最大値
min_sales = sales.min()  # 最小値
std_sales = sales.std()  # 標準偏差

これらはnumpy配列のメソッド(配列が持つ関数)です。Pythonのリストでは使えませんが、numpyのarrayなら使えます。全30要素を一瞬で計算します。

3
ブール配列によるフィルタリング(最重要!)
above_avg_mask = sales > avg
# → array([False, True, True, False, ...]) のようになる

above_avg_count = above_avg_mask.sum()
# Trueは1、Falseは0として計算される
# sum() = Trueの個数 = 平均超えの日数

above_avg_days = sales[above_avg_mask]
# ブール配列でインデックスすると、Trueの位置の要素だけ取り出せる

このパターン(条件 → ブール配列 → フィルタリング)はKaggleで毎日使う最重要テクニックです。pandasでも全く同じ考え方が使えます。

4
正規化の意味
normalized = (sales - sales.min()) / (sales.max() - sales.min())

正規化の直感的な意味:

  • 「最小値からの距離」÷「最大値と最小値の差」
  • 最小値の場合: (最小 - 最小) / (最大 - 最小) = 0 / 差 = 0
  • 最大値の場合: (最大 - 最小) / (最大 - 最小) = 1
  • 間の値は0〜1の間に収まる

これはMin-Max正規化(またはMin-Max スケーリング)と呼ばれます。

5
reshapeとaxisの使い方
weekly = sales[:28].reshape(4, 7)
# sales[:28] → 最初の28要素(インデックス0〜27)
# .reshape(4, 7) → 4行7列の2次元配列に変換

weekly_totals = weekly.sum(axis=1)
# axis=0 → 列方向(↓)に計算
# axis=1 → 行方向(→)に計算、各行の合計を出す

reshapeのイメージ:

[d1, d2, d3, d4, d5, d6, d7, d8, d9, ...]
         ↓ reshape(4, 7)
[[d1,  d2,  d3,  d4,  d5,  d6,  d7 ],   ← 第1週
 [d8,  d9,  d10, d11, d12, d13, d14],   ← 第2週
 [d15, d16, d17, d18, d19, d20, d21],   ← 第3週
 [d22, d23, d24, d25, d26, d27, d28]]   ← 第4週

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

ブール(Boolean)とは?

「True(真)」か「False(偽)」の2択しかない値のことです。条件を満たせばTrue、満たさなければFalse。プログラミングの世界では「Yes/No」の答えをこの形で表現します。

axisの覚え方

表計算ソフト(Excelなど)をイメージしてください:

  • axis=0(行方向): 列ごとに計算(↓方向)→ 各列の合計・平均を出す
  • axis=1(列方向): 行ごとに計算(→方向)→ 各行の合計・平均を出す

🏆 Kaggleでの実践的な使い方

1. 特徴量の正規化

機械学習モデル(特に線形回帰・ニューラルネットワーク)は、特徴量のスケールが揃っていないと性能が落ちます。今回学んだMin-Max正規化は特徴量エンジニアリングの基本中の基本です。

# Kaggleの前処理でよく見るパターン
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X)
# これは内部でnumpyの演算を使っている

2. ブール配列によるデータフィルタリング

外れ値の除去・特定条件のサンプル抽出など、コンペの前処理で毎日使います。

3. reshapeとベクトル化

画像データ(縦×横×チャンネル)や時系列データ(時間×特徴量)の操作にreshapeは必須です。


⚠️ よくある誤解・ミス

誤解・ミスなぜ起こるか正しい理解
sales > avg の結果をループで処理しようとするPythonリストの習慣ブール配列をそのままインデックスに使える
reshape でエラーが出る元の要素数と一致しない形を指定4×7=28 のように積が一致する必要がある
axis=0axis=1 を逆に使う直感と逆になることがあるaxis=1で「各行」の集計
std() がExcelと違う値になるExcelはデフォルトで不偏標準偏差(n-1)numpyはデフォルトで母標準偏差(n)。ddof=1 で一致
ブール配列の.sum().count()と思うpandasのcountと混同numpyにはcount()なし。True=1として.sum()を使う

🚀 次のステップ

  • 発展: 標準化(Standardization)= (値 - 平均) / 標準偏差。Min-Max正規化との使い分けを学ぶ
  • 次回予告: pandas入門(DataFrame・Series) — numpyの上に構築されたデータ分析の主力ライブラリ。表形式データの操作が格段に楽になる

🎯 自己評価

自分の回答

気づき・メモ