← Back to Documentations

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

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

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

template<typename T, typename I = unsigned long>
using exs_v = ExpoSmootherVisitor<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 is a transformer visitor. It means the column(s) passed to this visitor is not read-only and its values may change

This functor does exponential smoothing of the time-series by
Y0 = X0
Yt = aXt + (1 - a)Yt-1

This works with both scalar and multidimensional (i.e. vectors and arrays) datasets.
explicit
ExpoSmootherVisitor(value_type alfa,
                    // You can do multiple smoothing in one call
                    std::size_t repeat_count = 1);
        
alfa is the smoothing factor, and 0 < alfa < 1. Factor of 1 will not change the data. In case of multidimensional input, alfa is a vector of the same size as the dimension.
T: Column data type.
I: Index type.
#include <DataFrame/DataFrameTransformVisitors.h>

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

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

template<typename T, typename I = unsigned long>
using hwexp_v = HWExpoSmootherVisitor<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 is a transformer visitor. It means the column(s) passed to this visitor is not read-only and its values may change

This functor does double exponential smoothing by Holt-Winters method. The advantage for this over the above visitor is that HW takes care of trends in the data
Y0 = X0
B0 = X1 - X0
And for t > 0:
Yt = aXt + (1 - a) (Yt-1 + Bt-1)
Bt = b(Yt - Yt-1) + (1 - b)Bt-1

This works with both scalar and multidimensional (i.e. vectors and arrays) datasets.
HWExpoSmootherVisitor(value_type alfa, value_type beta);
        
