7  線形代数

7.1 ベクトル

n 個の成分を持つベクトル \mathbf{x} は, \mathbf{x} = \begin{pmatrix} x_1 \\ x_2 \\ \vdots \\ x_n \end{pmatrix}

で表される.ここで,x_1, x_2, \ldots, x_n はベクトルの成分と呼ぶ.ベクトルは,\mathbf{v}, \mathbf{w} のように太字で表すことが多い.ゼロベクトルは,すべての成分が 0 であるベクトルであり,\mathbf{0} と表す.また,すべての成分が 1 であるベクトルは,\mathbf{1} と表す.

ヒント高校数学とのちがい

高校数学では,ベクトルは向きと大きさを持つ量として学ぶが,データサイエンス,機械学習,OR などの分野では,単に成分の集まりとして扱うことが多い.

例 7.1 ベクトル \mathbf{a} \mathbf{a} = \begin{pmatrix} 2 \\ -1 \\ 3 \end{pmatrix}

と定義する.np.array() でベクトルを定義するには,次のようにする.

import numpy as np

a = np.array([2, -1, 3])
print(a)
[ 2 -1  3]

例 7.2 ある人の身長が 170 cm,体重が 60 kg,年齢が 30 歳であるとする.この人の情報をベクトル \mathbf{p} で表すと, \mathbf{p} = \begin{pmatrix} 170 \\ 60 \\ 30 \end{pmatrix}

となる.np.array() でベクトルを定義するには,次のようにする.

import numpy as np

p = np.array([170, 60, 30])
print(p)
[170  60  30]

7.1.1 ベクトルの和

ベクトル \mathbf{a}\mathbf{b} の和を \mathbf{a} + \mathbf{b} と表す.

例 7.3 ベクトル \mathbf{a}\mathbf{b} \mathbf{a} = \begin{pmatrix} 2 \\ -1 \\ 3 \end{pmatrix}, \quad \mathbf{b} = \begin{pmatrix} 4 \\ 0 \\ -2 \end{pmatrix} と定義する.これらの和 \mathbf{a} + \mathbf{b} は次のように計算される: \mathbf{a} + \mathbf{b} = \begin{pmatrix} 2 + 4 \\ -1 + 0 \\ 3 - 2 \end{pmatrix} = \begin{pmatrix} 6 \\ -1 \\ 1 \end{pmatrix}

numpy を使ってベクトルの和を計算するには,次のようにする.

import numpy as np

a = np.array([2, -1, 3])
b = np.array([4, 0, -2])
c = a + b
print(c)
[ 6 -1  1]

例 7.4 ある大学では,理工学部,経済学部,文学部のデータは次の表で与えられている.

学部 学生数 教員数 研究費(百万円)
理工学部 2000 150 500
経済学部 1500 100 300
文学部 1000 80 100

この大学全体の学生数,教員数,研究費を計算するには, \mathbf{a} = \begin{pmatrix}2000 \\ 150 \\ 500 \end{pmatrix}, \quad \mathbf{b} = \begin{pmatrix}1500 \\ 100 \\ 300 \end{pmatrix}, \quad \mathbf{c} = \begin{pmatrix}1000 \\ 80 \\ 100 \end{pmatrix} と定義し,これらの和を計算する.

\mathbf{a} + \mathbf{b} + \mathbf{c} = \begin{pmatrix} 2000 + 1500 + 1000 \\ 150 + 100 + 80 \\ 500 + 300 + 100 \end{pmatrix} = \begin{pmatrix} 4500 \\ 330 \\ 900 \end{pmatrix}

したがって,この大学全体の学生数は 4500 人,教員数は 330 人,研究費は 900 百万円である.

7.1.2 ベクトルのスカラー倍

ベクトル \mathbf{a} のスカラー倍を k \mathbf{a} と表す.ここで,k はスカラー(実数)である.

例 7.5 ベクトル \mathbf{a} \mathbf{a} = \begin{pmatrix} 2 \\ -1 \\ 3 \end{pmatrix} と定義する.このベクトルのスカラー倍 3 \mathbf{a} は次のように計算される: 3 \mathbf{a} = 3 \begin{pmatrix} 2 \\ -1 \\ 3 \end{pmatrix} = \begin{pmatrix} 6 \\ -3 \\ 9 \end{pmatrix}

numpy を使ってベクトルのスカラー倍を計算するには,次のようにする.

import numpy as np

