注目イベント!
春の新人向け連載2025開催中!
今年も春の新人向け連載が始動しました!!
現場で役立つ考え方やTipsを丁寧に解説、今日から学びのペースを整えよう。
詳細はこちらから!
event banner

統計の話をしようじゃないか - ソフトウェア品質のための統計入門(No.15 統計的品質管理(SQC)の実践事例紹介)

| 12 min read
Author: shuichi-takatsu shuichi-takatsuの画像

はじめに:いよいよ品質分析の集大成へ

#

「不具合がなぜ減らないのか?」「このプロセスは本当に安定しているのか?」
――そんな問いに、あなたは統計で答えられますか?

ここまで、ソフトウェア品質をテーマに、統計的な視点から多くの分析手法を学んできました。
そしていよいよ「統計の話をしようじゃないか」第15回、本シリーズの集大成として登場するのが、統計的品質管理(SQC: Statistical Quality Control) です。

SQCとは、統計手法を活用してプロセスや成果物の品質を「見える化」し、継続的に改善する枠組みです。
製造業だけでなく、ソフトウェア開発・テストの現場でも、バグの傾向分析プロセスの安定性確認に大いに役立ちます。

「品質は偶然ではなく、管理されるべきものである」—— そんな考え方を、SQCは強力に支えてくれます。
本章では、これまで学んできた知識を土台に、実際のソフトウェア品質管理にどう適用できるのかを、具体例を交えて解説していきます。


実務で使えるSQCの主な指標

#

「品質を可視化する」とは、具体的にはどういうことか?
それは、現場の状態を定量的に把握できる“指標(メトリクス)”を持つことに他なりません。
属人的な感覚や経験値に頼るのではなく、データに基づいて判断できる道具が必要なのです。

ここでは、ソフトウェア品質の管理において実際によく用いられる、SQCの代表的な指標を紹介します。
いずれも「品質を数値で語る」ための武器となるものばかりです。

指標 用途例
バグ密度 品質の定量的評価(KLOCあたりの不具合数など)
レビュー指摘率 レビューの網羅性・効果の確認
欠陥分布(Pareto) 不具合原因の集中箇所の把握
仮説検定(t検定など) 品質改善施策やレビュー改善の効果の有無を統計的に検証する
回帰分析(単回帰など) テスト工数やレビュー対象規模と成果の関係性を分析し、改善や設計の妥当性を定量的に把握する

指標は、ただ報告するための数値ではなく、「気づき」と「行動」を引き出すためのヒントであるべきです。


ケース1:バグ密度と納品判断

#

● 背景:

#

あるプロジェクト(PJ)において、最終リリースの可否を判断するための品質基準として、「不具合密度(バグ数/KLOC)」を導入しました。
これは単なるバグ件数ではなく、ソースコードの規模を考慮した指標であるため、プロジェクトごとの比較や、過去実績との対照がしやすいという利点があります。

● 対応:

#
  • 過去プロジェクトの平均バグ密度とその標準偏差(σ) を収集し、比較基準とした
  • 対象PJの不具合密度が「平均+3σ」以上の場合、統計的に異常なレベルの不具合発生とみなし、
    • 品質リスクありと判断
    • 追加レビューや重点確認を実施して、リリースの判断を再検討

● ポイント:

#
  • KLOCあたりのバグ数という正規化指標により、大規模/小規模PJ間でも比較が可能です。
  • 3σルールの活用により、客観的かつ説明可能な判断ができます。
  • この手法は、「納品判定の属人化」から脱却し、品質基準を定量的に運用する文化の第一歩となります。

数値で語る品質判断は、プロジェクトメンバー全体の納得感と意思決定の透明性を高める鍵になります。

● 例:バグ密度による納品判断ロジック(Python)

#

以下は、過去プロジェクトのバグ密度と現在プロジェクトのバグ密度を比較し、「平均+3σルール」により統計的に異常な値かどうかを判定するPythonコードです。

import numpy as np

import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'Meiryo'

# 過去プロジェクトのバグ密度(バグ数/KLOC)サンプルデータ
past_defect_densities = np.array([12.5, 15.0, 11.8, 14.3, 13.2, 16.1, 12.9])

# 現在のプロジェクトの不具合密度
current_density = 23.7  # ←ここを変えれば他のプロジェクトもチェック可能

# 平均と標準偏差を計算
mean = np.mean(past_defect_densities)
std_dev = np.std(past_defect_densities, ddof=1)  # 母集団ではなく標本として計算

