/*
* Concept profile generation tool suite
* Copyright (C) 2015 Biosemantics Group, Erasmus University Medical Center,
* Rotterdam, The Netherlands
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package org.erasmusmc.math;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class WeibullDistribution implements ProbablityDistribution {
/**
* location parameter
*/
private double omega;
/**
* shape parameter
*/
private double kappa;
/**
* scale parameter
*/
private double lambda;
public WeibullDistribution(double lambda,double kappa){
this.omega = 0d;
this.kappa= kappa;
this.lambda = lambda;
}
public WeibullDistribution(double lambda,double kappa,double omega){
this.omega = omega;
this.kappa = kappa;
this.lambda = lambda;
}
/**
* estimate parameters from values
* @param values
*/
public WeibullDistribution(Collection<Double> values){
estimateParameters(values);
}
public double getLocationParameter(){
return omega;
}
public double getShapeParameter(){
return kappa;
}
public double getScaleParameter(){
return lambda;
}
public double pValueBiggerThanX(double x){
if (x>0)
return Math.exp(-Math.pow((x-omega)/lambda,kappa));
else
return 1;
}
public double pValueSmallerThanX(double x){
if (x>0)
return 1d-Math.exp(-Math.pow((x-omega)/lambda,kappa));
else
return 0;
}
/**
* Least squared estimation of parameters: simplest but not necessarily best! Consider method of moments for better precision (but at lower speed);
*Note this function only matches beta and lambda, so assumes omega is zero!!!!
*Note 2: Do not put negative or zero values in here. For the same reason as above. There is no location estimation implemented and please take Weibull bounds into account(!).
*/
private void estimateParameters(Collection<Double> values){
List<Double> sortedValues = new ArrayList<Double>(values);
Collections.sort(sortedValues);
double sumOfRankScore = 0d;
double sumlnval = 0d;
double y = 0d;
double squaredLNvalSum = 0d;
int n= values.size();
for (int i = 1; i<=n;i++){
double value =sortedValues.get(i-1);
double rankscore = rankscore(n, i);
double lnx =Math.log(value);
sumOfRankScore+=rankscore;
sumlnval+=lnx;
y+=lnx*rankscore;
squaredLNvalSum+=lnx*lnx;
}
double avRankScore = sumOfRankScore/(double)n;
double avlnval=sumlnval/(double)n;
double nominator = y - sumOfRankScore * sumlnval/(double)n;
double denominator = squaredLNvalSum - sumlnval*sumlnval/(double) n;
kappa = nominator/ denominator;
lambda = Math.exp(avlnval-(avRankScore/kappa));
}
private double rankscore(int n, int i){
double medianRank = ((double)i-0.3)/(double)(n+0.4);
return Math.log(-Math.log(1d-medianRank));
}
}