alfa is the data smoothing factor, 0 < a < 1, and beta is the trend smoothing factor, 0 < b < 1. In case of multidimensional input, alfa/beta are vectors of the same size as the dimension.
T: Column data type.
I: Index type.
static void test_ExpoSmootherVisitor()  {

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

    StlVecType<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,
        };
    StlVecType<double>         d1 =
        { 2.5, 2.45, -1.65, -0.1, -1.1, 1.87, 0.98, 0.34, 1.56, -12.34, 2.3, -0.34, -1.9, 0.387, 0.123, 1.06, -0.65, 2.03, 0.4, -1.0, 0.59, 0.125,
          1.9, -0.68, 2.0045, 50.8, -1.0, 0.78, 0.48, 1.99, -0.97, 1.03, 8.678, -1.4, 1.59,
        };
    StlVecType<double>         d1_copy = d1;
    MyDataFrame                df;

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

    MyDataFrame df2 = df;

    ExpoSmootherVisitor<double> es_v1(1);

    df.single_act_visit<double>("dbl_col", es_v1);

    const auto  &col1 = df.get_column<double>("dbl_col");
    auto        actual = StlVecType<double> {
        2.5, 2.5, 2.45, -1.65, -0.1, -1.1, 1.87, 0.98, 0.34, 1.56, -12.34, 2.3, -0.34, -1.9, 0.387, 0.123, 1.06, -0.65, 2.03, 0.4, -1, 0.59, 0.125,
        1.9, -0.68, 2.0045, 50.8, -1, 0.78, 0.48, 1.99, -0.97, 1.03, 8.678, -1.4
    };

    for (size_t i = 0; i < col1.size(); ++i)
        assert((fabs(col1[i] - d1_copy[i]) < 0.00001) || (fabs(col1[i] - actual[i]) < 0.0001));

    ExpoSmootherVisitor<double> es_v2(0.3);

    df.single_act_visit<double>("dbl_col", es_v2);

    auto    actual2 = StlVecType<double> {
        2.5, 2.485, 1.2445, 0.84115, 0.258805, 0.742163, 0.813514, 0.67146, 0.938022, -3.04538, -1.44177, -1.11124, -1.34787, -0.827407, -0.542285,
        -0.0615993, -0.23812, 0.442316, 0.429621, 0.000734997, 0.177514, 0.16176, 0.683232, 0.274262, 0.793334, 15.7953, 10.7567, 7.76371,
        5.5786, 4.50202, 2.86041, 2.31129, 4.2213, 2.53491, 2.25144
    };

    for (size_t i = 0; i < col1.size(); ++i)
        assert((std::fabs(col1[i] - actual2[i]) < 0.0001));

    df.get_column<double>("dbl_col") = d1_copy;

    ExpoSmootherVisitor<double> es_v3(0.8);

    df.single_act_visit<double>("dbl_col", es_v3);

    auto    actual3 = StlVecType<double> {
        2.5, 2.46, -0.828, -0.2456, -0.92912, 1.31018, 1.04604, 0.481207, 1.34424, -9.60315, -0.0806303, -0.288126, -1.57763, -0.00592504,
        0.097215, 0.867443, -0.346511, 1.5547, 0.63094, -0.673812, 0.337238, 0.167448, 1.55349, -0.233302, 1.55694, 40.9514, 7.39028, 2.10206,
        0.804411, 1.75288, -0.425424, 0.738915, 7.09018, 0.298037, 1.33161
    };

    for (size_t i = 0; i < col1.size(); ++i)
        assert((std::fabs(col1[i] - actual3[i]) < 0.0001));

    ExpoSmootherVisitor<double> es_v3_4 (0.8, 4);
    const auto                  &col21 = df2.get_column<double>("dbl_col");

    df2.single_act_visit<double>("dbl_col", es_v3_4);

    auto    actual4 = StlVecType<double> {
        2.5, 2.47952, 0.783776, 0.066976, -0.509741, 0.363199, 0.815194, 0.687833, 1.00603, -4.38921, -2.79003, -1.28679, -1.28013, -0.639015,
        -0.190314, 0.396383, 0.0781416, 0.793802, 0.793116, 0.0362468, 0.10559, 0.151083, 0.873655, 0.387457, 0.925997, 21.4832, 16.5657, 8.44511,
        3.6629, 2.21433, 0.738794, 0.585184, 3.91034, 2.43449, 1.67792
    };

    for (size_t i = 0; i < col21.size(); ++i)
        assert((std::fabs(col21[i] - actual4[i]) < 0.0001));

    // Now multidimensional data
    //
    constexpr std::size_t   dim { 3 };

    using ary_col_t = std::array<double, dim>;
    using vec_col_t = std::vector<double>;

    StlVecType<ary_col_t>   ary_col  {
        {   2.5,     2.45, -1.65  },
        {  -0.1,    -1.1,   1.87  },
        {   0.98,    0.34,  1.56  },
        { -12.34,    2.3,  -0.34  },
        {  -1.9,     0.387, 0.123 },
        {   1.06,   -0.65,  2.03  },
        {   0.4,    -1.0,   0.59  },
        {   0.125,   1.9,  -0.68  },
        {   2.0045, 50.8,  -1.0   },
        {   0.78,    0.48,  1.99  },
        {  -0.97,    1.03,  8.678 },
        {  -1.4,     1.59,  0.7   }
    };
    StlVecType<vec_col_t>   vec_col  {
        {   2.5,     2.45, -1.65  },
        {  -0.1,    -1.1,   1.87  },
        {   0.98,    0.34,  1.56  },
        { -12.34,    2.3,  -0.34  },
        {  -1.9,     0.387, 0.123 },
        {   1.06,   -0.65,  2.03  },
        {   0.4,    -1.0,   0.59  },
        {   0.125,   1.9,  -0.68  },
        {   2.0045, 50.8,  -1.0   },
        {   0.78,    0.48,  1.99  },
        {  -0.97,    1.03,  8.678 },
        {  -1.4,     1.59,  0.7   }
    };

    df2.load_column<ary_col_t>("ARY COL", std::move(ary_col), nan_policy::dont_pad_with_nans);
    df2.load_column<vec_col_t>("VEC COL", std::move(vec_col), nan_policy::dont_pad_with_nans);

    const ary_col_t                 ary_alfa = { 0.8, 0.8, 0.8 };
    ExpoSmootherVisitor<ary_col_t>  ary_es (ary_alfa, 4);
    const vec_col_t                 vec_alfa = { 0.8, 0.8, 0.8 };
    ExpoSmootherVisitor<vec_col_t>  vec_es (vec_alfa, 4);

    df2.single_act_visit<ary_col_t>("ARY COL", ary_es);
    df2.single_act_visit<vec_col_t>("VEC COL", vec_es);

    const auto  &ary_col_ref { df2.get_column<ary_col_t>("ARY COL") };
    const auto  &vec_col_ref { df2.get_column<vec_col_t>("VEC COL") };

    assert(ary_es.get_result() == 12);
    assert(vec_es.get_result() == 12);

    assert(std::abs(ary_col_ref[0][0] - 2.5) < 0.00001);
    assert(std::abs(ary_col_ref[0][2] - -1.65) < 0.00001);
    assert(std::abs(ary_col_ref[3][0] - -4.50252) < 0.00001);
    assert(std::abs(ary_col_ref[3][1] - 1.11552) < 0.00001);
    assert(std::abs(ary_col_ref[8][1] - 21.2502) < 0.0001);
    assert(std::abs(ary_col_ref[8][2] - -0.398169) < 0.000001);
    assert(std::abs(ary_col_ref[11][0] - -0.627266) < 0.000001);
    assert(std::abs(ary_col_ref[11][2] - 3.38414) < 0.00001);
    assert(std::abs(vec_col_ref[0][0] - 2.5) < 0.00001);
    assert(std::abs(vec_col_ref[0][2] - -1.65) < 0.00001);
    assert(std::abs(vec_col_ref[3][0] - -4.50252) < 0.00001);
    assert(std::abs(vec_col_ref[3][1] - 1.11552) < 0.00001);
    assert(std::abs(vec_col_ref[8][1] - 21.2502) < 0.0001);
    assert(std::abs(vec_col_ref[8][2] - -0.398169) < 0.000001);
    assert(std::abs(vec_col_ref[11][0] - -0.627266) < 0.000001);
    assert(std::abs(vec_col_ref[11][2] - 3.38414) < 0.00001);
}

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

