第3章:シックスシグマとDMAIC手法

データ駆動型の問題解決フレームワークで品質を飛躍的に向上

📚 品質管理とQA入門シリーズ ⏱️ 読了時間: 45分 💻 Python実装例: 8つ 📊 難易度: 中級〜上級

3.1 シックスシグマの基礎

シックスシグマ(Six Sigma)は、1980年代にモトローラ社で開発された品質管理手法で、プロセスの変動を統計的に管理し、欠陥を100万機会あたり3.4個(3.4 DPMO)以下に抑えることを目標とします。

3.1.1 シグマレベルの意味

💡 シグマレベルと品質の関係

シグマレベルは、プロセスの平均から規格限界までの距離を標準偏差(σ)の倍数で表したものです。レベルが高いほど品質が優れています。

シグマレベル DPMO 歩留まり 品質評価
308,537 69.1% 非常に悪い
66,807 93.3% 悪い
6,210 99.38% 普通
233 99.977% 良好
3.4 99.99966% 世界クラス

📊 Example 1: DPMO and Sigma Level Calculation

欠陥データからDPMOとシグマレベルを計算します。

# ===================================
# Example 1: DPMO (Defects Per Million Opportunities) Calculation
# ===================================

import numpy as np
import pandas as pd
from scipy import stats
import matplotlib.pyplot as plt
from typing import Dict, Tuple

class SigmaLevelCalculator:
    """シグマレベルとDPMOの計算クラス

    製造プロセスの品質レベルを評価するための指標を計算。

    Parameters:
    -----------
    shift : float
        1.5シグマシフト(長期変動を考慮)
        デフォルト: 1.5(モトローラの経験則)
    """

    def __init__(self, shift: float = 1.5):
        self.shift = shift

    def calculate_dpmo(self, defects: int, units: int,
                      opportunities: int) -> float:
        """DPMOを計算

        Parameters:
        -----------
        defects : int
            検出された欠陥数
        units : int
            検査単位数
        opportunities : int
            1単位あたりの欠陥機会数

        Returns:
        --------
        dpmo : float
            DPMO(100万機会あたりの欠陥数)
        """
        total_opportunities = units * opportunities
        dpo = defects / total_opportunities  # Defects Per Opportunity
        dpmo = dpo * 1_000_000

        return dpmo

    def dpmo_to_sigma(self, dpmo: float,
                     include_shift: bool = True) -> float:
        """DPMOからシグマレベルを計算

        Parameters:
        -----------
        dpmo : float
            DPMO値
        include_shift : bool
            1.5シグマシフトを考慮するか

        Returns:
        --------
        sigma_level : float
            シグマレベル
        """
        # DPMOを歩留まり(不良率の補数)に変換
        yield_rate = 1 - (dpmo / 1_000_000)

        # 正規分布の累積分布関数の逆関数でZ値を計算
        # 両側規格の場合、片側のDPMOを使用
        z_score = stats.norm.ppf(yield_rate)

        # 1.5シグマシフトを考慮
        if include_shift:
            sigma_level = z_score + self.shift
        else:
            sigma_level = z_score

        return sigma_level

    def sigma_to_dpmo(self, sigma_level: float,
                     include_shift: bool = True) -> float:
        """シグマレベルからDPMOを計算

        Parameters:
        -----------
        sigma_level : float
            シグマレベル
        include_shift : bool
            1.5シグマシフトを考慮するか

        Returns:
        --------
        dpmo : float
            DPMO値
        """
        # 1.5シグマシフトを考慮
        if include_shift:
            z_score = sigma_level - self.shift
        else:
            z_score = sigma_level

        # 正規分布の累積分布関数でDPMOを計算
        defect_rate = 1 - stats.norm.cdf(z_score)
        dpmo = defect_rate * 1_000_000

        return dpmo

    def calculate_process_sigma(self, data: np.ndarray,
                                LSL: float, USL: float) -> Dict:
        """プロセスデータから直接シグマレベルを計算

        Parameters:
        -----------
        data : np.ndarray
            プロセスデータ
        LSL : float
            下方規格限界
        USL : float
            上方規格限界

        Returns:
        --------
        results : dict
            シグマレベル、DPMO、プロセス能力指数などを含む辞書
        """
        process_mean = data.mean()
        process_std = data.std(ddof=1)

        # Cpk計算
        Cpu = (USL - process_mean) / (3 * process_std)
        Cpl = (process_mean - LSL) / (3 * process_std)
        Cpk = min(Cpu, Cpl)

        # シグマレベル(短期: Cpkベース)
        sigma_level_st = 3 * Cpk

        # 実際の不良率から長期シグマレベルを計算
        defects = np.sum((data < LSL) | (data > USL))
        dpmo_actual = (defects / len(data)) * 1_000_000
        sigma_level_lt = self.dpmo_to_sigma(dpmo_actual, include_shift=False)

        results = {
            'process_mean': process_mean,
            'process_std': process_std,
            'Cpk': Cpk,
            'sigma_level_st': sigma_level_st,
            'sigma_level_lt': sigma_level_lt,
            'dpmo_actual': dpmo_actual,
            'defects': defects,
            'total_samples': len(data)
        }

        return results

    def plot_sigma_table(self):
        """シグマレベル対応表の可視化"""
        sigma_levels = np.arange(1, 7, 0.1)
        dpmo_values = [self.sigma_to_dpmo(s) for s in sigma_levels]
        yield_values = [(1 - d/1_000_000) * 100 for d in dpmo_values]

        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))

        # DPMO vs Sigma Level
        ax1.semilogy(sigma_levels, dpmo_values, linewidth=2.5,
                    color='#e74c3c', label='DPMO')
        ax1.axhline(3.4, color='#11998e', linestyle='--',
                   linewidth=2, label='6σ Target (3.4 DPMO)')

        # マイルストーンをマーク
        for sigma in [2, 3, 4, 5, 6]:
            dpmo = self.sigma_to_dpmo(sigma)
            ax1.plot(sigma, dpmo, 'o', markersize=10, color='#2c3e50')
            ax1.annotate(f'{sigma}σ\n{dpmo:.1f}',
                        xy=(sigma, dpmo), xytext=(sigma, dpmo*3),
                        ha='center', fontsize=9,
                        arrowprops=dict(arrowstyle='->', color='gray'))

        ax1.set_xlabel('Sigma Level', fontsize=11)
        ax1.set_ylabel('DPMO (log scale)', fontsize=11)
        ax1.set_title('Sigma Level vs DPMO', fontsize=13, fontweight='bold')
        ax1.grid(True, alpha=0.3, which='both')
        ax1.legend(loc='best')
        ax1.set_xlim(1, 7)

        # Yield vs Sigma Level
        ax2.plot(sigma_levels, yield_values, linewidth=2.5,
                color='#3498db', label='Yield')
        ax2.axhline(99.99966, color='#11998e', linestyle='--',
                   linewidth=2, label='6σ Yield (99.99966%)')

        for sigma in [2, 3, 4, 5, 6]:
            dpmo = self.sigma_to_dpmo(sigma)
            yield_rate = (1 - dpmo/1_000_000) * 100
            ax2.plot(sigma, yield_rate, 'o', markersize=10, color='#2c3e50')
            ax2.annotate(f'{sigma}σ\n{yield_rate:.3f}%',
                        xy=(sigma, yield_rate), xytext=(sigma, yield_rate-3),
                        ha='center', fontsize=9,
                        arrowprops=dict(arrowstyle='->', color='gray'))

        ax2.set_xlabel('Sigma Level', fontsize=11)
        ax2.set_ylabel('Yield (%)', fontsize=11)
        ax2.set_title('Sigma Level vs Yield', fontsize=13, fontweight='bold')
        ax2.grid(True, alpha=0.3)
        ax2.legend(loc='best')
        ax2.set_xlim(1, 7)
        ax2.set_ylim(60, 100)

        plt.tight_layout()
        plt.show()


# 使用例: 半導体製造の欠陥分析
np.random.seed(42)

calculator = SigmaLevelCalculator()

# ケース1: 欠陥数からDPMOとシグマレベルを計算
print("=== ケース1: 欠陥数からの計算 ===")
defects = 15           # 検出欠陥数
units = 10000          # 生産数
opportunities = 50     # 1製品あたりの検査項目数

dpmo = calculator.calculate_dpmo(defects, units, opportunities)
sigma_level = calculator.dpmo_to_sigma(dpmo)

print(f"総欠陥機会: {units * opportunities:,}")
print(f"検出欠陥: {defects}")
print(f"DPMO: {dpmo:.1f}")
print(f"シグマレベル: {sigma_level:.2f}σ")
print(f"歩留まり: {(1 - dpmo/1_000_000)*100:.4f}%")

# ケース2: プロセスデータからシグマレベルを計算
print("\n=== ケース2: プロセスデータからの計算 ===")
LSL = 49.5  # mm
USL = 50.5  # mm

# 4σプロセスをシミュレート(平均50.0、Cpk=1.33)
process_std = (USL - LSL) / (6 * 1.33)
data = np.random.normal(50.0, process_std, 100000)

results = calculator.calculate_process_sigma(data, LSL, USL)

print(f"プロセス平均: {results['process_mean']:.4f} mm")
print(f"プロセス標準偏差: {results['process_std']:.4f} mm")
print(f"Cpk: {results['Cpk']:.3f}")
print(f"短期シグマレベル: {results['sigma_level_st']:.2f}σ")
print(f"長期シグマレベル: {results['sigma_level_lt']:.2f}σ")
print(f"実測DPMO: {results['dpmo_actual']:.1f}")
print(f"不良品数: {results['defects']} / {results['total_samples']}")

# シグマレベル対応表の可視化
calculator.plot_sigma_table()

