1/10回で起こるバグの改修試験は何回すべきか統計学で考える

Pocket

僕「10回試行で1回発生するバグを改修した」
鬼「改修の効果を、繰り返し試験をして確認しなさい」
僕「10回試行して一度も現象が起きないことを確認した」

システム開発の現場で、経験あると思います!!

しかし、上記の確認方法では、改修できていなかったとしても35%の確率で事象は発生しないため、無意味な対応でシステムをリリースしかねません。また、確率的に発生するバグなので、何回試験しようが「<たまたま>今回は発生しなかったのでは?」と言われかねません。

では、「発生しないことの確認」とは、いったい何回試験すればよいのでしょうか?

本記事では、この考え方について簡単に書いていきます。

1/nの確率の事象をn回試行すると37%で一度も発生しない

よくあるn回試行で1回発生するバグ。改修確認はn回同じ試験をして起きないことを確認していませんか?
イントロで上げた例がまさにそれです。

実は改修対応が無意味で、発生確率に変化がないと仮定した時、10回試行でバグが発生しない確率を計算すると

1回の試行でバグる確率 1/10 = 0.1
1回の試行でバグらない確率 1 - 0.1= 0.9
10回の試行でバグらない確率  0.9^{10} = 0.35

となります。

これを一般化すると、n回試行したとき、一回も発生しない確率p
p=\left(1-\frac{1}{n}\right)^n
解りづらいので、横軸試行回数、縦軸発生しない確率でグラフにしました。

試行数nを大きくしていくと、ある値に収束していくことが見てとれます。この収束先が、0.37となります。

数学的な証明は本筋から外れる(眠くなる)ので省略しますが、n回試験程度では3回に1回は発生せず、無駄な試験になりかねないことがわかりますね。

何回改修試験すればいいのか?

結論から書くと、バグ発生確率pとしたとき、\frac{\ln(0.01)}{\ln(1-p)}回試験すればよいです。

lnという記号に馴染みがないかもしれませんが、自然対数記号であり、意味を知らなくてもWebブラウザ(Google Chrome等)で「ln(0.01) / ln(1 – p)」で検索すると計算してくれます。

例えば、発生確率0.1(1/10)のバグであるなら、「ln(0.01) / ln(1 – 0.1)」を検索すると「43.7」が得られます。

よって、「44回試験し、発生しないことを確認出来たら、10回に1回発生するバグを改修できた。」と判断してよいことになります。

式の根拠

式の根拠を解説しておきます。

統計学に「検定」という事象の確認方法があります。これを応用します。検定は、仮説をたて、実験した結果から確率的に仮説は棄却できる。と判断する道具です。

今回だと、以下のプロセスになります。

    1. 仮説を立てる
      • 帰無仮説「バグは治っていない」
      • 対立仮説「バグは治っている」
    2. 実験する
      • N回繰り返し試験を行い、1回も事象は発生しないことを確認する
    3. 検定する
      • 実験結果から「確率的にあり得ない」ことを示し、帰無仮説を棄却します。これにより、対立仮説「バグは治っている」を正とできます。

検定では「確率的にあり得ない」の基準を自由に決められますが、「95%あり得ない」、「99%あり得ない」を指標にすることが多いです。厳密性を問う改修試験であれば「99%あり得ない」で良いですが、試験手順が面倒など、工数から妥協できる確率で行ってよいかと思います。

よって、発生する確率p、試行回数Nとし、「99%ありえない」を式にすると、
1 - (1-p)^N > 0.99
両辺対数を取り、整理することで試験回数Nを確定できます。
N > \frac{\ln(0.01)}{\ln(1-p)}
きれいな式ではないですが、上記の手順から公式を導けました。

余談

せっかく統計検定2級をとったので、「システムエンジニアが現場で使える統計学」として、今回執筆してみました。

ほかにも、「10回に1回起こったバグの発生確率は10%ではない」「事象から真のバグ発生確率はどう求めるのか?」「チームメンバの日々の勤務時間からわかること」などなど話のネタがあるので、また機会があれば書いてみたいですね。

お問い合わせ先

執筆者プロフィール

Tominaga Kazuki
Tominaga Kazukitdi 西日本製造システム部
ヤフー知恵袋の「Java」「Android開発」「アプリ開発」カテゴリのマスターです。2年前くらいは「大学数学」カテゴリもマスターで、主に統計学の回答してました。今は人工知能がマイブーム
Pocket