100本ノック / 数値計算 / 数値計算100本ノック
製造業の固有値問題入門|設備振動・PCA・工程ネットワークをPythonで分析
設備振動と工程ネットワークを「固有値」で読み解く:製造業の意思決定に効く数値計算10本ノック(No.041〜No.050)
本記事では、固有値問題、反復法、行列分解、グラフ解析を、架空の精密部品工場における設備保全・センサー監視・工程改善へ結び付けます。数式を計算すること自体ではなく、「どの変動を優先して調べるか」「大規模データで何を近似するか」「停止リスクが集中する工程はどこか」を判断できることが目的です。
[!NOTE] 本資料は、数理工房 (もしくは代表である和山個人) が過去に企業研修において使用した notebook を企業様の許可を得て再構成・編集のうえ公開しています。
掲載データはすべて架空のものであり、実在する企業・工場・数値とは一切関係ありません。
はじめに:この記事で扱う製造業の実務課題
対象工場では、複数設備の振動センサーが相関して変動し、工程間では仕掛品、再加工、検査情報が循環しています。個別の平均や上限値だけでは、設備群に共通する異常モードや、ネットワーク全体で重要な工程を見落とします。本記事では行列の「主要な方向」を抽出し、有限な保全工数をどこへ振り向けるべきかを考えます。
現場でよくある状況
- センサー点数が増え、アラーム件数だけが増えている
- 相関した振動を設備ごとの単独閾値で監視している
- 全固有値を厳密計算しているが、意思決定に使うのは上位数個だけである
- 工程表はあるものの、再加工ループや情報依存を含む全体影響を評価できていない
なぜこの問題は判断が難しいのか
行列の各要素は局所的な関係ですが、固有値・固有ベクトルは関係が繰り返し伝播した結果を表します。一方、行列が大きいほど、精度・計算時間・メモリの間にトレードオフが生じます。さらに、数学的に大きな成分が、そのまま因果関係や投資効果を意味するわけではありません。現場知識、データ品質、停止損失を合わせて解釈する必要があります。
今回扱うノックの全体像
| No. | テーマ | 製造業での判断 |
|---|---|---|
| 041 | 固有値問題とは | 支配的な設備変動を特定 |
| 042 | べき乗法 | 最大変動モードを高速推定 |
| 043 | 逆反復法 | 注目周波数付近のモードを抽出 |
| 044 | QR法 | 小中規模行列の固有値を一括計算 |
| 045 | ランチョス法 | 大規模対称問題を低次元化 |
| 046 | アーノルディ法 | 非対称な工程伝播を近似 |
| 047 | 特異値分解 | センサー情報を圧縮・再構成 |
| 048 | PCAとの関係 | 監視指標と寄与率を設計 |
| 049 | PageRankとの関係 | 工程影響度を再帰的に評価 |
| 050 | グラフ解析への応用 | 分断・ボトルネック候補を発見 |
Python 環境の準備
NumPy で密行列、SciPy で疎行列と反復法、pandas で表、matplotlib でグラフを扱います。乱数シードを固定して再現性を確保します。
%matplotlib inline
import platform
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from scipy import linalg, sparse
from scipy.sparse import linalg as spla
SEED = 42
rng = np.random.default_rng(SEED)
pd.set_option("display.precision", 4)
print("Python :", platform.python_version())
print("NumPy :", np.__version__)
print("pandas :", pd.__version__)
print("SciPy :", __import__("scipy").__version__)
print("matplotlib :", matplotlib.__version__)
Python : 3.13.1
NumPy : 2.5.1
pandas : 3.0.3
SciPy : 1.18.0
matplotlib : 3.11.0
架空データの作成
120時間分、6点の振動センサーを作ります。共通の「回転アンバランス」と「支持部の緩み」に相当する潜在変動を混ぜ、後半20時間には駆動側の振幅増加を加えます。また、8工程の有向ネットワークを、通常搬送と再加工の比率から作ります。値は説明用の架空データです。
n_time = 120
sensor_names = ["Drive-X", "Drive-Y", "Bearing-A", "Bearing-B", "Frame", "Outlet"]
t = np.arange(n_time)
mode_1 = np.sin(2 * np.pi * t / 18) + 0.18 * rng.normal(size=n_time)
mode_2 = 0.65 * np.sin(2 * np.pi * t / 7 + 0.8) + 0.18 * rng.normal(size=n_time)
loadings = np.array([
[1.00, 0.15], [0.88, 0.10], [0.58, 0.72],
[0.52, 0.78], [0.30, 0.45], [0.20, 0.28]
])
X = np.column_stack([mode_1, mode_2]) @ loadings.T + 0.16 * rng.normal(size=(n_time, 6))
X[-20:, :2] *= 1.35
sensor_df = pd.DataFrame(X, columns=sensor_names)
processes = ["Material", "Machining", "HeatTreat", "Grinding", "Wash", "Inspection", "Rework", "Shipping"]
edges = [
(0,1,1.00),(1,2,.82),(1,6,.18),(2,3,.92),(2,6,.08),(3,4,.88),
(3,6,.12),(4,5,1.00),(5,7,.86),(5,6,.14),(6,1,.55),(6,3,.45)
]
A = np.zeros((8, 8))
for i, j, w in edges: A[i, j] = w
display(sensor_df.head().round(3))
print(f"sensor data shape: {sensor_df.shape}, process matrix shape: {A.shape}")
| Drive-X | Drive-Y | Bearing-A | Bearing-B | Frame | Outlet | |
|---|---|---|---|---|---|---|
| 0 | -0.043 | 0.061 | -0.046 | 0.014 | 0.484 | -0.116 |
| 1 | 0.081 | 0.498 | 1.042 | 0.421 | 0.292 | 0.275 |
| 2 | 1.111 | 0.564 | 0.684 | 0.823 | 0.473 | 0.201 |
| 3 | 1.017 | 0.693 | 0.578 | 0.512 | 0.357 | 0.124 |
| 4 | 0.639 | 0.673 | 0.057 | 0.022 | -0.011 | -0.004 |
sensor data shape: (120, 6), process matrix shape: (8, 8)
No.041:固有値問題とは
実務での意味
共分散行列の固有ベクトルは、複数センサーが同時に動く代表パターンです。固有値はそのパターンに沿った変動の大きさを表します。設備群のどの組合せが支配的かを整理でき、点検の優先順位付けに使えます。
分析・モデル化の考え方
正方行列 に対し、ゼロでないベクトル とスカラー が
を満たすとき、 を固有値、 を固有ベクトルと呼びます。ここでは標準化後の相関行列を使うため、センサー単位の違いに左右されにくくなります。ただし固有ベクトルの符号は反転しても同じ解です。
Pythonで確認する
Z = (sensor_df - sensor_df.mean()) / sensor_df.std(ddof=1)
C = Z.corr().to_numpy()
eigvals, eigvecs = np.linalg.eigh(C)
order = np.argsort(eigvals)[::-1]
eigvals, eigvecs = eigvals[order], eigvecs[:, order]
eig_table = pd.DataFrame({"eigenvalue": eigvals, "variance_ratio": eigvals / eigvals.sum()})
display(eig_table.round(4))
plt.figure(figsize=(7, 3.5))
plt.bar(np.arange(1, 7), eigvals, color="#3568a8")
plt.title("Eigenvalues of sensor correlation matrix")
plt.xlabel("Component")
plt.ylabel("Eigenvalue")
plt.grid(True, axis="y", alpha=0.3)
plt.tight_layout()
plt.show()
| eigenvalue | variance_ratio | |
|---|---|---|
| 0 | 4.6865 | 0.7811 |
| 1 | 0.6686 | 0.1114 |
| 2 | 0.3543 | 0.0590 |
| 3 | 0.1664 | 0.0277 |
| 4 | 0.0638 | 0.0106 |
| 5 | 0.0604 | 0.0101 |