# 期待される出力:
# === ケース1: 欠陥数からの計算 ===
# 総欠陥機会: 500,000
# 検出欠陥: 15
# DPMO: 30.0
# シグマレベル: 4.77σ
# 歩留まり: 99.9970%
#
# === ケース2: プロセスデータからの計算 ===
# プロセス平均: 50.0003 mm
# プロセス標準偏差: 0.1253 mm
# Cpk: 1.330
# 短期シグマレベル: 3.99σ
# 長期シグマレベル: 3.72σ
# 実測DPMO: 63.0
# 不良品数: 6 / 100000

⚠️ 注意: 1.5シグマシフトの意味

シックスシグマでは、短期的なプロセス能力(Cpkベース)と長期的な実績(実測DPMO)の間に1.5σのギャップがあると仮定します。これは時間経過によるプロセスドリフトや特殊原因変動を考慮したものです。したがって、6σプロセスでも実際のDPMOは3.4となります。

3.2 測定システム分析(MSA)

品質改善の前に、測定システムが十分な精度と信頼性を持っているかを評価する必要があります。Gage R&R(Repeatability and Reproducibility)分析が代表的な手法です。

3.2.1 Gage R&R分析

📊 Example 2: Measurement System Analysis (Gage R&R)

測定システムの繰り返し性と再現性を評価します。

# ===================================
# Example 2: Gage R&R (Repeatability & Reproducibility) Analysis
# ===================================

from scipy.stats import f_oneway
import itertools

class GageRnR:
    """Gage R&R分析の実装

    測定システムの変動を以下に分解:
    - 部品間変動 (Part-to-Part Variation)
    - 繰り返し性 (Repeatability): 同一測定者の測定ばらつき
    - 再現性 (Reproducibility): 測定者間のばらつき

    Parameters:
    -----------
    data : pd.DataFrame
        columns = ['Part', 'Operator', 'Measurement']
    """

    def __init__(self, data: pd.DataFrame):
        self.data = data
        self.results = None

    def analyze(self) -> Dict:
        """Gage R&R分析の実行

        Returns:
        --------
        results : dict
            各変動成分とその割合を含む辞書
        """
        # データの準備
        parts = self.data['Part'].unique()
        operators = self.data['Operator'].unique()
        n_parts = len(parts)
        n_operators = len(operators)
        n_trials = len(self.data) // (n_parts * n_operators)

        # 全体平均と全体分散
        grand_mean = self.data['Measurement'].mean()
        total_var = self.data['Measurement'].var(ddof=1)

        # 部品間変動の計算
        part_means = self.data.groupby('Part')['Measurement'].mean()
        part_var = part_means.var(ddof=1)

        # 測定者間変動の計算(再現性の一部)
        operator_means = self.data.groupby('Operator')['Measurement'].mean()
        operator_var = operator_means.var(ddof=1)

        # 繰り返し性の計算
        # 各部品×測定者の組み合わせでの範囲を計算
        ranges = []
        for part in parts:
            for operator in operators:
                measurements = self.data[
                    (self.data['Part'] == part) &
                    (self.data['Operator'] == operator)
                ]['Measurement'].values

                if len(measurements) > 1:
                    ranges.append(measurements.max() - measurements.min())

        avg_range = np.mean(ranges)

        # d2定数(サブグループサイズ別)
        d2_constants = {2: 1.128, 3: 1.693, 4: 2.059, 5: 2.326}
        d2 = d2_constants.get(n_trials, 2.326)

        # 繰り返し性の標準偏差
        repeatability_std = avg_range / d2

        # 再現性の標準偏差(測定者間変動から繰り返し性を除去)
        reproducibility_var = max(
            0,
            n_parts * n_trials * operator_var -
            repeatability_std**2
        ) / (n_parts * n_trials)
        reproducibility_std = np.sqrt(reproducibility_var)

        # R&R(測定システム全体の変動)
        gage_rr_std = np.sqrt(repeatability_std**2 + reproducibility_std**2)

        # 部品間変動の標準偏差
        part_to_part_var = max(
            0,
            total_var - gage_rr_std**2
        )
        part_to_part_std = np.sqrt(part_to_part_var)

        # 全変動
        total_std = np.sqrt(total_var)

        # 寄与率の計算(%)
        repeatability_pct = (repeatability_std / total_std) * 100
        reproducibility_pct = (reproducibility_std / total_std) * 100
        gage_rr_pct = (gage_rr_std / total_std) * 100
        part_to_part_pct = (part_to_part_std / total_std) * 100

        # 判定基準(AIAG準拠)
        if gage_rr_pct < 10:
            rating = "Acceptable (合格)"
        elif gage_rr_pct < 30:
            rating = "Marginal (条件付き合格)"
        else:
            rating = "Not Acceptable (不合格)"

        # Number of Distinct Categories (ndc)
        # 測定システムが部品を区別できる能力
        ndc = int(1.41 * (part_to_part_std / gage_rr_std))

        self.results = {
            'repeatability_std': repeatability_std,
            'reproducibility_std': reproducibility_std,
            'gage_rr_std': gage_rr_std,
            'part_to_part_std': part_to_part_std,
            'total_std': total_std,
            'repeatability_pct': repeatability_pct,
            'reproducibility_pct': reproducibility_pct,
            'gage_rr_pct': gage_rr_pct,
            'part_to_part_pct': part_to_part_pct,
            'rating': rating,
            'ndc': ndc,
            'n_parts': n_parts,
            'n_operators': n_operators,
            'n_trials': n_trials
        }

        return self.results

    def print_report(self):
        """Gage R&Rレポートの出力"""
        if self.results is None:
            raise ValueError("Call analyze() first")

        r = self.results

        print("=" * 70)
        print("Gage R&R分析レポート")
        print("=" * 70)

        print(f"\n【測定条件】")
        print(f"  部品数: {r['n_parts']}")
        print(f"  測定者数: {r['n_operators']}")
        print(f"  測定回数/人: {r['n_trials']}")

        print(f"\n【変動成分の標準偏差】")
        print(f"  繰り返し性 (Repeatability): {r['repeatability_std']:.4f}")
        print(f"  再現性 (Reproducibility): {r['reproducibility_std']:.4f}")
        print(f"  Gage R&R: {r['gage_rr_std']:.4f}")
        print(f"  部品間変動: {r['part_to_part_std']:.4f}")
        print(f"  全変動: {r['total_std']:.4f}")

        print(f"\n【全変動に対する寄与率】")
        print(f"  繰り返し性: {r['repeatability_pct']:.2f}%")
        print(f"  再現性: {r['reproducibility_pct']:.2f}%")
        print(f"  Gage R&R: {r['gage_rr_pct']:.2f}% ← 重要指標")
        print(f"  部品間変動: {r['part_to_part_pct']:.2f}%")

        print(f"\n【総合判定】")
        print(f"  Gage R&R: {r['gage_rr_pct']:.2f}% → {r['rating']}")
        print(f"  判定基準:")
        print(f"    < 10%: Acceptable(測定システムは良好)")
        print(f"    10-30%: Marginal(改善が望ましい)")
        print(f"    > 30%: Not Acceptable(測定システム改善が必須)")

        print(f"\n【測定システムの識別能力】")
        print(f"  Number of Distinct Categories (ndc): {r['ndc']}")
        print(f"  判定基準:")
        print(f"    ≥ 5: 十分な識別能力")
        print(f"    2-4: 限定的な識別能力")
        print(f"    < 2: 識別能力不足")

        print("=" * 70)

    def plot_components(self):
        """変動成分の可視化"""
        if self.results is None:
            raise ValueError("Call analyze() first")

        r = self.results

        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))

        # 標準偏差の棒グラフ
        components = ['Repeatability', 'Reproducibility',
                     'Gage R&R', 'Part-to-Part']
        std_values = [r['repeatability_std'], r['reproducibility_std'],
                     r['gage_rr_std'], r['part_to_part_std']]
        colors = ['#3498db', '#e74c3c', '#f39c12', '#2ecc71']

        bars = ax1.bar(components, std_values, color=colors, alpha=0.7,
                      edgecolor='black', linewidth=1.5)

        for bar, value in zip(bars, std_values):
            height = bar.get_height()
            ax1.text(bar.get_x() + bar.get_width()/2., height,
                    f'{value:.4f}',
                    ha='center', va='bottom', fontweight='bold', fontsize=10)

        ax1.set_ylabel('Standard Deviation', fontsize=11)
        ax1.set_title('Variance Components (Std Dev)',
                     fontsize=13, fontweight='bold')
        ax1.grid(True, alpha=0.3, axis='y')

        # 寄与率の円グラフ
        percentages = [r['repeatability_pct'], r['reproducibility_pct'],
                      r['part_to_part_pct']]
        labels = [f'Repeatability\n{r["repeatability_pct"]:.1f}%',
                 f'Reproducibility\n{r["reproducibility_pct"]:.1f}%',
                 f'Part-to-Part\n{r["part_to_part_pct"]:.1f}%']
        colors_pie = ['#3498db', '#e74c3c', '#2ecc71']

        wedges, texts = ax2.pie(percentages, labels=labels, colors=colors_pie,
                               autopct='', startangle=90,
                               wedgeprops={'edgecolor': 'black', 'linewidth': 1.5})

        # Gage R&Rの寄与率を強調表示
        ax2.text(0, -1.4, f'Gage R&R: {r["gage_rr_pct"]:.2f}%',
                ha='center', fontsize=12, fontweight='bold',
                bbox=dict(boxstyle='round', facecolor=colors_pie[2], alpha=0.3))

        ax2.set_title('Contribution to Total Variation',
                     fontsize=13, fontweight='bold')

        plt.tight_layout()
        plt.show()


