<?php /****************************/ /* 正準相関分析 */ /* coded by Y.Suganuma */ /****************************/ fscanf(STDIN, "%d %d %d", $r, $s, $n); // 各組の変数の数とデータの数 $q = $r + $s; $ryz = array($r); $v0 = array($r); $x = array($q); $ab = array($r); for ($i1 = 0; $i1 < $q; $i1++) $x[$i1] = array($n); for ($i1 = 0; $i1 < $r; $i1++) { $ab[$i1] = array($q); $v0[$i1] = 1.0; } for ($i1 = 0; $i1 < $n; $i1++) { // データ $str = trim(fgets(STDIN)); $x[0][$i1] = floatval(strtok($str, " ")); for ($i2 = 1; $i2 < $q; $i2++) $x[$i2][$i1] = floatval(strtok(" ")); } $sw = canonical($r, $s, $n, $x, $ryz, $ab, 1.0e-10, $v0, 15, 200); if ($sw > 0) { for ($i1 = 0; $i1 < $sw; $i1++) { printf("相関係数 %f\n", $ryz[$i1]); printf(" a"); for ($i2 = 0; $i2 < $r; $i2++) printf(" %f", $ab[$i1][$i2]); printf("\n"); printf(" b"); for ($i2 = 0; $i2 < $s; $i2++) printf(" %f", $ab[$i1][$r+$i2]); printf("\n"); } } else printf("***error 解を求めることができませんでした\n"); /***********************************/ /* 正準相関分析 */ /* r,s : 各組における変数の数 */ /* n : データの数 */ /* x : データ */ /* ryz : 相関係数 */ /* ab : 各組の係数(a,bの順) */ /* eps : 正則性を判定する規準 */ /* v0 : 固有ベクトルの初期値 */ /* m : 丸め誤差の修正回数 */ /* ct : 最大繰り返し回数 */ /* return : >0 : 相関係数の数 */ /* =0 : エラー */ /***********************************/ function canonical($r, $s, $n, $x, &$ryz, &$ab, $eps, $v0, $m, $ct) { $sw = 0; // 領域の確保 $q = $r + $s; $mean = array($q); $w1 = array($s); $v1 = array($r); $v2 = array($r); $A = array($s); $B = array($r); $C = array($q); $C11 = array($r); $C11i = array($r); $C12 = array($r); $C21 = array($s); $C22 = array($s); $C22i = array($s); $w = array($s); for ($i1 = 0; $i1 < $q; $i1++) $C[$i1] = array($q); for ($i1 = 0; $i1 < $r; $i1++) { $B[$i1] = array($r); $C11[$i1] = array($r); $C11i[$i1] = array($r); $C12[$i1] = array($s); } for ($i1 = 0; $i1 < $s; $i1++) { $A[$i1] = array($s); $C21[$i1] = array($r); $C22[$i1] = array($s); $C22i[$i1] = array($s); $w[$i1] = array(2*$s); } // 平均値の計算 for ($i1 = 0; $i1 < $q; $i1++) { $mean[$i1] = 0.0; for ($i2 = 0; $i2 < $n; $i2++) $mean[$i1] += $x[$i1][$i2]; $mean[$i1] /= $n; } // 分散強分散行列の計算 for ($i1 = 0; $i1 < $q; $i1++) { for ($i2 = $i1; $i2 < $q; $i2++) { $vv = 0.0; for ($i3 = 0; $i3 < $n; $i3++) $vv += ($x[$i1][$i3] - $mean[$i1]) * ($x[$i2][$i3] - $mean[$i2]); $vv /= ($n - 1); $C[$i1][$i2] = $vv; if ($i1 != $i2) $C[$i2][$i1] = $vv; } } // C11, C12, C21, C22 の設定 // C12 for ($i1 = 0; $i1 < $r; $i1++) { for ($i2 = 0; $i2 < $s; $i2++) $C12[$i1][$i2] = $C[$i1][$i2+$r]; } // C21 for ($i1 = 0; $i1 < $s; $i1++) { for ($i2 = 0; $i2 < $r; $i2++) $C21[$i1][$i2] = $C[$i1+$r][$i2]; } // C11とその逆行列 for ($i1 = 0; $i1 < $r; $i1++) { for ($i2 = 0; $i2 < $r; $i2++) { $w[$i1][$i2] = $C[$i1][$i2]; $C11[$i1][$i2] = $C[$i1][$i2]; } for ($i2 = $r; $i2 < 2*$r; $i2++) $w[$i1][$i2] = 0.0; $w[$i1][$i1+$r] = 1.0; } $sw1 = gauss($w, $r, $r, 1.0e-10); if ($sw1 == 0) { for ($i1 = 0; $i1 < $r; $i1++) { for ($i2 = 0; $i2 < $r; $i2++) $C11i[$i1][$i2] = $w[$i1][$i2+$r]; } } else $sw = 1; // C22とその逆行列 for ($i1 = 0; $i1 < $s; $i1++) { for ($i2 = 0; $i2 < $s; $i2++) { $w[$i1][$i2] = $C[$i1+$r][$i2+$r]; $C22[$i1][$i2] = $C[$i1+$r][$i2+$r]; } for ($i2 = $s; $i2 < 2*$s; $i2++) $w[$i1][$i2] = 0.0; $w[$i1][$i1+$s] = 1.0; } $sw1 = gauss($w, $s, $s, $eps); if ($sw1 == 0) { for ($i1 = 0; $i1 < $s; $i1++) { for ($i2 = 0; $i2 < $s; $i2++) $C22i[$i1][$i2] = $w[$i1][$i2+$s]; } } else $sw = 1; // 固有値λ及び固有ベクトルaの計算 if ($sw == 0) { // 行列の計算 for ($i1 = 0; $i1 < $s; $i1++) { for ($i2 = 0; $i2 < $r; $i2++) { $A[$i1][$i2] = 0.0; for ($i3 = 0; $i3 < $s; $i3++) $A[$i1][$i2] += $C22i[$i1][$i3] * $C21[$i3][$i2]; } } for ($i1 = 0; $i1 < $r; $i1++) { for ($i2 = 0; $i2 < $s; $i2++) { $w[$i1][$i2] = 0.0; for ($i3 = 0; $i3 < $s; $i3++) $w[$i1][$i2] += $C12[$i1][$i3] * $A[$i3][$i2]; } } for ($i1 = 0; $i1 < $r; $i1++) { for ($i2 = 0; $i2 < $r; $i2++) { $A[$i1][$i2] = 0.0; for ($i3 = 0; $i3 < $r; $i3++) $A[$i1][$i2] += $C11i[$i1][$i3] * $w[$i3][$i2]; } } // 固有値と固有ベクトル(べき乗法) for ($i1 = 0; $i1 < $r; $i1++) { for ($i2 = 0; $i2 < $r; $i2++) $B[$i1][$i2] = 0.0; $B[$i1][$i1] = 1.0; } $sw = power(0, $r, $m, $ct, $eps, $A, $B, $C, $ryz, $ab, $v0, $v1, $v2); if ($sw > 0) { for ($i1 = 0; $i1 < $r; $i1++) { // 相関係数 $ryz[$i1] = sqrt($ryz[$i1]); // 大きさの調整(a) for ($i2 = 0; $i2 < $r; $i2++) { $w1[$i2] = 0.0; for ($i3 = 0; $i3 < $r; $i3++) $w1[$i2] += $C11[$i2][$i3] * $ab[$i1][$i3]; } $len = 0.0; for ($i2 = 0; $i2 < $r; $i2++) $len += $ab[$i1][$i2] * $w1[$i2]; $len = sqrt($len); for ($i2 = 0; $i2 < $r; $i2++) $ab[$i1][$i2] /= $len; // bの計算 for ($i2 = 0; $i2 < $s; $i2++) { $w1[$i2] = 0.0; for ($i3 = 0; $i3 < $r; $i3++) $w1[$i2] += $C21[$i2][$i3] * $ab[$i1][$i3]; } for ($i2 = 0; $i2 < $s; $i2++) { $ab[$i1][$i2+$r] = 0.0; for ($i3 = 0; $i3 < $s; $i3++) $ab[$i1][$i2+$r] += $C22i[$i2][$i3] * $w1[$i3]; } for ($i2 = 0; $i2 < $s; $i2++) $ab[$i1][$i2+$r] /= $ryz[$i1]; // 大きさの調整(b) for ($i2 = 0; $i2 < $s; $i2++) { $w1[$i2] = 0.0; for ($i3 = 0; $i3 < $s; $i3++) $w1[$i2] += $C22[$i2][$i3] * $ab[$i1][$i3+$r]; } $len = 0.0; for ($i2 = 0; $i2 < $s; $i2++) $len += $ab[$i1][$i2+$r] * $w1[$i2]; $len = sqrt($len); for ($i2 = 0; $i2 < $s; $i2++) $ab[$i1][$i2+$r] /= $len; } } } else $sw = 0; return $sw; } /*******************************************************/ /* 線形連立方程式を解く(逆行列を求める) */ /* w : 方程式の左辺及び右辺 */ /* n : 方程式の数 */ /* m : 方程式の右辺の列の数 */ /* eps : 正則性を判定する規準 */ /* return : =0 : 正常 */ /* =1 : 逆行列が存在しない */ /*******************************************************/ function gauss(&$w, $n, $m, $eps) { $ind = 0; $nm = $n + $m; for ($i1 = 0; $i1 < $n && $ind == 0; $i1++) { $y1 = .0; $m1 = $i1 + 1; $m2 = 0; for ($i2 = $i1; $i2 < $n; $i2++) { $y2 = abs($w[$i2][$i1]); if ($y1 < $y2) { $y1 = $y2; $m2 = $i2; } } if ($y1 < $eps) $ind = 1; else { for ($i2 = $i1; $i2 < $nm; $i2++) { $y1 = $w[$i1][$i2]; $w[$i1][$i2] = $w[$m2][$i2]; $w[$m2][$i2] = $y1; } $y1 = 1.0 / $w[$i1][$i1]; for ($i2 = $m1; $i2 < $nm; $i2++) $w[$i1][$i2] *= $y1; for ($i2 = 0; $i2 < $n; $i2++) { if ($i2 != $i1) { for ($i3 = $m1; $i3 < $nm; $i3++) $w[$i2][$i3] -= $w[$i2][$i1] * $w[$i1][$i3]; } } } } return($ind); } /****************************************/ /* 最大固有値と固有ベクトル(べき乗法) */ /* i : 何番目の固有値かを示す */ /* n : 次数 */ /* m : 丸め誤差の修正回数 */ /* ct : 最大繰り返し回数 */ /* eps : 収束判定条件 */ /* A : 対象とする行列 */ /* B : nxnの行列,最初は,単位行列 */ /* C : 作業域,nxnの行列 */ /* r : 固有値 */ /* v : 各行が固有ベクトル(nxn) */ /* v0 : 固有ベクトルの初期値 */ /* v1,v2 : 作業域(n次元ベクトル) */ /* return : 求まった固有値の数 */ /* coded by Y.Suganuma */ /****************************************/ function power($i, $n, $m, $ct, $eps, $A, $B, $C, &$r, &$v, $v0, $v1, $v2) { // 初期設定 $ind = $i; $k = 0; $l1 = 0.0; for ($i1 = 0; $i1 < $n; $i1++) { $l1 += $v0[$i1] * $v0[$i1]; $v1[$i1] = $v0[$i1]; } $l1 = sqrt($l1); // 繰り返し計算 while ($k < $ct) { // 丸め誤差の修正 if ($k%$m == 0) { $l2 = 0.0; for ($i1 = 0; $i1 < $n; $i1++) { $v2[$i1] = 0.0; for ($i2 = 0; $i2 < $n; $i2++) $v2[$i1] += $B[$i1][$i2] * $v1[$i2]; $l2 += $v2[$i1] * $v2[$i1]; } $l2 = sqrt($l2); for ($i1 = 0; $i1 < $n; $i1++) $v1[$i1] = $v2[$i1] / $l2; } // 次の近似 $l2 = 0.0; for ($i1 = 0; $i1 < $n; $i1++) { $v2[$i1] = 0.0; for ($i2 = 0; $i2 < $n; $i2++) $v2[$i1] += $A[$i1][$i2] * $v1[$i2]; $l2 += $v2[$i1] * $v2[$i1]; } $l2 = sqrt($l2); for ($i1 = 0; $i1 < $n; $i1++) $v2[$i1] /= $l2; // 収束判定 // 収束した場合 if (abs(($l2-$l1)/$l1) < $eps) { $k1 = -1; for ($i1 = 0; $i1 < $n && $k1 < 0; $i1++) { if (abs($v2[$i1]) > 0.001) { $k1 = $i1; if ($v2[$k1]*$v1[$k1] < 0.0) $l2 = -$l2; } } $k = $ct; $r[$i] = $l2; for ($i1 = 0; $i1 < $n; $i1++) $v[$i][$i1] = $v2[$i1]; if ($i == $n-1) $ind = $i + 1; else { for ($i1 = 0; $i1 < $n; $i1++) { for ($i2 = 0; $i2 < $n; $i2++) { $C[$i1][$i2] = 0.0; for ($i3 = 0; $i3 < $n; $i3++) { $x = ($i1 == $i3) ? $A[$i1][$i3] - $l2 : $A[$i1][$i3]; $C[$i1][$i2] += $x * $B[$i3][$i2]; } } } for ($i1 = 0; $i1 < $n; $i1++) { for ($i2 = 0; $i2 < $n; $i2++) $B[$i1][$i2] = $C[$i1][$i2]; } for ($i1 = 0; $i1 < $n; $i1++) { $v1[$i1] = 0.0; for ($i2 = 0; $i2 < $n; $i2++) $v1[$i1] += $B[$i1][$i2] * $v0[$i2]; } for ($i1 = 0; $i1 < $n; $i1++) $v0[$i1] = $v1[$i1]; $ind = power($i+1, $n, $m, $ct, $eps, $A, $B, $C, $r, $v, $v0, $v1, $v2); } } // 収束しない場合 else { for ($i1 = 0; $i1 < $n; $i1++) $v1[$i1] = $v2[$i1]; $l1 = $l2; $k++; } } return $ind; } /* ---------データ例(コメント部分を除いて下さい)--------- 2 2 100 // 各組の変数の数(r と s, r ≦ s)とデータの数(n) 66 22 44 31 // x1, x2, x3, x4 25 74 17 81 50 23 53 71 25 57 19 81 74 47 64 47 39 33 48 46 14 22 9 69 67 60 49 26 42 40 77 65 11 80 0 86 32 0 43 74 68 69 44 68 24 49 9 71 42 74 28 46 60 58 73 28 36 37 33 68 24 44 19 83 30 40 31 50 55 40 60 49 63 47 94 41 72 30 100 45 19 22 13 75 43 39 43 34 90 83 92 31 51 77 52 82 53 70 34 31 28 51 53 44 40 62 42 79 31 48 22 68 57 29 51 30 64 89 57 42 49 82 72 29 53 31 55 43 79 52 70 10 45 19 43 57 35 34 34 89 4 69 0 100 49 49 66 66 92 82 97 6 5 89 0 100 65 26 83 28 56 36 64 38 48 50 25 22 30 30 15 55 40 65 38 42 14 67 9 67 84 96 90 8 53 64 51 54 50 89 60 52 76 41 68 9 49 40 53 49 78 66 66 17 76 58 90 29 41 15 40 49 63 60 55 33 40 36 49 67 78 54 71 18 62 72 69 12 64 47 42 53 56 64 9 15 77 35 56 25 44 12 46 87 80 9 56 19 36 21 52 78 48 63 64 48 43 61 50 47 58 23 28 50 90 12 100 0 13 33 11 77 67 44 48 28 75 45 68 17 81 22 89 9 46 45 59 55 56 49 64 55 65 62 72 27 34 49 29 77 45 33 60 63 20 45 14 99 33 38 26 87 44 51 69 52 64 57 64 48 44 64 51 28 63 48 56 11 29 39 33 84 40 48 51 54 40 38 26 62 68 46 61 26 58 45 68 48 64 44 77 63 59 62 44 66 81 53 93 19 23 34 12 68 51 35 55 46 74 70 84 17 42 33 56 44 46 31 46 53 33 57 38 63 40 24 20 42 53 36 60 31 0 34 0 100 */ ?>