第20章 数学処理

組み込み数学関数

Pythonには様々な組み込み数学関数があり、これらは基本的な数学的演算や計算に役立ちます。これらの関数はPythonの標準ライブラリの一部として提供されており、追加のインストールなしで利用できます。以下は、よく使われる組み込み数学関数のいくつかです。

  1. abs(x): 数値xの絶対値を返します。
  2. round(number[, ndigits]): 数値を丸めて、指定された桁数の精度で返します。ndigitsが省略された場合は整数に丸められます。
  3. min(iterable) / min(arg1, arg2, *args[, key]): 与えられたイテラブルの中で最小の要素、または与えられた引数の中で最小のものを返します。
  4. max(iterable) / max(arg1, arg2, *args[, key]): 与えられたイテラブルの中で最大の要素、または与えられた引数の中で最大のものを返します。
  5. sum(iterable[, start]): イテラブルの全要素の合計を返します。startに値を指定すると、その値に合計が加算されます。
  6. pow(base, exp[, mod]): baseexp乗を返します。modが指定された場合、baseexp乗に対するモジュロmodの値を返します。

mathモジュールの関数

さらに、mathモジュールにはより多くの数学関数が用意されています。mathモジュールを利用するには、まずimport mathでモジュールをインポートする必要があります。

  1. math.sqrt(x): xの平方根を返します。
  2. math.exp(x): ex乗(自然対数の底ex乗)を返します。
  3. math.log(x[, base]): xの自然対数を返します。baseが指定された場合、baseを底とする対数を返します。
  4. math.sin(x), math.cos(x), math.tan(x): xの正弦、余弦、正接を返します。
  5. math.radians(x) / math.degrees(x): 角度をラジアンに変換する(radians)、またはラジアンを角度に変換する(degrees)。

これらの関数は、様々な数学的計算やデータ分析、科学計算などに役立ちます。また、mathモジュールにはこれら以外にも多くの関数が用意されています。


線形代数

Pythonで線形代数の演算を行う際には、主にNumPyライブラリが使用されます。NumPyは高性能な数学計算をサポートし、ベクトルや行列などの多次元配列に対する幅広い演算機能を提供しています。線形代数における主要な概念や操作には以下のようなものがあります。

ベクトルと行列の作成

ベクトルや行列はNumPy配列として作成されます。例えば、以下のようにしてベクトルや行列を作成できます。

import numpy as np

# ベクトルの作成
v = np.array([1, 2, 3])

# 行列の作成
A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])


基本的な演算

ベクトルや行列の加算、減算、スカラー乗算などの基本的な演算が直感的に行えます。

# ベクトルの加算
v1 = np.array([1, 2, 3])
v2 = np.array([4, 5, 6])
v_sum = v1 + v2

# 行列とスカラーの乗算
alpha = 3
A_scaled = A * alpha


行列積

NumPyのdot関数や@演算子を使用して行列積(またはベクトルと行列の積)を計算します。

# 行列積
product = np.dot(A, v)
# または
product = A @ v


行列の逆行列と行列式

numpy.linalgモジュールは、逆行列や行列式などの線形代数の基本的な演算を提供します。

# 行列式の計算
det_A = np.linalg.det(A)

# 逆行列の計算
inv_A = np.linalg.inv(A)


固有値と固有ベクトル

固有値と固有ベクトルの計算もnumpy.linalgモジュールを使用して行います。

# 固有値と固有ベクトルの計算
eigenvalues, eigenvectors = np.linalg.eig(A)


特異値分解 (SVD)

特異値分解は、任意の行列を特定の成分に分解する手法です。この分解により、行列は3つの成分に分解されます

import numpy as np
from scipy.linalg import svd

# 行列の定義
A = np.array([[1, 2], [3, 4], [5, 6]])

# SVDの実行
U, s, VT = svd(A)

# U, s, VTの出力
print("左特異ベクトルを列に持つ行列:", U)
print("特異値を対角成分に持つ対角行列:", s)
print("右特異ベクトルを列に持つ行列の転置:", VT)


