Lesson3, Lesson5, Lesson6で開発したプログラムをもとに、Lesson7用の仕様を追加していきます。
これにより、自身の計測値さえあれば、開発に対する多少のブレを含めた上での見積時間と見積総行数を見積もることが出来ます。
※ なお、Lesson5, 6に関しては、クラスとして利用出来るよう変更してください。
Lesson7: 「線形回帰パラメータと予測区間を計算する」
● プログラム仕様スクリプト
ASGKIT PROG7を参照のこと
● 実行結果
線形回帰パラメータと予測区間を計算する
rxy: 0.954497
r2: 0.911064
tail area: 0.000018
β0: -22.552533
β1: 1.727932
yk: 644.429384
range: 230.001974
UPI: 874.431357
LPI: 414.42741
● ソースコード
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Iterator;
import java.util.LinkedList;
/**
* PSP Lesson7:
* 線形回帰パラメータと予測区間を計算する
*
*/
public class Program7 {
private int size;
private double[] data1;
private double[] data2;
private double sumData1;
private double sumData2;
private double avgData1;
private double avgData2;
private double powData1;
private double powData2;
private double sumMulti;
private double beta0;
private double beta1;
private double r;
private double r2;
private double y;
private double tailArea;
private double p;
private double x;
private double deviation;
private double ran;
private double range;
private double upi;
private double lpi;
public static void main(String[] args) {
Program7 pg7 = new Program7();
try {
File f = new File(args[0]);
FileInputStream fi = new FileInputStream(f);
BufferedReader br = new BufferedReader(new InputStreamReader(fi,
"UTF-8"));
// 分析対象となるデータ行を指定する
int data1 = Integer.parseInt(args[1]);
int data2 = Integer.parseInt(args[2]);
// 分析対象のLOC
long num = Long.parseLong(args[3]);
LinkedList<Double> linkData1 = new LinkedList<Double>();
LinkedList<Double> linkData2 = new LinkedList<Double>();
String line;
while ((line = br.readLine()) != null) {
String[] strrec = line.split("t");
linkData1.add(Double.parseDouble(strrec[data1 - 1]));
linkData2.add(Double.parseDouble(strrec[data2 - 1]));
}
pg7.size = linkData1.size();
pg7.data1 = new double[pg7.size];
pg7.data2 = new double[pg7.size];
// 合計値を計算する
pg7.sumData1 = pg7.calcSum(linkData1);
pg7.sumData2 = pg7.calcSum(linkData2);
// 合計値から平均値を計算する
pg7.avgData1 = pg7.calcAvg(pg7.sumData1);
pg7.avgData2 = pg7.calcAvg(pg7.sumData2);
// X, Yの二乗の合計値、X*Yの合計値を計算する
pg7.powData1 = pg7.calcSumPow(linkData1);
pg7.powData2 = pg7.calcSumPow(linkData2);
pg7.sumMulti = pg7.calcSumMulti(linkData1, linkData2);
// β1 を計算する
pg7.beta1 = pg7.calcBeta1();
// β0 を計算する
pg7.beta0 = pg7.calcBeta0();
// R, R2 を計算する
pg7.r = pg7.calcR();
pg7.r2 = pg7.calcR2();
// tail areaを計算する
pg7.tailArea = pg7.calcTail();
// yを計算する
pg7.y = pg7.calcY(num);
// xを計算する
pg7.x = pg7.calcX();
// 標準偏差を計算する
pg7.deviation = pg7.calcDeviation();
// Rangeを前計算する
pg7.ran = pg7.calcRan(num);
// Rangeを計算する
pg7.range = pg7.calcRange();
// UPIを計算する
pg7.upi = pg7.calcUPI();
// LPIを計算する
pg7.lpi = pg7.calcLPI();
System.out.println("rxy: " + pg7.changeScale(pg7.r, 6));
System.out.println("r2: " + pg7.changeScale(pg7.r2, 6));
System.out.println("tail area: "
+ new DecimalFormat("0.#######").format(pg7.changeScale(
pg7.tailArea, 8)));
System.out.println("β0: " + pg7.changeScale(pg7.beta0, 6));
System.out.println("β1: " + pg7.changeScale(pg7.beta1, 6));
System.out.println("yk: " + pg7.changeScale(pg7.y, 6));
System.out.println("range: " + pg7.changeScale(pg7.range, 6));
System.out.println("UPI: " + pg7.changeScale(pg7.upi, 6));
System.out.println("LPI: " + pg7.changeScale(pg7.lpi, 6));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 合計値を計算する
*
*/
private Double calcSum(LinkedList<Double> linkArray) {
double sum = 0;
for (Iterator i = linkArray.iterator(); i.hasNext();) {
sum = sum + Double.parseDouble(i.next().toString());
}
return sum;
}
/**
* 平均値を計算する
*
*/
private Double calcAvg(Double sum) {
return sum / size;
}
/**
* X, Yの2乗合計値を計算する
*
*/
private Double calcSumPow(LinkedList<Double> linkArray) {
double sum = 0;
for (Iterator i = linkArray.iterator(); i.hasNext();) {
sum = sum + Math.pow(Double.parseDouble(i.next().toString()), 2);
}
return sum;
}
/**
* X*Yの合計値を計算する
*
*/
private Double calcSumMulti(LinkedList<Double> linkData1,
LinkedList<Double> linkData2) {
double sum = 0;
int i = 0;
while (linkData1.size() != 0 || linkData2.size() != 0) {
data1[i] = linkData1.pop();
data2[i] = linkData2.pop();
sum = sum + (data1[i] * data2[i]);
i++;
}
return sum;
}
/**
* β1 を計算する
*
*/
private Double calcBeta1() {
double num1 = (sumMulti - (size * avgData1 * avgData2));
double num2 = (powData1 - (size * avgData1 * avgData1));
return num1 / num2;
}
/**
* β0 を計算する
*
*/
private Double calcBeta0() {
return avgData2 - (beta1 * avgData1);
}
/**
* R を計算する
*
*/
private Double calcR() {
double num1 = (size * sumMulti) - (sumData1 * sumData2);
double num21 = (size * powData1) - (sumData1 * sumData1);
double num22 = (size * powData2) - (sumData2 * sumData2);
return num1 / (Math.sqrt(num21 * num22));
}
/**
* R2 を計算する
*
*/
private Double calcR2() {
return r * r;
}
/**
* Tail Area を計算する
*
*/
private Double calcTail() {
double num1 = r * Math.sqrt(size - 2);
double num2 = Math.sqrt(1 - r * r);
Tdist tDist = new Tdist();
tDist.start(num1 / num2, size - 2);
p = tDist.getP();
return (double) (1 - 2 * p);
}
/**
* Y を計算する
*
*/
private Double calcY(long num) {
return beta0 + beta1 * num;
}
/**
* PからXを計算する
*
*/
private Double calcX() {
RevTdist RevTdist = new RevTdist();
RevTdist.start(0.0, size - 2, 0.35);
double x = RevTdist.getX();
return x;
}
/**
* 標準偏差を計算する
*
*/
private Double calcDeviation() {
double sum = 0;
for (int i = 0; i < data1.length; i++) {
sum += Math.pow((data2[i] - beta0 - beta1 * data1[i]), 2);
}
double dist = sum / (size - 2);
double dev = Math.sqrt(dist);
return dev;
}
/**
* Rangeを前計算する
*
*/
private Double calcRan(long num) {
double num1 = Math.pow(num - avgData1, 2);
double num2 = 0;
for (int i = 0; i < data1.length; i++) {
num2 += Math.pow(data1[i] - avgData1, 2);
}
double sq = 1 + (double) 1 / size + (double) (num1 / num2);
return Math.sqrt(sq);
}
/**
* Rangeを計算する
*
*/
private Double calcRange() {
return x * deviation * ran;
}
/**
* UPIを計算する
*
*/
private Double calcUPI() {
return y + range;
}
/**
* LPIを計算する
*
*/
private Double calcLPI() {
return y - range;
}
/**
* 四捨五入を行う
*
*/
private double changeScale(double val, int i) {
BigDecimal bd = new BigDecimal(val);
return bd.setScale(i, BigDecimal.ROUND_HALF_UP).doubleValue();
}
}