数理最適化セミナーのご案内

2.20 格付け推移行列推定問題

 格付け(rating)とは,企業の発行する社債の元本,利息の支払い能力をランク形式で表示したものです.格付け会社は独自の調査結果のもと,A,B,Cや+,-などの記号を用いて対象社債のリスク度合いを示します.格付けは,社債の購入者側からすると購入判断時の評価指標になりますし,発行体となる企業側からすると,資金調達の際の利回り決定の基準となります.

 格付け推移行列とは,ある格付け評価を受けている企業が,一定期間後にどのような格付けとなるかについての確率を表す行列のことをいいます.

 以下では,この格付け推移行列の推定に関する例題を考えます.

例題

 格付けとして,{AAA, AA, A, BBB, BB, B, CCC, CC, C}の9種類があるものとして,格付けに関する1年後の推移行列$Q_{0}$が以下のように与えられているものとする.

 $Q_{0}$を基に,1ヶ月単位期間の格付け推移行列$Q$を推定せよ.

 推移確率行列 $Q$はマルコフ過程に従うものとします.そのとき,題意より行列$Q^{12}$は行列$Q_0$と本来一致するはずです.従って,行列$Q$を推定するとは,$\| Q_0 - Q^{12} \|_F$を最小にするような$Q$を求めるということになります.なお$\| \cdot \|_F$は,Frobenius(フロベニウス)ノルムのことで,行列の各成分の二乗和の平方根を表すものとします.

 また,格付け推移行列の性質として,行列$Q$の各行の和は1で各成分は非負であるものとします.

 以上を踏まえると,定式化は以下のようになります.

順序集合
$Rating$ 格付けの集合
 
定数
$q^{0}_{ij}, i, j \in Rating$ 1年後の格付け推移行列($Q_0$)の各要素
 
変数
$q_{ij}, i, j \in Rating$ 1ヶ月単位の格付け推移行列($Q$)の各要素
 
目的関数(最小化)
$\| Q_0 - Q^{12} \|^2_F$ 行列$Q_0$$Q^{12}$の差のフロベニウスノルムの二乗
 
制約条件
$\displaystyle \sum_{j \in Rating} q_{ij}  = 1, \forall i \in Rating$ 行列$Q$の各行の和は1
$0 \le q_{ij} \le 1, \forall i, j \in Rating$ 行列$Q$の各要素条件

 この問題は目的関数が非線形ですので,非線形計画問題になります.

 定式化した結果をC++SIMPLEで記述すると以下のようになります.

 なお,行列$Q^{12}$に関しては,

\[Q^{12} = Q^8 \cdot Q^4 = (Q^2 \cdot Q^2)^2 \cdot (Q^2 \cdot Q^2)\]

で表現することにより,演算の回数を節約することができます.

 また,局所解に陥ることを回避するため,および収束までの反復回数を軽減するため,行列$Q$の初期値として,対角成分に0.9を与え,非対角要素の上限値を0.05としておきます.

// 集合と添字
OrderedSet Rating; // 格付け集合
Element i(set = Rating), j(set = Rating), k(set = Rating);

// パラメータ
Parameter q0(name = "Q0", index = (i,j)); // 1 年後の格付け推移行列の各要素

// 変数
Variable q(name = "Q", index = (i, j)); // 1 ヶ月単位の格付け推移行列の各要素

// 定式の定義に利用する演算の回数を節約する記法
Expression q2(name = "q2", index=(i, j));
Expression q4(name = "q4", index=(i, j));
Expression q8(name = "q8", index=(i, j));
Expression q12(name = "q12", index=(i, j));
q2[i, j] = sum(q[i, k] * q[k, j], k);
q4[i, j] = sum(q2[i, k] * q2[k, j], k);
q8[i, j] = sum(q4[i, k] * q4[k, j], k);
q12[i, j] = sum(q8[i, k] * q4[k, j], k);

Expression diff(name = "diff", index = (i, j));
diff[i, j] = q0[i, j] - q12[i, j];

// 目的関数
Objective diffnrm(name="行列 Q0 と 行列 Q の 12 乗 の差ノルムの二乗", type = minimize);
diffnrm = sum(pow(diff[i, j], 2), (i, j));

// 制約条件
sum(q[i, j], j) == 1; // 行列 Q について,各行の和は 1
0 <= q[i, i] <= 1; // 行列 Q の対角要素条件
0 <= q[i, j] <= 0.05, i != j; // 行列 Q の非対角要素条件

// 初期値設定
q[k, k] = 0.9;

// 求解
solve();

// 結果出力
diffnrm.val.print();
simple_printf("\n");
simple_printf("Q");
simple_printf(", %s", k);
simple_printf("\n");
Element k_tmp;
for(k_tmp = Rating.first(); k_tmp < Rating; k_tmp = Rating.next(k_tmp)){
  simple_printf("%s", k_tmp);
  simple_printf(", %7.5f", q[k_tmp, j]);
  simple_printf("\n");
}

 データファイル(csv形式)は以下のようになります.

Q0, AAA, AA, A, BBB, BB, B, CCC, CC, C
AAA, 0.9651, 0.0349, 0, 0, 0, 0, 0, 0, 0
AA, 0.0356, 0.9382, 0.0262, 0, 0, 0, 0, 0, 0
A, 0.0014, 0.0433, 0.9364, 0.0186, 0.0003, 0, 0, 0, 0
BBB, 0, 0, 0.0352, 0.9456, 0.0154, 0.0038, 0, 0, 0
BB, 0, 0, 0, 0.1078, 0.872, 0.0049, 0.0153, 0, 0
B, 0, 0, 0, 0, 0.0747, 0.8762, 0.041, 0.0081, 0
CCC, 0, 0, 0, 0, 0, 0.0278, 0.9654, 0.0068, 0
CC, 0, 0, 0, 0, 0, 0, 0.0083, 0.9675, 0.0242
C, 0, 0, 0, 0, 0, 0, 0, 0.0266, 0.9734

 このモデルを実行すると以下のような解が得られます.

行列 Q0 と 行列 Q の 12 乗 の差ノルムの二乗 = 2.82001e-005

Q, AAA, AA, A, BBB, BB, B, CCC, CC, C
AAA, 0.99697, 0.00303, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000
AA, 0.00310, 0.99459, 0.00231, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000
A, 0.00006, 0.00383, 0.99446, 0.00164, 0.00001, 0.00000, 0.00000, 0.00000, 0.00000
BBB, 0.00000, 0.00000, 0.00307, 0.99523, 0.00137, 0.00032, 0.00000, 0.00000, 0.00000
BB, 0.00000, 0.00000, 0.00000, 0.00976, 0.98852, 0.00039, 0.00133, 0.00000, 0.00000
B, 0.00000, 0.00000, 0.00000, 0.00000, 0.00693, 0.98889, 0.00355, 0.00063, 0.00000
CCC, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00247, 0.99699, 0.00054, 0.00000
CC, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00071, 0.99722, 0.00207
C, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00227, 0.99772

 

 

上に戻る