# しきい値 = 平均 + 3σ
threshold = mean + 3 * std_dev

# 判定
print(f"過去平均: {mean:.2f}, 標準偏差: {std_dev:.2f}, しきい値: {threshold:.2f}")
print(f"現在プロジェクトの不具合密度: {current_density:.2f}")

if current_density > threshold:
    print("△:品質リスクあり:追加レビューを検討してください。")
else:
    print("〇:品質リスクは低いと判断されます。")

結果は以下のようになりました。

過去平均: 13.69, 標準偏差: 1.51, しきい値: 18.23
現在プロジェクトの不具合密度: 23.70
△:品質リスクあり:追加レビューを検討してください。

● 統計手法の解説

#

1. バグ密度(不具合密度)の算出

  • 定義

    バグ密度=バグ数KLOC(千行あたりのコード行数)\text{バグ密度} = \frac{\text{バグ数}}{\text{KLOC(千行あたりのコード行数)}}

  • 役割:ソフトウェアの品質をコード規模で正規化した指標。プロジェクト間での比較が可能。

2. 基本統計量の利用(平均・標準偏差)

  • 平均(Mean):過去の実績値の「中心的傾向」を把握。
  • 標準偏差(Standard Deviation):バグ密度のばらつき具合(=品質の安定性)を評価。
  • 使用目的:現在のプロジェクトが「過去の通常範囲」に収まっているかを判断する。

3. 3σルール(正規分布に基づく外れ値検出)

  • 考え方
    • 正規分布を仮定した場合、データの約99.7%は「平均 ± 3σ」の範囲に収まる。
    • それを超えるデータは「統計的に異常」と判断する。
  • 実務的解釈
    • 平均+3σを超えるバグ密度 → 品質リスクが高い状態と判断し、追加レビューなどの対処を行う。

4. 外れ値検出と意思決定支援

  • この手法は、数理的根拠に基づいてリスクを定量化し、属人的な判断ではなく、客観的な基準で品質判断を下すためのものです。

● ケース1のまとめ

#

このケースでは「バグ密度」という実務指標に対して、記述統計(平均・標準偏差)+3σルールを組み合わせることで、プロセスの安定性評価とリリース判断支援を実現しています。
SQC(統計的品質管理)の基本中の基本とも言えるアプローチです。


ケース2:レビュー指摘率の分析

#

● 背景:

#

コードレビューは実施されているのに、後工程で多くのバグが見つかっていた。
「レビューをしたはずなのに、なぜバグが取りこぼされているのか?」という疑問から調査を開始。

● 対応:

#
  • ファイル単位で「レビュー指摘件数」と「レビュー実施件数」の比率(=レビュー指摘率)を可視化
  • その結果、特定の領域で極端にレビュー指摘率が低いことが判明
  • 該当領域は「レビューを実施したことになっているが、実質的には形式的なレビュー」であると推定
  • 対象箇所に対して、レビュー体制の見直し(レビュー観点の明文化、ペアレビュー導入など) を実施

● ポイント:

#
  • 形式的なレビューを可視化し、実効性を問えるのがレビュー指摘率の強みです。
  • 極端なゼロ指摘や偏りのある傾向を検出することで、見えない品質リスクの兆候をあぶり出せます。

● 例:レビュー指摘率の可視化(Python)

#

以下は、各モジュールごとのレビュー件数と指摘件数から「レビュー指摘率」を算出し、棒グラフで可視化するPythonコードの例です。

import matplotlib.pyplot as plt
import numpy as np

# 日本語フォント(Windows環境)
plt.rcParams['font.family'] = 'Meiryo'

# 各モジュールのレビュー実施数と指摘件数
modules = ['ModuleA', 'ModuleB', 'ModuleC', 'ModuleD', 'ModuleE']
review_counts = np.array([10, 12, 9, 15, 13])       # レビュー実施数
defect_counts = np.array([4, 0, 5, 1, 6])           # 指摘件数

# 指摘率を計算(0割りを避ける)
with np.errstate(divide='ignore', invalid='ignore'):
    review_rates = np.where(review_counts > 0, defect_counts / review_counts, 0)

# 棒グラフで可視化
plt.figure(figsize=(8, 5))
bars = plt.bar(modules, review_rates, color='skyblue')
plt.ylabel('レビュー指摘率')
plt.ylim(0, 1.0)
plt.title('モジュール別レビュー指摘率')

# 値を上に表示
for bar, rate in zip(bars, review_rates):
    plt.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 0.02,
             f'{rate:.2f}', ha='center')

