Transition Matrix

We can convert an annual transition matrix, M, into a monthly transition matrix, x, using two approaches:

  1. N-th root of a square matrix: ensures \(x^n = M\), but some elements of \(x\) may be negative
  2. Regularization of the N-th root: approximates \(x^n \approx M\) and all elements of \(x\) are between 0 and 1

Suppose you have the following annual transition matrix from a credit rating agency like Moody’s or S&P.

rc <- c("AAA", "AA", "A", "BBB", "BB", "B", "CCC", "D") 
M <- matrix(c(90.81, 8.33, 0.68, 0.06, 0.08, 0.02, 0.01, 0.01, 
0.70, 90.65, 7.79, 0.64, 0.06, 0.13, 0.02, 0.01, 
0.09, 2.27, 91.05, 5.52, 0.74, 0.26, 0.01, 0.06, 
0.02, 0.33, 5.95, 85.93, 5.30, 1.17, 1.12, 0.18, 
0.03, 0.14, 0.67, 7.73, 80.53, 8.84, 1.00, 1.06, 
0.01, 0.11, 0.24, 0.43, 6.48, 83.46, 4.07, 5.20, 
0.21, 0, 0.22, 1.30, 2.38, 11.24, 64.86, 19.79, 
0, 0, 0, 0, 0, 0, 0, 100 
)/100, 8, 8, dimnames = list(rc, rc), byrow = TRUE) 

M
##        AAA     AA      A    BBB     BB      B    CCC      D
## AAA 0.9081 0.0833 0.0068 0.0006 0.0008 0.0002 0.0001 0.0001
## AA  0.0070 0.9065 0.0779 0.0064 0.0006 0.0013 0.0002 0.0001
## A   0.0009 0.0227 0.9105 0.0552 0.0074 0.0026 0.0001 0.0006
## BBB 0.0002 0.0033 0.0595 0.8593 0.0530 0.0117 0.0112 0.0018
## BB  0.0003 0.0014 0.0067 0.0773 0.8053 0.0884 0.0100 0.0106
## B   0.0001 0.0011 0.0024 0.0043 0.0648 0.8346 0.0407 0.0520
## CCC 0.0021 0.0000 0.0022 0.0130 0.0238 0.1124 0.6486 0.1979
## D   0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 1.0000

The defining feature of M is each each row sums to 1.

apply(M, 1, sum)
## AAA  AA   A BBB  BB   B CCC   D 
##   1   1   1   1   1   1   1   1

The second defining feature of M is that all elements are between 0 and 1.

all(M >= 0 & M <= 1)
## [1] TRUE

N-th root of a square matrix

There are two approaches in R to find the matrix root of a square matrix. First, use the expm package. Alternatively, you could use the pracma package.

The first approach was found here.

library(expm)

monthly.TM.expm <- expm((1/12)*logm(M))

dimnames(monthly.TM.expm) = list(rc, rc)

round(monthly.TM.expm, 5)
##         AAA       AA       A     BBB      BB       B      CCC       D
## AAA 0.99197  0.00759 0.00032 0.00002 0.00007 0.00001  0.00001 0.00001
## AA  0.00064  0.99174 0.00708 0.00039 0.00002 0.00011  0.00002 0.00000
## A   0.00007  0.00206 0.99198 0.00513 0.00056 0.00019 -0.00003 0.00005
## BBB 0.00001  0.00024 0.00554 0.98706 0.00518 0.00081  0.00117 0.00000
## BB  0.00003  0.00011 0.00039 0.00762 0.98156 0.00878  0.00084 0.00067
## B   0.00000  0.00010 0.00020 0.00011 0.00645 0.98444  0.00446 0.00424
## CCC 0.00022 -0.00002 0.00017 0.00129 0.00217 0.01230  0.96420 0.01967
## D   0.00000  0.00000 0.00000 0.00000 0.00000 0.00000  0.00000 1.00000

The second approach is to use the pracma package. The rootm function finds the p-th matrix root using a complex integral.

library(pracma)

monthly.TM.pracma <- rootm(M, p=12, kmax=20, tol=1e-10)

round(monthly.TM.pracma$B,5)
##         AAA       AA       A     BBB      BB       B      CCC       D
## AAA 0.99197  0.00759 0.00032 0.00002 0.00007 0.00001  0.00001 0.00001
## AA  0.00064  0.99174 0.00708 0.00039 0.00002 0.00011  0.00002 0.00000
## A   0.00007  0.00206 0.99198 0.00513 0.00056 0.00019 -0.00003 0.00005
## BBB 0.00001  0.00024 0.00554 0.98706 0.00518 0.00081  0.00117 0.00000
## BB  0.00003  0.00011 0.00039 0.00762 0.98156 0.00878  0.00084 0.00067
## B   0.00000  0.00010 0.00020 0.00011 0.00645 0.98444  0.00446 0.00424
## CCC 0.00022 -0.00002 0.00017 0.00129 0.00217 0.01230  0.96420 0.01967
## D   0.00000  0.00000 0.00000 0.00000 0.00000 0.00000  0.00000 1.00000

Check matrix properties

Does \(x^n = M\)?

M.expm <- monthly.TM.expm %^% 12
M.pracma <- monthly.TM.pracma$B %^% 12