結果の読み取り
第1・第2固有値が残りより大きければ、6本のセンサー信号を少数の共通変動で説明できる可能性があります。個別アラームを増やす前に、上位固有ベクトルで負荷の大きいセンサー群を同時点検する判断が有効です。固有値だけで故障原因は確定できないため、回転数、負荷、整備履歴との照合が必要です。
No.042:べき乗法
実務での意味
最大固有値と対応ベクトルだけが欲しい場合、全固有値計算は過剰です。べき乗法は支配的な振動モードを、行列とベクトルの積の反復だけで推定します。
分析・モデル化の考え方
を反復すると、初期値が最大固有ベクトルと直交せず、最大固有値の絶対値が一意なら、その方向へ収束します。固有値はレイリー商 で見積もります。収束速度は に左右されます。
Pythonで確認する
x = np.ones(C.shape[0]) / np.sqrt(C.shape[0])
history = []
for k in range(30):
x_new = C @ x
x_new /= np.linalg.norm(x_new)
lam = float(x_new @ C @ x_new)
history.append(lam)
if np.linalg.norm(x_new - x) < 1e-10 or np.linalg.norm(x_new + x) < 1e-10:
x = x_new
break
x = x_new
display(pd.DataFrame({"sensor": sensor_names, "power_loading": x}).round(4))
print(f"iterations={len(history)}, estimate={lam:.6f}, exact={eigvals[0]:.6f}")
plt.figure(figsize=(7, 3.5))
plt.plot(range(1, len(history)+1), history, marker="o", ms=3)
plt.axhline(eigvals[0], color="crimson", linestyle="--", label="exact")
plt.title("Convergence of power iteration")
plt.xlabel("Iteration")
plt.ylabel("Estimated dominant eigenvalue")
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
plt.show()
| sensor | power_loading | |
|---|---|---|
| 0 | Drive-X | 0.4026 |
| 1 | Drive-Y | 0.3938 |
| 2 | Bearing-A | 0.4377 |
| 3 | Bearing-B | 0.4253 |
| 4 | Frame | 0.4090 |
| 5 | Outlet | 0.3782 |
iterations=11, estimate=4.686548, exact=4.686548