plt.grid(axis='y', linestyle='--', alpha=0.7)
plt.tight_layout()
plt.show()

結果は以下のようになりました。

  • ModuleB はレビュー12件に対し指摘0件 → 形式的レビューの可能性
  • ModuleD も低指摘率(1/15) → 観点不足やレビュワー熟練度の影響が考えられる

こうした可視化により、問題のあるレビュー領域を定量的に抽出し、ピンポイントでのプロセス改善につなげることが可能になります。

● 統計手法の解説

#
  1. 比率指標(レビュー指摘率)

    • 指摘率 = 指摘件数 ÷ レビュー件数
    • レビューの“質”を測るための代表的なプロセスメトリクス
  2. 視覚的異常値検出(EDAの一部)

    • 極端なゼロやばらつきを棒グラフで可視化し、形式化・形骸化レビューの兆候を発見
  3. 実務的な定量改善サイクルの導入

    • 「なぜ指摘が少ないのか?」を起点に、レビューの目的・方法・観点の改善につなげる

● ケース2のまとめ

#

このケースは、指摘件数ではなく“率”を使うことでレビューの質を可視化し、「形式的レビュー」という見えにくい課題をデータで浮かび上がらせた事例です。
高度な統計分析ではないが、実務に直結するSQCの基本的なアプローチです。


ケース3:欠陥分布(Pareto分析)での重点管理

#

● 背景:

#

不具合が多発していたが、どこから手をつけるべきかの優先度が曖昧だった。
「すべてに手を打つ」にはリソースが足りず、改善の効果が上がらないという課題があった。

● 対応:

#
  • 不具合の原因カテゴリ別・モジュール別に件数を集計
  • パレート図を作成し、上位20%の原因が全体の80%近くを占めていることを確認
  • 上位原因に対して優先的に改善活動(教育・レビュー重点化・設計改善)を実施

● ポイント:

#
  • 「全部はできない」現場において、限られたリソースをどこに投下すべきかを見える化する手法です。
  • 数字に基づいて改善の“重点化”ができるため、現場での説明力・納得感が高いです。
  • 実際の改善成果が出やすく、「SQCの成果」が可視化されやすい代表的なアプローチです。

● 例:欠陥カテゴリ別のパレート図作成(Python)

#
import matplotlib.pyplot as plt
import numpy as np

# 日本語フォント設定(Windows環境向け)
plt.rcParams['font.family'] = 'Meiryo'

# 不具合カテゴリと件数(例)
categories = ['仕様漏れ', '設計ミス', 'コーディングミス', 'レビュー不足', 'テスト漏れ']
counts = np.array([35, 25, 20, 10, 5])

# 件数で降順に並べ替え
sorted_idx = np.argsort(counts)[::-1]
sorted_categories = np.array(categories)[sorted_idx]
sorted_counts = counts[sorted_idx]

# 累積比率の計算
cumulative = np.cumsum(sorted_counts)
cumulative_percent = cumulative / cumulative[-1] * 100

# グラフ描画
fig, ax1 = plt.subplots()

ax1.bar(sorted_categories, sorted_counts, color='skyblue', label='不具合件数')
ax1.set_ylabel('不具合件数')
ax1.set_ylim(0, max(sorted_counts)*1.2)

ax2 = ax1.twinx()
ax2.plot(sorted_categories, cumulative_percent, color='red', marker='o', label='累積比率(%)')
ax2.set_ylabel('累積比率(%)')
ax2.set_ylim(0, 110)

plt.title('不具合カテゴリ別 パレート図')
fig.tight_layout()
plt.grid(True, axis='y', linestyle='--', alpha=0.6)
plt.show()

結果は以下のようになりました。

● 統計手法の解説

#

1. パレート分析(Pareto Analysis)

  • 80:20ルールに基づき、「少数の原因が大多数の結果を生む」現象を可視化
  • 棒グラフ(個別値)+折れ線グラフ(累積比率)の組み合わせ

2. 項目の優先度設定

  • 単に件数が多い順ではなく、「影響度」「頻度」なども考慮可能
  • 改善の“重点化”が数値根拠を持って実施できる

3. SQCにおける改善意思決定支援

  • パレート図は改善活動の説得力・優先度を説明するための可視化ツールとして非常に有効

● ケース3のまとめ

#

このケースは、「どこにリソースを集中すべきか」をデータで示すSQCの代表的活用例です。
限られた時間・人員・コストの中で最大効果を得るための“重点管理”に役立ちます。


