Java8による関数型ビジネス統計分析Excelプログラミング(1)

そろそろ、Java8を試してみようとJava7のおさらいをしてから、気づけば1年以上たってます

しかし1年がたつのは早い。

ということで、以下の本を読了したので、実際に手を動かして、ラムダ式やらなんやらを身に着けておきたいと思ってます。今回は、Java5でジェネリックスとかが導入されたとき同様、ある程度コードを書かないと理解できなさそうです。そういえば、Java5のときは、SJCPを更新受験したな。今回は試験受けてもよいくらいのバージョンアップかも。

Javaによる関数型プログラミング ―Java 8ラムダ式とStream

ということで、やみくもにタイピングするのも面白みがないので、データを分析しながら、Java8を学んでいきたいなと。

手元にあった、以下の本とのからめ手で行こうと思います。

EXCELビジネス統計分析 [ビジテク] 第2版 2013/2010/2007/2003対応

1.JRA の単勝払戻金のヒストグラムを作成してみる

1.1 JRA-VAN データフォーマット

これまた、適当な量があるデータがないので、何年か前に入手した、JRA-VAN のデータを使ってみたいと思います。

以下のような、感じでデータファイルの定義が提供されています。

払戻金情報は、HRから始まるファイルで、105byte目から9byte分が、単勝の金額データとなってます。

jra-van_data_type

データレイアウト

jra-van_data_harai

実際のデータ

jra-van_data

1.2 Java8 Streamによる実装

Javaによる関数型プログラミング ―Java 8ラムダ式とStream で学んだことを思い出しながら、実装してみます。コメント中、に 「2.4 ラムダ式の再利用」とか書いているのは、上記書籍の参照章。

package info.typea.jra.stat;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.DirectoryStream.Filter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 払戻ファイル  の統計分析
 */
public class HaraiStat {

    /** データルートディレクトリ */
    private static final String JRAVAN_DATA_DIR = "E:\\jravan\\data";
    
    /** 払戻 ファイル名フィルタ */
    // 2.4 ラムダ式の再利用
    private static final Filter haraiFileFilter = path -> path.getFileName().toString().startsWith("HR");

    /**
     * 払戻ファイル から 単勝払戻_払戻金頻度データを作成する
     * 
     * @return
     * @throws IOException
     */
    public static void makeTanHaraiHistgramData() throws IOException {
        
        List tanHaraiList = new ArrayList<>();
        
        /* ****************************************
         *  払戻ファイル から 単勝払戻_払戻金 リストを作成する
         * ****************************************/
        
        // 3.6 ディレクトリの特定のファイルのみをリスト
        Files.newDirectoryStream(Paths.get(JRAVAN_DATA_DIR),haraiFileFilter)
            .forEach(path -> {
                try(BufferedReader reader = Files.newBufferedReader(path)){
                    // 2.7 コレクションを単一の要素に集約
                    // 3.4 collect メソッドの使用
                    List tanHaraiTempList = 
                        reader.lines()
                            .mapToInt(line -> Integer.parseInt(line.substring(104, 113)))
                            .collect(ArrayList::new, ArrayList::add, ArrayList::addAll)
                            ;
                    tanHaraiList.addAll(tanHaraiTempList);
                }catch(IOException e) {
                    // 4.6 例外処理
                    throw new RuntimeException(e);
                }
            });
        
        /* ****************************
         * テキストファイルに結果を出力する
         * ****************************/
        
        Collections.sort(tanHaraiList);
        int cnt = tanHaraiList.size();
        int min = tanHaraiList.get(0);
        int max = tanHaraiList.get(cnt-1);
        int range = max - min;
        int histCnt = (int)Math.sqrt(max);
        int histWid = (int)Math.ceil(((double)range) / histCnt);
        double firstPeriod = min - (100d / 2d);
        
        try (BufferedWriter writer = Files.newBufferedWriter(Paths.get("c:\\work\\jra\\jraout.txt"))) {
            int sep = 1;
            for (Integer harai : tanHaraiList){
                writer.write(String.format("%d%s", harai, (((sep++ % 100)== 0)?"\r\n":"    ")));
            }
            
            writer.write("\r\n\r\n");
            writer.write(String.format("データの個数    %d\r\n", cnt));
            writer.write(String.format("最大値    %d\r\n", max));
            writer.write(String.format("最小値    %d\r\n", min));
            writer.write(String.format("範囲    %d\r\n", range));
            writer.write(String.format("区間の数    %d\r\n", histCnt));
            writer.write(String.format("区間の幅    %d\r\n", histWid));
            
            writer.write("\r\n\r\n");
            writer.write("データ区間\r\n");
            double period = firstPeriod;
            while(period <= (double)max) {
                writer.write(String.format("%#.1f\r\n", period));
                period += histWid;
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            System.out.println("Finish!");
        }
    }
}

実際には、「払戻ファイル から 単勝払戻_払戻金 リストを作成する」 の部分が、主眼の、Java 8 のストリームを使ったコードになります。

まずは、Java Doc 読んだほうがいいですかね。

http://docs.oracle.com/javase/jp/8/api/java/util/stream/Stream.html

1.2.1 Stream

まず、Streamとは、

順次および並列の集約操作をサポートする要素のシーケンス

で、プリミティブ型用の、IntStream、LongStreamおよびDoubleStream も存在してます。

複数のストリーム操作を組み合わせて1つのストリーム・パイプラインが形成されます。

これは、1つのデータソース に対して、0個以上の中間操作、1つの終端操作から構成されます。

また、中間操作は、ラムダ式のような動作を記述するパラメータを受け取ります。

絵にすると、こんな感じでしょうか。

java8_stream_image

ということで、上のコードでは、ディレクトリStream から、ファイル一覧を取得するときに、ファイル名の先頭文字にマッチさせるラムダ式を変数に格納したフィルタを適用(中間操作)した結果をforEach で処理(終端操作)しつつ、、、さらにそのファイルを開いて、ファイルを読んだ行をStreamとして、行の一部分を切り出し、int 型 Stream に変換(中間操作) した結果を コレクションに変換(collect 終端操作) しています。

この概念が分かっていれば、処理を命令の羅列ではなく、宣言的に記述することができるようになります。

1.3 ヒストグラムを作成してみる

ということで、EXCELビジネス統計分析 [ビジテク] 第2版 2013/2010/2007/2003対応

「002 ヒストグラムを書くには」の手順に従って、吐き出したテキストをExcel(2003しかないので2003に)貼り付け、データ分析(デフォルトではインストールされないので、インストールとアドオンの有効化が必要)からヒストグラムを作成してみます。

java8_stat_hist

入力範囲に、実際のデータ部分、データ区間に、データ区間以下のデータ範囲を指定して、グラフの作成にチェックを入れて、OK

java8_stat_hist_graph

とりあえず、ヒストグラムのグラフができました~

データの特性として、ヒストグラムを作成する意味があるかどうかとかよくわかりませんが。。。

9万件程度の結果の集計なんですが、500円未満で4万8千件程度あるので、半数は、500円未満の馬が勝ってるんですね。パレート図にするとよくわかりそうです。

Follow me!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です