結果の読み取り
推定値が厳密計算値へ速やかに近づけば、日次監視で最大モードだけを更新する用途に適します。上位2固有値が近い設備では収束が遅くなるため、反復上限と残差 を監視し、必要ならランチョス法へ切り替えます。
No.043:逆反復法
実務での意味
共振試験では最大モードではなく、設計上注意する周波数に近いモードが重要です。逆反復法は指定値(シフト)付近の固有値を選択的に抽出します。
分析・モデル化の考え方
シフト に対して を解き、 とします。 では に最も近い固有値の成分が支配的になります。シフトが固有値そのものだと行列が特異になるため、数値的な条件を確認します。
Pythonで確認する
shift = 0.50
x_inv = np.ones(C.shape[0]) / np.sqrt(C.shape[0])
inv_history = []
for k in range(20):
y = np.linalg.solve(C - shift * np.eye(C.shape[0]), x_inv)
x_inv = y / np.linalg.norm(y)
lam_inv = float(x_inv @ C @ x_inv)
residual = np.linalg.norm(C @ x_inv - lam_inv * x_inv)
inv_history.append((k + 1, lam_inv, residual))
if residual < 1e-10: break
display(pd.DataFrame(inv_history, columns=["iteration", "eigenvalue", "residual"]).tail().round(8))
print("nearest exact eigenvalue:", eigvals[np.argmin(np.abs(eigvals - shift))].round(6))
| iteration | eigenvalue | residual | |
|---|---|---|---|
| 15 | 16 | 0.3547 | 0.0110 |
| 16 | 17 | 0.3546 | 0.0095 |
| 17 | 18 | 0.3545 | 0.0082 |
| 18 | 19 | 0.3545 | 0.0071 |
| 19 | 20 | 0.3544 | 0.0062 |
nearest exact eigenvalue: 0.354291
結果の読み取り
シフトに最も近い固有値へ収束するため、対象帯域を決めたモード探索に向きます。実務では「狙った帯域に固有値がある」だけでなく、対応ベクトルのセンサー位置と、回転数由来の加振周波数が重なるかを確認します。
No.044:QR法
実務での意味
小中規模のモデルで全固有値を把握したいとき、QR法は基本となる手法です。設備モデルの全モードを並べ、危険帯域との接近を確認できます。
分析・モデル化の考え方
とQR分解し、 と更新します。相似変換なので固有値は保存され、対称行列では反復により対角成分が固有値へ収束します。実用ライブラリはシフトやHessenberg化で高速化しています。
Pythonで確認する
A_qr = C.copy()
offdiag_history = []
for k in range(80):
Q, R = np.linalg.qr(A_qr)
A_qr = R @ Q
offdiag_history.append(np.linalg.norm(A_qr - np.diag(np.diag(A_qr))))
qr_vals = np.sort(np.diag(A_qr))[::-1]
display(pd.DataFrame({"QR_iteration": qr_vals, "numpy_eigh": eigvals, "abs_error": np.abs(qr_vals-eigvals)}).round(8))
plt.figure(figsize=(7, 3.5))
plt.semilogy(range(1, 81), offdiag_history)
plt.title("QR iteration: off-diagonal norm")
plt.xlabel("Iteration")
plt.ylabel("Off-diagonal Frobenius norm")
plt.grid(True, which="both", alpha=0.3)
plt.tight_layout()
plt.show()
| QR_iteration | numpy_eigh | abs_error | |
|---|---|---|---|
| 0 | 4.6865 | 4.6865 | 0.0000e+00 |
| 1 | 0.6686 | 0.6686 | 0.0000e+00 |
| 2 | 0.3543 | 0.3543 | 0.0000e+00 |
| 3 | 0.1664 | 0.1664 | 0.0000e+00 |
| 4 | 0.0638 | 0.0638 | 3.0000e-08 |
| 5 | 0.0604 | 0.0604 | 3.0000e-08 |

