Hadoop MapReduceで相関行列を計算する:ステップ3:対角化、ステップ4:逆行列の算出 (step3: making diagonal matrix from standard deviations, step4: inverse matr

前回までで、Hadoop MapReduceによって観測値の平均と標準偏差を算出した。今回のログでは、標準偏差を対角要素としてもつ行列とその逆行列を計算する。

話を進めるにあたり、少しだけ式を書かなければならない。まず、対角行列とは、以下のフォーマットを満たす行列のことである。

次に、逆行列とは、

のとき、

を満たすA^{-1}のことをさす。


先のログに示したように、相関行列の計算式は、


ただし、

で表される。

これは、対角行列の以下の性質から導くことができる。

(性質1)対角行列の逆数は、対角要素の逆数により構成される対角行列となる。

(性質2)対角行列を行列の前方から掛けることは、i番目の対角要素を(行列の)第i行に掛けることと同義である。

(性質3)対角行列を行列の後方から掛けることは、i番目の対角要素を(行列の)第i列に掛けることと同義である。


ステップ3において、各変量について(不偏)標準偏差を求めた。

1	2.93
2	2.39
3	2.34
4	2.33
5	2.41
6	1.99
7	2.51
8	3.49
9	3.54
10	2.4


これを対角行列の標準入力フォーマット

行インデックス  列インデックス 対角要素

とすることもできるが、この(疎な)行列について、密な行列の積と同じ手続きを踏むことは無駄が多い。

そこで、ステップ3、4を統合したプログラムを作成する。このプログラムではMapperしか使用しない。実行時の引数として、入力値(StandardDeviationクラスの出力)フォルダーと結果の出力先フォルダーを渡す。



プログラムは以下となる。GitHubでも公開しています(InvertSD.java)。

package com.tetsuyaodaka.hadoop.math.matrix;
import java.io.IOException;
import java.math.BigDecimal;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

/**
 *
 * InvertSDクラス
 * 
 * 標準偏差の逆数を計算する。
 * 
 */
public class InvertSD {

    public static class Map extends Mapper<LongWritable, Text, IntWritable, DoubleWritable>{

        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException{
           	String strArr[] = value.toString().split("\t");
        	int var= Integer.parseInt(strArr[0]);
        	double inv = 1/Double.parseDouble(strArr[1]);

            BigDecimal bd = new BigDecimal(inv);
			BigDecimal r = bd.setScale(2, BigDecimal.ROUND_HALF_UP); 

            context.write(new IntWritable(var), new DoubleWritable(r.doubleValue()));
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
        Job job = new Job(new Configuration(), "InvertSD");
        job.setJarByClass(InvertSD.class);

        job.setMapperClass(Map.class);
        job.setInputFormatClass(TextInputFormat.class);
        
        job.setOutputKeyClass(IntWritable.class);
        job.setOutputValueClass(DoubleWritable.class);
        
        FileInputFormat.setInputPaths(job, new Path(args[0]));
        FileOutputFormat.setOutputPath(job, new Path(args[1]));

        boolean success = job.waitForCompletion(true);
        System.out.println(success);
    }
}

テスト

先のログで算出した標準偏差(以下)を用いてテストする。

1	2.93
2	2.39
3	2.34
4	2.33
5	2.41
6	1.99
7	2.51
8	3.49
9	3.54
10	2.4

実行結果は以下となる。

1	0.34
2	0.42
3	0.43
4	0.43
5	0.41
6	0.5
7	0.4
8	0.29
9	0.28
10	0.42