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");

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

    ExpoSmootherVisitor<double> es_v2(0.3);

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

    auto    actual2 = StlVecType<double> {
        2.5, 2.485, 1.22, -1.185, -0.4, -0.209, 1.603, 0.788, 0.706, -2.61, -7.948, 1.508, -0.808, -1.2139,
        0.3078, 0.4041, 0.547, 0.154, 1.541, -0.02, -0.523, 0.4505, 0.6575, 1.126, 0.12535, 16.6431, 35.26, -0.466,
        0.69, 0.933, 1.102, -0.37, 3.3244, 5.6546, -0.503
    };

    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;

    ExpoSmootherVisitor<double> es_v3(0.8);

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

    auto    actual3 = StlVecType<double> {
        2.5, 2.46, -0.83, -0.41, -0.9, 1.276, 1.158, 0.468, 1.316, -9.56, -0.628, 0.188, -1.588, -0.0704,
        0.1758, 0.8726, -0.308, 1.494, 0.726, -0.72, 0.272, 0.218, 1.545, -0.164, 1.4676, 41.0409, 9.36, 0.424,
        0.54, 1.688, -0.378, 0.63, 7.1484, 0.6156, 0.992
    };

    for (size_t i = 0; i < col1.size(); ++i)
       assert(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.77968, -0.27248, -0.67824, 0.261712, 0.9932, 0.799584, 0.97488, -4.33518, -3.8625, -1.05213, -0.877632, -0.632813, -0.087968,
        0.494816, 0.193696, 0.731832, 0.922821, 0.051104, -0.055568, 0.152752, 0.895104, 0.532416, 0.838499, 21.5731, 20.6916, 7.763, 1.66618,
        1.1872, 0.509888, 0.343776, 3.87912, 3.11763, 1.43558
    };

    for (size_t i = 0; i < col21.size(); ++i)
       assert(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.60042) < 0.00001);
    assert(std::abs(ary_col_ref[3][1] - 0.979024) < 0.000001);
    assert(std::abs(ary_col_ref[8][1] - 21.4163) < 0.0001);
    assert(std::abs(ary_col_ref[8][2] - -0.545339) < 0.000001);
    assert(std::abs(ary_col_ref[11][0] - -0.799429) < 0.000001);
    assert(std::abs(ary_col_ref[11][2] - 4.1202) < 0.0001);
    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.60042) < 0.00001);
    assert(std::abs(vec_col_ref[3][1] - 0.979024) < 0.000001);
    assert(std::abs(vec_col_ref[8][1] - 21.4163) < 0.0001);
    assert(std::abs(vec_col_ref[8][2] - -0.545339) < 0.000001);
    assert(std::abs(vec_col_ref[11][0] - -0.799429) < 0.000001);
    assert(std::abs(vec_col_ref[11][2] - 4.1202) < 0.0001);
}

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

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, -2.354, -0.6674, -0.64944, 2.17034, 0.879202, 0.581521, -2.34309, -11.6799, 3.36809, -0.431147, -1.42459,
        0.821747, 0.638548, 0.950029, -0.0829826, 2.14921, -0.111474, -0.969884, 0.627569, 0.633542, 1.60863, -0.307475, 17.1351, 49.2179, -6.59525,
        -2.48915, -1.05849, 0.329906, -1.66206, 3.10917, 7.6669, -2.11746,
    };

    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, -1.068, -0.7836, 1.13928, 1.60586, 0.415171, 1.20303, -9.38739, -2.81748, 2.0925, -1.6295, -0.3283,
        0.49014, 0.893228, -0.153954, 1.25121, 1.10624, -0.904752, 0.0110497, 0.42021, 1.51104, 0.113208, 1.11024, 41.3989, 17.2389, -6.28822,
        -0.517644, 1.42847, -0.188306, 0.194339, 7.38127, 1.88585, -0.366429
    };

    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.6072) < 0.0001);
    assert(std::abs(ary_col_ref[3][1] - 1.9964) < 0.0001);
    assert(std::abs(ary_col_ref[8][1] - 41.4642) < 0.0001);
    assert(std::abs(ary_col_ref[8][2] - -1.17294) < 0.00001);
    assert(std::abs(ary_col_ref[11][0] - -1.62144) < 0.00001);
    assert(std::abs(ary_col_ref[11][2] - 3.45742) < 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.6072) < 0.0001);
    assert(std::abs(vec_col_ref[3][1] - 1.9964) < 0.0001);
    assert(std::abs(vec_col_ref[8][1] - 41.4642) < 0.0001);
    assert(std::abs(vec_col_ref[8][2] - -1.17294) < 0.00001);
    assert(std::abs(vec_col_ref[11][0] - -1.62144) < 0.00001);
    assert(std::abs(vec_col_ref[11][2] - 3.45742) < 0.00001);
}

C++ DataFrame