結果の読み取り
非対角成分のノルムが低下し、対角値が既製関数の固有値と一致することを確認できます。教材としての単純QR法は仕組みの確認用です。本番では自作反復ではなく、十分に検証された numpy.linalg.eigh などを使用します。
No.045:ランチョス法
実務での意味
有限要素モデルや多数センサーの共分散行列は大規模でも、必要なのは低次の数モードだけということがあります。ランチョス法は対称行列を小さな三重対角行列へ射影します。
分析・モデル化の考え方
Krylov部分空間 に基底を作り、 の固有値(Ritz値)で元の固有値を近似します。有限精度では直交性が失われるため、実装では再直交化が重要です。
Pythonで確認する
n = 240
main = 2.2 + 0.15 * rng.random(n)
off = -1.0 * np.ones(n-1)
K = sparse.diags([off, main, off], [-1, 0, 1], format="csr")
def lanczos(A, m, seed=42):
local_rng = np.random.default_rng(seed)
q = local_rng.normal(size=A.shape[0]); q /= np.linalg.norm(q)
Q, alphas, betas = [], [], []
q_prev = np.zeros_like(q); beta = 0.0
for j in range(m):
Q.append(q.copy())
z = A @ q - beta * q_prev
alpha = float(q @ z); z -= alpha * q
# 教材でも数値直交性を保つため、既存基底へ再直交化する
for qi in Q: z -= (qi @ z) * qi
alphas.append(alpha)
beta_new = np.linalg.norm(z)
if beta_new < 1e-12: break
if j < m-1: betas.append(beta_new)
q_prev, q, beta = q, z / beta_new, beta_new
return np.array(alphas), np.array(betas)
rows = []
exact_large = spla.eigsh(K, k=1, which="LA", return_eigenvectors=False)[0]
for m in [5, 10, 20, 30]:
alpha, beta = lanczos(K, m)
T = np.diag(alpha) + np.diag(beta, 1) + np.diag(beta, -1)
ritz = np.linalg.eigvalsh(T)[-1]
rows.append((m, ritz, abs(ritz-exact_large)))
display(pd.DataFrame(rows, columns=["Krylov_dim", "largest_Ritz", "abs_error"]).round(8))
| Krylov_dim | largest_Ritz | abs_error | |
|---|---|---|---|
| 0 | 5 | 4.1556 | 0.1362 |
| 1 | 10 | 4.2555 | 0.0363 |
| 2 | 20 | 4.2772 | 0.0145 |
| 3 | 30 | 4.2846 | 0.0071 |
結果の読み取り
240次元の行列でも、はるかに小さいKrylov部分空間から最大固有値を近似できます。設備モデルでは、必要モード数、残差、計算時間を受入基準にします。対称性が崩れるモデルには、そのまま適用せずアーノルディ法などを選びます。
No.046:アーノルディ法
実務での意味
工程間の流れは上流・下流があり、行列は一般に非対称です。アーノルディ法は、再加工や遅延が方向を持って伝播するモデルの主要固有値を近似できます。
分析・モデル化の考え方
アーノルディ法はKrylov部分空間の正規直交基底 を作り、 となる上Hessenberg行列 へ射影します。ランチョス法を非対称行列へ拡張した位置付けです。複素固有値が現れる場合は、絶対値と偏角の両方を解釈します。
Pythonで確認する
def arnoldi(A, m):
n = A.shape[0]
Q = np.zeros((n, m+1)); H = np.zeros((m+1, m))
Q[:, 0] = np.ones(n) / np.sqrt(n)
for k in range(m):
v = A @ Q[:, k]
for j in range(k+1):
H[j, k] = Q[:, j] @ v
v -= H[j, k] * Q[:, j]
H[k+1, k] = np.linalg.norm(v)
if H[k+1, k] < 1e-12: return H[:k+1, :k+1]
Q[:, k+1] = v / H[k+1, k]
return H[:m, :m]
H = arnoldi(A.T, 6)
ritz = np.linalg.eigvals(H)
exact = np.linalg.eigvals(A.T)
arnoldi_table = pd.DataFrame({
"method": ["Arnoldi Ritz", "Exact"],
"largest_abs_eigenvalue": [np.max(np.abs(ritz)), np.max(np.abs(exact))]
})
display(arnoldi_table.round(6))
plt.figure(figsize=(6, 4))
plt.scatter(exact.real, exact.imag, label="Exact", s=55)
plt.scatter(ritz.real, ritz.imag, marker="x", s=70, label="Arnoldi Ritz")
plt.title("Eigenvalues of directed process matrix")
plt.xlabel("Real part")
plt.ylabel("Imaginary part")
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
plt.show()
| method | largest_abs_eigenvalue | |
|---|---|---|
| 0 | Arnoldi Ritz | 0.8004 |
| 1 | Exact | 0.7457 |