ケース4:レビュー改善施策の効果検証

#

● 背景:

#

レビュー観点の強化施策(チェックリスト導入、観点の明文化など)を実施したが、「実際にレビューの質(指摘件数)は向上したのか?」という効果検証が求められた。

● 対応:

#
  • t検定による平均の差の検定
  • レビュー改善施策「実施前」と「実施後」のレビュー指摘件数データを収集
  • それぞれのグループにおける平均指摘数に差があるかを t検定(対応のない2群の検定) によって評価
  • 統計的に有意な差があれば、「施策に効果あり」と判断

● ポイント:

#
  • 「施策の成果があったかどうか」を感覚ではなくデータで判断できます。
  • 検定は、品質改善の意思決定に統計的根拠を与える最も直接的な手段です。
  • 帰無仮説と対立仮説、p値、有意水準など、統計の本質概念が詰まっています。

● 例:レビュー改善施策前後の効果検証(Python)

#
import numpy as np
from scipy import stats

# 日本語フォント(Windows環境)
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'Meiryo'

# 改善前のレビュー指摘件数(例:1レビューあたりの指摘数)
before = np.array([2, 3, 1, 2, 3, 2, 1])

# 改善後のレビュー指摘件数
after = np.array([4, 5, 3, 4, 5, 6, 4])

# t検定(等分散を仮定しない Welchのt検定)
t_stat, p_value = stats.ttest_ind(after, before, equal_var=False)

print(f"t値: {t_stat:.2f}")
print(f"p値: {p_value:.4f}")

# 結果の判定
alpha = 0.05
if p_value < alpha:
    print("〇 有意差あり:施策は統計的に効果があったと判断されます。")
else:
    print("△ 有意差なし:施策の効果は統計的には確認できません。")

結果は以下のようになりました。

t値: 5.05
p値: 0.0003
〇 有意差あり:施策は統計的に効果があったと判断されます。

● 統計手法の解説

#

1. 仮説検定(t検定)

  • 帰無仮説 H0H_0:「改善前と後の指摘件数の平均に差はない」
  • 対立仮説 H1H_1:「平均に差がある」
  • t値とp値を算出し、有意水準5%(p < 0.05)で差があるかを判断

2. Welchのt検定

  • 母分散が異なることを想定して、等分散を仮定しないt検定を使用
  • 実務では標本サイズが小さいことも多く、Welch法が汎用的

3. 意思決定支援

  • 検定結果が「改善活動の有効性」を数値的に説明する根拠になる
  • SQCにおける「品質変化の検出」に直結する

● ケース4のまとめ

#

このケースは、「施策に意味があったのか?」という問いに、統計的根拠をもって答える事例です。
検定は、SQCの“判断の瞬間”を支える技術として、締めくくりにふさわしいアプローチです。


ケース5:レビュー規模と指摘件数の関係分析

#

● 背景:

#

レビューの対象行数が多いほど、指摘件数も増えるのではないか?という仮説を検証する。
レビュー負荷に見合った成果が出ているかを確認し、レビュー設計や観点の最適化につなげることが目的。

● 対応:

#
  • 過去のレビュー記録から「対象行数(SLOC)」と「指摘件数」のデータを収集
  • 単回帰分析により、レビュー対象規模と指摘件数の関係をモデル化
  • 相関の強さ・回帰式の傾きを確認し、妥当なレビュー粒度を検討

● ポイント:

#
  • 「たくさん見れば、たくさん見つかるのか?」というレビューの質と量のバランスを検証
  • 回帰係数から、レビュー効果の“期待値” を定量的に得られる
  • 想定よりも指摘が少ない場合、レビュー観点の漏れや形式化の兆候も疑える

● 例:レビュー規模と指摘件数の回帰分析(Python)

#
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression

plt.rcParams['font.family'] = 'Meiryo'

# レビュー対象行数(SLOC)と指摘件数のデータ
x = np.array([100, 200, 300, 400, 500]).reshape(-1, 1)
y = np.array([2, 4, 6, 7, 8])

# 回帰分析
model = LinearRegression()
model.fit(x, y)

# 回帰係数・切片
a = model.coef_[0]
b = model.intercept_
print(f"回帰式:指摘件数 = {a:.2f} × 行数 + {b:.2f}")

# 可視化
x_pred = np.linspace(50, 600, 100).reshape(-1, 1)
y_pred = model.predict(x_pred)