LU分解

LU分解は、行列を下三角行列(L)と上三角行列(U)の積に分解する方法です。これは、主に線形方程式系の解法や行列の逆行列の計算に利用されます

import numpy as np
from scipy.linalg import lu

# 行列の定義
A = np.array([[1, 2], [3, 4]])

# LU分解の実行
P, L, U = lu(A)

# P, L, Uの出力
print("置換行列:", P)
print("下三角行列:", L)
print("上三角行列:", U)

scipy.linalg.lu関数は、実際にはPLU分解を行い、行列P(置換行列)も返します。これにより、元の行列AはPA=LUとして表されます。


微分積分学

Pythonで微分積分学を扱う場合、主にNumPySciPySymPyといったライブラリが利用されます。これらは数値計算やシンボリック計算をサポートし、科学技術計算に広く使用されています。

数値微分

数値微分では、関数の定義域内のある点での傾き(導関数の値)を近似的に計算します。例えば、中心差分法を使って導関数を求めることができます。

import numpy as np

def f(x):
    return x**2

def numerical_derivative(f, x, h=1e-5):
    return (f(x + h) - f(x - h)) / (2 * h)

# x = 1での導関数の値を求める
x = 1
derivative = numerical_derivative(f, x)
print(derivative)


数値積分

SciPyintegrateモジュールは数値積分をサポートしています。例えば、定積分を計算する際に使用します。

import scipy.integrate as spi

def f(x):
    return x**2

# 0から1までの積分を計算
integral, _ = spi.quad(f, 0, 1)
print(integral)


シンボリック微分

SymPyを使用して関数の導関数を求め、それをさまざまな点で評価できます。

from sympy import symbols, diff

x = symbols('x')
f = x**2

# 導関数を求める
dfdx = diff(f, x)

# 導関数を表示
print(dfdx)

# x = 1での導関数の値を評価
print(dfdx.subs(x, 1))


シンボリック積分

SymPyを使って関数の積分を計算することもできます。

from sympy import symbols, integrate

x = symbols('x')
f = x**2

# 不定積分
F = integrate(f, x)
print(F)

# 定積分
integral = integrate(f, (x, 0, 1))
print(integral)


常微分方程式の解法

SciPyのodeint関数またはsolve_ivp関数を使用して、常微分方程式を解くことができます。これらの関数は、初期条件と方程式を定義し、数値的に解を求めます。

例:単振動の方程式

単振動(調和振動子)の方程式は次のようになります。

d y 2 d t 2 + ω 2 y = 0

これを一階の方程式の系に変換するために、 v = d y d t と置くと、以下のようになります。

d y d t = v
d v d t = ω 2 y

これをPythonで解くには以下のようにします。

import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt

# 方程式の定義
def harmonic_oscillator(yv, t, omega_squared):
    y, v = yv
    dydt = v
    dvdt = -omega_squared * y
    return [dydt, dvdt]

# 初期条件と時間の定義
omega_squared = 1.0
y0 = [1.0, 0.0]  # 初期位置と初速度
t = np.linspace(0, 10, 100)  # 時間範囲

# ODEの解法
solution = odeint(harmonic_oscillator, y0, t, args=(omega_squared,))

# 結果のプロット
plt.plot(t, solution[:, 0])
plt.xlabel('time')
plt.ylabel('y(t)')
plt.show()

このコードは、調和振動子の運動を時間に対してプロットします。


確率論と統計

Pythonにおける確率論と統計学の扱いは、データ分析、科学計算、機械学習など多岐にわたる分野で重要です。Pythonでは、NumPySciPyPandasStatsModelsscikit-learn などのライブラリがこれらのタスクをサポートしています。

NumPyでの確率論と統計

NumPyは、基本的な統計計算やランダムなデータの生成に使用されます。

import numpy as np

