Mahout版本:0.7,hadoop版本:1.0.4,jdk:1.7.0_25 64bit。
1. 前奏:
本篇接着上篇继续分析,分析LanczosSolver中的:Vector nextVector = isSymmetric ? corpus.times(currentVector) : corpus.timesSquared(currentVector);之后。前篇说到这个是建立了一个job任务,并且按照一定的算法求得了一个nextVector,那么接下来是?
if (state.getScaleFactor() <= 0) { state.setScaleFactor(calculateScaleFactor(nextVector)); }这里首先判断getScaleFactor的值是否小于等于0,因为刚开始的时候初始化scaleFactor = 0;,所以这里要调用calculateScaleFactor(nextVector)函数:
protected double calculateScaleFactor(Vector nextVector) { return nextVector.norm(2); }这个是如何计算的呢?else if (power == 2.0) { return Math.sqrt(dotSelf()); 这个就是norm函数中当参数是2的时候调用的代码了,所以这里返回的是先nextVector自点乘,然后开根号;(测试的时候这个值是:2029123.4011255247,excel计算的这个值是:2034667.82368468)接下来:
nextVector.assign(new Scale(1.0 / state.getScaleFactor()));nextVector 乘以1除以scaleFactor其实就是nextVector除以scaleFactor而已,数值太大了要变小点?经过这一步,nextVector变为:
{0:0.011875906226907599,1:0.0017759586067652153,2:0.0021729514771005837,3:0.014292365192727802,4:0.09660595016979406,5:0.002638859113021243,6:0.0026868791091140517,7:2.476888783392492E-4,8:0.001831833994868574,9:0.005012618192500366,10:8.604490527160895E-4,11:0.0029456317791350514,12:0.9951190694939772}excel里面变为:
0.0118771 | 0.001776226 | 0.002173228 | 0.01429431 | 0.096617439 | 0.00263899 | 0.00268705 | 0 | 0 | 0.0050126 | 0 | 0 | 0.99511791 |
接下来还是更新nextVector的:
double alpha = currentVector.dot(nextVector); nextVector.assign(currentVector, new PlusMult(-alpha));首先是currentVector和nextVector的点积,然后用nextVector中的项减去currentVector中的项乘以alpha的值更新nextVector中的项;上面的测试结果,alpha的值为:0.315642761491587,excel计算的值是0.31564687543564,这里就很接近了;然后是nextVector的值:
{0:-0.07566764464132066,1:-0.08576759226146304,2:-0.08537059939112766,3:-0.07325118567550044,4:0.009062399301565813,5:-0.08490469175520701,6:-0.0848566717591142,7:-0.087295861989889,8:-0.08571171687335968,9:-0.08253093267572789,10:-0.08668310181551216,11:-0.0845979190890932,12:0.9075755186257489}excel中的值是:
-0.075668 | -0.08576847 | -0.08537146 | -0.073250382 | 0.009072747 | -0.0849057 | -0.0848576 | -0.1 | -0.1 | -0.082532 | -0.1 | -0.1 | 0.90757322 |
endTime(TimingSection.ITERATE); startTime(TimingSection.ORTHOGANLIZE); orthoganalizeAgainstAllButLast(nextVector, state); endTime(TimingSection.ORTHOGANLIZE);endTime和startTime应该只是和目录有关的设置吧,这里不管了,直接看orthoganalizeAgainstAllButLast函数:
protected void orthoganalizeAgainstAllButLast(Vector nextVector, LanczosState state) { for (int i = 0; i < state.getIterationNumber(); i++) { Vector basisVector = state.getBasisVector(i); double alpha; if (basisVector == null || (alpha = nextVector.dot(basisVector)) == 0.0) { continue; } nextVector.assign(basisVector, new PlusMult(-alpha)); } }这个函数的操作就是使用bisis来更新nextVector,更新采用原始值减去basisVector对应值乘以(nextVector和basisVector的点积)来更新;第一次basisVector中只有一个值,是13个1初始根号13的向量,那么更新后的nextVector是:
{0:-0.07566764464132064,1:-0.08576759226146302,2:-0.08537059939112765,3:-0.07325118567550043,4:0.009062399301565828,5:-0.084904691755207,6:-0.08485667175911418,7:-0.08729586198988899,8:-0.08571171687335967,9:-0.08253093267572788,10:-0.08668310181551214,11:-0.08459791908909318,12:0.9075755186257489}感觉和之前没有啥差别,因为nextVector和basisVector的点积很小的缘故;接下来是:
beta = nextVector.norm(2);额,这个函数之前分析过:就是nextVector自己点积,然后开根号即可,得到的beta值是:0.9488780991876485,然后判断alpha和beta是否超过某个数,如下:
if (outOfRange(beta) || outOfRange(alpha)) { log.warn("Lanczos parameters out of range: alpha = {}, beta = {}. Bailing out early!", alpha, beta); break; }看到outOfRange函数:
private static boolean outOfRange(double d) { return Double.isNaN(d) || d > SAFE_MAX || -d > SAFE_MAX; }由于SAFE_MAX=1.0E150,所以肯定是不会超过的;那么就继续往下分析了;
nextVector.assign(new Scale(1 / beta)); state.setBasisVector(i, nextVector); previousVector = currentVector; currentVector = nextVector; // save the projections and norms! triDiag.set(i - 1, i - 1, alpha); if (i < desiredRank - 1) { triDiag.set(i - 1, i, beta); triDiag.set(i, i - 1, beta); } state.setIterationNumber(++i);感觉和刚才一样了,nextVector先出示beta的值,然后设置basisVector的第1个值(所谓第1个值是因为这时i为1,计数从0开始),那么basisVector就有两个值了,第0个是13个1除以根号13,第1个是nextVector了;然后重新赋值,previousVector、currentVector,最后就是triDiag的设置了,这个是一个3乘以3的矩阵,这个3是前面设置的rank值;triDiag设置后的值是:
[[0.315642761491587, 0.9488780991876485, 0.0], [0.9488780991876485, 0.0, 0.0], [0.0, 0.0, 0.0]]
2. 循环,job2
接着开始第二次while循环,使用nextVector更新后的currentVector再针对输入数据跑一边job1的算法;感觉这里的rank值有点像是控制循环的次数的感觉;由于这里i初始就被设置为1了,而且rank设置为3,所以这里只循环两次;最后循环完成后,triDiag的值是:[[0.315642761491587, 0.9488780991876485, 0.0], [0.9488780991876485, 2.855117440373572, 0.0], [0.0, 0.0, 0.0]]因为接下来就是只对这个值进行操作,所以记录下这个值;
3.处理triDiag(3*3矩阵)
首先是初始化:
EigenDecomposition decomp = new EigenDecomposition(triDiag);看着个初始化做的事情:首先去判断triDiag是否是对称的,是的话就执行if里面的操作:
public EigenDecomposition(Matrix x, boolean isSymmetric) { n = x.columnSize(); d = new DenseVector(n); e = new DenseVector(n); v = new DenseMatrix(n, n); if (isSymmetric) { v.assign(x); // Tridiagonalize. tred2(); // Diagonalize. tql2(); } else { // Reduce to Hessenberg form. // Reduce Hessenberg to real Schur form. hqr2(orthes(x)); } }assign就是把x赋值给v,tred2和tql2是做什么的呢?
额,吓我一跳,because 太他X长了,果然java不适合做矩阵处理。。。
分享,成长,快乐
转载请注明blog地址:http://blog.csdn.net/fansy1990