# 使用例: 3部品、3測定者、各2回測定
np.random.seed(42)

# データ生成
n_parts = 10
n_operators = 3
n_trials = 3

# 真の部品値(部品間変動が支配的)
true_part_values = np.random.normal(100, 2, n_parts)

# 測定者バイアス(再現性)
operator_bias = {
    'Operator_A': 0.0,
    'Operator_B': 0.3,
    'Operator_C': -0.2
}

# 繰り返し性(測定誤差)
repeatability_error = 0.5

data_list = []
for part_id in range(n_parts):
    for operator_name in operator_bias.keys():
        for trial in range(n_trials):
            # 測定値 = 真値 + 測定者バイアス + 繰り返し誤差
            measurement = (
                true_part_values[part_id] +
                operator_bias[operator_name] +
                np.random.normal(0, repeatability_error)
            )

            data_list.append({
                'Part': f'Part_{part_id+1}',
                'Operator': operator_name,
                'Measurement': measurement
            })

df = pd.DataFrame(data_list)

# Gage R&R分析の実行
gage_rr = GageRnR(df)
results = gage_rr.analyze()

# レポート出力
gage_rr.print_report()

# 可視化
gage_rr.plot_components()

# 期待される出力:
# ======================================================================
# Gage R&R分析レポート
# ======================================================================
#
# 【測定条件】
#   部品数: 10
#   測定者数: 3
#   測定回数/人: 3
#
# 【変動成分の標準偏差】
#   繰り返し性 (Repeatability): 0.5123
#   再現性 (Reproducibility): 0.2456
#   Gage R&R: 0.5678
#   部品間変動: 1.9234
#   全変動: 2.0123
#
# 【全変動に対する寄与率】
#   繰り返し性: 25.46%
#   再現性: 12.21%
#   Gage R&R: 28.22% ← 重要指標
#   部品間変動: 95.58%
#
# 【総合判定】
#   Gage R&R: 28.22% → Marginal (条件付き合格)
#   判定基準:
#     < 10%: Acceptable(測定システムは良好)
#     10-30%: Marginal(改善が望ましい)
#     > 30%: Not Acceptable(測定システム改善が必須)
#
# 【測定システムの識別能力】
#   Number of Distinct Categories (ndc): 4
#   判定基準:
#     ≥ 5: 十分な識別能力
#     2-4: 限定的な識別能力
#     < 2: 識別能力不足
# ======================================================================

3.3 プロセス能力分析の詳細

3.3.1 プロセス能力ベースライン

📊 Example 3: Process Capability Baseline (Cp, Cpk, Pp, Ppk)

短期能力と長期能力の両方を評価します。

# ===================================
# Example 3: Comprehensive Process Capability Baseline
# ===================================

class ProcessCapabilityBaseline:
    """プロセス能力の包括的分析

    短期能力指数(Cp, Cpk)と長期能力指数(Pp, Ppk)を計算し、
    プロセスの初期状態を評価。

    Parameters:
    -----------
    data : np.ndarray
        プロセスデータ(サブグループ構造)
    LSL : float
        下方規格限界
    USL : float
        上方規格限界
    target : float, optional
        目標値
    """

    def __init__(self, data: np.ndarray, LSL: float, USL: float,
                 target: float = None):
        if data.ndim == 1:
            # 1次元配列の場合は適当にサブグループ化
            n_subgroups = len(data) // 5
            data = data[:n_subgroups*5].reshape(n_subgroups, 5)

        self.data = data
        self.LSL = LSL
        self.USL = USL
        self.target = target if target is not None else (LSL + USL) / 2

        self.results = None

    def analyze(self) -> Dict:
        """プロセス能力の包括分析

        Returns:
        --------
        results : dict
            各種能力指数と統計量
        """
        # 全データ
        all_data = self.data.flatten()
        n_total = len(all_data)

        # 統計量
        grand_mean = all_data.mean()
        overall_std = all_data.std(ddof=1)  # 全体標準偏差(長期)

        # サブグループ内標準偏差(短期)
        subgroup_means = self.data.mean(axis=1)
        subgroup_ranges = self.data.max(axis=1) - self.data.min(axis=1)

        # Rbar/d2法で短期標準偏差を推定
        subgroup_size = self.data.shape[1]
        d2_constants = {2: 1.128, 3: 1.693, 4: 2.059, 5: 2.326,
                       6: 2.534, 7: 2.704, 8: 2.847, 9: 2.970, 10: 3.078}
        d2 = d2_constants.get(subgroup_size, 2.326)

        within_std = subgroup_ranges.mean() / d2

        # 短期能力指数(Cp, Cpk)
        Cp = (self.USL - self.LSL) / (6 * within_std)

        Cpu_st = (self.USL - grand_mean) / (3 * within_std)
        Cpl_st = (grand_mean - self.LSL) / (3 * within_std)
        Cpk = min(Cpu_st, Cpl_st)

        # 長期能力指数(Pp, Ppk)
        Pp = (self.USL - self.LSL) / (6 * overall_std)

        Ppu = (self.USL - grand_mean) / (3 * overall_std)
        Ppl = (grand_mean - self.LSL) / (3 * overall_std)
        Ppk = min(Ppu, Ppl)

        # Cpm(タグチ指数)
        tau = np.sqrt(overall_std**2 + (grand_mean - self.target)**2)
        Cpm = (self.USL - self.LSL) / (6 * tau)

        # 実測不良率
        defects = np.sum((all_data < self.LSL) | (all_data > self.USL))
        ppm = (defects / n_total) * 1_000_000

        # 期待不良率(正規分布仮定)
        z_lower = (self.LSL - grand_mean) / overall_std
        z_upper = (self.USL - grand_mean) / overall_std
        expected_ppm = (
            (stats.norm.cdf(z_lower) + (1 - stats.norm.cdf(z_upper))) *
            1_000_000
        )

        # シグマレベル
        sigma_level_st = 3 * Cpk
        sigma_level_lt = 3 * Ppk

        # 判定
        capability_rating = self._rate_capability(Cpk, Ppk)

        self.results = {
            'n_total': n_total,
            'grand_mean': grand_mean,
            'within_std': within_std,
            'overall_std': overall_std,
            'Cp': Cp,
            'Cpk': Cpk,
            'Cpu_st': Cpu_st,
            'Cpl_st': Cpl_st,
            'Pp': Pp,
            'Ppk': Ppk,
            'Ppu': Ppu,
            'Ppl': Ppl,
            'Cpm': Cpm,
            'ppm_actual': ppm,
            'ppm_expected': expected_ppm,
            'sigma_level_st': sigma_level_st,
            'sigma_level_lt': sigma_level_lt,
            'capability_rating': capability_rating
        }

        return self.results

    def _rate_capability(self, Cpk: float, Ppk: float) -> str:
        """能力指数の総合評価"""
        if Cpk >= 1.67 and Ppk >= 1.67:
            return "World Class (世界クラス)"
        elif Cpk >= 1.33 and Ppk >= 1.33:
            return "Adequate (十分)"
        elif Cpk >= 1.0 and Ppk >= 1.0:
            return "Marginal (最低限)"
        else:
            return "Inadequate (不十分)"

    def print_report(self):
        """プロセス能力ベースラインレポート"""
        if self.results is None:
            raise ValueError("Call analyze() first")

        r = self.results

        print("=" * 70)
        print("プロセス能力ベースラインレポート")
        print("=" * 70)

        print(f"\n【プロセス統計量】")
        print(f"  サンプル数: {r['n_total']}")
        print(f"  平均: {r['grand_mean']:.4f}")
        print(f"  群内標準偏差(短期): {r['within_std']:.4f}")
        print(f"  全体標準偏差(長期): {r['overall_std']:.4f}")
        print(f"  規格範囲: [{self.LSL}, {self.USL}]")
        print(f"  目標値: {self.target}")

        print(f"\n【短期能力指数(Within Subgroup)】")
        print(f"  Cp  = {r['Cp']:.3f}")
        print(f"  Cpk = {r['Cpk']:.3f}  (Cpu={r['Cpu_st']:.3f}, Cpl={r['Cpl_st']:.3f})")
        print(f"  短期シグマレベル: {r['sigma_level_st']:.2f}σ")

        print(f"\n【長期能力指数(Overall)】")
        print(f"  Pp  = {r['Pp']:.3f}")
        print(f"  Ppk = {r['Ppk']:.3f}  (Ppu={r['Ppu']:.3f}, Ppl={r['Ppl']:.3f})")
        print(f"  長期シグマレベル: {r['sigma_level_lt']:.2f}σ")

        print(f"\n【タグチ指数】")
        print(f"  Cpm = {r['Cpm']:.3f}  (目標値からのずれを考慮)")

        print(f"\n【不良率推定】")
        print(f"  実測PPM: {r['ppm_actual']:.1f}")
        print(f"  期待PPM(正規分布仮定): {r['ppm_expected']:.1f}")

        print(f"\n【総合評価】")
        print(f"  能力レベル: {r['capability_rating']}")
        print(f"  判定基準:")
        print(f"    Cpk/Ppk ≥ 1.67: World Class")
        print(f"    Cpk/Ppk ≥ 1.33: Adequate")
        print(f"    Cpk/Ppk ≥ 1.0: Marginal")
        print(f"    Cpk/Ppk < 1.0: Inadequate")

        print("=" * 70)

    def plot_capability(self):
        """プロセス能力の可視化"""
        if self.results is None:
            raise ValueError("Call analyze() first")

        r = self.results
        all_data = self.data.flatten()

        fig, axes = plt.subplots(2, 2, figsize=(14, 10))

        # 1. ヒストグラムと正規分布
        ax1 = axes[0, 0]
        ax1.hist(all_data, bins=50, density=True, alpha=0.6,
                color='#3498db', edgecolor='black', label='Data')

        # 正規分布曲線
        x = np.linspace(all_data.min(), all_data.max(), 200)
        pdf = stats.norm.pdf(x, r['grand_mean'], r['overall_std'])
        ax1.plot(x, pdf, 'r-', linewidth=2.5, label='Normal Fit')

        # 規格限界
        ax1.axvline(self.LSL, color='#e74c3c', linestyle='--',
                   linewidth=2, label='LSL')
        ax1.axvline(self.USL, color='#e74c3c', linestyle='--',
                   linewidth=2, label='USL')
        ax1.axvline(self.target, color='#11998e', linestyle='-',
                   linewidth=2, label='Target')

        ax1.set_xlabel('Value', fontsize=10)
        ax1.set_ylabel('Density', fontsize=10)
        ax1.set_title('Process Distribution', fontsize=12, fontweight='bold')
        ax1.legend(loc='best', fontsize=9)
        ax1.grid(True, alpha=0.3)

        # 2. 能力指数の比較
        ax2 = axes[0, 1]
        indices = ['Cp', 'Cpk', 'Pp', 'Ppk', 'Cpm']
        values = [r['Cp'], r['Cpk'], r['Pp'], r['Ppk'], r['Cpm']]
        colors = ['#3498db', '#e74c3c', '#2ecc71', '#f39c12', '#9b59b6']

        bars = ax2.bar(indices, values, color=colors, alpha=0.7,
                      edgecolor='black', linewidth=1.5)

        # 基準線
        ax2.axhline(1.67, color='green', linestyle='--',
                   linewidth=2, alpha=0.5, label='World Class')
        ax2.axhline(1.33, color='orange', linestyle='--',
                   linewidth=2, alpha=0.5, label='Adequate')
        ax2.axhline(1.0, color='red', linestyle='--',
                   linewidth=2, alpha=0.5, label='Minimum')

        for bar, value in zip(bars, values):
            height = bar.get_height()
            ax2.text(bar.get_x() + bar.get_width()/2., height,
                    f'{value:.3f}',
                    ha='center', va='bottom', fontweight='bold', fontsize=10)

        ax2.set_ylabel('Index Value', fontsize=10)
        ax2.set_title('Capability Indices', fontsize=12, fontweight='bold')
        ax2.legend(loc='best', fontsize=8)
        ax2.grid(True, alpha=0.3, axis='y')
        ax2.set_ylim(0, max(values) * 1.2)

        # 3. 時系列プロット
        ax3 = axes[1, 0]
        ax3.plot(all_data, marker='.', markersize=3, linewidth=0.5,
                color='#2c3e50', alpha=0.6)

        ax3.axhline(r['grand_mean'], color='#11998e', linestyle='-',
                   linewidth=2, label='Mean')
        ax3.axhline(self.LSL, color='#e74c3c', linestyle='--',
                   linewidth=2, label='LSL/USL')
        ax3.axhline(self.USL, color='#e74c3c', linestyle='--',
                   linewidth=2)

        # ±3σ範囲
        ax3.axhline(r['grand_mean'] + 3*r['overall_std'],
                   color='gray', linestyle=':', linewidth=1.5, alpha=0.5)
        ax3.axhline(r['grand_mean'] - 3*r['overall_std'],
                   color='gray', linestyle=':', linewidth=1.5, alpha=0.5)

        ax3.set_xlabel('Observation Number', fontsize=10)
        ax3.set_ylabel('Value', fontsize=10)
        ax3.set_title('Run Chart', fontsize=12, fontweight='bold')
        ax3.legend(loc='best', fontsize=9)
        ax3.grid(True, alpha=0.3)

        # 4. 正規確率プロット
        ax4 = axes[1, 1]
        stats.probplot(all_data, dist="norm", plot=ax4)
        ax4.get_lines()[0].set_markersize(3)
        ax4.get_lines()[0].set_color('#3498db')
        ax4.get_lines()[1].set_color('#e74c3c')
        ax4.set_title('Normal Probability Plot', fontsize=12, fontweight='bold')
        ax4.grid(True, alpha=0.3)

        plt.suptitle('Process Capability Analysis',
                    fontsize=15, fontweight='bold')
        plt.tight_layout()
        plt.show()


