前回は、
サンプルのソースコードが少々長くなりますが、
問題 最小二乗法を用いて、回帰直線の定数を求め、データにフィットするグラフを描きましょう。
今回の問題で示すソースコードには、
できる限り短いコードにするために、
今回読み込むデータは次のCSV
- 100,120
- 200,195
- 278,280
コンパイル時には、
正しくプログラムを作成したとしても、
C:\>javac Sample_RegLine.java -Xlint:unchecked
Sample_RegLine.java:126: 警告:[unchecked] raw 型java.util.Vector のメンバとしてのadd(E) への無検査呼び出しです。
Data.add(pos);
^
Sample_RegLine.java:145: 警告:[unchecked] raw 型java.util.Vector のメンバとして
のadd(E) への無検査呼び出しです。
v.add(rdata);
^
注:Sample_RegLine.java は推奨されないAPI を使用またはオーバーライドしています。
注:詳細については、-Xlint:deprecation オプションを指定して再コンパイルしてください。
警告2個
今回のプログラムが正しく実行されると、

C:\>java Sample_RegLine
y=ax+b
value of a = 0.4660083326656518
value of b = 125.40942232192933
バッチジョブを終了しますか(Y/N)? y
「バッチジョブを~」
それでは、
001: /*
002: * filename : Sample_RegLine.java
003: * CVSファイルを読み込んで、回帰直線の
004: * 定数値を求め、グラフ化します。
005: * compile : c:\>javac Sample_RegLine.java -Xlint:unchecked
006: * usage : c:\>java Sample_RegLine
007: */
008:
009: import java.io.*;
010: import java.util.*;
011: import java.lang.*;
012: import java.awt.*;
013:
014:
015: public class Sample_RegLine extends Frame {
016:
017: //データファイル名
018: static String DATAFILE = "./data001.csv";
019:
020: //表示するウインドウの最大・最小座標値
021: static int SCREEN_MAX_X = 300;
022: static int SCREEN_MIN_X = 0;
023: static int SCREEN_MAX_Y = 300;
024: static int SCREEN_MIN_Y = 0;
025: //
026: //グラフ中にデータをプロットする丸のサイズ
027: static int DATA_PLOT_OVAL_WIDTH = 4;
028: static int DATA_PLOT_OVAL_HEIGHT = 4;
029: //図形を描画するオブジェクト
030: MyCanvas mc;
031:
032: /**
033: * メインメソッド
034: * 簡略のためすべてここから呼び出し
035: */
036: public static void main (String args []) {
037:
038: //線形最小二乗法によって得られた定数
039: //y=ax+b のa,b を格納する。val[0]=a,val[1]=b
040: //基本型は参照渡しできないのでこうしてみる
041: double val[] = new double[2];
042: //ファイルから読み込んだデータの一時保管用
043: Vector v1 = new Vector();
044: //ファイルから読み込んだ元データは文字列であるため、
045: //数値に変換したものをこちらに格納する。
046: Vector DataA = new Vector();
047:
048: //データファイル読み込み
049: try{
050: readTextFromFile_AndSetVector(DATAFILE,v1);
051: }
052: catch(Exception e){
053: System.out.println(e.toString());
054: System.exit(-1);
055: }// of try catch
056:
057: //一時読み込みしたデータは文字列なので数値に変換し、
058: //配列にセットする
059: KataHenkan(v1,DataA);
060: //得られた数値データに最小二乗法を適用し、近似
061: //直線の定数を得る
062: SenkeiSaishouJijyouHou(DataA,val);
063:
064: System.out.println("y=ax+b");
065: System.out.println("value of a = "+val[0]);
066: System.out.println("value of b = "+val[1]);
067:
068: //ウインドウを作成し、結果を表示
069: new Sample_RegLine(DataA,val).show();
070:
071: }// end of main()
072:
073:
074:
075: /*
076: * 目的: 線形最小二乗法を実行
077: * 引数: data 数値データの配列への参照
078: * val[] 戻り値用 回帰直線の定数値
079: */
080: static void SenkeiSaishouJijyouHou(Vector Data,
081: double val[]){
082:
083: //----ここから
084:
085: //----ここまで
086:
087: }// end of SenkeiSaishouJijyouHou
088:
089: /*
090: * 目的: CSVの数値データを数値型に型変換
091: * 引数: v文字列のデータを格納したVector
092: * Data変換後のデータを格納したVector
093: */
094: static void KataHenkan(Vector v, Vector Data){
095: for(int i=0; i <= (v.size()-1); i++){
096: String str = (String)v.get(i);
097: StringTokenizer st
098: = new StringTokenizer(str, ",");
099: Point pos =
100: new Point(
101: Integer.parseInt((String)st.nextToken()),
102: Integer.parseInt((String)st.nextToken())
103: );
104: Data.add(pos);
105: }// of for i
106: }// end of static void KataHenkan
107:
108:
109:
110: /*
111: * 目的: CSVファイルから1行ずつデータを読み込む
112: * 引数: filenameデータファイルのファイル名
113: * vデータファイルから読み込んだデータ
114: */
115: static void readTextFromFile_AndSetVector
116: (String filename,Vector v) {
117: try {
118: FileReader fr = new FileReader(filename);
119: BufferedReader br = new BufferedReader(fr);
120: String rdata;
121: String alldata = "";
122: while((rdata = br.readLine()) != null) {
123: v.add(rdata);
124: }// of while
125: fr.close();
126: }catch(Exception e){
127: System.out.println(e);
128: }// of try catch
129: }// of readTextFromFile_AndSetVector
130:
131: /*
132: * 目的: コンストラクタ
133: * 引数: Dataプロットするデータ
134: * val回帰直線の定数
135: */
136: public Sample_RegLine
137: (Vector Data,double val[]) {
138: super();
139: setTitle("最小二乗法のグラフをプロットする");
140: setSize(SCREEN_MAX_X-SCREEN_MIN_X,
141: SCREEN_MAX_Y-SCREEN_MIN_Y);
142: setLayout(null);
143:
144: mc = new MyCanvas();
145: mc.setBounds(SCREEN_MIN_X,SCREEN_MIN_Y, //左上隅の座標値
146: SCREEN_MAX_X,SCREEN_MAX_Y);//Width とHeight
147:
148: mc.setData(Data);
149: mc.setVals(val);
150: this.add(mc);
151: }// end of Sample_RegLine(コンストラクタ)
152:
153: /**
154: *目的: 描画関係をまとめた。
155: */
156: class MyCanvas extends Canvas {
157:
158: Vector plotData;
159: double val[];
160:
161: //ウインドウが再描画されるときにデータと
162: //直線を再描画
163: public void paint(Graphics g) {
164: plotPoints();
165: plotLine();
166: }// end of paint
167:
168: //描画するデータへの参照を受け取る
169: public void setData(Vector Data){
170: plotData = Data;
171: }//end of setData
172:
173: //描画する近似直線式の定数を受け取る
174: public void setVals(double vals[]){
175: val = vals;
176: }// end of setVals
177:
178: //近似直線を描画する
179: void plotLine(){
180: Graphics g=getGraphics();
181: g.setColor(Color.blue);
182: g.drawLine(0,-(int)(val[1]) + SCREEN_MAX_Y,
183: SCREEN_MAX_X,
184: - (int)(SCREEN_MAX_X*val[0]+val[1]) + SCREEN_MAX_Y);
185: }// end of plotLine
186:
187: //データを画面に点をプロットする。
188: void plotPoints(){
189: Graphics g=getGraphics();
190: g.setColor(Color.red);
191:
192: Point temp = new Point();
193: for (int i=0; i< plotData.size() ; i++){
194: temp = (Point)plotData.get(i);
195: g.drawOval((int)temp.getX(),
196: -(int)temp.getY() + SCREEN_MAX_Y,
197: DATA_PLOT_OVAL_WIDTH,
198: DATA_PLOT_OVAL_HEIGHT);
199: }// of for i
200: }//end fo plotPoints()
201: }// end of MyCanvas
202: }// end of this file...
解説
問題 最小二乗法を用いて、
コードの不足していた部分を示します。いかがでしょう。前回までに学んだややこしい数式の羅列も、
01: /*
02: * 目的: 線形最小二乗法を実行
03: * 引数: data数値データの配列への参照
04: * val[] 戻り値用 回帰直線の定数値
05: */
06: static void SenkeiSaishouJijyouHou(Vector Data,
07: double val[]){
08: double x,y,x_sum=0,y_sum=0, xx_sum=0,xy_sum=0;
09: int n;
10: Point temp;
11: n = Data.size();
12: for(int i=0;i<Data.size();i++){
13: temp = (Point)Data.get(i);
14: x=(double)temp.getX();
15: y=(double)temp.getY();
16: x_sum+=x;
17: y_sum+=y;
18: xx_sum+=x*x;
19: xy_sum+=x*y;
20: }// of for i
21: val[0]= (double) (n*xy_sum-x_sum*y_sum)
22: / (double) (n*xx_sum-x_sum*x_sum);
23: val[1]= (double) (xx_sum*y_sum - xy_sum * x_sum)
24: / (double) (n*xx_sum-x_sum*x_sum);
25: }// end of SenkeiSaishouJijyouHou
今回はここまで
Java言語を使って回帰直線を得る実習は、
お疲れ様でした。長いコードを打ち込むことは大変だったことでしょう。