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

template<typename T, typename I = unsigned long>
struct MeanVisitor;
        
This functor class calculates the mean of a given column.
The constructor takes a single optional Boolean argument to whether skip NaN values. The default is True.
T: Column data type
I: Index type
#include <DataFrame/DataFrameStatsVisitors.h>

template<typename T, typename I = unsigned long>
struct WeightedMeanVisitor;
        
This functor class calculates weighted mean of a given column. It favors more recent data.
The numerator is V0 * 1 + V1 * 2 + ... + Vn-1 * n. The denominator is (n * (n + 1)) / 2.
The constructor takes a single optional Boolean argument to whether skip NaN values. The default is True.
T: Column data type
I: Index type
#include <DataFrame/DataFrameStatsVisitors.h>

template<typename T, typename I = unsigned long>
struct GeometricMeanVisitor;
        
This functor class calculates the geometric mean of a given column.
The constructor takes a single optional Boolean argument to whether skip NaN values. The default is True.
T: Column data type.
I: Index type.
#include <DataFrame/DataFrameStatsVisitors.h>

template<typename T, typename I = unsigned long>
struct HarmonicMeanVisitor;
        
This functor class calculates the harmonic mean of a given column.
The constructor takes a single optional Boolean argument to whether skip NaN values. The default is True.
T: Column data type.
I: Index type.
#include <DataFrame/DataFrameStatsVisitors.h>

template<typename T, typename I = unsigned long>
struct QuadraticMeanVisitor;
        