結果の読み取り
小さなHessenberg行列のRitz値が、元行列の外側の固有値を捉える様子を確認できます。工程モデルで絶対値1に近い固有値があると、影響が循環して減衰しにくい可能性があります。ただし行列の正規化規則で意味が変わるため、重量が確率か数量かを明示します。
No.047:特異値分解
実務での意味
センサーデータは長方形行列です。特異値分解(SVD)は、時間方向とセンサー方向の代表パターンへ分け、保存容量の削減、ノイズ除去、代表波形の抽出に使えます。
分析・モデル化の考え方
と分解します。特異値 は非負で、 の固有値との間に があります。上位 成分による は、Frobeniusノルムの意味で最良の階数 近似です。
Pythonで確認する
U, s, Vt = np.linalg.svd(Z.to_numpy(), full_matrices=False)
svd_rows = []
for k in range(1, 7):
Zk = U[:, :k] @ np.diag(s[:k]) @ Vt[:k, :]
rel_error = np.linalg.norm(Z.to_numpy()-Zk, "fro") / np.linalg.norm(Z.to_numpy(), "fro")
svd_rows.append((k, 1-rel_error, rel_error))
display(pd.DataFrame(svd_rows, columns=["rank", "reconstruction_score", "relative_error"]).round(4))
plt.figure(figsize=(7, 3.5))
plt.plot(range(1, 7), s, marker="o")
plt.title("Singular values of standardized sensor data")
plt.xlabel("Component")
plt.ylabel("Singular value")
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
| rank | reconstruction_score | relative_error | |
|---|---|---|---|
| 0 | 1 | 0.5321 | 0.4679 |
| 1 | 2 | 0.6722 | 0.3278 |
| 2 | 3 | 0.7799 | 0.2201 |
| 3 | 4 | 0.8562 | 0.1438 |
| 4 | 5 | 0.8997 | 0.1003 |
| 5 | 6 | 1.0000 | 0.0000 |

