NumPy は Python での数値計算の土台になるライブラリです。pandas / Polars / matplotlib / scikit-learn など、本サイトで扱うほとんどのライブラリが NumPy の配列(ndarray)を内部で使っています。
本記事では、NumPy の中心オブジェクトである ndarray を、株価風のサンプルデータで作成・操作・集計しながら、配列で考える発想を身につけます。
目次
- インストール
- NumPy が解く問題
- 配列を作る
- 形状を扱う(reshape / axis)
- ベクトル化された演算
- ブロードキャスト
- 真偽値配列でフィルタする
- 統計関数のまとめ
インストール
pip install numpy検証バージョン: Python 3.12.5 / NumPy 2.0.1
NumPy が解く問題
Python の標準リストは柔軟ですが、数千〜数百万件の数値計算には向いていません。値ごとに型情報を持つ汎用オブジェクトのため、要素ごとの計算がループで回り、速度・メモリの両面で重くなります。
NumPy の ndarray は、同一型の値が連続したメモリに並ぶ「型付きの配列」です。要素ごとの演算は内部で C 実装のループに落ちるため、Python の for 文より 1〜2 桁高速になります。
配列を作る
リストから配列を作るのが最も基本的な方法です。
import numpy as np
closes = np.array([2900, 2925, 2880, 2910, 2945])print(closes)print(closes.dtype, closes.shape)[2900 2925 2880 2910 2945]int64 (5,)dtype は要素の型、shape は各次元の長さを示すタプルです。1 次元配列なので (5,) となります。
専用の生成関数もよく使います。
zeros = np.zeros(5) # [0. 0. 0. 0. 0.]ones = np.ones((2, 3)) # 2 行 3 列の 1 で埋めた行列seq = np.arange(0, 10, 2) # [0 2 4 6 8]linspace = np.linspace(0, 1, 5) # [0. 0.25 0.5 0.75 1.]rng = np.random.default_rng(42)random_values = rng.normal(loc=0, scale=1, size=1000) # 正規分布から 1000 件乱数は default_rng 経由で生成します。np.random.rand の旧 API より再現性とスレッド安全性が改善されています。
形状を扱う(reshape / axis)
複数銘柄の価格表は 2 次元配列で表現できます。
# 行: 営業日, 列: 銘柄(7203, 9984, 8306)prices = np.array([ [2900, 9800, 1450], [2925, 9750, 1448], [2880, 9900, 1462], [2910, 9850, 1470], [2945, 9820, 1480],])print(prices.shape) # (5, 3)軸(axis)を指定すると「列ごと」「行ごと」の集計を切り替えられます。
print(prices.mean(axis=0)) # 銘柄ごとの平均(列方向)print(prices.mean(axis=1)) # 日付ごとの平均(行方向)axis=0 は「行を潰して 1 行にする」、axis=1 は「列を潰して 1 列にする」と覚えると迷いません。
reshape で形を変えられます。要素数が同じであれば、自由に並べ替えできます。
flat = prices.reshape(-1) # (15,)mat = flat.reshape(3, 5) # (3, 5)-1 は「残りの次元から自動で計算」の意味です。
ベクトル化された演算
NumPy の真価は、要素ごとの演算をループ無しで書けるところにあります。
# 単純リターン(前日比)を一括で計算returns = (prices[1:] - prices[:-1]) / prices[:-1]print(returns.round(4))prices[1:] は 2 行目以降、prices[:-1] は最終行を除く全行です。差分を取って前日価格で割るだけで、全銘柄・全日付のリターン行列が得られます。
ブロードキャスト
形が異なる配列同士の演算を「自動で合わせる」仕組みがブロードキャストです。
mean_per_stock = prices.mean(axis=0) # shape (3,)deviation = prices - mean_per_stock # shape (5, 3) と (3,) の演算print(deviation.round(2))(5, 3) の行列から (3,) のベクトルを引くと、ベクトルが各行に同じ形でコピーされて差し引かれます。明示的にループや np.tile を書く必要はありません。
ブロードキャストの基本ルールは次の通りです。
- 末尾から軸を比較する
- 各軸の長さが「同じ」または「片方が 1」なら合致
- 合致しない軸があると
ValueError
真偽値配列でフィルタする
条件式は要素ごとに True / False の配列を返します。
mask = closes > 2900print(mask) # [False True False True True]print(closes[mask]) # [2925 2910 2945]複数条件は &(かつ)・|(または)で繋ぎ、各条件をカッコで囲むのが必須です。
big_moves = (closes > 2900) & (closes < 2940)print(closes[big_moves])統計関数のまとめ
代表的な集計を一覧で示します。
| 関数 | 役割 |
|---|---|
arr.sum() | 合計 |
arr.mean() | 平均 |
arr.std(ddof=0) | 標準偏差(母集団) |
arr.std(ddof=1) | 標準偏差(標本) |
arr.min() / arr.max() | 最小・最大 |
arr.argmin() / arr.argmax() | 最小・最大の位置 |
np.median(arr) | 中央値 |
np.percentile(arr, [25, 50, 75]) | 分位点 |
リターン列の代表値を求めると、銘柄ごとのボラティリティの違いが見えます。
daily_ret = (prices[1:] - prices[:-1]) / prices[:-1]print("mean :", daily_ret.mean(axis=0))print("std :", daily_ret.std(axis=0, ddof=1))print("max :", daily_ret.max(axis=0))print("min :", daily_ret.min(axis=0))生成AI へのプロンプト例
NumPy のコードは仕様が短く、生成AI が安定して書ける領域です。
NumPy で次の処理を行うコードを書いてください。
入力:- closes: shape (n_days, n_tickers) の終値行列- weights: shape (n_tickers,) のポートフォリオ比率(合計 1)
要件:- 日次の単純リターン行列を計算する- ポートフォリオの日次リターンを計算する(銘柄ごとのリターン × 比率の総和)- 累積リターン(初期 1 の元本が時系列でいくらになるか)を返す- NumPy 2 系を想定し、ループは使わない「入力の形」「処理の手順」「禁止事項(ループ禁止など)」を明示すると、ブロードキャストを使った簡潔なコードが返ってきます。
まとめ
ndarrayは「同一型・連続メモリ」の数値配列で、要素ごとの演算が高速- 形(
shape)と軸(axis)を意識すると、銘柄方向・日付方向の集計を書き分けられる - 形の異なる配列同士の演算は ブロードキャスト で自動的に合う
- 真偽値配列でフィルタ・統計関数で集計までを、ループ無しで書ける