plt.scatter(x, y, color='blue', label='実測データ')
plt.plot(x_pred, y_pred, color='red', label='回帰直線')
plt.xlabel('レビュー対象行数(SLOC)')
plt.ylabel('指摘件数')
plt.title('レビュー規模と指摘件数の関係')
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

結果は以下のようになりました。

● 統計手法の解説

#

1. 単回帰分析

  • 説明変数:レビュー対象行数(SLOC)
  • 目的変数:指摘件数
  • 回帰直線:y=ax+by = ax + b を推定して予測や比較に活用

2. 回帰係数の意味

  • 係数が大きければ、「行数が増えるほど指摘が増える」=指摘の密度が一定
  • 係数が小さければ、増加しても指摘が増えない → レビューの形骸化が疑われる

3. モデル評価と残差

  • R2R^2 や残差プロットにより、モデルの当てはまりを確認し、説明力やパターンの偏りを評価

以下はモデル評価と残差分析(Pythonによる可視化)です。

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score

plt.rcParams['font.family'] = 'Meiryo'

# データ
x = np.array([100, 200, 300, 400, 500]).reshape(-1, 1)
y = np.array([2, 4, 6, 7, 8])

# モデル学習
model = LinearRegression()
model.fit(x, y)

# 予測と決定係数
y_pred = model.predict(x)
r2 = r2_score(y, y_pred)
print(f"決定係数 R^2 = {r2:.3f}")

# 残差の計算
residuals = y - y_pred

# 残差プロット
plt.figure(figsize=(6, 4))
plt.scatter(y_pred, residuals, color='purple')
plt.axhline(0, color='red', linestyle='--')
plt.xlabel('予測値(指摘件数)')
plt.ylabel('残差(実測値 - 予測値)')
plt.title('残差プロット(レビュー行数と指摘件数)')
plt.grid(True)
plt.tight_layout()
plt.show()


回帰モデルの 決定係数 R2R^2 を計算し、残差プロットを描画しました。

決定係数 R2=0.970R^2 = 0.970 から、レビュー行数が指摘件数をよく説明できる関係にあるとわかります。
残差はランダムに分布しており、線形回帰モデルの妥当性も高いと判断できます。
この結果は、レビューの規模と成果の関係を予測する上で、実務的に信頼できる根拠となります。

● ケース5のまとめ

#

このケースでは、レビュー対象の規模と成果(指摘数)の関係を回帰分析により可視化し、レビュー活動の最適化やレビュー体制の検証に活かすための根拠を得ました。
品質活動の“量”と“成果”の関係に踏み込む視点として、非常に実務的なアプローチです。


SQC導入のポイント(統計は難しくなくていい)

#
  • 単なる数値報告で終わらせず、「変化」や「逸脱」を発見し、気づきにつなげることがSQCの本質です。
    たとえ複雑な数式やモデルを使わなくても、簡単な棒グラフ・パレート図・指標の時系列推移などの可視化だけでも、十分な実践的効果があります。

  • 実際に本シリーズで扱った事例も、多くは「比率」「密度」「差の検定」など、基本的な記述統計+シンプルな手法で構成されています。
    難しい理論を使わなくても、「気づける」「判断できる」「説明できる」ことこそが重要なのです。

  • また、個人でSQCを完結させようとしないこともポイントです。
    チーム内での定期的な共有・可視化・レビューの仕組みに組み込むことで、継続的な品質改善の文化が根付きやすくなります。

SQCは“統計の知識”よりも、“観察し、考え、対話する姿勢”の方がはるかに重要です。


本シリーズを終えるにあたって

#

ここまで15回にわたり、「統計の話をしようじゃないか」シリーズをご覧いただきありがとうございました。
本シリーズでは、ソフトウェア品質の現場において“統計がどう役立つのか” をテーマに、基本的な統計手法から実践事例までを紹介してきました。
単なる理論解説にとどまらず、品質を「見える化」し、改善に結びつけるための考え方と技法を学んでいただけたなら幸いです。

統計は、難しい数式よりも「観察・気づき・対話」のための道具です。

今回でシリーズはいったんの区切りとなりますが、今後も実務や教育で役立つ統計・品質管理の話題を、必要に応じて番外編として発信していく予定です。
ぜひ、みなさん自身の現場で、統計を使って品質を語る文化を広げていってください。

こちらに統計関連情報をまとめています。

データ分析にご活用いただければ幸いです。

豆蔵では共に高め合う仲間を募集しています!

recruit

具体的な採用情報はこちらからご覧いただけます。