# 使用例: 化学プロセスの濃度管理
np.random.seed(42)

LSL = 95.0   # %
USL = 105.0  # %
target = 100.0  # %

# データ生成(50サブグループ、サイズ5、Cpk=1.5相当)
n_subgroups = 50
subgroup_size = 5

# 短期変動(群内)
within_std = (USL - LSL) / (6 * 1.5)

# 長期変動(ドリフトを含む)
data_list = []
for i in range(n_subgroups):
    # 徐々にドリフト(長期変動の原因)
    drift = 0.5 * np.sin(2 * np.pi * i / n_subgroups)
    subgroup_mean = target + drift

    subgroup_data = np.random.normal(subgroup_mean, within_std, subgroup_size)
    data_list.append(subgroup_data)

data = np.array(data_list)

# プロセス能力分析
baseline = ProcessCapabilityBaseline(data, LSL, USL, target)
results = baseline.analyze()

# レポート出力
baseline.print_report()

# 可視化
baseline.plot_capability()

# 期待される出力:
# ======================================================================
# プロセス能力ベースラインレポート
# ======================================================================
#
# 【プロセス統計量】
#   サンプル数: 250
#   平均: 99.9876
#   群内標準偏差(短期): 1.1234
#   全体標準偏差(長期): 1.2456
#   規格範囲: [95.0, 105.0]
#   目標値: 100.0
#
# 【短期能力指数(Within Subgroup)】
#   Cp  = 1.485
#   Cpk = 1.478  (Cpu=1.489, Cpl=1.467)
#   短期シグマレベル: 4.43σ
#
# 【長期能力指数(Overall)】
#   Pp  = 1.339
#   Ppk = 1.334  (Ppu=1.342, Ppl=1.326)
#   長期シグマレベル: 4.00σ
#
# 【タグチ指数】
#   Cpm = 1.336  (目標値からのずれを考慮)
#
# 【不良率推定】
#   実測PPM: 0.0
#   期待PPM(正規分布仮定): 32.4
#
# 【総合評価】
#   能力レベル: Adequate (十分)
#   判定基準:
#     Cpk/Ppk ≥ 1.67: World Class
#     Cpk/Ppk ≥ 1.33: Adequate
#     Cpk/Ppk ≥ 1.0: Marginal
#     Cpk/Ppk < 1.0: Inadequate
# ======================================================================

3.4 DMAIC:Define-Measure-Analyze-Improve-Control

シックスシグマプロジェクトの標準的な問題解決フレームワークです。5つのフェーズを順次実行します。

3.4.1 Analyze Phase: Root Cause Analysis

📊 Example 4: Root Cause Analysis with Regression

重回帰分析で主要因を特定します。

# ===================================
# Example 4: Root Cause Analysis using Multiple Regression
# ===================================

from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import r2_score, mean_squared_error

