mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[apps/regression] Power regression uses logarithm of series
This matches other apps results and we directly compute the values from the data instead of doing a gradient descent.
This commit is contained in:
@@ -176,8 +176,8 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int
|
||||
const int numberSignificantDigits = Preferences::LargeNumberOfSignificantDigits;
|
||||
if (i > 0 && j > 0 && j <= k_totalNumberOfDoubleBufferRows) {
|
||||
ArgCalculPointer calculationMethods[k_totalNumberOfDoubleBufferRows] = {&Store::meanOfColumn, &Store::sumOfColumn, &Store::squaredValueSumOfColumn, &Store::standardDeviationOfColumn, &Store::varianceOfColumn};
|
||||
double calculation1 = (m_store->*calculationMethods[j-1])(seriesNumber, 0);
|
||||
double calculation2 = (m_store->*calculationMethods[j-1])(seriesNumber, 1);
|
||||
double calculation1 = (m_store->*calculationMethods[j-1])(seriesNumber, 0, false);
|
||||
double calculation2 = (m_store->*calculationMethods[j-1])(seriesNumber, 1, false);
|
||||
EvenOddDoubleBufferTextCellWithSeparator * myCell = (EvenOddDoubleBufferTextCellWithSeparator *)cell;
|
||||
constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(numberSignificantDigits);
|
||||
char buffer[bufferSize];
|
||||
@@ -196,8 +196,16 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int
|
||||
}
|
||||
if (i > 0 && j > k_totalNumberOfDoubleBufferRows && j < k_regressionCellIndex) {
|
||||
assert(j != k_regressionCellIndex);
|
||||
CalculPointer calculationMethods[] = {&Store::doubleCastedNumberOfPairsOfSeries, &Store::covariance, &Store::columnProductSum};
|
||||
double calculation = (m_store->*calculationMethods[j-k_totalNumberOfDoubleBufferRows-1])(seriesNumber);
|
||||
double calculation = 0;
|
||||
const int calculationIndex = j-k_totalNumberOfDoubleBufferRows-1;
|
||||
if (calculationIndex == 0) {
|
||||
calculation = m_store->doubleCastedNumberOfPairsOfSeries(seriesNumber);
|
||||
} else if (calculationIndex == 1) {
|
||||
calculation = m_store->covariance(seriesNumber);
|
||||
} else {
|
||||
assert(calculationIndex == 2);
|
||||
calculation = m_store->columnProductSum(seriesNumber);
|
||||
}
|
||||
constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(numberSignificantDigits);
|
||||
char buffer[bufferSize];
|
||||
PoincareHelpers::ConvertFloatToText<double>(calculation, buffer, bufferSize, numberSignificantDigits);
|
||||
@@ -228,8 +236,8 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int
|
||||
if (j > k_regressionCellIndex + maxNumberCoefficients) {
|
||||
// Fill r and r2 if needed
|
||||
if (modelType == Model::Type::Linear) {
|
||||
CalculPointer calculationMethods[2] = {&Store::correlationCoefficient, &Store::squaredCorrelationCoefficient};
|
||||
double calculation = (m_store->*calculationMethods[j - k_regressionCellIndex - maxNumberCoefficients - 1])(seriesNumber);
|
||||
const int calculationIndex = j - k_regressionCellIndex - maxNumberCoefficients - 1;
|
||||
double calculation = calculationIndex == 0 ? m_store->correlationCoefficient(seriesNumber) : m_store->squaredCorrelationCoefficient(seriesNumber);
|
||||
constexpr int bufferSize = PrintFloat::charSizeForFloatsWithPrecision(numberSignificantDigits);
|
||||
char buffer[bufferSize];
|
||||
PoincareHelpers::ConvertFloatToText<double>(calculation, buffer, bufferSize, numberSignificantDigits);
|
||||
|
||||
@@ -12,7 +12,7 @@ public:
|
||||
I18n::Message formulaMessage() const override { return I18n::Message::LinearRegressionFormula; }
|
||||
double evaluate(double * modelCoefficients, double x) const override;
|
||||
double levelSet(double * modelCoefficients, double xMin, double step, double xMax, double y, Poincare::Context * context) override;
|
||||
virtual void fit(Store * store, int series, double * modelCoefficients, Poincare::Context * context) override;
|
||||
void fit(Store * store, int series, double * modelCoefficients, Poincare::Context * context) override;
|
||||
double partialDerivate(double * modelCoefficients, int derivateCoefficientIndex, double x) const override;
|
||||
int numberOfCoefficients() const override { return 2; }
|
||||
int bannerLinesCount() const override { return 3; }
|
||||
|
||||
@@ -61,6 +61,12 @@ double PowerModel::partialDerivate(double * modelCoefficients, int derivateCoeff
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void PowerModel::fit(Store * store, int series, double * modelCoefficients, Poincare::Context * context) {
|
||||
/* Y1 = aX1^b => ln(Y1) = ln(a) + b*ln(X1)*/
|
||||
modelCoefficients[0] = exp(store->yIntercept(series, true));
|
||||
modelCoefficients[1] = store->slope(series, true);
|
||||
}
|
||||
|
||||
bool PowerModel::dataSuitableForFit(Store * store, int series) const {
|
||||
if (!Model::dataSuitableForFit(store, series)) {
|
||||
return false;
|
||||
|
||||
@@ -13,10 +13,11 @@ public:
|
||||
double evaluate(double * modelCoefficients, double x) const override;
|
||||
double levelSet(double * modelCoefficients, double xMin, double step, double xMax, double y, Poincare::Context * context) override;
|
||||
double partialDerivate(double * modelCoefficients, int derivateCoefficientIndex, double x) const override;
|
||||
void fit(Store * store, int series, double * modelCoefficients, Poincare::Context * context) override;
|
||||
int numberOfCoefficients() const override { return 2; }
|
||||
int bannerLinesCount() const override { return 2; }
|
||||
protected:
|
||||
virtual bool dataSuitableForFit(Store * store, int series) const override;
|
||||
bool dataSuitableForFit(Store * store, int series) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -204,45 +204,53 @@ float Store::minValueOfColumn(int series, int i) const {
|
||||
return minColumn;
|
||||
}
|
||||
|
||||
double Store::squaredValueSumOfColumn(int series, int i) const {
|
||||
double Store::squaredValueSumOfColumn(int series, int i, bool lnOfSeries) const {
|
||||
double result = 0;
|
||||
for (int k = 0; k < numberOfPairsOfSeries(series); k++) {
|
||||
result += m_data[series][i][k]*m_data[series][i][k];
|
||||
if (lnOfSeries) {
|
||||
result += log(m_data[series][i][k]) * log(m_data[series][i][k]);
|
||||
} else {
|
||||
result += m_data[series][i][k]*m_data[series][i][k];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double Store::columnProductSum(int series) const {
|
||||
double Store::columnProductSum(int series, bool lnOfSeries) const {
|
||||
double result = 0;
|
||||
for (int k = 0; k < numberOfPairsOfSeries(series); k++) {
|
||||
result += m_data[series][0][k]*m_data[series][1][k];
|
||||
if (lnOfSeries) {
|
||||
result += log(m_data[series][0][k]) * log(m_data[series][1][k]);
|
||||
} else {
|
||||
result += m_data[series][0][k] * m_data[series][1][k];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double Store::meanOfColumn(int series, int i) const {
|
||||
return numberOfPairsOfSeries(series) == 0 ? 0 : sumOfColumn(series, i)/numberOfPairsOfSeries(series);
|
||||
double Store::meanOfColumn(int series, int i, bool lnOfSeries) const {
|
||||
return numberOfPairsOfSeries(series) == 0 ? 0 : sumOfColumn(series, i, lnOfSeries)/numberOfPairsOfSeries(series);
|
||||
}
|
||||
|
||||
double Store::varianceOfColumn(int series, int i) const {
|
||||
double mean = meanOfColumn(series, i);
|
||||
return squaredValueSumOfColumn(series, i)/numberOfPairsOfSeries(series) - mean*mean;
|
||||
double Store::varianceOfColumn(int series, int i, bool lnOfSeries) const {
|
||||
double mean = meanOfColumn(series, i, lnOfSeries);
|
||||
return squaredValueSumOfColumn(series, i, lnOfSeries)/numberOfPairsOfSeries(series) - mean*mean;
|
||||
}
|
||||
|
||||
double Store::standardDeviationOfColumn(int series, int i) const {
|
||||
return std::sqrt(varianceOfColumn(series, i));
|
||||
double Store::standardDeviationOfColumn(int series, int i, bool lnOfSeries) const {
|
||||
return std::sqrt(varianceOfColumn(series, i, lnOfSeries));
|
||||
}
|
||||
|
||||
double Store::covariance(int series) const {
|
||||
return columnProductSum(series)/numberOfPairsOfSeries(series) - meanOfColumn(series, 0)*meanOfColumn(series, 1);
|
||||
double Store::covariance(int series, bool lnOfSeries) const {
|
||||
return columnProductSum(series, lnOfSeries)/numberOfPairsOfSeries(series) - meanOfColumn(series, 0, lnOfSeries)*meanOfColumn(series, 1, lnOfSeries);
|
||||
}
|
||||
|
||||
double Store::slope(int series) const {
|
||||
return LinearModelHelper::Slope(covariance(series), varianceOfColumn(series, 0));
|
||||
double Store::slope(int series, bool lnOfSeries) const {
|
||||
return LinearModelHelper::Slope(covariance(series, lnOfSeries), varianceOfColumn(series, 0, lnOfSeries));
|
||||
}
|
||||
|
||||
double Store::yIntercept(int series) const {
|
||||
return LinearModelHelper::YIntercept(meanOfColumn(series, 1), meanOfColumn(series, 0), slope(series));
|
||||
double Store::yIntercept(int series, bool lnOfSeries) const {
|
||||
return LinearModelHelper::YIntercept(meanOfColumn(series, 1, lnOfSeries), meanOfColumn(series, 0, lnOfSeries), slope(series, lnOfSeries));
|
||||
}
|
||||
|
||||
double Store::yValueForXValue(int series, double x, Poincare::Context * globalContext) {
|
||||
|
||||
@@ -56,14 +56,14 @@ public:
|
||||
// Calculation
|
||||
double * coefficientsForSeries(int series, Poincare::Context * globalContext);
|
||||
double doubleCastedNumberOfPairsOfSeries(int series) const;
|
||||
double squaredValueSumOfColumn(int series, int i) const;
|
||||
double columnProductSum(int series) const;
|
||||
double meanOfColumn(int series, int i) const;
|
||||
double varianceOfColumn(int series, int i) const;
|
||||
double standardDeviationOfColumn(int series, int i) const;
|
||||
double covariance(int series) const;
|
||||
double slope(int series) const;
|
||||
double yIntercept(int series) const;
|
||||
double squaredValueSumOfColumn(int series, int i, bool lnOfSeries = false) const;
|
||||
double columnProductSum(int series, bool lnOfSeries = false) const;
|
||||
double meanOfColumn(int series, int i, bool lnOfSeries = false) const;
|
||||
double varianceOfColumn(int series, int i, bool lnOfSeries = false) const;
|
||||
double standardDeviationOfColumn(int series, int i, bool lnOfSeries = false) const;
|
||||
double covariance(int series, bool lnOfSeries = false) const;
|
||||
double slope(int series, bool lnOfSeries = false) const;
|
||||
double yIntercept(int series, bool lnOfSeries = false) const;
|
||||
double yValueForXValue(int series, double x, Poincare::Context * globalContext);
|
||||
double xValueForYValue(int series, double y, Poincare::Context * globalContext);
|
||||
double correlationCoefficient(int series) const;
|
||||
@@ -89,8 +89,7 @@ private:
|
||||
Poincare::Preferences::AngleUnit m_angleUnit;
|
||||
};
|
||||
|
||||
typedef double (Store::*ArgCalculPointer)(int, int) const;
|
||||
typedef double (Store::*CalculPointer)(int) const;
|
||||
typedef double (Store::*ArgCalculPointer)(int, int, bool) const;
|
||||
typedef void (Store::*RangeMethodPointer)();
|
||||
|
||||
}
|
||||
|
||||
@@ -98,12 +98,12 @@ int DoublePairStore::indexOfKthNonEmptySeries(int k) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
double DoublePairStore::sumOfColumn(int series, int i) const {
|
||||
double DoublePairStore::sumOfColumn(int series, int i, bool lnOfSeries) const {
|
||||
assert(series >= 0 && series < k_numberOfSeries);
|
||||
assert(i == 0 || i == 1);
|
||||
double result = 0;
|
||||
for (int k = 0; k < m_numberOfPairs[series]; k++) {
|
||||
result += m_data[series][i][k];
|
||||
result += lnOfSeries ? log(m_data[series][i][k]) : m_data[series][i][k];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
int indexOfKthNonEmptySeries(int k) const;
|
||||
|
||||
// Calculations
|
||||
double sumOfColumn(int series, int i) const;
|
||||
double sumOfColumn(int series, int i, bool lnOfSeries = false) const;
|
||||
bool seriesNumberOfAbscissaeGreaterOrEqualTo(int series, int i) const;
|
||||
uint32_t storeChecksum() const;
|
||||
uint32_t storeChecksumForSeries(int series) const;
|
||||
|
||||
Reference in New Issue
Block a user