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

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

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

template<typename T, typename I = unsigned long>
using ewm_v = ExponentiallyWeightedMeanVisitor<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 visitor calculates exponentially weighted mean (EWM). EWM gives more weight to recent data by using a decay factor.
Formula if finite_adjust is false (default):
    Yt = decay * Xt + (1 − decay) * Yt-1
		
Formula if finite_adjust is true:
          Xt + (1 - decay) * Xt-1 + (1 - decay)2 * Xt-2 + ... + (1 - decay)t * X0
    Yt = ------------------------------------------------------------------------
                  1 + (1 - decay) + (1 - decay)2 + ... + (1 - decay)t
		
Constructor:
    ExponentiallyWeightedMeanVisitor(
        exponential_decay_spec eds,  // See exponential_decay_spec type
        double value,                // Value to be decayed
        bool finite_adjust = false); // Adjust for the fact that this is not an infinite data set
        
T: Column data type
I: Index type
static void test_ExponentiallyWeightedMeanVisitor()  {

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

    std::vector<unsigned long>  idx =
        { 123450, 123451, 123452, 123453, 123454, 123455, 123456, 123457, 123458, 123459, 123460 };
    std::vector<double> d1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
    std::vector<double> d2 = { 8, 9, 10, 11,
                               std::numeric_limits<double>::quiet_NaN(),
                               13, 14,
                               std::numeric_limits<double>::quiet_NaN(),
                               16, 17, 18 };
    std::vector<double> d3 = { 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 };
    std::vector<double> d4 = { 22, 23, 24, 25, 26, 27 };
    std::vector<std::string> s1 = { "11", "22", "33", "aa", "bb", "cc", "dd" "tt", "uu", "ii", "88" };
    MyDataFrame         df;

    df.load_data(std::move(idx),
                 std::make_pair("col_1", d1),
                 std::make_pair("col_2", d2),
                 std::make_pair("col_3", d3),
                 std::make_pair("col_str", s1));
    df.load_column("col_4", std::move(d4), nan_policy::dont_pad_with_nans);

    ewm_v<double>   hl_expo_mean_roller(exponential_decay_spec::halflife, 0.5);
    const auto      &hl_expo_result = df.single_act_visit<double>("col_3", hl_expo_mean_roller).get_result();

    assert(hl_expo_result.size() == 11);
    assert(hl_expo_result[0] == 15.0);
    assert(fabs(hl_expo_result[1] - 15.75) < 0.01);
    assert(fabs(hl_expo_result[2] - 16.6875) < 0.0001);
    assert(fabs(hl_expo_result[5] - 19.667) < 0.001);
    assert(fabs(hl_expo_result[8] - 22.6667) < 0.0001);

    ewm_v<double>   cg_expo_mean_roller(exponential_decay_spec::center_of_gravity, 0.5);
    const auto      &cg_expo_result = df.single_act_visit<double>("col_3", cg_expo_mean_roller).get_result();

    assert(cg_expo_result.size() == 11);
    assert(cg_expo_result[0] == 15.0);
    assert(fabs(cg_expo_result[1] - 15.6667) < 0.0001);
    assert(fabs(cg_expo_result[2] - 16.5556) < 0.0001);
    assert(fabs(cg_expo_result[5] - 19.5021) < 0.0001);
    assert(fabs(cg_expo_result[8] - 22.5001) < 0.0001);

    ewm_v<double>   s_expo_mean_roller(exponential_decay_spec::span, 1.5);
    const auto      &s_expo_result = df.single_act_visit<double>("col_3", s_expo_mean_roller).get_result();

    assert(s_expo_result.size() == 11);
    assert(s_expo_result[0] == 15.0);
    assert(fabs(s_expo_result[1] - 15.8) < 0.01);
    assert(fabs(s_expo_result[2] - 16.76) < 0.001);
    assert(fabs(s_expo_result[5] - 19.7501) < 0.0001);
    assert(fabs(s_expo_result[8] - 22.75) < 0.001);

    ewm_v<double>   f_expo_mean_roller(exponential_decay_spec::fixed, 0.5);
    const auto      &f_expo_result = df.single_act_visit<double>("col_3", f_expo_mean_roller).get_result();

    assert(f_expo_result.size() == 11);
    assert(f_expo_result[0] == 15.0);
    assert(fabs(f_expo_result[1] - 15.5) < 0.01);
    assert(fabs(f_expo_result[2] - 16.25) < 0.001);
    assert(fabs(f_expo_result[5] - 19.0312) < 0.0001);
    assert(fabs(f_expo_result[8] - 22.0039) < 0.0001);

    ewm_v<double>   expo_mean_roller_3(exponential_decay_spec::span, 3);
    const auto      &expo_result_3 = df.single_act_visit<double>("col_3", expo_mean_roller_3).get_result();

    assert(expo_result_3.size() == 11);
    assert(expo_result_3[0] == 15.0);
    assert(std::fabs(expo_result_3[1] - 15.5) < 0.01);
    assert(std::fabs(expo_result_3[2] - 16.25) < 0.001);
    assert(std::fabs(expo_result_3[5] - 19.0312) < 0.0001);
    assert(std::fabs(expo_result_3[8] - 22.0039) < 0.0001);

    ewm_v<double>   expo_mean_roller_3_t(exponential_decay_spec::span, 3, true);
    const auto      &expo_result_3_t = df.single_act_visit<double>("col_3", expo_mean_roller_3_t).get_result();

    assert(expo_result_3_t.size() == 11);
    assert(expo_result_3_t[0] == 15.0);
    assert(std::fabs(expo_result_3_t[1] - 15.6667) < 0.0001);
    assert(std::fabs(expo_result_3_t[2] - 16.4286) < 0.0001);
    assert(std::fabs(expo_result_3_t[5] - 19.0952) < 0.0001);
    assert(std::fabs(expo_result_3_t[8] - 22.0176) < 0.0001);
}
C++ DataFrame