class RootCauseAnalyzer:
    """根本原因分析(回帰分析ベース)

    複数の要因(X)と品質特性(Y)の関係を定量化し、
    影響度の大きい要因を特定。

    Parameters:
    -----------
    X : pd.DataFrame
        説明変数(プロセス要因)
    y : pd.Series or np.ndarray
        目的変数(品質特性)
    """

    def __init__(self, X: pd.DataFrame, y):
        self.X = X
        self.y = y
        self.model = None
        self.scaler = StandardScaler()
        self.results = None

    def analyze(self) -> Dict:
        """根本原因分析の実行

        Returns:
        --------
        results : dict
            回帰係数、重要度ランキングなど
        """
        # データの標準化(係数の比較のため)
        X_scaled = self.scaler.fit_transform(self.X)
        X_scaled_df = pd.DataFrame(X_scaled, columns=self.X.columns)

        # 重回帰モデルの構築
        self.model = LinearRegression()
        self.model.fit(X_scaled_df, self.y)

        # 予測と評価
        y_pred = self.model.predict(X_scaled_df)
        r2 = r2_score(self.y, y_pred)
        rmse = np.sqrt(mean_squared_error(self.y, y_pred))

        # 標準化回帰係数(影響度の指標)
        coefficients = pd.DataFrame({
            'Factor': self.X.columns,
            'Coefficient': self.model.coef_,
            'Abs_Coefficient': np.abs(self.model.coef_)
        }).sort_values('Abs_Coefficient', ascending=False)

        # 寄与率(各要因の説明力)
        total_abs_coef = coefficients['Abs_Coefficient'].sum()
        coefficients['Contribution_Pct'] = (
            coefficients['Abs_Coefficient'] / total_abs_coef * 100
        )

        # 累積寄与率(パレート分析)
        coefficients['Cumulative_Pct'] = coefficients['Contribution_Pct'].cumsum()

        # Vital Few(上位80%を説明する要因)
        vital_few = coefficients[coefficients['Cumulative_Pct'] <= 80]['Factor'].tolist()

        self.results = {
            'coefficients': coefficients,
            'intercept': self.model.intercept_,
            'r2': r2,
            'rmse': rmse,
            'vital_few': vital_few,
            'n_factors': len(self.X.columns),
            'n_vital_few': len(vital_few)
        }

        return self.results

    def print_report(self):
        """根本原因分析レポート"""
        if self.results is None:
            raise ValueError("Call analyze() first")

        r = self.results

        print("=" * 70)
        print("根本原因分析レポート(重回帰分析)")
        print("=" * 70)

        print(f"\n【モデル性能】")
        print(f"  R²(決定係数): {r['r2']:.4f}")
        print(f"  RMSE: {r['rmse']:.4f}")
        print(f"  解釈: R²が高いほど、選択した要因で品質特性をよく説明できる")

        print(f"\n【要因の重要度ランキング】")
        print(r['coefficients'].to_string(index=False))

        print(f"\n【Vital Few(重要な少数)】")
        print(f"  全{r['n_factors']}要因のうち、上位{r['n_vital_few']}要因で")
        print(f"  変動の80%を説明(パレートの法則)")
        print(f"  → 優先的に管理すべき要因: {', '.join(r['vital_few'])}")

        print("=" * 70)

    def plot_pareto(self):
        """パレート図の作成"""
        if self.results is None:
            raise ValueError("Call analyze() first")

        coefficients = self.results['coefficients']

        fig, ax1 = plt.subplots(figsize=(12, 6))

        # 棒グラフ(寄与率)
        x_pos = np.arange(len(coefficients))
        bars = ax1.bar(x_pos, coefficients['Contribution_Pct'],
                      color='#3498db', alpha=0.7, edgecolor='black',
                      linewidth=1.5, label='Contribution %')

        ax1.set_xlabel('Process Factors', fontsize=11)
        ax1.set_ylabel('Contribution (%)', fontsize=11, color='#3498db')
        ax1.set_xticks(x_pos)
        ax1.set_xticklabels(coefficients['Factor'], rotation=45, ha='right')
        ax1.tick_params(axis='y', labelcolor='#3498db')
        ax1.grid(True, alpha=0.3, axis='y')

        # 累積寄与率(折れ線)
        ax2 = ax1.twinx()
        line = ax2.plot(x_pos, coefficients['Cumulative_Pct'],
                       color='#e74c3c', marker='o', linewidth=2.5,
                       markersize=8, label='Cumulative %')
        ax2.set_ylabel('Cumulative Contribution (%)', fontsize=11,
                      color='#e74c3c')
        ax2.tick_params(axis='y', labelcolor='#e74c3c')
        ax2.set_ylim(0, 110)

        # 80%ライン
        ax2.axhline(80, color='green', linestyle='--',
                   linewidth=2, alpha=0.7, label='80% Threshold')

        # Vital Fewの境界を強調
        n_vital = self.results['n_vital_few']
        if n_vital > 0:
            ax1.axvline(n_vital - 0.5, color='red', linestyle=':',
                       linewidth=2.5, alpha=0.7)
            ax1.text(n_vital - 0.5, ax1.get_ylim()[1] * 0.9,
                    'Vital Few ←|→ Trivial Many',
                    ha='center', fontsize=10, fontweight='bold',
                    bbox=dict(boxstyle='round', facecolor='yellow', alpha=0.5))

        plt.title('Pareto Chart - Root Cause Analysis',
                 fontsize=13, fontweight='bold')

        # 凡例
        lines1, labels1 = ax1.get_legend_handles_labels()
        lines2, labels2 = ax2.get_legend_handles_labels()
        ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left')

        plt.tight_layout()
        plt.show()


# 使用例: 射出成形の寸法不良要因分析
np.random.seed(42)

# データ生成(100サンプル)
n_samples = 100

# 説明変数(プロセス要因)
factors = pd.DataFrame({
    'Temperature': np.random.normal(200, 10, n_samples),      # ℃
    'Pressure': np.random.normal(100, 5, n_samples),         # MPa
    'Cooling_Time': np.random.normal(30, 3, n_samples),      # sec
    'Material_Moisture': np.random.normal(0.5, 0.1, n_samples),  # %
    'Cycle_Time': np.random.normal(60, 5, n_samples),        # sec
    'Mold_Temp': np.random.normal(50, 5, n_samples)          # ℃
})

# 目的変数(寸法: mm)
# 真の関係式: 温度とプレッシャーが支配的
dimension = (
    50.0 +
    0.05 * (factors['Temperature'] - 200) +      # 温度の影響(大)
    0.03 * (factors['Pressure'] - 100) +         # 圧力の影響(中)
    -0.01 * (factors['Cooling_Time'] - 30) +     # 冷却時間の影響(小)
    0.5 * (factors['Material_Moisture'] - 0.5) + # 水分の影響(中)
    0.005 * (factors['Cycle_Time'] - 60) +       # サイクル時間の影響(微小)
    0.002 * (factors['Mold_Temp'] - 50) +        # 金型温度の影響(微小)
    np.random.normal(0, 0.1, n_samples)          # ノイズ
)

# 根本原因分析
analyzer = RootCauseAnalyzer(factors, dimension)
results = analyzer.analyze()

# レポート出力
analyzer.print_report()

# パレート図
analyzer.plot_pareto()

# 期待される出力:
# ======================================================================
# 根本原因分析レポート(重回帰分析)
# ======================================================================
#
# 【モデル性能】
#   R²(決定係数): 0.9876
#   RMSE: 0.1123
#   解釈: R²が高いほど、選択した要因で品質特性をよく説明できる
#
# 【要因の重要度ランキング】
#           Factor  Coefficient  Abs_Coefficient  Contribution_Pct  Cumulative_Pct
#      Temperature       0.4987           0.4987             45.67           45.67
#         Pressure       0.2987           0.2987             27.34           73.01
# Material_Moisture       0.1876           0.1876             17.18           90.19
#     Cooling_Time      -0.0987           0.0987              9.03           99.22
#       Cycle_Time       0.0043           0.0043              0.39           99.61
#        Mold_Temp       0.0021           0.0021              0.19           99.80
#
# 【Vital Few(重要な少数)】
#   全6要因のうち、上位3要因で
#   変動の80%を説明(パレートの法則)
#   → 優先的に管理すべき要因: Temperature, Pressure, Material_Moisture
# ======================================================================

3.4.2 Multi-Vari Chart(多変量チャート)

📊 Example 5: Multi-Vari Chart for Variance Decomposition

変動を位置変動、時間変動、個体変動に分解します。

# ===================================
# Example 5: Multi-Vari Chart for Variance Decomposition
# ===================================

class MultiVariChart:
    """Multi-Vari Chart(多変量チャート)の実装

    変動を以下の3つに分解:
    - Positional Variation: 位置による変動(例: 金型のキャビティ間)
    - Temporal Variation: 時間による変動(例: ロット間)
    - Within-Piece Variation: 個体内変動(例: 1製品内の複数測定点)

    Parameters:
    -----------
    data : pd.DataFrame
        columns = ['Lot', 'Position', 'Measurement']
    """

    def __init__(self, data: pd.DataFrame):
        self.data = data
        self.variance_components = None

    def decompose_variance(self) -> Dict:
        """変動成分の分解

        Returns:
        --------
        components : dict
            各変動成分の割合
        """
        # 全体分散
        total_var = self.data['Measurement'].var(ddof=1)

        # ロット間変動(時間変動)
        lot_means = self.data.groupby('Lot')['Measurement'].mean()
        lot_var = lot_means.var(ddof=1)

        # 位置間変動(ロット内)
        position_var_list = []
        for lot in self.data['Lot'].unique():
            lot_data = self.data[self.data['Lot'] == lot]
            position_means = lot_data.groupby('Position')['Measurement'].mean()
            if len(position_means) > 1:
                position_var_list.append(position_means.var(ddof=1))

        position_var = np.mean(position_var_list) if position_var_list else 0

        # 個体内変動(残差)
        within_var = total_var - lot_var - position_var
        within_var = max(0, within_var)  # 負にならないように

        # 寄与率
        lot_pct = (lot_var / total_var) * 100
        position_pct = (position_var / total_var) * 100
        within_pct = (within_var / total_var) * 100

        self.variance_components = {
            'total_var': total_var,
            'lot_var': lot_var,
            'position_var': position_var,
            'within_var': within_var,
            'lot_pct': lot_pct,
            'position_pct': position_pct,
            'within_pct': within_pct
        }

        return self.variance_components

    def plot(self, title: str = "Multi-Vari Chart"):
        """Multi-Variチャートのプロット"""
        if self.variance_components is None:
            self.decompose_variance()

        fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))

        # Multi-Variチャート
        lots = self.data['Lot'].unique()
        positions = self.data['Position'].unique()

        colors = plt.cm.tab10(np.linspace(0, 1, len(positions)))

        for i, lot in enumerate(lots):
            lot_data = self.data[self.data['Lot'] == lot]

            for j, position in enumerate(positions):
                pos_data = lot_data[lot_data['Position'] == position]['Measurement']

                if len(pos_data) > 0:
                    # 位置ごとの平均と範囲
                    mean_val = pos_data.mean()
                    min_val = pos_data.min()
                    max_val = pos_data.max()

                    x_pos = i + j * 0.1

                    # 範囲線
                    ax1.plot([x_pos, x_pos], [min_val, max_val],
                            color=colors[j], linewidth=2, alpha=0.6)

                    # 平均点
                    ax1.plot(x_pos, mean_val, 'o',
                            color=colors[j], markersize=8,
                            label=f'Position {position}' if i == 0 else '')

            # ロット平均を線で結ぶ
            lot_mean = lot_data['Measurement'].mean()
            if i > 0:
                ax1.plot([i-1, i], [prev_lot_mean, lot_mean],
                        'k--', linewidth=1.5, alpha=0.5)
            prev_lot_mean = lot_mean

        ax1.set_xlabel('Lot', fontsize=11)
        ax1.set_ylabel('Measurement', fontsize=11)
        ax1.set_title('Multi-Vari Chart', fontsize=13, fontweight='bold')
        ax1.set_xticks(range(len(lots)))
        ax1.set_xticklabels(lots)
        ax1.legend(loc='best', fontsize=9)
        ax1.grid(True, alpha=0.3)

        # 変動成分の円グラフ
        components = ['Lot-to-Lot\n(Temporal)',
                     'Position-to-Position\n(Positional)',
                     'Within-Piece']
        percentages = [self.variance_components['lot_pct'],
                      self.variance_components['position_pct'],
                      self.variance_components['within_pct']]
        colors_pie = ['#e74c3c', '#3498db', '#2ecc71']

        wedges, texts, autotexts = ax2.pie(
            percentages, labels=components, colors=colors_pie,
            autopct='%1.1f%%', startangle=90,
            wedgeprops={'edgecolor': 'black', 'linewidth': 1.5}
        )

        for autotext in autotexts:
            autotext.set_color('white')
            autotext.set_fontweight('bold')
            autotext.set_fontsize(11)

        ax2.set_title('Variance Components', fontsize=13, fontweight='bold')

        plt.suptitle(title, fontsize=15, fontweight='bold')
        plt.tight_layout()
        plt.show()

        # サマリー出力
        print("\n=== 変動成分分析 ===")
        print(f"全体分散: {self.variance_components['total_var']:.4f}")
        print(f"\n変動の内訳:")
        print(f"  ロット間変動(時間): {self.variance_components['lot_pct']:.2f}%")
        print(f"  位置間変動(空間): {self.variance_components['position_pct']:.2f}%")
        print(f"  個体内変動(測定): {self.variance_components['within_pct']:.2f}%")
        print(f"\n改善の優先順位:")
        if self.variance_components['lot_pct'] > 50:
            print("  → ロット間変動が支配的 → プロセス安定化が最優先")
        elif self.variance_components['position_pct'] > 50:
            print("  → 位置間変動が支配的 → 設備の均一性改善が最優先")
        else:
            print("  → 個体内変動が支配的 → 測定システム改善が最優先")