data = np.array([1, 2, 3, 4, 5])
# 平均
mean = np.mean(data)
# 中央値
median = np.median(data)
# 標準偏差
std_dev = np.std(data)
# 平均0、標準偏差1の正規分布から1000個の数値を生成
normal_data = np.random.normal(0, 1, 1000)


SciPyでの確率分布と統計

SciPyは、より高度な統計計算や確率分布の扱いに使用されます。

確率分布の使用

from scipy.stats import norm

# 正規分布の確率密度関数 (PDF)
pdf_value = norm.pdf(0)  # 平均0、標準偏差1の正規分布におけるx=0でのPDF値

# 累積分布関数 (CDF)
cdf_value = norm.cdf(1)  # x=1でのCDF値

統計的テスト

from scipy import stats

data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(1, 1, 1000)

# t検定を実施
t_stat, p_val = stats.ttest_ind(data1, data2)


Pandasでのデータ解析

Pandasは、データフレーム(表形式のデータ構造)を使用して統計的なデータ解析を行います。

import pandas as pd

# データフレームの作成
df = pd.DataFrame({
    'A': np.random.normal(0, 1, 1000),
    'B': np.random.normal(1, 1, 1000)
})

# 基本的な統計量
mean = df.mean()
summary = df.describe()


統計モデリングと機械学習

StatsModelsは統計モデルの構築、推定、テスト、データ探索に使われます。

scikit-learnは分類、回帰、クラスタリング、次元削減などの機械学習タスクに広く使用されます。

import statsmodels.api as sm
from sklearn.linear_model import LinearRegression

# StatsModelsでの線形回帰モデル
X = sm.add_constant(df['A'])  # 定数項(切片)を追加
model = sm.OLS(df['B'], X).fit()
print(model.summary())

# scikit-learnでの線形回帰モデル
model = LinearRegression().fit(df[['A']], df['B'])
print(model.coef_, model.intercept_)


数値解析

Pythonでの数値解析は、数学的な問題を数値的に近似して解くプロセスです。これには方程式の解法、最適化、数値積分、微分方程式の解法などが含まれます。以下は、Pythonでの数値解析の主要な側面とその実装についての概要です。

方程式の数値的解法

方程式の数値的解法には、ニュートン法や二分法などがあります。これらは、非線形方程式の解を近似的に求めるために用いられます。

ニュートン法

def newton_method(f, df, x0, tol=1e-5, max_iter=100):
    x = x0
    for _ in range(max_iter):
        x_new = x - f(x) / df(x)
        if abs(x_new - x) < tol:
            return x_new
        x = x_new
    return x

# 使用例
import math

f = lambda x: math.cos(x) - x
df = lambda x: -math.sin(x) - 1
root = newton_method(f, df, 0.5)

二分法

def f(x):
    return x**2 - 2

def binary_search(f, lower, upper, tol=1e-5, max_iter=100):
    for _ in range(max_iter):
        mid = (lower + upper) / 2
        if f(mid) == 0 or (upper - lower) / 2 < tol:
            return mid
        elif f(mid) * f(lower) < 0:
            upper = mid
        else:
            lower = mid
    return mid

# 二分法による根の近似値を求める
root = binary_search(f, 0, 2)
print(root)


最適化問題の解法

最適化は、関数の最小値または最大値を見つけるプロセスです。SciPyのoptimizeモジュールは、さまざまな最適化アルゴリズムを提供します。

from scipy.optimize import minimize

# 最適化する関数
def objective_function(x):
    return x[0]**2 + x[1]**2

# 初期値
x0 = [1, 1]

# 最適化の実行
result = minimize(objective_function, x0)


練習問題1.

NumPynumpy.linalg.solve関数を使って以下の線形方程式系を解いてください。

3x + 2y - z = 1
2x - 2y + 4z = -2
-x + 1 2 y - z = 0


練習問題2.

SciPyscipy.integrate.quad関数を使って f ( x ) = x 2 の区間 [0, 1] における定積分を計算してください。


練習問題3.

方程式 x 2 - 612 = 0 の正の根をニュートン法を用いて求めてください。初期値として10を使用してください。