This functor class calculates weighted mean of a given column. It favors more recent data.
The mean is calculated as √(X02 + X12 + ... + Xn-12) / n
The constructor takes a single optional Boolean argument to whether skip NaN values. The default is True.
T: Column data type
I: Index type
static void test_view_visitors()  {

    std::cout << "\nTesting View visitors ..." << std::endl;

    MyDataFrame         df;

    std::vector<unsigned long>  idxvec = { 1UL, 2UL, 3UL, 4UL, 5UL, 6UL, 7UL, 8UL, 9UL, 10UL };
    std::vector<double>         dblvec1 = { 1.1, 2.2, 3.3, 4.4, 5.5 };
    std::vector<double>         dblvec2 = { 2.2, 3.3, 4.4, 5.5, 6.6 };
    std::vector<double>         dblvec3 = { 0.0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9 };
    std::vector<double>         dblvec4 = { 5.9, 4.4, 1.0, 9.8, 5.3, 7.2, 3.8, 4.1 };
    std::vector<double>         dblvec5 = { 1.1, 5.9, 4.4, 1.0, 9.8, 5.3, 7.2, 3.8, 4.1, 10.1 };
    std::vector<double>         dblvec6 = { 1.1, 1.1, 3.3, 3.3, 1.1 };

    df.load_data(std::move(idxvec),
                 std::make_pair("dbl_col1", dblvec1),
                 std::make_pair("dbl_col2", dblvec2),
                 std::make_pair("dbl_col3", dblvec3),
                 std::make_pair("dbl_col4", dblvec4),
                 std::make_pair("dbl_col5", dblvec5),
                 std::make_pair("dbl_col6", dblvec6));

    typedef DataFrameView<unsigned long> MyDataFrameView;

    MyDataFrameView dfv = df.get_view_by_idx<double>(Index2D<unsigned long> { 2, 4 });
    assert(dfv.get_index().size() == 3);
    MeanVisitor<double> mean_visitor;
    assert(fabs(dfv.visit<double>("dbl_col1", mean_visitor).get_result() - 3.3) < 0.00001);

    DotProdVisitor<double> dp_visitor;
    assert(fabs(dfv.visit<double, double>("dbl_col1", "dbl_col2", dp_visitor).get_result() - 45.98) < 0.00001);


    SimpleRollAdopter<MeanVisitor<double>, double> mean_roller1(MeanVisitor<double>(), 3);
    const auto &res_sra = dfv.single_act_visit<double>("dbl_col1", mean_roller1).get_result();

    assert(fabs(res_sra[2] - 3.3) < 0.00001);

    SimpleRollAdopter<GeometricMeanVisitor<double>, double> geo_mean_roller(GeometricMeanVisitor<double>(), 3);
    const auto  &res_srga = df.single_act_visit<double>("dbl_col4", geo_mean_roller).get_result();

    assert(fabs(res_srga[2] - 2.96098) < 0.00001);
    assert(fabs(res_srga[6] - 5.25368) < 0.00001);

    SimpleRollAdopter<HarmonicMeanVisitor<double>, double> har_mean_roller(HarmonicMeanVisitor<double>(), 3);
    const auto  &res_srha = df.single_act_visit<double>("dbl_col4", har_mean_roller).get_result();

    assert(fabs(res_srha[2] - 2.14782) < 0.00001);
    assert(fabs(res_srha[6] - 5.0785) < 0.00001);

    CumSumVisitor<double> cs_visitor;
    const auto &res_cs = dfv.single_act_visit<double>("dbl_col1", cs_visitor).get_result();
    assert(fabs(res_cs[0] - 2.2) < 0.00001);
    assert(fabs(res_cs[1] - 5.5) < 0.00001);
    assert(fabs(res_cs[2] - 9.9) < 0.00001);

    CumProdVisitor<double> cp_visitor;
    const auto &res_cp = dfv.single_act_visit<double>("dbl_col1", cp_visitor).get_result();
    assert(fabs(res_cp[0] - 2.2) < 0.00001);
    assert(fabs(res_cp[1] - 7.26) < 0.00001);
    assert(fabs(res_cp[2] - 31.944) < 0.00001);

    CumMinVisitor<double> cmin_visitor;
    const auto &res_cmin = dfv.single_act_visit<double>("dbl_col1", cmin_visitor).get_result();
    assert(fabs(res_cmin[0] - 2.2) < 0.00001);
    assert(fabs(res_cmin[1] - 2.2) < 0.00001);
    assert(fabs(res_cmin[2] - 2.2) < 0.00001);

    CumMaxVisitor<double> cmax_visitor;
    const auto &res_cmax = dfv.single_act_visit<double>("dbl_col1", cmax_visitor).get_result();
    assert(fabs(res_cmax[0] - 2.2) < 0.00001);
    assert(fabs(res_cmax[1] - 3.3) < 0.00001);
    assert(fabs(res_cmax[2] - 4.4) < 0.00001);

    MyDataFrameView dfv2 = df.get_view_by_idx<double>(Index2D<unsigned long> { 2, 9 });

    AutoCorrVisitor<double> ac_visitor;
    const auto &res_ac = dfv2.single_act_visit<double>("dbl_col5", ac_visitor).get_result();
    assert(fabs(res_ac[1] - -0.36855) < 0.00001);
    // assert(fabs(res_ac[5] - 0.67957) < 0.0001);

    ReturnVisitor<double> ret_visitor(return_policy::monetary);
    const auto &res_ret = df.single_act_visit<double>("dbl_col4", ret_visitor).get_result();
    assert(fabs(res_ret[0] - -1.5) < 0.00001);
    assert(fabs(res_ret[6] - 0.3) < 0.00001);

    MedianVisitor<double> med_visitor;
    const auto &res_med = dfv2.single_act_visit<double>("dbl_col3", med_visitor).get_result();
    assert(fabs(res_med - 4.95) < 0.00001);

    ModeVisitor<2, double> mode_visitor;
    const auto &res_mode = dfv2.single_act_visit<double>("dbl_col6", mode_visitor).get_result();
    assert(fabs(res_mode[1].get_value() - 3.3) < 0.00001);

    DiffVisitor<double> diff_visitor(1);
    const auto &res_diff = dfv.single_act_visit<double>("dbl_col1", diff_visitor).get_result();
    assert(res_diff.size() == 2);
    assert(fabs(res_diff[0] - 1.1) < 0.00001);
    assert(fabs(res_diff[1] - 1.1) < 0.00001);

    ZScoreVisitor<double> zs_visitor;
    const auto &res_zs = dfv2.single_act_visit<double>("dbl_col5", zs_visitor).get_result();
    assert(fabs(res_zs[2] - -1.61418) < 0.00001);
    assert(fabs(res_zs[4] - 0.04336) < 0.00001);
}
static void test_DoubleCrossOver()  {

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

    MyDataFrame::set_thread_level(10);

    std::vector<unsigned long>  idx =
        { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
          21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 };
    std::vector<double> d1 =
        { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
          19, 18, 17, 17, 16, 15, 14, 13, 14, 13, 12, 11, 12, 10, 9, 8, 7, 6, 7, 5 };
    MyDataFrame         df;

    df.load_data(std::move(idx), std::make_pair("col_1", d1));

    using geo_mean_t = GeometricMeanVisitor<double>;
    using mean_t = MeanVisitor<double>;
    using short_roller_t = SimpleRollAdopter<geo_mean_t, double>;
    using long_roller_t = ExponentialRollAdopter<mean_t, double>;
    using double_cross_t = DoubleCrossOver<short_roller_t, long_roller_t, double>;

    double_cross_t  visitor(short_roller_t(geo_mean_t(), 3), long_roller_t(mean_t(), 4, exponential_decay_spec::span, 1.5));

    df.single_act_visit<double>("col_1", visitor);

    auto    &raw_to_short = visitor.get_raw_to_short_term();
    auto    &raw_to_long = visitor.get_raw_to_long_term();
    auto    &short_to_long = visitor.get_short_term_to_long_term();

    assert(raw_to_short.size() == 40);
    assert(std::isnan(raw_to_short[1]));
    assert(fabs(raw_to_short[8] - 1.04189) < 0.00001);
    assert(fabs(raw_to_short[12] - 1.02784) < 0.00001);
    assert(fabs(raw_to_short[39] - -0.943922) < 0.00001);
    assert(fabs(raw_to_short[38] - 0.3506) < 0.00001);

    assert(raw_to_long.size() == 40);
    assert(std::isnan(raw_to_long[2]));
    assert(fabs(raw_to_long[8] - 0.2504) < 0.00001);
    assert(fabs(raw_to_long[12] - 0.250001) < 0.00001);
    assert(fabs(raw_to_long[39] - -0.370008) < 0.00001);
    assert(fabs(raw_to_long[38] - 0.149962) < 0.00001);

    assert(short_to_long.size() == 40);
    assert(std::isnan(short_to_long[0]));
    assert(fabs(short_to_long[8] - -0.791486) < 0.00001);
    assert(fabs(short_to_long[12] - -0.777842) < 0.00001);
    assert(fabs(short_to_long[39] - 0.573914) < 0.00001);
    assert(fabs(short_to_long[38] - -0.200639) < 0.00001);

    MyDataFrame::set_thread_level(0);
}