round(M.expm, 5) == round(M, 5)
##      AAA   AA    A  BBB   BB    B  CCC    D
## AAA TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## AA  TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## A   TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## BBB TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## BB  TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## B   TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## CCC TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## D   TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
round(M.pracma, 5) == round(M, 5)
##      AAA   AA    A  BBB   BB    B  CCC    D
## AAA TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## AA  TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## A   TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## BBB TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## BB  TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## B   TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## CCC TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
## D   TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE

Does the row sum equal 1?

apply(monthly.TM.expm, 1, sum)
## AAA  AA   A BBB  BB   B CCC   D 
##   1   1   1   1   1   1   1   1
apply(monthly.TM.pracma$B, 1, sum)
## AAA  AA   A BBB  BB   B CCC   D 
##   1   1   1   1   1   1   1   1

Unfortunately, some elements of \(x\) are negative.

all(monthly.TM.expm >= 0, monthly.TM.expm <= 1)
## [1] FALSE
all(monthly.TM.pracma$B >= 0, monthly.TM.pracma$B <= 1)
## [1] FALSE

Regularization

The ctmcd package finds a valid transition matrix (i.e., rows sum to 1 and all elements are between 0 and 1) where \(x^n \approx M\). You can find the package documentation here.

The code below uses the quasi-optimization of the generator (QOG) approach from Kreinin and Sidelnikova (2001).

library(ctmcd)

monthly.g.qo <- gm(monthly.TM.pracma$B, te=1, method="QO")
monthly.TM.qo <- expm(monthly.g.qo$par)

round(monthly.TM.qo, 5)
##         AAA      AA       A     BBB      BB       B     CCC       D
## AAA 0.99197 0.00759 0.00032 0.00002 0.00007 0.00001 0.00001 0.00000
## AA  0.00064 0.99174 0.00708 0.00039 0.00002 0.00011 0.00002 0.00000
## A   0.00007 0.00205 0.99197 0.00512 0.00055 0.00019 0.00000 0.00004
## BBB 0.00001 0.00024 0.00553 0.98705 0.00518 0.00080 0.00117 0.00002
## BB  0.00000 0.00012 0.00040 0.00763 0.98156 0.00878 0.00084 0.00068
## B   0.00000 0.00010 0.00020 0.00011 0.00645 0.98444 0.00446 0.00424
## CCC 0.00022 0.00000 0.00017 0.00129 0.00216 0.01230 0.96420 0.01966
## D   0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 1.00000
apply(monthly.TM.qo, 1, sum)
##       AAA        AA         A       BBB        BB         B       CCC 
## 1.0000001 0.9999999 0.9999999 1.0000002 1.0000001 0.9999999 1.0000000 
##         D 
## 1.0000000
all(monthly.TM.qo >= 0, monthly.TM.qo <= 1)
## [1] TRUE

There is no free lunch. Here are the differences between M and M.qo.

M.qo <- monthly.TM.qo %^% 12

round(M - M.qo, 5)
##          AAA       AA      A    BBB     BB      B      CCC        D
## AAA -0.00001 -0.00001 -1e-05 -1e-05 -1e-05 -1e-05 -0.00001  0.00008
## AA   0.00000  0.00000  0e+00  0e+00  0e+00  0e+00 -0.00002  0.00002
## A    0.00006  0.00006  6e-05  6e-05  5e-05  3e-05 -0.00035  0.00001
## BBB  0.00003  0.00002  3e-05  3e-05  2e-05  3e-05  0.00001 -0.00017
## BB   0.00027 -0.00003 -4e-05 -4e-05 -4e-05 -4e-05 -0.00003 -0.00005
## B    0.00004 -0.00001  0e+00  0e+00  0e+00  0e+00  0.00000  0.00000
## CCC  0.00004 -0.00023  2e-05  3e-05  3e-05  4e-05  0.00003  0.00004
## D    0.00000  0.00000  0e+00  0e+00  0e+00  0e+00  0.00000  0.00000

With enough rounding, \(x^n \approx M\).

round(M - M.qo, 3)
##     AAA AA A BBB BB B CCC D
## AAA   0  0 0   0  0 0   0 0
## AA    0  0 0   0  0 0   0 0
## A     0  0 0   0  0 0   0 0
## BBB   0  0 0   0  0 0   0 0
## BB    0  0 0   0  0 0   0 0
## B     0  0 0   0  0 0   0 0
## CCC   0  0 0   0  0 0   0 0
## D     0  0 0   0  0 0   0 0

For documention purposes, here is the monthly transition matrix.

library(printr)

knitr::kable(monthly.TM.qo)
AAA AA A BBB BB B CCC D
AAA 0.9919728 0.0075893 0.0003208 0.0000228 0.0000740 0.0000103 0.0000099 0.0000002
AA 0.0006352 0.9917447 0.0070829 0.0003937 0.0000161 0.0001106 0.0000162 0.0000005
A 0.0000688 0.0020519 0.9919737 0.0051237 0.0005509 0.0001866 0.0000037 0.0000406
BBB 0.0000110 0.0002383 0.0055333 0.9870533 0.0051785 0.0008034 0.0011671 0.0000153
BB 0.0000002 0.0001161 0.0003976 0.0076258 0.9815602 0.0087820 0.0008430 0.0006752
B 0.0000005 0.0000981 0.0001967 0.0001110 0.0064470 0.9844436 0.0044632 0.0042398
CCC 0.0002179 0.0000019 0.0001663 0.0012903 0.0021619 0.0122954 0.9642013 0.0196650
D 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 1.0000000