a = np.array([2, -1, 3])
b = 3 * a
print(b)
[ 6 -3  9]
ノートブロードキャスト

NumPy では,broadcasting と呼ばれる仕組みを使って,ベクトルとスカラーの演算を行う.

例 7.6 ある会社では,社員3人の月給がそれぞれ 30 万円,40 万円,50 万円であるとする.次年度,この会社は全社員の給料を 10\% 増加させることにした.社員の給料をベクトル \mathbf{s} で表すと, \mathbf{s} = \begin{pmatrix}30 \\ 40 \\ 50 \end{pmatrix} となる.このベクトルの 1.1 倍を計算することで,次年度の社員の給料を求めることができる. 1.1 \mathbf{s} = 1.1 \begin{pmatrix}30 \\ 40 \\ 50 \end{pmatrix} = \begin{pmatrix}33 \\ 44 \\ 55 \end{pmatrix}

7.1.3 内積

ベクトル \mathbf{a}\mathbf{b} の内積(inner product)を \mathbf{a} \cdot \mathbf{b} = \sum_{i=1}^{n} a_i b_i =a_1 b_1 + a_2 b_2 + \cdots + a_n b_n

と表す.ドット積(dot product)とも呼ばれる.

例 7.7 ベクトル \mathbf{a}\mathbf{b} \mathbf{a} = \begin{pmatrix} 2 \\ -1 \\ 3 \end{pmatrix}, \quad \mathbf{b} = \begin{pmatrix} 4 \\ 0 \\ -2 \end{pmatrix} と定義する.これらの内積 \mathbf{a} \cdot \mathbf{b} は次のように計算される: \mathbf{a} \cdot \mathbf{b} = 2 \times 4 + (-1) \times 0 + 3 \times (-2) = 8 + 0 - 6 = 2

numpy を使ってベクトルの内積を計算するには,np.dot() 関数を使う.

import numpy as np

a = np.array([2, -1, 3])
b = np.array([4, 0, -2])
dot_product = np.dot(a, b)
print(dot_product)
2

内積は

\mathbf{a}^{\top} \mathbf{b} と書くこともできる.ここで,\mathbf{a}^{\top} はベクトル \mathbf{a} の転置を表す.

例 7.8 ある店舗で販売されている商品の単価と販売数が次の表で与えられている.

商品名 単価(円) 販売数
商品A 1000 50
商品B 2000 30
商品C 1500 20

この店舗の総売上を計算するには,単価をベクトル \mathbf{p},販売数をベクトル \mathbf{q} として, \mathbf{p} = \begin{pmatrix}1000 \\ 2000 \\ 1500 \end{pmatrix}, \quad \mathbf{q} = \begin{pmatrix}50 \\ 30 \\ 20 \end{pmatrix} と定義し,\mathbf{p}^{\top} \mathbf{q} を計算する.

\mathbf{p}^{\top} \mathbf{q} = 1000 \times 50 + 2000 \times 30 + 1500 \times 20 = 140000

したがって,この店舗の総売上は 140000 円である.

7.1.4 ユークリッドノルム

ベクトル \mathbf{a}ユークリッドノルム(Euclidean norm)は,

\|\mathbf{a}\| = \sqrt{a_1^2 + a_2^2 + \cdots + a_n^2}

と定義され,そのベクトルの大きさを表す.

例 7.9 ベクトル \mathbf{a} \mathbf{a} = \begin{pmatrix} 3 \\ 4 \end{pmatrix} と定義する.このベクトルのユークリッドノルム \|\mathbf{a}\| \|\mathbf{a}\| = \sqrt{3^2 + 4^2} = \sqrt{9 + 16} = \sqrt{25} = 5 と計算される.

numpy を使ってベクトルのユークリッドノルムを計算するには,np.linalg.norm() 関数を使う.

import numpy as np

a = np.array([3, 4])
norm_a = np.linalg.norm(a)
print(norm_a)
5.0

\mathbf{a}\mathbf{b}ユークリッド距離(Euclidean distance)は

d(\mathbf{a}, \mathbf{b}) = \|\mathbf{a} - \mathbf{b}\| = \sqrt{(a_1 - b_1)^2 + (a_2 - b_2)^2 + \cdots + (a_n - b_n)^2} と定義される.

