Signature Description Parameters
#include <DataFrame/DataFrameStatsVisitors.h>

template<typename T, typename I = unsigned long>
struct PolyFitVisitor;

// -------------------------------------

template<typename T, typename I = unsigned long>
using pfit_v = PolyFitVisitor<T, I>;
        
This is a “single action visitor”, meaning it is passed the whole data vector in one call and you must use the single_act_visit() interface.

This functor fits a N-degree polynomial through the given x-y coordinates by the way of Least-Squares and Gaussian-Elimination
The result gives you the vector of coefficients.

There is also a method get_slope() which returns the first (0-degree) coefficient.
There is also a method get_residual() which returns the sum of weighted squared residuals.
    using weight_func = std::function<T (const I &idx, size_t val_index)>;

    explicit
    PolyFitVisitor(std::size_t degree,
                   weight_func w_func =
                       [](const I &, size_t) -> T { return (T(1)); });
		
degree: The polynomial degree
w_func: A functor that provides weights to be applied to sigma values. w_func is passed two parameters: (1) The value of the index column corresponding to the given y value, (2) The corresponding index into the y vector. The default is no weights.
T: Column data type.
I: Index type.
#include <DataFrame/DataFrameStatsVisitors.h>

template<typename T, typename I = unsigned long>
struct LogFitVisitor;

// -------------------------------------

template<typename T, typename I = unsigned long>
using lfit_v = LogFitVisitor<T, I>;
        
This is a “single action visitor”, meaning it is passed the whole data vector in one call and you must use the single_act_visit() interface.

This functor fits a y = b0 + b1 * log(x) through the given x-y coordinates by the way of calling PolyFit above on log(x).
The result gives you the vector of two coefficients.

There is also a method get_slope() which returns the first (0-degree) coefficient.
There is also a method get_residual() which returns the sum of weighted squared residuals.
    using weight_func = std::function<T (const I &idx, size_t val_index)>;

    explicit
    PolyFitVisitor(std::size_t degree,
                   weight_func w_func =
                       [](const I &, size_t) -> T { return (T(1)); });
		
degree: The polynomial degree
w_func: A functor that provides weights to be applied to sigma values. w_func is passed two parameters: (1) The value of the index column corresponding to the given y value, (2) The corresponding index into the y vector. The default is no weights.
T: Column data type.
I: Index type.
static void test_PolyFitVisitor()  {

    std::cout << "\nTesting PolyFitVisitor{  } ..." << std::endl;

    std::vector<unsigned long>  idx =
        { 123450, 123451, 123452, 123453, 123454, 123455, 123456, 123457, 123458, 123459, 123460, 123461, 123462, 123466,
          123467, 123468, 123469, 123470, 123471, 123472, 123473, 123467, 123468, 123469, 123470, 123471, 123472, 123473,
          123467, 123468, 123469, 123470, 123471, 123472, 123473,
        };
    MyDataFrame                 df;

    df.load_index(std::move(idx));
    df.load_column<double>("X1", { 1, 2, 3, 4, 5 }, nan_policy::dont_pad_with_nans);
    df.load_column<double>("Y1", { 6, 7, 8, 9, 3 }, nan_policy::dont_pad_with_nans);
    df.load_column<double>("X2", { 0.0, 1.0, 2.0, 3.0,  4.0,  5.0 }, nan_policy::dont_pad_with_nans);
    df.load_column<double>("Y2", { 0.0, 0.8, 0.9, 0.1, -0.8, -1.0 }, nan_policy::dont_pad_with_nans);

    PolyFitVisitor<double>  poly_v1 (2);
    PolyFitVisitor<double>  poly_v12 (
        2,
        [](const unsigned int &, std::size_t idx) -> double {
            const std::array<double, 5> weights = { 0.1, 0.8, 0.3, 0.5, 0.2 };

            return (weights[idx]);
        });
    auto                    result1 = df.single_act_visit<double, double>("X1", "Y1", poly_v1).get_result();
    auto                    result12 = df.single_act_visit<double, double>("X1", "Y1", poly_v12).get_result();
    auto                    actual1 = std::vector<double> { 0.8, 5.6, -1 };
    auto                    actual12 = std::vector<double> { -1.97994, 6.99713, -1.14327 };

    assert(std::fabs(poly_v1.get_residual() - 5.6) < 0.00001);
    for (size_t idx = 0; idx < result1.size(); ++idx)
       assert(fabs(result1[idx] - actual1[idx]) < 0.00001);

    assert(std::fabs(poly_v12.get_residual() - 0.70981) < 0.00001);
    for (size_t idx = 0; idx < result12.size(); ++idx)
       assert(fabs(result12[idx] - actual12[idx]) < 0.00001);

    PolyFitVisitor<double>  poly_v2 (3);
    auto                    result2 = df.single_act_visit<double, double>("X2", "Y2", poly_v2).get_result();
    auto                    actual2 = std::vector<double> { -0.0396825, 1.69312, -0.813492, 0.087037 };

    for (size_t idx = 0; idx < result2.size(); ++idx)
       assert(fabs(result2[idx] - actual2[idx]) < 0.00001);
}
// -----------------------------------------------------------------------------

static void test_LogFitVisitor()  {

    std::cout << "\nTesting LogFitVisitor{  } ..." << std::endl;

    std::vector<unsigned long>  idx =
        { 123450, 123451, 123452, 123453, 123454, 123455, 123456, 123457, 123458, 123459, 123460, 123461, 123462, 123466,
          123467, 123468, 123469, 123470, 123471, 123472, 123473, 123467, 123468, 123469, 123470, 123471, 123472, 123473,
          123467, 123468, 123469, 123470, 123471, 123472, 123473,
        };
    MyDataFrame                 df;

    df.load_index(std::move(idx));
    df.load_column<double>("X1", { 1, 2, 3, 4, 5 }, nan_policy::dont_pad_with_nans);
    df.load_column<double>("Y1", { 6, 7, 8, 9, 3 }, nan_policy::dont_pad_with_nans);
    df.load_column<double>("X2", { 1, 2, 4, 6, 8 }, nan_policy::dont_pad_with_nans);
    df.load_column<double>("Y2", { 1, 3, 4, 5, 6 }, nan_policy::dont_pad_with_nans);

    LogFitVisitor<double>   log_v1;
    auto                    result1 = df.single_act_visit<double, double>("X1", "Y1", log_v1).get_result();
    auto                    actual1 = std::vector<double> { 6.98618, -0.403317 };

    assert(std::fabs(log_v1.get_residual() - 20.9372) < 0.0001);
    for (size_t idx = 0; idx < result1.size(); ++idx)
       assert(fabs(result1[idx] - actual1[idx]) < 0.00001);

    LogFitVisitor<double>   log_v2;
    auto                    result2 = df.single_act_visit<double, double>("X2", "Y2", log_v2).get_result();
    auto                    actual2 = std::vector<double> { 1.11199, 2.25859 };

    assert(std::fabs(log_v2.get_residual() - 0.237476) < 0.00001);
    for (size_t idx = 0; idx < result2.size(); ++idx)
       assert(fabs(result2[idx] - actual2[idx]) < 0.00001);
}
C++ DataFrame