分散分析というと、その名前自体によく「一元配置」「二元配置」とか「対応あり」「対応なし」とか「繰り返しのある」とか「繰り返しのない」とかいう言葉がついて回る。統計学の書籍でも、「一元配置分散分析」と「二元配置分散分析」は項目を分けて説明されることが多い。さらにそれぞれが「対応あり/なし」「繰り返しあり/なし」等で分けられると、目次に「分散分析」がたくさん並ぶことになる。Excelの「分析ツール」のメニューにも分散分析の項目があるが、
- 分散分析: 一元配置
- 分散分析: 繰り返しのある二元配置
- 分散分析: 繰り返しのない二元配置
筆者は未だに、どういう時にどの種類の分散分析を使うべきなのかよくわかっていない。 頭の中を整理するために、いつものように体当たり的に、
- 一元配置(対応なし)
- 一元配置(対応あり)
- 二元配置(繰り返しなし)
- 二元配置(繰り返しあり、対応なし)
- 二元配置(繰り返しあり、1要因対応あり)
- 二元配置(繰り返しあり、2要因対応あり)
以下のデータは、全て架空のものである。
筆者はExcelを持っていないので、分散分析の計算にはRを使う。Rにも分散分析の関数はoneway.test(), aov(), anova(), lme()など色々あるが、今回は上記の全てをカバーできるaov()を使う。
最もシンプルな、一元配置(対応なし)の例として、次のようなデータを考える。
要因:モジュールの階層 | |||
---|---|---|---|
アプリ | ミドル | ドライバ | |
生産性 (steps/人月) |
490 410 590 500 460 690 750 500 770 720 730 |
480 650 310 450 530 550 350 |
460 370 610 240 500 |
"Df"が自由度、"module"の行の"Sum Sq"が群間平方和(ここではモジュールの階層の違いによる効果)、"Mean Sq"が群間の不偏分散(モジュールの階層の違いによるばらつきの分散値)、Residuals(残差=群内のばらつき=全体に共通するはずのばらつき)の行のMean Sqが群内(全群共通)の不偏分散、"F value"が(群間/群内)の分散比、"Pr"(P値、そのF値以上が起こる確率)の右の'*'が有意水準0.05で有意であることを表す。> sample1 <- read.table("anova01.dat", header=TRUE) > summary(aov(productivity ~ module, data=sample1)) Df Sum Sq Mean Sq F value Pr(>F) module 2 120939 60470 3.5656 0.04738 * Residuals 20 339182 16959 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 >
分散分析の帰無仮説は「全ての標本は同じ分布に従う母集団から得られたもの」→「各群の分布が同じであること」→「群間にばらつきがないこと」なので、分散比が有意であれば、「全体のばらつきに対して群間にばらつきがないとは言えない」、細かいことを言わなければ、群間にばらつきが認められ、各群の分布は同じでないことになる。
この例では、生産性はモジュールの階層によって違いがありそうということになる。
次の例は、同じ観測値を別の要因(観点)で分けたものである。
要因:所属 | |||
---|---|---|---|
A社 | B社 | C社 | |
生産性 (steps/人月) |
490 410 460 590 500 370 460 690 |
750 480 500 650 770 |
610 310 720 450 530 240 550 350 730 500 |
測定値が同じであることを明確にする為に、データファイルを同じsample1にしている。'*'のマークとその説明が出力されていないので、所属別では群間に有意な差が無く、このデータでは所属によって生産性にばらつきがあるとは言えないことになる。> summary(aov(productivity ~ company, data=sample1)) Df Sum Sq Mean Sq F value Pr(>F) company 2 68444 34222 1.7475 0.1998 Residuals 20 391677 19584 >
もう1つ例を考えた。
要因:仕様書のファイル形式 | ||||
---|---|---|---|---|
.doc | .txt | .xls | .ppt | |
システムテスト 不具合数(/kstep) |
3 10 8 2 2 5 4 4 6 0 11 |
11 7 1 3 |
7 5 10 4 10 11 |
12 5 10 14 11 |
このデータでは、システムテストで見つかったバグ数は、仕様書のファイル形式によって違いがありそうということになる。> sample2 <- read.table("anova02.dat", header=TRUE) > summary(aov(error ~ format, data=sample2)) Df Sum Sq Mean Sq F value Pr(>F) format 3 113.58 37.861 3.1192 0.04672 * Residuals 22 267.03 12.138 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
測定データを一元配置分散分析(対応なし)する時のポイントを整理する。
- 測定値は正規分布することを仮定できるものであること
- 差があることを調べる群は、3群以上あること
(2群しか無いなら、その差をt検定するのと変わらない)
つまり、要因(群の分け方)はその水準(標本が属する群を決めるもの、値やID)が3つ以上あるように選ぶこと - 各水準のデータ数は同じでなくても良い
- 水準はなるべく定量的な数値でないこと、数値であれば、なるべく測定値の従属変数でないことが明確であること
(要因と測定値に明確な関係があっても、群間のばらつきが十分に大きくないと有意差が検出できないため。また、水準(値の範囲)の取り方によって結果が変わってしまうため。例えば測定値と線形の関係にあるなら、無相関の検定をする方が良い)
一元配置(対応あり)の例として、次のようなデータを考える。
各開発者がその4種類の開発プロセス(作業手順)を経験した時の、それぞれの開発プロセスにおける成績が、次のように得られたとする。
生産性 (steps/人月) | 要因:開発プロセス | ||||
---|---|---|---|---|---|
Waterfall | Spiral | Incremental | TDD | ||
対 応 要 因 |
開発者A | 490 | 750 | 450 | 610 |
開発者B | 410 | 480 | 530 | 780 | |
開発者C | 460 | 500 | 240 | 680 | |
開発者D | 590 | 650 | 550 | 880 | |
開発者E | 500 | 770 | 350 | 520 | |
開発者F | 370 | 610 | 730 | 600 | |
開発者G | 460 | 310 | 500 | 400 | |
開発者H | 690 | 720 | 640 | 1030 |
開発者の能力や向き不向きには個人差があることを前提とし、それを計算に入れて、開発プロセスは生産性に影響するかどうかを、分散分析で調べる。
"Error: developer"の部分は開発者の個人差による(開発者の違いを誤差要因とする)ばらつきに関するものであり、以降の計算はそれが除外されていることを示す。"Error: Within"の部分が、群内変動を誤差と見なして群間変動を検定するものである。> sample3 <- read.table("anova03.dat", header=TRUE) > summary(aov(productivity ~ process + Error(developer), data=sample3)) Error: developer Df Sum Sq Mean Sq F value Pr(>F) Residuals 7 337872 48267 Error: Within Df Sum Sq Mean Sq F value Pr(>F) process 3 201184 67061 3.8348 0.02464 * Residuals 21 367241 17488 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
このデータでは、個人差の影響を差し引くと、開発プロセスは生産性に影響する要因と言えることになる。
もし、同じデータを「対応なし」として計算する(開発者の個人差を差し引かない)と、次のように、開発プロセス間に同じ有意差が出ない。
実際には各開発プロセスを短期間に経験することは難しく、開発者の経年変化や学習効果もあるので、こういうデータは取りにくいが、例えば開発者がソフトハウスのことであり、ソフトハウス内ではばらつきが無いと仮定すれば、各プロセスを同時に行うことも可能であるし、何より、筆者がこれ以上単純明快な例を思い付かないので、これで良しとする。> summary(aov(productivity ~ process, data=sample3)) Df Sum Sq Mean Sq F value Pr(>F) process 3 201184 67061 2.663 0.06729 . Residuals 28 705112 25183 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
次の例は、会社による差(観測対象の個体差)はあるものとして、業務分野の違いが生産性に影響すると言えるかどうかを調べる。
生産性 (steps/人月) | 要因:開発分野 | ||||
---|---|---|---|---|---|
組み込み | 汎用 | 業務システム | ゲーム | ||
対 応 要 因 |
M社 | 330 | 470 | 450 | 320 |
N社 | 290 | 440 | 370 | 630 | |
O社 | 450 | 550 | 580 | 750 | |
P社 | 320 | 360 | 470 | 460 | |
Q社 | 370 | 320 | 430 | 480 |
1つ目のaov()が会社間に「対応あり」として計算した例、2つ目のaov()が「対応なし」として計算した例である。このデータだと、会社間の個体差を考慮に入れると、開発分野は生産性に影響する要因だったと言えることになる。> sample4 <- read.table("anova04.dat", header=TRUE) > summary(aov(performance ~ product + Error(company), data=sample4)) Error: company Df Sum Sq Mean Sq F value Pr(>F) Residuals 4 102420 25605 Error: Within Df Sum Sq Mean Sq F value Pr(>F) product 3 80080 26693.3 4.0332 0.03379 * Residuals 12 79420 6618.3 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 summary(aov(performance ~ product, data=sample4)) Df Sum Sq Mean Sq F value Pr(>F) product 3 80080 26693 2.3487 0.1111 Residuals 16 181840 11365
測定データを一元配置(対応あり)にする時のポイントを整理する。
- 群内の各測定値が、どの個体から得られた標本であるか(または、誤差要因のどの水準に属する標本であるか)がわかること
- 個体差によるばらつきはあるものとし、差し引いて考えるものであること
- 個体に有意差があるかどうかを調べる必要は無いこと
- 一部のデータが抜けていても計算可能
- 同水準、同個体のデータは1つでなく複数あっても計算可能(但し全てのセルのデータ数が同じであることが望ましい)
二元配置(繰り返しなし)の例として、次のようなデータを考える。
生産性 (steps/人月) | 要因1:開発プロセス | ||||
---|---|---|---|---|---|
Waterfall | Spiral | Incremental | TDD | ||
要因2: 座席の形態 | 大部屋 | 490 | 700 | 450 | 560 |
自由席 | 410 | 430 | 530 | 730 | |
パーティション | 460 | 450 | 240 | 630 | |
小部屋 | 590 | 720 | 550 | 830 | |
自宅 | 500 | 600 | 350 | 470 |
よって、このデータでは、開発プロセスの違いによる効果は有意水準0.05で有意差あり、作業空間の違いによる効果は有意差なし(有意水準が0.1だと有意差あり)となる。> sample5 <- read.table("anova05.dat", header=TRUE) > summary(aov(productivity ~ process + workspace, data=sample5)) Df Sum Sq Mean Sq F value Pr(>F) process 3 141255 47085 4.8533 0.01951 * workspace 4 121420 30355 3.1288 0.05589 . Residuals 12 116420 9702 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
ちなみに、開発プロセスと作業空間についてそれぞれ、同じデータを一元配置とみなして計算すると、次のように、同じ水準の有意差は出ない。
このデータの特徴は、全体のばらつきを、2つの要因のばらつきと共通のばらつきの3つに分解するからこそ、明確になるのである。> summary(aov(productivity ~ process, data=sample5)) Df Sum Sq Mean Sq F value Pr(>F) process 3 141255 47085 3.1675 0.05318 . Residuals 16 237840 14865 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 > summary(aov(productivity ~ workspace, data=sample5)) Df Sum Sq Mean Sq F value Pr(>F) workspace 4 121420 30355 1.7671 0.188 Residuals 15 257675 17178
次の例は、何らかの開発成果物の欠陥数を、作業期間と納入した曜日との組み合わせのそれぞれについて1つずつ、データを採取したとするものである。
欠陥数 /kstep |
要因1:開発期間 | |||
---|---|---|---|---|
1週間 | 2週間 | 1ヶ月 | ||
要因2: 曜日 | 月曜 | 10 | 6 | 4 |
火曜 | 6 | 9 | 6 | |
水曜 | 8 | 6 | 4 | |
木曜 | 4 | 9 | 4 | |
金曜 | 8 | 6 | 4 | |
土曜 | 10 | 9 | 9 | |
日曜 | N/A | 6 | 9 |
よって、このデータでは、開発期間の違いによる差も考慮すると、納品日の曜日によって有意水準0.05で有意な差があるという結果になる。> sample6 <- read.table("anova06.dat", header=TRUE) > summary(aov(error ~ time_limit + delivery, data=sample6)) Df Sum Sq Mean Sq F value Pr(>F) time_limit 2 14.360 7.1798 2.8898 0.09803 . delivery 6 48.861 8.1435 3.2777 0.04224 * Residuals 11 27.329 2.4845 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 1 observation deleted due to missingness > summary(aov(error ~ delivery, data=sample6)) Df Sum Sq Mean Sq F value Pr(>F) delivery 6 51.217 8.5361 2.8213 0.05523 . Residuals 13 39.333 3.0256 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 1 observation deleted due to missingness
2つ目のaov()は、上の例と同様、一元配置では同じ有意差が出ないことを確認したものである。
二元配置(繰り返しなし)にする時のポイントを整理する。
- 2つの要因の全ての水準の組み合わせについて、データは1つ
- どちらの要因も何らか影響していると思われ、それぞれの影響を分離して調べようとしていること
- 一部のデータが抜けていても計算可能
- 一元配置(対応あり、繰り返しなし)の代用として行うことも可能
Excelの分析ツールに「対応のある一元配置」が無いのは、二元配置で代用できるからだろう。
二元配置(繰り返しあり、対応なし)は、表の形としては、繰り返しのない二元配置の各セルに複数のデータが含まれるだけの違いなので、同じような要因のペアが使える。
生産性 (steps/人月) | 要因1:開発プロセス | ||||
---|---|---|---|---|---|
Waterfall | Spiral | Incremental | TDD | ||
要因2: 座席の形態 | 大部屋 | 570 660 450 |
710 480 570 |
570 450 620 |
520 540 740 |
自由席 | 570 500 270 |
590 460 670 |
510 450 410 |
620 350 350 |
|
パーティション | 300 480 580 |
670 500 710 |
610 540 540 |
430 650 600 |
|
小部屋 | 510 530 530 |
660 620 510 |
310 550 780 |
760 400 590 |
|
自宅 | 510 560 530 |
570 750 590 |
400 380 520 |
600 610 580 |
交互作用とは、2要因の水準の特定の組み合わせにだけに影響する効果のことで、例えばその行とその列は大体高い値なのにそのセルだけやたら低い値が多いということを起こす要因である。
aov()で交互作用を分離して分散分析するには、引数において2つの要因を'*'で繋ぐ。
"process:workspace"の行が交互作用に関する行で、このデータでは有意差は出なかった。また、交互作用を分離すると、開発プロセスにも作業空間にも有意水準0.05の有意差はなしである。> sample7 <- read.table("anova07.dat", header=TRUE) > summary(aov(productivity ~ process * workspace, data=sample7)); Df Sum Sq Mean Sq F value Pr(>F) process 3 98952 32984 2.4676 0.07599 . workspace 4 65823 16456 1.2311 0.31308 process:workspace 12 69657 5805 0.4343 0.93963 Residuals 40 534667 13367 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
交互作用を分離せずに計算するには、aov()の引数において、2つの要因を'+'で繋ぐ。
このデータでは、交互作用を分離しなければ、開発プロセスには有意差が認められる(交互作用の効果を分離しない方が有意差が出る)ことがわかる。> summary(aov(productivity ~ process + workspace, data=sample7)); Df Sum Sq Mean Sq F value Pr(>F) process 3 98952 32984 2.8382 0.04686 * workspace 4 65823 16456 1.4160 0.24170 Residuals 52 604323 11622 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
ちなみに、繰り返しがないと、'+'でも'*'でも結果は変わらない。
もう1つ例を作る。
結合テストエラー数 /kstep |
要因1:仕様書の配布形態 | ||||
---|---|---|---|---|---|
Word | Excel | HTML | |||
要因2: 設計書の フォーマット | Word | 8 6 2 1 7 |
5 7 3 9 10 |
4 11 5 6 3 |
11 7 14 7 9 |
Excel | 11 5 8 13 8 |
4 10 6 3 6 |
5 9 13 6 10 |
17 12 11 5 10 |
|
Text | 5 6 6 10 11 |
6 12 7 9 8 |
5 12 8 9 6 |
9 8 13 11 3 |
|
HTML | 12 14 7 13 12 |
10 15 6 13 13 |
12 7 5 13 7 |
4 10 3 8 9 |
1つ目のaov()の結果より、このデータでは仕様書のフォーマットが欠陥数に影響しており、また設計書のフォーマットとの交互作用もある結果となった。 2つ目のaov()の結果は、交互作用を分離しないと、仕様書のフォーマットについても同じ有意差は出ない(1つ前のデータ例とは逆に、交互作用を分離する方が有意差が出る)ことを示している。> sample8 <- read.table("anova08.dat", header=TRUE) > summary(aov(error ~ given_spec * design_desc, data=sample8)) Df Sum Sq Mean Sq F value Pr(>F) given_spec 3 86.5 28.8333 2.9254 0.04043 * design_desc 3 17.1 5.7000 0.5783 0.63137 given_spec:design_desc 9 198.4 22.0444 2.2366 0.03056 * Residuals 64 630.8 9.8562 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 > summary(aov(error ~ given_spec + design_desc, data=sample8)) Df Sum Sq Mean Sq F value Pr(>F) given_spec 3 86.5 28.833 2.5384 0.06314 . design_desc 3 17.1 5.700 0.5018 0.68221 Residuals 73 829.2 11.359 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
二元配置(繰り返しあり、対応なし)にする時のポイントを整理する。
- 2つの要因の全ての水準の組み合わせについて、複数のデータがある
- それにより、2つの要因の交互作用が混入する
- 交互作用によるばらつきを分離して計算するかどうかは場合による
- 一元配置(対応あり、繰り返しあり)の代用として行うことも可能
「二元配置(1要因対応あり)」は、「対応のある要因と対応のない要因の二元配置」と書かれることが多いようだが、そう書かれると余計にややこしく見えるのは、筆者だけだろうか。
「対応あり」とは、一元配置の場合と同様、繰り返しのある(セル内に複数ある)データのそれぞれが、他の水準(セル)のどのデータに対応するかがわかる、という意味であり、対応を取るからには、個体差の影響を取り除いて計算する必要があると考えていることになる。
1要因についてのみ対応が取れる状況として、次のような例を考える。
生産性 (steps/人月) | 要因1:開発プロセス | |||||
---|---|---|---|---|---|---|
Waterfall | Spiral | Incremental | TDD | |||
要因2: 座席の形態 + 人 | 作業場 | 開発者 | ||||
大部屋 | A | 630 | 660 | 570 | 340 | |
B | 530 | 430 | 430 | 400 | ||
C | 390 | 640 | 520 | 530 | ||
パーティション | D | 400 | 760 | 500 | 680 | |
E | 550 | 670 | 290 | 890 | ||
F | 650 | 620 | 280 | 820 | ||
小部屋 | G | 470 | 680 | 760 | 410 | |
H | 530 | 580 | 670 | 930 | ||
I | 850 | 980 | 790 | 980 | ||
自宅 | J | 610 | 850 | 530 | 310 | |
K | 400 | 640 | 230 | 400 | ||
L | 530 | 430 | 470 | 330 |
前記のように同じ人が4つの開発プロセスを経験するというのは現実的に多少無理があるが、それはなされたとする。
全ての開発者がこれらの全ての作業空間を経験するのは現実的に不可能であろう。と思うので、そういう席替えはなされず、作業場毎に別の人を選んでデータを採取したとする。
つまり、開発プロセスについては、水準間でどれとどれが同じ人のデータであるかの対応があり、作業空間に関しては、水準間でそういう対応がない、というデータである。
このように、開発プロセスの違いによる影響には有意差があり、また開発プロセスと作業空間の間には何らかの交互作用があるという結果になった。> sample9 <- read.table("anova09.dat", header=TRUE) > summary(aov(productivity ~ process * workspace + Error(developer), data=sample9)) Error: developer Df Sum Sq Mean Sq F value Pr(>F) workspace 3 424492 141497 3.8251 0.05734 . Residuals 8 295933 36992 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 Error: Within Df Sum Sq Mean Sq F value Pr(>F) process 3 163692 54564 3.0262 0.04914 * process:workspace 9 391275 43475 2.4112 0.04123 * Residuals 24 432733 18031 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
もし同じデータを対応なしの二元配置として計算すると、次のように全く異なる結果になる。
これは、データをよく見るとわかるのだが、小部屋に飛び抜けて成績が良い人が居ることに起因しており、作業空間の違いによる効果だと言うにはかなり不適切であろう。> summary(aov(productivity ~ process * workspace, data=sample9)) Df Sum Sq Mean Sq F value Pr(>F) process 3 163692 54564 2.3962 0.086440 . workspace 3 424492 141497 6.2140 0.001898 ** process:workspace 9 391275 43475 1.9092 0.086483 . Residuals 32 728667 22771 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
1要因にのみ対応がある例としてもう1つ、次のようなデータを考える。
開発者A〜Fで構成されるグループが、6つの分野の業務を行った時の生産性を測ったという例である。
生産性 (steps/人月) |
要因1:性別 + 人 | |||||||
---|---|---|---|---|---|---|---|---|
性別 | 男性 | 女性 | ||||||
開発者 | A | B | C | D | E | F | ||
要因2: 業務分野 | 組み込み(アプリ) | 470 | 720 | 550 | 610 | 580 | 550 | |
業務システム | 490 | 530 | 530 | 570 | 310 | 380 | ||
生産システム | 530 | 520 | 570 | 600 | 520 | 490 | ||
PCアプリ | 530 | 310 | 460 | 420 | 690 | 650 | ||
Javaアプリ | 600 | 530 | 500 | 450 | 790 | 590 | ||
ゲーム機ソフト | 450 | 530 | 400 | 530 | 350 | 530 |
開発者の能力には当然個人差がある。 全開発者が6つの分野にて仕事をしたので、分野間ではどれとどれが同じ人のデータであるかの対応が取れる。
1人の開発者は男性と女性の両方を経験できないので、男性群と女性群のデータには対応が取れない。
1つ目のaov()の出力より、このデータでは、性別による影響に有意差が見られるという結果になる。> sample10 <- read.table("anova10.dat", header=TRUE) > summary(aov(productivity ~ sex * area - Error(developer), data=sample10)) Error: developer Df Sum Sq Mean Sq F value Pr(>F) sex 1 4225.0 4225.0 9.6266 0.03613 * Residuals 4 1755.6 438.9 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 Error: Within Df Sum Sq Mean Sq F value Pr(>F) area 5 77314 15463 1.2919 0.3066 sex:area 5 51892 10378 0.8671 0.5202 Residuals 20 239378 11969 > summary(aov(productivity ~ sex * area, data=sample10)) Df Sum Sq Mean Sq F value Pr(>F) sex 1 4225 4225 0.4205 0.5228 area 5 77314 15463 1.5390 0.2153 sex:area 5 51892 10378 1.0330 0.4209 Residuals 24 241133 10047
2つ目のaov()の出力は、2要因とも対応なしとして計算すると、どの要因、交互作用にも有意差が見られないことを示すものである。
二元配置(1要因のみ対応あり)にする時のポイントを整理する。
- 標本には個体差があることを前提とする
- 1つの要因については、複数の水準に同じ個体からの標本があり、水準間でデータの対応が取れる
例えば、同じ被験者から、各水準の条件下でデータが取られている - もう1つの要因については、1つの個体からの標本は1つの水準にしかなく、水準間でデータに対応がない
例えば、水準を決める条件は同時に発生するので、水準毎に異なる被験者を選ぶ
二元配置(2要因対応あり)の標本のデータ構造は、1要因のみ対応ありのものよりも単純である。
欠陥数 (steps/人月) | 要因1:開発プロセス | |||||
---|---|---|---|---|---|---|
Waterfall | Spiral | Incremental | TDD | |||
要因2: 座席の形態 + フェーズ |
作業空間 | 開発フェーズ | ||||
大部屋 | 仕様作成 | 6 | 6 | 7 | 3 | |
全体設計 | 4 | 7 | 8 | 7 | ||
個別設計 | 6 | 8 | 10 | 5 | ||
テスト設計 | 3 | 2 | 6 | 4 | ||
実装 | 6 | 5 | 8 | 8 | ||
小部屋 | 仕様作成 | 2 | 6 | 3 | 5 | |
全体設計 | 5 | 7 | 4 | 6 | ||
個別設計 | 6 | 3 | 10 | 4 | ||
テスト設計 | 7 | 5 | 6 | 4 | ||
実装 | 12 | 5 | 6 | 7 | ||
自宅 | 仕様作成 | 5 | 4 | 9 | 4 | |
全体設計 | 9 | 2 | 9 | 6 | ||
個別設計 | 7 | 9 | 9 | 7 | ||
テスト設計 | 5 | 3 | 3 | 2 | ||
実装 | 4 | 9 | 10 | 11 |
開発フェーズが違うと仕事の性質が全く違うので、フェーズの違いは当然ミスの数に影響する。
どんな開発プロセスにも、これくらいのフェーズは存在するので、各フェーズのデータはあり得る。また、どんな作業空間でも、一通りの開発をすれば全てのフェーズを経るので、各フェーズのデータが得られる。従って、異なる開発プロセスのデータ間でも異なる作業空間のデータ間でも、フェーズの違いによる対応が取れる。
2要因対応ありのデータ構造は単純だが、その計算は、コンピューター任せでも複雑である。対応を決める要因の違いによる影響が、要因1との交互作用、要因2との交互作用、要因1と要因2と対応要因との交互作用と多岐に渡って分離して計算されるからである。> sample11 <- read.table("anova11.dat", header=TRUE) > summary(aov(error ~ process * workspace - Error(phase/(process*workspace)), data=sample11)) Error: phase Df Sum Sq Mean Sq F value Pr(>F) Residuals 4 94.733 23.683 Error: phase:process Df Sum Sq Mean Sq F value Pr(>F) process 3 30.850 10.2833 3.8482 0.03852 * Residuals 12 32.067 2.6722 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 Error: phase:workspace Df Sum Sq Mean Sq F value Pr(>F) workspace 2 4.9333 2.4667 0.6251 0.5594 Residuals 8 31.5667 3.9458 Error: phase:process:workspace Df Sum Sq Mean Sq F value Pr(>F) process:workspace 6 17.20 2.8667 0.5148 0.7912 Residuals 24 133.63 5.5681
上記のaov()の構造式のError()の部分は、その構造がわかりやすいように
- Error(phase + phase/process + phase/workspace)
- Error(phase + phase:process + phase:workspace)
- Error(phase + phase:process + phase:workspace + phase:process:workspace)
- Error(phase / (process * workspace))
上の計算結果では開発プロセス間に有意差が出たが、同じデータを対応なしとして計算すると、次のようにどこにも有意差が出ない。
> summary(aov(error ~ process * workspace, data=sample11)) Df Sum Sq Mean Sq F value Pr(>F) process 3 30.850 10.2833 1.6904 0.1816 workspace 2 4.933 2.4667 0.4055 0.6689 process:workspace 6 17.200 2.8667 0.4712 0.8262 Residuals 48 292.000 6.0833
もう1つ例を考える。新規に参入した人がそこの設計業務をマスターするのに何ヶ月かかったかというデータが、次のように得られたとする。
定着期間 (ヶ月) | 要因1:設計手法 | |||||
---|---|---|---|---|---|---|
構造化設計 | データ指向 | オブジェクト指向 | コンポーネント指向 | |||
要因2: 開発内容 + 性別 |
開発内容 | 性別 | ||||
プラットフォーム | 男性 | 8 | 9 | 7 | 11 | |
女性 | 3 | 6 | 7 | 7 | ||
ミドルウェア | 男性 | 2 | 4 | 3 | 6 | |
女性 | 9 | 5 | 9 | 8 | ||
フレームワーク | 男性 | 10 | 9 | 10 | 9 | |
女性 | 9 | 10 | 5 | 11 | ||
アプリケーション | 男性 | 11 | 9 | 5 | 5 | |
女性 | 12 | 10 | 1 | 5 |
このデータでは、男女の違いによる対応ありとすると、設計手法の違いによる有意差が見られ、対応なしとすると、設計手法にも開発内容にもその違いによる差が見られないという結果になった。> sample12 <- read.table("anova12.dat", header=TRUE) > summary(aov(takes_month ~ design_policy * target - Error(gender/(design_policy*target)), data=sample12)) Error: gender Df Sum Sq Mean Sq F value Pr(>F) Residuals 1 0.03125 0.03125 Error: gender:design_policy Df Sum Sq Mean Sq F value Pr(>F) design_policy 3 23.3438 7.7813 14.647 0.0269 * Residuals 3 1.5938 0.5313 --- Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 Error: gender:target Df Sum Sq Mean Sq F value Pr(>F) target 3 45.844 15.281 0.8886 0.5375 Residuals 3 51.594 17.198 Error: gender:design_policy:target Df Sum Sq Mean Sq F value Pr(>F) design_policy:target 9 95.531 10.6146 2.3142 0.1136 Residuals 9 41.281 4.5868 > summary(aov(takes_month ~ design_policy, data=sample12)) Df Sum Sq Mean Sq F value Pr(>F) design_policy 3 23.344 7.7812 0.9237 0.4422 Residuals 28 235.875 8.4241
この正月は、これらの例を作るので潰してしまった。というか、それぞれ適切な例でないことに気付いては作り直すのを2ヶ月くらいずっとやっていて、正月休みこそは区切りを付けようと思ったのに、それもできなかった。これ以上私自身がこれらの例のクリティカルな誤りに気付かないことを願う。
開発量や作業量をステップ数で測るのは、仕事の質の良し悪しを無視しているから愚か、だとか、1人が1ヶ月かかる仕事を10人なら3日で片付けられる訳じゃないから、人月で割って生産性を求めるのはナンセンスだ、とか、理解度や習熟度を定量的に測るのは不可能だ、とかいうことは百も承知であるが、かといって開発量の尺度としてステップ数に代わる現実的に運用可能なものは無く、FP法などではない客観的で線形な尺度は必要だし、開発者の給料は人月単位で払われていることが多いので、対コストと考えると結局対人月だし、理解度や習熟度が測れないからといって理解度や習熟度のばらつきが存在しない訳ではないのである。
コメント