結果の読み取り
上位少数の特異値が大きければ、少数成分で主要変動を保持できます。圧縮率だけでなく、故障直前の小さな兆候まで消していないかを検証してください。再構成誤差は異常スコアにもできますが、正常期間だけで基準を作る運用が必要です。
No.048:PCAとの関係
実務での意味
主成分分析(PCA)は、相関した多数の監視値を、互いに無相関な少数のKPIへまとめます。監視画面の指標削減や、設備状態の二次元表示に利用できます。
分析・モデル化の考え方
標準化データ の相関行列 を固有分解する方法と、 をSVDする方法は同じ主成分方向を与えます。寄与率は です。PCAは分散を説明する手法であり、品質不良を最もよく予測する方向とは限りません。
Pythonで確認する
scores = Z.to_numpy() @ eigvecs[:, :2]
loadings_df = pd.DataFrame(eigvecs[:, :2], index=sensor_names, columns=["PC1", "PC2"])
display(loadings_df.round(3))
print("Cumulative variance ratio (PC1+PC2):", round((eigvals[:2].sum()/eigvals.sum()), 4))
plt.figure(figsize=(7, 4))
plt.scatter(scores[:-20, 0], scores[:-20, 1], alpha=0.65, label="Earlier")
plt.scatter(scores[-20:, 0], scores[-20:, 1], color="crimson", label="Latest 20h")
plt.title("PCA score map for equipment monitoring")
plt.xlabel("PC1 score")
plt.ylabel("PC2 score")
plt.grid(True, alpha=0.3)
plt.legend()
plt.tight_layout()
plt.show()
| PC1 | PC2 | |
|---|---|---|
| Drive-X | -0.403 | 0.558 |
| Drive-Y | -0.394 | 0.600 |
| Bearing-A | -0.438 | -0.185 |
| Bearing-B | -0.425 | -0.302 |
| Frame | -0.409 | -0.336 |
| Outlet | -0.378 | -0.301 |
Cumulative variance ratio (PC1+PC2): 0.8925

結果の読み取り
負荷量表は各主成分をどのセンサーが構成するかを示します。最新20時間の点群が過去からずれる場合、単一センサー値ではなく設備状態全体が変化した可能性があります。管理限界は同じデータに後付けせず、正常期間と検証期間を分けて設定します。
No.049:PageRankとの関係
実務での意味
工程の重要度を単純な接続数だけで測ると、重要工程から影響を受ける工程を過小評価します。PageRankは「重要な工程から参照・流入される工程も重要」という再帰的評価を行います。
分析・モデル化の考え方
行確率行列 を用い、定常ベクトル を
で定義します。 はネットワーク伝播を続ける確率、 は一様な再出発分布です。これはGoogle行列の固有値1に対応する固有ベクトル問題です。ここでの順位は工程価値ではなく、定義したリンク上の構造的重要度です。
Pythonで確認する
P = A.copy()
row_sum = P.sum(axis=1)
for i in range(len(P)):
P[i] = P[i] / row_sum[i] if row_sum[i] > 0 else np.ones(len(P)) / len(P)
alpha = 0.85
G = alpha * P + (1-alpha) * np.ones_like(P) / len(P)
r = np.ones(len(P)) / len(P)
pr_history = []
for k in range(100):
r_new = G.T @ r
pr_history.append(np.linalg.norm(r_new-r, 1))
if pr_history[-1] < 1e-12: break
r = r_new
pagerank_df = pd.DataFrame({"process": processes, "PageRank": r_new}).sort_values("PageRank", ascending=False)
display(pagerank_df.round(4))
plt.figure(figsize=(8, 3.8))
plt.bar(pagerank_df["process"], pagerank_df["PageRank"], color="#4f8f5b")
plt.title("Process influence based on PageRank")
plt.xlabel("Process")
plt.ylabel("PageRank score")
plt.xticks(rotation=35, ha="right")
plt.grid(True, axis="y", alpha=0.3)
plt.tight_layout()
plt.show()
| process | PageRank | |
|---|---|---|
| 5 | Inspection | 0.1682 |
| 3 | Grinding | 0.1609 |
| 7 | Shipping | 0.1585 |
| 4 | Wash | 0.1560 |
| 2 | HeatTreat | 0.1130 |
| 1 | Machining | 0.1111 |
| 6 | Rework | 0.0967 |
| 0 | Material | 0.0356 |