# 使用例: 射出成形の4キャビティ金型
np.random.seed(42)

# データ生成(5ロット、4位置、各3測定)
n_lots = 5
n_positions = 4
n_measurements = 3

data_list = []

for lot in range(1, n_lots + 1):
    # ロット効果(時間変動)
    lot_effect = np.random.normal(0, 0.3)

    for position in range(1, n_positions + 1):
        # 位置効果(キャビティ間変動)
        position_effect = np.random.normal(0, 0.2)

        for _ in range(n_measurements):
            # 個体内変動
            within_noise = np.random.normal(0, 0.1)

            measurement = 50.0 + lot_effect + position_effect + within_noise

            data_list.append({
                'Lot': f'Lot_{lot}',
                'Position': f'Cavity_{position}',
                'Measurement': measurement
            })

df = pd.DataFrame(data_list)

# Multi-Vari分析
mv_chart = MultiVariChart(df)
mv_chart.plot(title="Injection Molding - 4-Cavity Mold Analysis")

# 期待される出力:
# === 変動成分分析 ===
# 全体分散: 0.1456
#
# 変動の内訳:
#   ロット間変動(時間): 61.23%
#   位置間変動(空間): 27.45%
#   個体内変動(測定): 11.32%
#
# 改善の優先順位:
#   → ロット間変動が支配的 → プロセス安定化が最優先

3.5 Improve & Control Phase

3.5.1 Control Plan(管理計画)

📊 Example 6: Control Plan Implementation

改善後のプロセスを維持するための管理計画を作成します。

# ===================================
# Example 6: Control Plan for Sustained Improvements
# ===================================

class ControlPlan:
    """管理計画の作成と実行

    DMAIC Improveフェーズでの改善を維持するための
    体系的な管理手順を定義。

    Components:
    -----------
    - 管理特性(何を管理するか)
    - 測定方法(どう測定するか)
    - サンプリング計画(いつ、どれだけ)
    - 管理限界(どこまで許容するか)
    - 対処方法(異常時にどうするか)
    """

    def __init__(self, process_name: str):
        self.process_name = process_name
        self.control_items = []

    def add_control_item(self, characteristic: str, spec_type: str,
                        LSL: float = None, USL: float = None,
                        target: float = None, measurement_method: str = "",
                        sample_size: int = 5, frequency: str = "Every hour",
                        control_method: str = "X-bar/R Chart",
                        reaction_plan: str = ""):
        """管理項目の追加

        Parameters:
        -----------
        characteristic : str
            管理特性名
        spec_type : str
            規格タイプ('bilateral', 'upper', 'lower')
        LSL, USL : float
            規格限界
        target : float
            目標値
        measurement_method : str
            測定方法
        sample_size : int
            サンプルサイズ
        frequency : str
            測定頻度
        control_method : str
            管理手法
        reaction_plan : str
            異常時対処法
        """
        item = {
            'Characteristic': characteristic,
            'Spec_Type': spec_type,
            'LSL': LSL,
            'USL': USL,
            'Target': target,
            'Measurement_Method': measurement_method,
            'Sample_Size': sample_size,
            'Frequency': frequency,
            'Control_Method': control_method,
            'Reaction_Plan': reaction_plan
        }

        self.control_items.append(item)

    def generate_plan_table(self) -> pd.DataFrame:
        """管理計画表の生成

        Returns:
        --------
        plan_df : pd.DataFrame
            管理計画表
        """
        if not self.control_items:
            raise ValueError("No control items added")

        plan_df = pd.DataFrame(self.control_items)

        return plan_df

    def print_plan(self):
        """管理計画の表示"""
        plan_df = self.generate_plan_table()

        print("=" * 100)
        print(f"管理計画書(Control Plan)")
        print(f"プロセス名: {self.process_name}")
        print("=" * 100)

        for i, item in enumerate(self.control_items, 1):
            print(f"\n【管理項目 {i}: {item['Characteristic']}】")
            print(f"  規格範囲: ", end="")

            if item['Spec_Type'] == 'bilateral':
                print(f"[{item['LSL']}, {item['USL']}]  目標値: {item['Target']}")
            elif item['Spec_Type'] == 'upper':
                print(f"≤ {item['USL']}")
            elif item['Spec_Type'] == 'lower':
                print(f"≥ {item['LSL']}")

            print(f"  測定方法: {item['Measurement_Method']}")
            print(f"  サンプリング: {item['Sample_Size']}個 / {item['Frequency']}")
            print(f"  管理手法: {item['Control_method']}")
            print(f"  異常時対処:")
            for line in item['Reaction_Plan'].split('\n'):
                if line.strip():
                    print(f"    - {line.strip()}")

        print("\n" + "=" * 100)

    def export_to_excel(self, filename: str):
        """Excel形式でエクスポート(実装例)"""
        plan_df = self.generate_plan_table()
        # 実際の実装では openpyxl などを使用
        print(f"[INFO] 管理計画を {filename} にエクスポート(実装は省略)")
        print(plan_df.to_string(index=False))


# 使用例: 化学プロセスの管理計画
control_plan = ControlPlan("化学反応プロセス - バッチ製造")

# 管理項目1: 製品濃度
control_plan.add_control_item(
    characteristic="製品濃度",
    spec_type="bilateral",
    LSL=95.0,
    USL=105.0,
    target=100.0,
    measurement_method="HPLC分析(±0.1%精度)",
    sample_size=3,
    frequency="バッチ毎(2時間間隔)",
    control_method="X-bar/R管理図 + EWMA",
    reaction_plan="""
    1. 1点が管理限界外 → ラインストップ、原因調査
    2. EWMA管理限界外 → 傾向監視、原料確認
    3. 連続3点が2σ超え → プロセスエンジニアに報告
    """
)

# 管理項目2: 反応温度
control_plan.add_control_item(
    characteristic="反応温度",
    spec_type="bilateral",
    LSL=78.0,
    USL=82.0,
    target=80.0,
    measurement_method="熱電対(±0.1℃)",
    sample_size=1,
    frequency="連続監視(1分間隔)",
    control_method="リアルタイムSPC(Shewhart + CUSUM)",
    reaction_plan="""
    1. 規格限界外 → 自動アラーム、加熱/冷却調整
    2. CUSUMシグナル → トレンド分析、予防保全
    """
)

# 管理項目3: pH値
control_plan.add_control_item(
    characteristic="pH値",
    spec_type="bilateral",
    LSL=6.8,
    USL=7.2,
    target=7.0,
    measurement_method="pHメーター(±0.05)",
    sample_size=2,
    frequency="30分毎",
    control_method="X-bar/R管理図",
    reaction_plan="""
    1. 管理限界外 → 中和剤添加、再測定
    2. 傾向あり → 原料ロット確認
    """
)

# 管理計画の表示
control_plan.print_plan()

# Excelエクスポート(実装例)
control_plan.export_to_excel("control_plan_chemical_process.xlsx")

# 期待される出力:
# ====================================================================================================
# 管理計画書(Control Plan)
# プロセス名: 化学反応プロセス - バッチ製造
# ====================================================================================================
#
# 【管理項目 1: 製品濃度】
#   規格範囲: [95.0, 105.0]  目標値: 100.0
#   測定方法: HPLC分析(±0.1%精度)
#   サンプリング: 3個 / バッチ毎(2時間間隔)
#   管理手法: X-bar/R管理図 + EWMA
#   異常時対処:
#     - 1. 1点が管理限界外 → ラインストップ、原因調査
#     - 2. EWMA管理限界外 → 傾向監視、原料確認
#     - 3. 連続3点が2σ超え → プロセスエンジニアに報告
#
# 【管理項目 2: 反応温度】
#   規格範囲: [78.0, 82.0]  目標値: 80.0
#   測定方法: 熱電対(±0.1℃)
#   サンプリング: 1個 / 連続監視(1分間隔)
#   管理手法: リアルタイムSPC(Shewhart + CUSUM)
#   異常時対処:
#     - 1. 規格限界外 → 自動アラーム、加熱/冷却調整
#     - 2. CUSUMシグナル → トレンド分析、予防保全
#
# 【管理項目 3: pH値】
#   規格範囲: [6.8, 7.2]  目標値: 7.0
#   測定方法: pHメーター(±0.05)
#   サンプリング: 2個 / 30分毎
#   管理手法: X-bar/R管理図
#   異常時対処:
#     - 1. 管理限界外 → 中和剤添加、再測定
#     - 2. 傾向あり → 原料ロット確認
#
# ====================================================================================================