例 7.10 都市 A の位置をベクトル \mathbf{a},都市 B の位置をベクトル \mathbf{b} とする. \mathbf{a} = \begin{pmatrix}2 \\ 3 \end{pmatrix}, \quad \mathbf{b} = \begin{pmatrix}7 \\ 11 \end{pmatrix} と定義する.これらの都市間のユークリッド距離 d(\mathbf{a}, \mathbf{b}) d(\mathbf{a}, \mathbf{b}) = \|\mathbf{a} - \mathbf{b}\| = \sqrt{(2 - 7)^2 + (3 - 11)^2} と計算される.

numpy を使ってベクトルのユークリッド距離を計算するには,次のようにする.

import numpy as np

a = np.array([2, 3])
b = np.array([7, 11])
distance = np.linalg.norm(a - b)
print(distance)
9.433981132056603

7.1.5 要素ごとの積

n 次元ベクトル \mathbf{a}\mathbf{b} の要素ごとの積(element-wise product)は, \mathbf{a} \circ \mathbf{b} = \begin{pmatrix} a_1 b_1 \\ a_2 b_2 \\ \vdots \\ a_n b_n \end{pmatrix} で定義される.

例 7.11 ベクトル \mathbf{a}\mathbf{b} \mathbf{a} = \begin{pmatrix}2 \\ -1 \\ 3 \end{pmatrix}, \quad \mathbf{b} = \begin{pmatrix}4 \\ 0 \\ -2 \end{pmatrix} と定義する.これらの要素ごとの積 \mathbf{a} \circ \mathbf{b} は次のように計算される: \mathbf{a} \circ \mathbf{b} = \begin{pmatrix} 2 \times 4 \\ -1 \times 0 \\ 3 \times (-2) \end{pmatrix} = \begin{pmatrix}8 \\ 0 \\ -6 \end{pmatrix} numpy を使ってベクトルの要素ごとの積を計算するには,次のようにする.

import numpy as np

a = np.array([2, -1, 3])
b = np.array([4, 0, -2])
elementwise_product = a * b
print(elementwise_product)
[ 8  0 -6]
ノート内積と要素ごとの積

内積と要素ごとの積は異なる演算であることに注意されたい.

ヒントNumPy の線形代数関数

NumPy では,様々な線形代数の演算がサポートされている.詳細は,NumPy Linear Algebra を参照されたい.

7.1.6 ベクトル化

本来であれば反復構造を用いて計算すべきところを,配列を用いてプログラミングする手法をベクトル化(vectorization)と呼ぶ.ベクトル化により,コードが簡潔になり,計算速度が向上することが多い.

以下のコードは,1 から 1,000,000 までの整数の平方を計算する例である.反復構造を用いた場合とベクトル化を用いた場合の両方を示す.ベクトル化の方が高速であることがわかる.

import numpy as np
import time

# 反復構造を用いた場合
start_time = time.time()
squares_loop = []
for i in range(1, 1000001):
    squares_loop.append(i ** 2)
end_time = time.time()
print("反復構造の計算時間: {:.6f} 秒".format(end_time - start_time))

# ベクトル化を用いた場合
start_time = time.time()
numbers = np.arange(1, 1000001)
squares_vectorized = numbers ** 2
end_time = time.time()
print("ベクトル化の計算時間: {:.6f} 秒".format(end_time - start_time))
反復構造の計算時間: 0.173699 秒
ベクトル化の計算時間: 0.002640 秒
ヒントベクトル化のすすめ

Python では,可能な限り反復構造を避け,ベクトル化を用いることが推奨される.

7.2 練習問題

可能な限り,反復構造を使わずに,ベクトル演算を用いて解答せよ.

練習 7.1 n 次元ベクトル \mathbf{x}\mathbf{w} が与えられたとき,次の和を計算するプログラムを作成せよ. \sum_{i=1}^{n} w_i x_i ここで,w_i はベクトル \mathbf{w}i 番目の成分,x_i はベクトル \mathbf{x}i 番目の成分である.

import numpy as np

def func(x, w):
    # ここに 1 行のコードを書け

# 計算例
x = np.array([1, 2, 3, 4, 5])
w = np.array([0.1, 0.2, 0.3, 0.2, 0.2])
result = func(x, w)
print(result)  # 出力: 3.2

練習 7.2 n 次元ベクトル \mathbf{a}\mathbf{b}\mathbf{c} が与えられたとき,次の和を計算するプログラムを作成せよ.

\sum_{i=1}^{n} (a_i + b_i) c_i

import numpy as np

def func(a, b, c):
    # ここに 1 行のコードを書け

# 計算例
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.array([7, 8, 9])
result = func(a, b, c)
print(result)  # 出力: 172