static void test_HWExpoSmootherVisitor()  {

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

    StlVecType<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,
        };
    StlVecType<double>         d1 =
        { 2.5, 2.45, -1.65, -0.1, -1.1, 1.87, 0.98, 0.34, 1.56, -12.34, 2.3, -0.34, -1.9, 0.387,
          0.123, 1.06, -0.65, 2.03, 0.4, -1.0, 0.59, 0.125, 1.9, -0.68, 2.0045, 50.8, -1.0, 0.78,
          0.48, 1.99, -0.97, 1.03, 8.678, -1.4, 1.59,
        };
    StlVecType<double>         d1_copy = d1;
    MyDataFrame                 df;

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

    HWExpoSmootherVisitor<double>   es_v1(1, 1);

    df.single_act_visit<double>("dbl_col", es_v1);

    const auto  &col1 = df.get_column<double>("dbl_col");

    for (size_t i = 0; i < col1.size(); ++i)
       assert(fabs(col1[i] - d1_copy[i]) < 0.00001);

    HWExpoSmootherVisitor<double>   es_v2(0.3, 0.4);

    df.single_act_visit<double>("dbl_col", es_v2);

    auto    actual2 = StlVecType<double> {
        2.5, 2.45, 1.185, 0.4243, -0.471106, -0.282357, -0.158951, -0.127892, 0.315996, -3.394, -2.67252, -2.36278, -2.37123, -1.6345, -0.955403,
        -0.0695294, 0.173125, 1.04821, 1.28958, 0.931793, 0.926526, 0.742956, 1.0728, 0.628958, 0.966542, 15.9661, 15.1058, 13.1049, 10.1353,
        7.35094, 3.87058, 1.45345, 2.00505, 0.168523, -0.408269
    };

    for (size_t i = 0; i < col1.size(); ++i)
       assert(fabs(col1[i] - actual2[i]) < 0.0001);

    df.get_column<double>("dbl_col") = d1_copy;

    HWExpoSmootherVisitor<double>   es_v3(0.8, 0.8);

    df.single_act_visit<double>("dbl_col", es_v3);

    auto    actual3 = StlVecType<double> {
        2.5, 2.45, -0.84, -0.7764, -1.13078, 1.19404, 1.37962, 0.648979, 1.2811, -9.53398, -1.78085, 0.26952, -0.958499, 0.0229365, 0.241024,
        0.958706, -0.200929, 1.42374, 0.832679, -0.682447, 0.0832937, 0.188734, 1.58903, 0.00411128, 1.3969, 41.1007, 13.809, 0.296909, -2.33634,
        0.14747, -0.54455, 0.644758, 7.24757, 1.42121, 0.842363
    };

    for (size_t i = 0; i < col1.size(); ++i)
       assert(fabs(col1[i] - actual3[i]) < 0.0001);

    // Now multidimensional data
    //
    constexpr std::size_t   dim { 3 };

    using ary_col_t = std::array<double, dim>;
    using vec_col_t = std::vector<double>;

    StlVecType<ary_col_t>   ary_col  {
        {   2.5,     2.45, -1.65  },
        {  -0.1,    -1.1,   1.87  },
        {   0.98,    0.34,  1.56  },
        { -12.34,    2.3,  -0.34  },
        {  -1.9,     0.387, 0.123 },
        {   1.06,   -0.65,  2.03  },
        {   0.4,    -1.0,   0.59  },
        {   0.125,   1.9,  -0.68  },
        {   2.0045, 50.8,  -1.0   },
        {   0.78,    0.48,  1.99  },
        {  -0.97,    1.03,  8.678 },
        {  -1.4,     1.59,  0.7   }
    };
    StlVecType<vec_col_t>   vec_col  {
        {   2.5,     2.45, -1.65  },
        {  -0.1,    -1.1,   1.87  },
        {   0.98,    0.34,  1.56  },
        { -12.34,    2.3,  -0.34  },
        {  -1.9,     0.387, 0.123 },
        {   1.06,   -0.65,  2.03  },
        {   0.4,    -1.0,   0.59  },
        {   0.125,   1.9,  -0.68  },
        {   2.0045, 50.8,  -1.0   },
        {   0.78,    0.48,  1.99  },
        {  -0.97,    1.03,  8.678 },
        {  -1.4,     1.59,  0.7   }
    };

    df.load_column<ary_col_t>("ARY COL", std::move(ary_col), nan_policy::dont_pad_with_nans);
    df.load_column<vec_col_t>("VEC COL", std::move(vec_col), nan_policy::dont_pad_with_nans);

    const ary_col_t                     ary_alfa = { 0.8, 0.8, 0.8 };
    const ary_col_t                     ary_beta = { 0.8, 0.8, 0.8 };
    HWExpoSmootherVisitor<ary_col_t>    ary_es (ary_alfa, ary_beta);
    const vec_col_t                     vec_alfa = { 0.8, 0.8, 0.8 };
    const vec_col_t                     vec_beta = { 0.8, 0.8, 0.8 };
    HWExpoSmootherVisitor<vec_col_t>    vec_es (vec_alfa, vec_beta);

    df.single_act_visit<ary_col_t>("ARY COL", ary_es);
    df.single_act_visit<vec_col_t>("VEC COL", vec_es);

    assert(ary_es.get_result() == 12);
    assert(vec_es.get_result() == 12);

    const auto  &ary_col_ref { df.get_column<ary_col_t>("ARY COL") };
    const auto  &vec_col_ref { df.get_column<vec_col_t>("VEC COL") };

    assert(std::abs(ary_col_ref[0][0] - 2.5) < 0.00001);
    assert(std::abs(ary_col_ref[0][2] - -1.65) < 0.00001);
    assert(std::abs(ary_col_ref[3][0] - -9.87216) < 0.00001);
    assert(std::abs(ary_col_ref[3][1] - 1.63712) < 0.00001);
    assert(std::abs(ary_col_ref[8][1] - 41.1924) < 0.0001);
    assert(std::abs(ary_col_ref[8][2] - -1.10146) < 0.00001);
    assert(std::abs(ary_col_ref[11][0] - -1.53468) < 0.00001);
    assert(std::abs(ary_col_ref[11][2] - 3.14189) < 0.00001);
    assert(std::abs(vec_col_ref[0][0] - 2.5) < 0.00001);
    assert(std::abs(vec_col_ref[0][2] - -1.65) < 0.00001);
    assert(std::abs(vec_col_ref[3][0] - -9.87216) < 0.00001);
    assert(std::abs(vec_col_ref[3][1] - 1.63712) < 0.00001);
    assert(std::abs(vec_col_ref[8][1] - 41.1924) < 0.0001);
    assert(std::abs(vec_col_ref[8][2] - -1.10146) < 0.00001);
    assert(std::abs(vec_col_ref[11][0] - -1.53468) < 0.00001);
    assert(std::abs(vec_col_ref[11][2] - 3.14189) < 0.00001);
}

C++ DataFrame