Regression Analysis: Add logarithmic, exponential and logistic regression.

This commit is contained in:
Kristian Bendiksen 2023-05-30 13:45:05 +02:00
parent d702b7a5d4
commit ca4d05dec9
3 changed files with 94 additions and 18 deletions

View File

@ -21,7 +21,10 @@
#include "cafPdmUiLineEditor.h" #include "cafPdmUiLineEditor.h"
#include "cafPdmUiTextEditor.h" #include "cafPdmUiTextEditor.h"
#include "ExponentialRegression.hpp"
#include "LinearRegression.hpp" #include "LinearRegression.hpp"
#include "LogarithmicRegression.hpp"
#include "LogisticRegression.hpp"
#include "PolynominalRegression.hpp" #include "PolynominalRegression.hpp"
#include "PowerFitRegression.hpp" #include "PowerFitRegression.hpp"
@ -38,6 +41,9 @@ void caf::AppEnum<RimSummaryRegressionAnalysisCurve::RegressionType>::setUp()
addItem( RimSummaryRegressionAnalysisCurve::RegressionType::LINEAR, "LINEAR", "Linear" ); addItem( RimSummaryRegressionAnalysisCurve::RegressionType::LINEAR, "LINEAR", "Linear" );
addItem( RimSummaryRegressionAnalysisCurve::RegressionType::POLYNOMINAL, "POLYNOMINAL", "Polynominal" ); addItem( RimSummaryRegressionAnalysisCurve::RegressionType::POLYNOMINAL, "POLYNOMINAL", "Polynominal" );
addItem( RimSummaryRegressionAnalysisCurve::RegressionType::POWER_FIT, "POWER_FIT", "Power Fit" ); addItem( RimSummaryRegressionAnalysisCurve::RegressionType::POWER_FIT, "POWER_FIT", "Power Fit" );
addItem( RimSummaryRegressionAnalysisCurve::RegressionType::EXPONENTIAL, "EXPONENTIAL", "Exponential" );
addItem( RimSummaryRegressionAnalysisCurve::RegressionType::LOGARITHMIC, "LOGARITHMIC", "Logarithmic" );
addItem( RimSummaryRegressionAnalysisCurve::RegressionType::LOGISTIC, "LOGISTIC", "Logistic" );
setDefault( RimSummaryRegressionAnalysisCurve::RegressionType::LINEAR ); setDefault( RimSummaryRegressionAnalysisCurve::RegressionType::LINEAR );
} }
}; // namespace caf }; // namespace caf
@ -132,6 +138,31 @@ std::tuple<std::vector<time_t>, std::vector<double>, QString>
return doubleVector; return doubleVector;
}; };
auto convertToTimeT = []( const std::vector<double>& timeSteps )
{
std::vector<time_t> tVector( timeSteps.size() );
std::transform( timeSteps.begin(),
timeSteps.end(),
tVector.begin(),
[]( const auto& timeVal ) { return static_cast<time_t>( timeVal ); } );
return tVector;
};
auto filterValues = []( const std::vector<double>& timeSteps, const std::vector<double>& values )
{
std::vector<double> filteredTimeSteps;
std::vector<double> filteredValues;
for ( size_t i = 0; i < timeSteps.size(); i++ )
{
if ( timeSteps[i] > 0.0 && values[i] > 0.0 )
{
filteredTimeSteps.push_back( timeSteps[i] );
filteredValues.push_back( values[i] );
}
}
return std::make_pair( filteredTimeSteps, filteredValues );
};
std::vector<double> timeStepsD = convertToDouble( timeSteps ); std::vector<double> timeStepsD = convertToDouble( timeSteps );
if ( m_regressionType == RegressionType::LINEAR ) if ( m_regressionType == RegressionType::LINEAR )
@ -150,25 +181,34 @@ std::tuple<std::vector<time_t>, std::vector<double>, QString>
} }
else if ( m_regressionType == RegressionType::POWER_FIT ) else if ( m_regressionType == RegressionType::POWER_FIT )
{ {
auto filterValues = []( const std::vector<double>& timeSteps, const std::vector<double>& values )
{
std::vector<double> filteredTimeSteps;
std::vector<double> filteredValues;
for ( size_t i = 0; i < timeSteps.size(); i++ )
{
if ( timeSteps[i] > 0.0 && values[i] > 0.0 )
{
filteredTimeSteps.push_back( timeSteps[i] );
filteredValues.push_back( values[i] );
}
}
return std::make_pair( filteredTimeSteps, filteredValues );
};
auto [filteredTimeSteps, filteredValues] = filterValues( timeStepsD, values ); auto [filteredTimeSteps, filteredValues] = filterValues( timeStepsD, values );
regression::PowerFitRegression powerFitRegression; regression::PowerFitRegression powerFitRegression;
powerFitRegression.fit( filteredTimeSteps, filteredValues ); powerFitRegression.fit( filteredTimeSteps, filteredValues );
std::vector<double> predictedValues = powerFitRegression.predict( timeStepsD ); std::vector<double> predictedValues = powerFitRegression.predict( filteredTimeSteps );
return { timeSteps, predictedValues, generateRegressionText( powerFitRegression ) }; return { convertToTimeT( filteredTimeSteps ), predictedValues, generateRegressionText( powerFitRegression ) };
}
else if ( m_regressionType == RegressionType::EXPONENTIAL )
{
auto [filteredTimeSteps, filteredValues] = filterValues( timeStepsD, values );
regression::ExponentialRegression exponentialRegression;
exponentialRegression.fit( filteredTimeSteps, filteredValues );
std::vector<double> predictedValues = exponentialRegression.predict( filteredTimeSteps );
return { convertToTimeT( filteredTimeSteps ), predictedValues, generateRegressionText( exponentialRegression ) };
}
else if ( m_regressionType == RegressionType::LOGARITHMIC )
{
auto [filteredTimeSteps, filteredValues] = filterValues( timeStepsD, values );
regression::LogarithmicRegression logarithmicRegression;
logarithmicRegression.fit( filteredTimeSteps, filteredValues );
std::vector<double> predictedValues = logarithmicRegression.predict( filteredTimeSteps );
return { convertToTimeT( filteredTimeSteps ), predictedValues, generateRegressionText( logarithmicRegression ) };
}
else if ( m_regressionType == RegressionType::LOGISTIC )
{
regression::LogisticRegression logisticRegression;
logisticRegression.fit( timeStepsD, values );
std::vector<double> predictedValues = logisticRegression.predict( timeStepsD );
return { timeSteps, predictedValues, generateRegressionText( logisticRegression ) };
} }
return { timeSteps, values, "" }; return { timeSteps, values, "" };
@ -315,3 +355,30 @@ QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regress
return QString( "y = %1 + x<sup>%2</sup>" ).arg( formatDouble( reg.scale() ) ).arg( formatDouble( reg.exponent() ) ) + return QString( "y = %1 + x<sup>%2</sup>" ).arg( formatDouble( reg.scale() ) ).arg( formatDouble( reg.exponent() ) ) +
QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() ); QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() );
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::ExponentialRegression& reg )
{
return QString( "y = %1 * e<sup>%2x</sup>" ).arg( formatDouble( reg.a() ) ).arg( formatDouble( reg.b() ) ) +
QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::LogarithmicRegression& reg )
{
return QString( "y = %1 + %2 * ln(x)" ).arg( formatDouble( reg.a() ) ).arg( formatDouble( reg.b() ) ) +
QString( "<br>R<sup>2</sup> = %1" ).arg( reg.r2() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimSummaryRegressionAnalysisCurve::generateRegressionText( const regression::LogisticRegression& reg )
{
// TODO: Display more parameters here.
return "";
}

View File

@ -30,7 +30,10 @@
namespace regression namespace regression
{ {
class ExponentialRegression;
class LinearRegression; class LinearRegression;
class LogarithmicRegression;
class LogisticRegression;
class PolynominalRegression; class PolynominalRegression;
class PowerFitRegression; class PowerFitRegression;
} // namespace regression } // namespace regression
@ -48,7 +51,10 @@ public:
{ {
LINEAR, LINEAR,
POLYNOMINAL, POLYNOMINAL,
POWER_FIT POWER_FIT,
EXPONENTIAL,
LOGARITHMIC,
LOGISTIC
}; };
RimSummaryRegressionAnalysisCurve(); RimSummaryRegressionAnalysisCurve();
@ -79,6 +85,9 @@ private:
static QString generateRegressionText( const regression::LinearRegression& reg ); static QString generateRegressionText( const regression::LinearRegression& reg );
static QString generateRegressionText( const regression::PolynominalRegression& reg ); static QString generateRegressionText( const regression::PolynominalRegression& reg );
static QString generateRegressionText( const regression::PowerFitRegression& reg ); static QString generateRegressionText( const regression::PowerFitRegression& reg );
static QString generateRegressionText( const regression::LogarithmicRegression& reg );
static QString generateRegressionText( const regression::ExponentialRegression& reg );
static QString generateRegressionText( const regression::LogisticRegression& reg );
static QString formatDouble( double v ); static QString formatDouble( double v );

@ -1 +1 @@
Subproject commit 8cb0644ae6983f4b69568164a595e2b287bc04ee Subproject commit 34bfe0f1eab0c8946ae5b988a39f7a2884508851