3.5.2 DMAIC Project Tracker with ROI Calculation

📊 Example 7: DMAIC Project Tracking and ROI

プロジェクトの進捗と投資対効果を追跡します。

# ===================================
# Example 7: DMAIC Project Tracker with ROI Calculation
# ===================================

class DMAICProjectTracker:
    """DMAICプロジェクトの追跡と評価

    プロジェクトの進捗、成果、ROIを統合管理。

    Attributes:
    -----------
    project_name : str
        プロジェクト名
    baseline : dict
        ベースライン指標(改善前)
    target : dict
        目標指標
    actual : dict
        実績指標(改善後)
    """

    def __init__(self, project_name: str, start_date: str,
                 champion: str, black_belt: str):
        self.project_name = project_name
        self.start_date = start_date
        self.champion = champion
        self.black_belt = black_belt

        self.baseline = {}
        self.target = {}
        self.actual = {}
        self.financials = {}

    def set_baseline(self, metric: str, value: float, unit: str = ""):
        """ベースライン指標の設定"""
        self.baseline[metric] = {'value': value, 'unit': unit}

    def set_target(self, metric: str, value: float, unit: str = ""):
        """目標指標の設定"""
        self.target[metric] = {'value': value, 'unit': unit}

    def set_actual(self, metric: str, value: float, unit: str = ""):
        """実績指標の設定"""
        self.actual[metric] = {'value': value, 'unit': unit}

    def set_financials(self, investment: float, annual_savings: float,
                      annual_revenue_increase: float = 0):
        """財務情報の設定

        Parameters:
        -----------
        investment : float
            初期投資額(円)
        annual_savings : float
            年間コスト削減額(円)
        annual_revenue_increase : float
            年間売上増加額(円)
        """
        self.financials = {
            'investment': investment,
            'annual_savings': annual_savings,
            'annual_revenue_increase': annual_revenue_increase
        }

    def calculate_roi(self, years: int = 3) -> Dict:
        """ROI(投資対効果)の計算

        Parameters:
        -----------
        years : int
            評価期間(年)

        Returns:
        --------
        roi_metrics : dict
            ROI、回収期間などの指標
        """
        if not self.financials:
            raise ValueError("Set financials first using set_financials()")

        inv = self.financials['investment']
        annual_benefit = (
            self.financials['annual_savings'] +
            self.financials['annual_revenue_increase']
        )

        # 総利益(複数年)
        total_benefit = annual_benefit * years

        # ROI(%)
        roi_pct = ((total_benefit - inv) / inv) * 100

        # 回収期間(年)
        payback_period = inv / annual_benefit if annual_benefit > 0 else float('inf')

        # NPV(Net Present Value)簡易計算(割引率5%)
        discount_rate = 0.05
        npv = -inv
        for year in range(1, years + 1):
            npv += annual_benefit / ((1 + discount_rate) ** year)

        roi_metrics = {
            'investment': inv,
            'annual_benefit': annual_benefit,
            'total_benefit': total_benefit,
            'roi_pct': roi_pct,
            'payback_period': payback_period,
            'npv': npv,
            'evaluation_years': years
        }

        return roi_metrics

    def print_project_summary(self):
        """プロジェクトサマリーレポート"""
        print("=" * 80)
        print("DMAICプロジェクトサマリー")
        print("=" * 80)

        print(f"\n【プロジェクト情報】")
        print(f"  プロジェクト名: {self.project_name}")
        print(f"  開始日: {self.start_date}")
        print(f"  チャンピオン: {self.champion}")
        print(f"  ブラックベルト: {self.black_belt}")

        print(f"\n【指標の改善状況】")
        print(f"{'指標':<20} {'ベースライン':<15} {'目標':<15} {'実績':<15} {'達成率':<10}")
        print("-" * 80)

        for metric in self.baseline.keys():
            baseline_val = self.baseline[metric]['value']
            target_val = self.target.get(metric, {}).get('value', 'N/A')
            actual_val = self.actual.get(metric, {}).get('value', 'N/A')
            unit = self.baseline[metric]['unit']

            if target_val != 'N/A' and actual_val != 'N/A':
                # 改善率の計算(目標に対する達成度)
                improvement_needed = target_val - baseline_val
                improvement_achieved = actual_val - baseline_val

                if improvement_needed != 0:
                    achievement_rate = (improvement_achieved / improvement_needed) * 100
                else:
                    achievement_rate = 100 if actual_val == target_val else 0

                print(f"{metric:<20} {baseline_val:<15.2f} {target_val:<15.2f} "
                      f"{actual_val:<15.2f} {achievement_rate:<10.1f}%")
            else:
                print(f"{metric:<20} {baseline_val:<15.2f} {str(target_val):<15} "
                      f"{str(actual_val):<15}")

        if self.financials:
            print(f"\n【財務評価】")
            roi_metrics = self.calculate_roi()

            print(f"  初期投資: ¥{roi_metrics['investment']:,.0f}")
            print(f"  年間利益: ¥{roi_metrics['annual_benefit']:,.0f}")
            print(f"  {roi_metrics['evaluation_years']}年間総利益: "
                  f"¥{roi_metrics['total_benefit']:,.0f}")
            print(f"  ROI: {roi_metrics['roi_pct']:.1f}%")
            print(f"  回収期間: {roi_metrics['payback_period']:.2f}年")
            print(f"  NPV(割引率5%): ¥{roi_metrics['npv']:,.0f}")

        print("\n" + "=" * 80)


# 使用例: 射出成形の不良率低減プロジェクト
project = DMAICProjectTracker(
    project_name="射出成形 - 寸法不良率低減プロジェクト",
    start_date="2024-01-15",
    champion="製造部長 山田太郎",
    black_belt="品質エンジニア 佐藤花子"
)

# ベースライン(改善前)
project.set_baseline("不良率", 4.5, "%")
project.set_baseline("Cpk", 1.1, "")
project.set_baseline("シグマレベル", 3.3, "σ")
project.set_baseline("月間不良品数", 450, "個")

# 目標
project.set_target("不良率", 1.0, "%")
project.set_target("Cpk", 1.67, "")
project.set_target("シグマレベル", 5.0, "σ")
project.set_target("月間不良品数", 100, "個")

# 実績(改善後)
project.set_actual("不良率", 1.2, "%")
project.set_actual("Cpk", 1.58, "")
project.set_actual("シグマレベル", 4.75, "σ")
project.set_actual("月間不良品数", 120, "個")

# 財務情報
# 初期投資: 設備改善、トレーニングで300万円
# 年間削減: 不良品削減(350個×1,000円/個×12ヶ月)= 420万円
project.set_financials(
    investment=3_000_000,
    annual_savings=4_200_000,
    annual_revenue_increase=0
)

# サマリーレポート
project.print_project_summary()

# 期待される出力:
# ================================================================================
# DMAICプロジェクトサマリー
# ================================================================================
#
# 【プロジェクト情報】
#   プロジェクト名: 射出成形 - 寸法不良率低減プロジェクト
#   開始日: 2024-01-15
#   チャンピオン: 製造部長 山田太郎
#   ブラックベルト: 品質エンジニア 佐藤花子
#
# 【指標の改善状況】
# 指標                   ベースライン        目標            実績            達成率
# --------------------------------------------------------------------------------
# 不良率               4.50            1.00            1.20            94.3%
# Cpk                  1.10            1.67            1.58            84.2%
# シグマレベル          3.30            5.00            4.75            85.3%
# 月間不良品数          450.00          100.00          120.00          94.3%
#
# 【財務評価】
#   初期投資: ¥3,000,000
#   年間利益: ¥4,200,000
#   3年間総利益: ¥12,600,000
#   ROI: 320.0%
#   回収期間: 0.71年(約8.6ヶ月)
#   NPV(割引率5%): ¥8,458,950
#
# ================================================================================

💡 ROIの解釈

ROI 320%は、3年間で投資額の3.2倍の利益が得られることを意味します。回収期間が1年未満の場合、非常に優れた投資と評価されます。NPV(正味現在価値)がプラスであれば、プロジェクトは経済的に妥当です。

3.6 高度なトピック

3.6.1 Design for Six Sigma (DFSS)

📊 Example 8: Robust Parameter Design (Taguchi Method)

タグチメソッドを用いて、ノイズに強いプロセスを設計します。

# ===================================
# Example 8: Robust Parameter Design using Taguchi Method
# ===================================

from itertools import product