結果の読み取り
再加工ループへ接続する工程が上位なら、停止時の直接損失だけでなく、循環を介した波及を重点評価する候補です。順位はリンク重量と減衰率に依存します。改善投資ではPageRankに、処理量、停止時間、代替可否、品質コストを掛け合わせます。
No.050:グラフ解析への応用
実務での意味
設備・工程をノード、関係をエッジとすることで、工場全体をグラフとして扱えます。スペクトル解析は、密に結び付く工程群、分断しやすい境界、監視単位の候補を見つけます。
分析・モデル化の考え方
方向をいったん無視した重み行列 から次数行列 とラプラシアン を作ります。正規化ラプラシアン
の第2最小固有値(代数的連結度)が小さいほど分断されやすく、対応するFiedlerベクトルの符号で2群への分割候補を得られます。
Pythonで確認する
W = (A + A.T) / 2
d = W.sum(axis=1)
D_inv_sqrt = np.diag(1 / np.sqrt(d))
Lsym = np.eye(len(W)) - D_inv_sqrt @ W @ D_inv_sqrt
lap_vals, lap_vecs = np.linalg.eigh(Lsym)
fiedler = lap_vecs[:, 1]
cluster = np.where(fiedler >= 0, "Group A", "Group B")
graph_df = pd.DataFrame({"process": processes, "Fiedler_value": fiedler, "candidate_group": cluster})
display(graph_df.sort_values("Fiedler_value").round(4))
print("normalized algebraic connectivity:", round(lap_vals[1], 6))
plt.figure(figsize=(8, 3.8))
colors = np.where(fiedler >= 0, "#3568a8", "#d1792f")
plt.bar(processes, fiedler, color=colors)
plt.axhline(0, color="black", linewidth=0.8)
plt.title("Spectral partition candidate by Fiedler vector")
plt.xlabel("Process")
plt.ylabel("Fiedler vector value")
plt.xticks(rotation=35, ha="right")
plt.grid(True, axis="y", alpha=0.3)
plt.tight_layout()
plt.show()
| process | Fiedler_value | candidate_group | |
|---|---|---|---|
| 5 | Inspection | -0.5414 | Group B |
| 7 | Shipping | -0.4346 | Group B |
| 4 | Wash | -0.3317 | Group B |
| 3 | Grinding | 0.0197 | Group A |
| 6 | Rework | 0.1728 | Group A |
| 2 | HeatTreat | 0.2314 | Group A |
| 0 | Material | 0.3464 | Group A |
| 1 | Machining | 0.4519 | Group A |
normalized algebraic connectivity: 0.183177

結果の読み取り
符号で分かれる2群は、保全担当範囲、データ収集単位、工程間バッファの検討候補です。ゼロ付近の工程や群をつなぐエッジは境界候補ですが、スペクトル分割は物理レイアウトや安全規則を知りません。現場導線と照合して採否を決めます。
対象ノックを通して見える実務上の示唆
- 全部を計算する必要はない:最大モードだけならべき乗法、対称大規模ならランチョス法、非対称ならアーノルディ法と、意思決定に必要な固有対へ計算を絞れます。
- 同じ分解が複数業務につながる:固有分解とSVDは、振動モード、PCA、圧縮、異常監視の共通基盤です。
- ネットワークの定義が結論を決める:PageRankやラプラシアンの順位・分割は、何をエッジとし、どの重量を与えるかで変わります。
- 数値結果は原因ではなく候補:大きな固有値や中心性は調査の優先順位を示しますが、故障や品質不良の因果を単独で証明しません。
実務導入する場合に必要なこと
- センサー校正、欠測、時刻同期、設備停止区間を含むデータ品質基準
- 正常期間、異常期間、負荷条件を分けた検証データ
- 行列の定義、標準化、シフト、収束許容値、乱数シードの記録
- 残差、再構成誤差、計算時間、誤報率を含む受入基準
- 工程責任者・保全・品質保証が結果を確認するレビュー手順
- アラームから点検、原因確認、モデル更新までの業務フロー
まとめ
No.041〜No.050では、固有値問題の基本から、べき乗法・逆反復法・QR法、Krylov部分空間法、SVD・PCA、PageRank・グラフラプラシアンまでを、製造業の一貫した架空例で確認しました。重要なのは高度な手法名ではなく、必要な情報だけを安定して計算し、現場の点検・投資・監視設計へ翻訳することです。
法人向けのご相談
数理工房では、設備データ解析、異常検知、工程ネットワーク分析、数値計算の高速化、現場担当者向け研修まで、課題定義から実装・運用設計を支援します。手元データで何が判断できるか、検証設計からご一緒できます。
📩 お問い合わせ: surikobo.co.jp/contact
まずはお気軽にご相談ください。