Hadoop MapReduceで相関行列を計算する:ステップ3:対角化、ステップ4:逆行列の算出 (step3: making diagonal matrix from standard deviations, step4: inverse matr
前回までで、Hadoop MapReduceによって観測値の平均と標準偏差を算出した。今回のログでは、標準偏差を対角要素としてもつ行列とその逆行列を計算する。
話を進めるにあたり、少しだけ式を書かなければならない。まず、対角行列とは、以下のフォーマットを満たす行列のことである。
次に、逆行列とは、
のとき、
を満たすA^{-1}のことをさす。
先のログに示したように、相関行列の計算式は、
これは、対角行列の以下の性質から導くことができる。
(性質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