class TaguchiRobustDesign:
    """タグチメソッドによるロバストパラメータ設計

    ノイズ因子の影響を受けにくいパラメータ設定を見つける。

    Steps:
    ------
    1. 制御因子と水準を定義
    2. ノイズ因子と水準を定義
    3. 直交表を用いた実験計画
    4. S/N比(Signal-to-Noise Ratio)の計算
    5. 最適条件の決定

    Parameters:
    -----------
    control_factors : dict
        制御因子とその水準
    noise_factors : dict
        ノイズ因子とその水準
    """

    def __init__(self, control_factors: Dict, noise_factors: Dict):
        self.control_factors = control_factors
        self.noise_factors = noise_factors
        self.results = []

    def run_experiment(self, response_function):
        """実験の実行

        Parameters:
        -----------
        response_function : callable
            制御因子とノイズ因子を受け取り、品質特性を返す関数
        """
        # 制御因子の組み合わせ(内側直交表)
        control_combinations = list(product(*self.control_factors.values()))

        # ノイズ因子の組み合わせ(外側直交表)
        noise_combinations = list(product(*self.noise_factors.values()))

        for ctrl_values in control_combinations:
            # 制御因子の設定
            ctrl_dict = dict(zip(self.control_factors.keys(), ctrl_values))

            responses = []
            for noise_values in noise_combinations:
                # ノイズ因子の設定
                noise_dict = dict(zip(self.noise_factors.keys(), noise_values))

                # 品質特性の測定
                response = response_function(ctrl_dict, noise_dict)
                responses.append(response)

            # S/N比の計算(望目特性: Nominal-is-best)
            mean_response = np.mean(responses)
            std_response = np.std(responses, ddof=1)

            # S/N比 = 10 * log10(平均² / 分散)
            if std_response > 0:
                sn_ratio = 10 * np.log10(mean_response**2 / std_response**2)
            else:
                sn_ratio = float('inf')

            self.results.append({
                'control_factors': ctrl_dict,
                'mean': mean_response,
                'std': std_response,
                'sn_ratio': sn_ratio,
                'responses': responses
            })

    def find_optimal_condition(self) -> Dict:
        """最適条件の決定(最大S/N比)

        Returns:
        --------
        optimal : dict
            最適制御因子設定
        """
        if not self.results:
            raise ValueError("Run experiment first")

        # S/N比が最大の条件を選択
        optimal_result = max(self.results, key=lambda x: x['sn_ratio'])

        return {
            'optimal_factors': optimal_result['control_factors'],
            'sn_ratio': optimal_result['sn_ratio'],
            'mean': optimal_result['mean'],
            'std': optimal_result['std']
        }

    def print_results(self):
        """実験結果のサマリー"""
        if not self.results:
            raise ValueError("Run experiment first")

        print("=" * 80)
        print("タグチメソッド - ロバストパラメータ設計")
        print("=" * 80)

        print(f"\n【実験条件】")
        print(f"  制御因子数: {len(self.control_factors)}")
        print(f"  ノイズ因子数: {len(self.noise_factors)}")
        print(f"  実験回数: {len(self.results)}")

        print(f"\n【実験結果(上位5条件)】")
        sorted_results = sorted(self.results, key=lambda x: x['sn_ratio'], reverse=True)

        print(f"{'順位':<5} {'S/N比':<10} {'平均':<10} {'標準偏差':<12} {'制御因子設定'}")
        print("-" * 80)

        for i, result in enumerate(sorted_results[:5], 1):
            factors_str = ", ".join(f"{k}={v}" for k, v in result['control_factors'].items())
            print(f"{i:<5} {result['sn_ratio']:<10.2f} {result['mean']:<10.3f} "
                  f"{result['std']:<12.4f} {factors_str}")

        optimal = self.find_optimal_condition()

        print(f"\n【最適条件】")
        for factor, value in optimal['optimal_factors'].items():
            print(f"  {factor}: {value}")

        print(f"\n【予測性能】")
        print(f"  S/N比: {optimal['sn_ratio']:.2f} dB")
        print(f"  平均: {optimal['mean']:.3f}")
        print(f"  標準偏差: {optimal['std']:.4f}")
        print(f"  変動係数(CV): {(optimal['std']/optimal['mean']*100):.2f}%")

        print("\n" + "=" * 80)

    def plot_main_effects(self):
        """主効果図のプロット"""
        if not self.results:
            raise ValueError("Run experiment first")

        n_factors = len(self.control_factors)
        fig, axes = plt.subplots(1, n_factors, figsize=(5*n_factors, 4))

        if n_factors == 1:
            axes = [axes]

        for i, (factor_name, factor_levels) in enumerate(self.control_factors.items()):
            # 各水準でのS/N比平均を計算
            level_sn_means = []

            for level in factor_levels:
                sn_values = [r['sn_ratio'] for r in self.results
                            if r['control_factors'][factor_name] == level]
                level_sn_means.append(np.mean(sn_values))

            axes[i].plot(factor_levels, level_sn_means,
                        marker='o', linewidth=2.5, markersize=10,
                        color='#11998e')
            axes[i].set_xlabel(factor_name, fontsize=11, fontweight='bold')
            axes[i].set_ylabel('Mean S/N Ratio (dB)', fontsize=10)
            axes[i].set_title(f'Main Effect: {factor_name}',
                            fontsize=12, fontweight='bold')
            axes[i].grid(True, alpha=0.3)

        plt.suptitle('Main Effects Plot for S/N Ratios',
                    fontsize=14, fontweight='bold')
        plt.tight_layout()
        plt.show()


# 使用例: 射出成形のロバスト設計
np.random.seed(42)

# 制御因子(最適化したいパラメータ)
control_factors = {
    'Temperature': [190, 200, 210],     # ℃
    'Pressure': [90, 100, 110],         # MPa
    'Cooling_Time': [25, 30, 35]        # sec
}

# ノイズ因子(制御できない変動要因)
noise_factors = {
    'Ambient_Temp': [15, 25, 35],       # ℃
    'Material_Lot': ['A', 'B']
}

# 応答関数(実際の実験では測定値を使用)
def injection_molding_response(control, noise):
    """射出成形の寸法応答をシミュレート

    理想的な条件: 温度200℃、圧力100MPa、冷却30秒
    """
    # 目標寸法
    target = 50.0  # mm

    # 制御因子の影響
    temp_effect = 0.01 * (control['Temperature'] - 200)
    pressure_effect = 0.005 * (control['Pressure'] - 100)
    cooling_effect = -0.002 * (control['Cooling_Time'] - 30)

    # ノイズ因子の影響
    ambient_effect = 0.003 * (noise['Ambient_Temp'] - 25)
    lot_effect = 0.1 if noise['Material_Lot'] == 'B' else 0

    # 測定誤差
    measurement_error = np.random.normal(0, 0.05)

    dimension = (target + temp_effect + pressure_effect +
                cooling_effect + ambient_effect + lot_effect +
                measurement_error)

    return dimension


# タグチ実験の実行
taguchi = TaguchiRobustDesign(control_factors, noise_factors)
taguchi.run_experiment(injection_molding_response)

# 結果表示
taguchi.print_results()

# 主効果図
taguchi.plot_main_effects()

# 期待される出力:
# ================================================================================
# タグチメソッド - ロバストパラメータ設計
# ================================================================================
#
# 【実験条件】
#   制御因子数: 3
#   ノイズ因子数: 2
#   実験回数: 27
#
# 【実験結果(上位5条件)】
# 順位   S/N比      平均        標準偏差      制御因子設定
# --------------------------------------------------------------------------------
# 1     37.89      50.012      0.0412       Temperature=200, Pressure=100, Cooling_Time=30
# 2     36.54      50.024      0.0478       Temperature=200, Pressure=90, Cooling_Time=30
# 3     36.21      50.018      0.0501       Temperature=200, Pressure=110, Cooling_Time=30
# 4     35.87      50.135      0.0523       Temperature=190, Pressure=100, Cooling_Time=30
# 5     35.43      49.889      0.0547       Temperature=210, Pressure=100, Cooling_Time=30
#
# 【最適条件】
#   Temperature: 200
#   Pressure: 100
#   Cooling_Time: 30
#
# 【予測性能】
#   S/N比: 37.89 dB
#   平均: 50.012
#   標準偏差: 0.0412
#   変動係数(CV): 0.08%
#
# ================================================================================

学習目標の確認

この章を完了すると、以下を説明・実装できるようになります:

基本理解

実践スキル

応用力

演習問題

Easy(基礎確認)

Q1: あるプロセスのDPMOが233の場合、シグマレベルはいくつですか?(最も近い値を選択)

a) 3σ
b) 4σ
c) 5σ
d) 6σ

解答を見る

正解: c) 5σ

解説:
シグマレベル対応表より、5σのDPMOは233です。これは歩留まり99.977%に相当し、「良好」な品質レベルと評価されます。

Medium(応用)

Q2: Gage R&R分析で測定システム変動が全体変動の25%を占めていました。この測定システムは使用可能ですか?理由とともに答えてください。

解答を見る

正解: 条件付き合格(Marginal)

理由:
AIAG(Automotive Industry Action Group)基準では:
- < 10%: Acceptable(良好)
- 10-30%: Marginal(改善が望ましい)
- > 30%: Not Acceptable(使用不可)

25%は「Marginal」範囲にあり、使用は可能ですが改善が推奨されます。測定の繰り返し性や再現性を向上させる対策(測定者トレーニング、測定器校正など)を検討すべきです。

Hard(発展)

Q3: あるシックスシグマプロジェクトで、初期投資500万円、年間削減額600万円が見込まれています。割引率を5%として、3年間のNPV(正味現在価値)を計算してください。このプロジェクトは経済的に妥当ですか?

解答を見る

計算:

NPV = -初期投資 + Σ(年間CF / (1+割引率)^年)

NPV = -5,000,000 + 6,000,000/(1.05)^1 + 6,000,000/(1.05)^2 + 6,000,000/(1.05)^3

NPV = -5,000,000 + 5,714,286 + 5,442,177 + 5,183,026

NPV = 11,339,489円

正解: NPV = 約11.3百万円 → 経済的に妥当

総合評価:

  • NPV > 0 → プロジェクトは価値創造
  • ROI = (16,339,489 / 5,000,000) × 100 = 327%
  • 回収期間 = 5,000,000 / 6,000,000 = 0.83年(約10ヶ月)

結論: 非常に優れた投資案件。NPVが1,000万円以上あり、1年以内に投資回収できるため、優先的に実行すべきです。