Commits

barbasa committed b9de435

Added Smoother object to smooth data series trend

* Implemented exponential and weighted exponential algorithm

  • Participants
  • Parent commits 180211e

Comments (0)

Files changed (9)

Statistics-Descriptive/lib/Statistics/Descriptive.pm

 $VERSION = '3.0500';
 
 use vars qw(%fields);
+use Statistics::Descriptive::Smoother;
 use Carp;
 
 sub _make_accessors
 
 $VERSION = '3.0500';
 
+use Statistics::Descriptive::Smoother;
 use Carp;
 
 use POSIX ();
 %fields = (
   _permitted => undef,  ##Place holder for the inherited key hash
   data       => undef,  ##Our data
+  samples    => undef,  ##Number of samples for each value of the data set
   presorted  => undef,  ##Flag to indicate the data is already sorted
   _reserved  => undef,  ##Place holder for this lookup hash
 );
 
 __PACKAGE__->_make_private_accessors(
-    [qw(data frequency geometric_mean harmonic_mean 
+    [qw(data samples frequency geometric_mean harmonic_mean
         least_squares_fit median mode
         skewness kurtosis
        )
 
     # Empty array ref for holding data later!
     $self->_data([]);
+    $self->_samples([]);
     $self->_reserved(\%fields);
     $self->presorted(0);
     $self->_trimmed_mean_cache(+{});
   return 1;
 }
 
+sub add_data_with_samples {
+    my ($self,$aref_values) = @_;
+
+    return 1 if (!@{ $aref_values });
+
+    my $aref_data = [map { keys %$_ } @{ $aref_values }];
+    my $aref_samples = [map { values %$_ } @{ $aref_values }];
+
+    $self->add_data($aref_data);
+    push @{ $self->_samples() }, @{ $aref_samples };
+
+    return 1;
+}
+
+
 sub get_data {
   my $self = shift;
   return @{ $self->_data() };
     return $outlier_candidate_index;
 }
 
+sub set_smoother {
+    my ($self, $args) = @_;
+
+    $args->{data}    = $self->_data();
+    $args->{samples} = $self->_samples();
+
+    $self->{_smoother} = Statistics::Descriptive::Smoother->instantiate($args);
+}
+
+sub get_smoothed_data {
+    my ($self, $args) = @_;
+
+    if (!defined $self->{_smoother}) {
+        carp("Smoother object not defined\n");
+        return;
+    }
+    $self->{_smoother}->get_smoothed_data();
+}
+
 sub sort_data {
   my $self = shift;
 
 Full method cached values!  Cached values for the sparse methods are
 not changed>
 
+=item $stat->add_data_with_samples([{1 => 10}, {2 => 20}, {3 => 30},]);
+
+Add data to the statistics variable and set the number of samples each value has been
+built with. The data is the key of each element of the input array ref, while
+the value is the number of samples: [{data1 => smaples1}, {data2 => samples2}, ...]
+
 =item $stat->get_data();
 
 Returns a copy of the data array.
 
 =back
 
+=item $stat->set_smoother({ method => 'exponential', coeff => 0, });
+
+Set the method used to smooth the data and the smoothing coefficient.
+See C<Statistics::Smoother> for more details.
+
+=item $stat->get_smoothed_data();
+
+Returns a copy of the smoothed data array.
+
+The smoothing method and coefficient need to be defined (see C<set_smoother>),
+otherwise the function will return an undef value.
+
 =item $stat->sort_data();
 
 Sort the stored data and update the mindex and maxdex methods.  This

Statistics-Descriptive/lib/Statistics/Descriptive/Smoother.pm

+package Statistics::Descriptive::Smoother;
+
+use strict;
+use warnings;
+use Carp;
+
+our $VERSION = '3.0500';
+
+sub instantiate {
+    my ($class, $args) = @_;
+
+    my $method     = delete $args->{method};
+    my $coeff      = delete $args->{coeff} || 0;
+    my $ra_samples = delete $args->{samples};
+    my $ra_data    = delete $args->{data};
+ 
+    if ($coeff < 0 || $coeff > 1) {
+        carp("Invalid smoothing coefficient C $coeff\n");
+        return;
+    }
+    if (@$ra_data < 2) {
+        carp("Need at least 2 samples to smooth the data\n");
+        return;
+    }
+    $method = ucfirst(lc($method));
+    my $sub_class = __PACKAGE__."::$method";
+    eval "require $sub_class";
+    die "No such class $sub_class: $@" if $@;
+
+    return $sub_class->new({
+        data       => $ra_data,
+        samples    => $ra_samples,
+        count      => scalar @$ra_data,
+        coeff      => $coeff,
+    });
+}
+
+sub get_smoothing_coeff { $_[0]->{coeff} }
+
+sub set_smoothing_coeff {
+    my ($self, $coeff) = @_;
+    
+    if ($coeff < 0 || $coeff > 1) {
+        carp("Invalid smoothing coefficient C $coeff\n");
+        return;
+    }
+
+    $self->{coeff} = $coeff;
+    return 1;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Statistics::Descriptive::Smoother - Base module for smoothing statistical data
+
+=head1 SYNOPSIS
+
+  use Statistics::Descriptive::Smoother;
+  my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'exponential',
+           coeff    => 0.5,
+           data     => [1, 2, 3, 4, 5],
+           samples  => [110, 120, 130, 140, 150],
+    });
+  my @smoothed_data = $smoother->get_smoothed_data();
+
+=head1 DESCRIPTION
+
+This module provide methods to smooth the trend of a series of statistical data.
+
+The methods provided are the C<Exponential> and the C<Weighted Exponential> (see respectively
+C<Statistics::Descriptive::Smoother::Exponential> and C<Statistics::Descriptive::Smoother::Weightedexponential>
+for more details).
+
+This class is just a factory that will instantiate the object to perform the
+choosen smoothing algorithm.
+
+=head1 METHODS
+
+=over 5
+
+=item Statistics::Descriptive::Smoother->instantiate({});
+
+Create a new Smoother object.
+
+This method require several parameters:
+
+=over 5
+
+=item method
+
+Method used for the smoothing. Allowed values are: C<exponential> and C<weightedexponential>
+
+=item coeff
+
+Smoothing coefficient. It needs to be in the [0;1] range, otherwise undef will be reutrned.
+C<0> means that the series is not smoothed at all, while C<1> the series is universally equal to the initial unsmoothed value.
+
+=item data
+
+Array ref with the data of the series. At least 2 values are needed to smooth the series, undef is returned otherwise.
+
+=item samples
+
+Array ref with the samples each data value has been built with. This is an optional parameter since it is not used by all the
+smoothing algorithm.
+
+=back 
+
+=item $smoother->get_smoothing_coeff();
+
+Returns the smoothing coefficient.
+
+=item $smoother->set_smoothing_coeff(0.5);
+
+Set the smoothing coefficient value. It needs to be in the [0;1] range, otherwise undef will be reutrned.
+
+=back 
+
+=head1 AUTHOR
+
+Fabio Ponciroli
+
+=head1 LICENSE
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+=cut

Statistics-Descriptive/lib/Statistics/Descriptive/Smoother/Exponential.pm

+package Statistics::Descriptive::Smoother::Exponential;
+use strict;
+use warnings;
+
+use base 'Statistics::Descriptive::Smoother';
+    
+our $VERSION = '3.0500';
+    
+sub new {
+    my ($class, $args) = @_;
+        
+    return bless $args || {}, $class;
+}   
+
+# The name of the variables used in the code refers to the explanation in the pod
+sub get_smoothed_data {
+    my ($self) = @_;
+
+    my @smoothed_values;
+    push @smoothed_values, @{$self->{data}}[0];
+    my $C = $self->get_smoothing_coeff();
+
+    foreach my $sample_idx (1 .. $self->{count} -1) {
+        my $smoothed_value = $C * ($smoothed_values[-1]) + (1 - $C) * $self->{data}->[$sample_idx];
+        push @smoothed_values, $smoothed_value;
+    }
+    return @smoothed_values;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Statistics::Descriptive::Smoother::Exponential - Implement exponential smoothing
+
+=head1 SYNOPSIS
+
+  use Statistics::Descriptive::Smoother;
+  my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'exponential',
+           coeff    => 0.5,
+           data     => [1, 2, 3, 4, 5],
+           samples  => [110, 120, 130, 140, 150],
+    });
+  my @smoothed_data = $smoother->get_smoothed_data();
+
+=head1 DESCRIPTION
+
+This module implement the exponential smoothing algorithm to smooth the trend of a series of statistical data.
+
+This algorithm works well for unsmoothed data build with big number of samples. If this is not
+the case you might consider using the C<Weighted Exponential> one.
+
+The algorithm implements the following formula:
+
+S(0) = X(0)
+
+S(t) = C*S(t-1) + (1-C)*X(t)
+
+where:
+
+=over 3
+
+=item * t = index in the series
+
+=item * S(t) = smoothed series value at position t
+
+=item * C = smoothing coefficient. Value in the [0;1] range. C<0> means that the series is not smoothed at all,
+while C<1> the series is universally equal to the initial unsmoothed value.
+
+=item * X(t) = unsmoothed series value at position t
+
+=back
+
+=head1 METHODS
+
+=over 5
+
+=item $stats->get_smoothed_data();
+
+Returns a copy of the smoothed data array.
+
+=back
+
+=head1 AUTHOR
+
+Fabio Ponciroli
+
+=head1 LICENSE
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+=cut

Statistics-Descriptive/lib/Statistics/Descriptive/Smoother/Weightedexponential.pm

+package Statistics::Descriptive::Smoother::Weightedexponential;
+use strict;
+use warnings;
+
+use base 'Statistics::Descriptive::Smoother';
+use Carp;
+
+our $VERSION = '3.0500';
+
+sub new {
+    my ($class, $args) = @_;
+
+    if (scalar @{$args->{data}} != scalar @{$args->{samples}}) {
+        carp("Number of data values and samples need to be the same\n");
+        return;
+    }
+
+    return bless $args || {}, $class;
+}
+
+# The name of the variables used in the code refers to the explanation in the pod
+sub get_smoothed_data {
+    my ($self) = @_;
+
+    my (@smoothed_values, @Wts);
+    # W(0) = N(0)
+    push @Wts, @{$self->{samples}}[0];
+    # S(0) = X(0)
+    push @smoothed_values, @{$self->{data}}[0];
+    my $C = $self->get_smoothing_coeff();
+
+    foreach my $idx (1 .. ($self->{count} -1)) {
+        my $Xt   = $self->{data}->[$idx];
+        my $Nt   = $self->{samples}->[$idx];
+        my $St_1 = $smoothed_values[-1];
+        my $Wt_1 = $Wts[-1];
+        
+        push @Wts, $self->_get_Wt($Wt_1, $Nt); 
+
+        my $coeff_a = $self->_get_coeff_A($Wt_1, $Nt);
+        my $coeff_b = $self->_get_coeff_B($Wt_1, $Nt);
+        
+        my $smoothed_value = ( $St_1 * $coeff_a + $Xt * $coeff_b ) / ( $coeff_a + $coeff_b ); 
+        push @smoothed_values, $smoothed_value;
+    }
+    return @smoothed_values;
+}
+
+sub _get_Wt {
+    my ($self, $Wt_1, $Nt) = @_;
+  
+    my $C = $self->get_smoothing_coeff();
+    my $coeff_a = $self->_get_coeff_A($Wt_1, $Nt);
+    my $coeff_b = $self->_get_coeff_B($Wt_1, $Nt);;
+ 
+    return (($Wt_1 * $coeff_a + $Nt * $coeff_b)/($coeff_a + $coeff_b));
+}
+
+sub _get_coeff_A { 
+    my ($self, $Wt_1, $Nt) = @_;
+
+    my $C = $self->get_smoothing_coeff();
+    return $C * ( $Wt_1 / ($Wt_1 + $Nt) );
+}
+
+sub _get_coeff_B {
+    my ($self, $Wt_1, $Nt) = @_;
+
+    my $C = $self->get_smoothing_coeff();
+    return (1 - $C) * ( $Nt / ($Nt + $Wt_1) );
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Statistics::Descriptive::Smoother::Weigthedexponential - Implement weigthed exponential smoothing
+
+=head1 SYNOPSIS
+
+  use Statistics::Descriptive::Smoother;
+  my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'weigthedexponential',
+           coeff    => 0.5,
+           data     => [1, 2, 3, 4, 5],
+           samples  => [110, 120, 130, 140, 150],
+    });
+  my @smoothed_data = $smoother->get_smoothed_data();
+
+=head1 DESCRIPTION
+
+This module implement the weigthed exponential smoothing algorithm to smooth the trend of a series of statistical data.
+
+This algorithm can help to control large swings in the unsmoothed data that arise from small samples for
+those data points.
+
+The algorithm implements the following formula:
+
+W(0) = N(0)
+
+W(t) = ( W(t-1) * CoeffA + N(t) * CoeffB ) / (CoeffA + CoeffB)
+
+CoeffA = C * ( W(t-1) / (W(t-1) + N(t) ) )
+
+CoeffB = (1 - C) * ( N(t) * (W(t-1) + N(t)) )
+
+
+S(t) = (S(t-1)*CoeffA + X(t)*CoeffB) / (CoeffA + CoeffB)
+
+where:
+
+=over 3
+
+=item * t = index in the series
+
+=item * S(t) = smoothed series value at position t
+
+=item * C = smoothing coefficient. Value in the [0;1] range. C<0> means that the series is not smoothed at all,
+while C<1> the series is universally equal to the initial unsmoothed value.
+
+=item * X(t) = unsmoothed series value at position t
+
+=back
+
+=head1 METHODS
+
+=over 5
+
+=item $stats->get_smoothed_data();
+
+Returns a copy of the smoothed data array.
+
+=back
+
+=head1 AUTHOR
+
+Fabio Ponciroli
+
+=head1 LICENSE
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl itself.
+
+=cut

Statistics-Descriptive/t/descr.t

 use strict;
 use warnings;
 
-use Test::More tests => 52;
+use Test::More tests => 54;
 
 use Benchmark;
 use Statistics::Descriptive;
         "->standard_deviation() Returns undef in list-context.",
     );
 }
+
+{
+    my $stats = Statistics::Descriptive::Full->new();
+
+    $stats->add_data_with_samples([{1 => 10}, {2 => 20}, {3 => 30}, {4 => 40}, {5 => 50}]);
+
+    # TEST
+    is_deeply(
+        $stats->_data(),
+        [ 1, 2, 3, 4, 5 ],
+        'add_data_with_samples: data set is correct',
+    );
+
+    # TEST
+    is_deeply(
+        $stats->_samples(),
+        [ 10, 20, 30, 40, 50 ],
+        'add_data_with_samples: samples are correct',
+    );
+
+}

Statistics-Descriptive/t/descr_smooth_methods.t

+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 3;
+use Test::Exception;
+
+use Statistics::Descriptive;
+
+local $SIG{__WARN__} = sub { };
+
+my @original_data = qw/1 2 3 4 5 6 7 8 9 10/;
+
+{
+    # testing set_smoother
+    my $stats = Statistics::Descriptive::Full->new();
+
+    $stats->add_data(\@original_data );
+
+    $stats->set_smoother({
+           method   => 'exponential',
+           coeff    => 0,
+    });
+    # TEST
+    isa_ok ( $stats->{_smoother}, 'Statistics::Descriptive::Smoother::Exponential', 'set_smoother: smoother set correctly');
+
+}
+
+{
+    # testing get_smoothed_data
+    my $stats = Statistics::Descriptive::Full->new();
+
+    # TEST
+    is ( $stats->get_smoothed_data(), undef, 'get_smoothed_data: smoother needs to be defined');
+
+    $stats->add_data(\@original_data );
+
+    $stats->set_smoother({
+           method   => 'exponential',
+           coeff    => 0.5,
+    });
+
+    my @expected_values = qw/
+          1
+          1.5
+          2.25
+          3.125
+          4.0625
+          5.03125
+          6.015625
+          7.0078125
+          8.00390625
+          9.001953125
+    /; 
+
+    my @smoothed_data = $stats->get_smoothed_data();
+
+    #TEST
+    is_deeply( \@smoothed_data, \@expected_values, 'Smoothing with C=0.5');
+}

Statistics-Descriptive/t/smoother.t

+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 11;
+
+use Statistics::Descriptive::Smoother;
+use Test::Exception;
+
+local $SIG{__WARN__} = sub { };
+
+{
+
+    #Test factory pattern
+    my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'exponential',
+           coeff    => 0,
+           data     => [1,2,3],
+           samples  => [100, 100, 100],
+    });
+
+    #TEST
+    isa_ok ($smoother, 'Statistics::Descriptive::Smoother::Exponential', 'Exponential class correctly created');
+}
+
+{
+
+    my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'weightedExponential',
+           coeff    => 0,
+           data     => [1,2,3],
+           samples  => [100, 100, 100],
+    });
+
+    #TEST
+    isa_ok ($smoother, 'Statistics::Descriptive::Smoother::Weightedexponential', 'Weightedexponential class correctly created');
+    
+}
+
+{
+
+    # Test invalid smoothing method
+    #TEST
+    dies_ok (sub {
+                Statistics::Descriptive::Smoother->instantiate({
+                        method   => 'invalid_method',
+                        coeff    => 0,
+                        data     => [1,2,3],
+                        samples  => [100, 100, 100],
+            });}, 
+            'Invalid method');
+    
+}
+
+{
+
+    #TODO get output from Carp
+    #Test invalid coefficient
+    my $smoother_neg = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'exponential',
+           coeff    => -123,
+           data     => [1,2,3],
+           samples  => [100, 100, 100],
+        });
+
+    #TEST
+    is ($smoother_neg, undef, 'Invalid coefficient: < 0');
+
+    my $smoother_pos = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'exponential',
+           coeff    => 123,
+           data     => [1,2,3],
+           samples  => [100, 100, 100],
+        });
+
+    #TEST
+    is ($smoother_pos, undef, 'Invalid coefficient: > 1');
+ 
+}
+
+{
+
+    #Test unsufficient number of samples
+    my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'exponential',
+           coeff    => 0,
+           data     => [1],
+           samples  => [100],
+        });
+
+    #TEST
+    is ($smoother, undef, 'Insufficient number of samples');
+
+}
+
+{
+
+    #Test smoothing coefficient accessors
+    my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'exponential',
+           coeff    => 0.5,
+           data     => [1,2,3],
+           samples  => [100, 100, 100],
+        });
+
+    #TEST
+    is ($smoother->get_smoothing_coeff(), 0.5, 'get_smoothing_coeff');
+
+    my $ok = $smoother->set_smoothing_coeff(0.7);
+
+    #TEST
+    ok ($ok, 'set_smoothing_coeff: set went fine');
+
+    #TEST
+    is ($smoother->get_smoothing_coeff(), 0.7, 'set_smoothing_coeff: correct value set');
+
+    my $ok2 = $smoother->set_smoothing_coeff(123);
+
+    #TEST
+    is ($ok2, undef, 'set_smoothing_coeff: set failed');
+
+    #TEST
+    is ($smoother->get_smoothing_coeff(), 0.7, 'set_smoothing_coeff: value not modified after failure');
+
+}
+
+1;

Statistics-Descriptive/t/smoother_exponential.t

+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 3;
+
+use Statistics::Descriptive::Smoother;
+
+my @original_data       = qw/1 2 3 4 5 6 7 8 9 10/;
+my @original_samples    = qw/3 3 3 3 3 3 3 3 3 3/;
+
+{
+
+    #Test no smoothing
+    my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'exponential',
+           coeff    => 0,
+           data     => \@original_data,
+           samples  => \@original_samples,
+    });
+
+    my @smoothed_data = $smoother->get_smoothed_data();
+
+    # When the smoothing coefficient is 0 the series is not smoothed
+    #TEST
+    is_deeply( \@smoothed_data, \@original_data, 'No smoothing C=0');
+}
+
+{
+
+    #Test max smoothing
+    my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'exponential',
+           coeff    => 1,
+           data     => \@original_data,
+           samples  => \@original_samples,
+    });
+
+    my @smoothed_data = $smoother->get_smoothed_data();
+
+    # When the smoothing coefficient is 1 the series is universally equal to the initial unsmoothed value
+    my @expected_values = map { $original_data[0] } 1 .. $smoother->{count};
+    #TEST
+    is_deeply( \@smoothed_data, \@expected_values, 'Max smoothing C=1');
+}
+
+{
+
+    #Test smoothing coeff 0.5
+    my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'exponential',
+           coeff    => 0.5,
+           data     => \@original_data,
+           samples  => \@original_samples,
+    });
+
+    my @smoothed_data = $smoother->get_smoothed_data();
+    my @expected_values = qw/
+          1
+          1.5
+          2.25
+          3.125
+          4.0625
+          5.03125
+          6.015625
+          7.0078125
+          8.00390625
+          9.001953125
+    /; 
+
+    #TEST
+    is_deeply( \@smoothed_data, \@expected_values, 'Smoothing with C=0.5');
+}
+
+1;

Statistics-Descriptive/t/smoother_weightedexponential.t

+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 4;
+
+use Statistics::Descriptive::Smoother;
+
+local $SIG{__WARN__} = sub { };
+
+my @original_data    = qw/1 2 3 4 5 6 7 8 9 10/;
+my @original_samples = qw/100 50 100 50 100 50 100 50 100 50/;
+
+{
+
+    #Test no smoothing
+    my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'weightedExponential',
+           coeff    => 0,
+           data     => \@original_data,
+           samples  => \@original_samples,
+    });
+
+    my @smoothed_data = $smoother->get_smoothed_data();
+
+    # When the smoothing coefficient is 0 the series is not smoothed
+    #TEST
+    is_deeply( \@smoothed_data, \@original_data, 'No smoothing C=0');
+}
+
+{
+
+    #Test max smoothing
+    my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'weightedExponential',
+           coeff    => 1,
+           data     => \@original_data,
+           samples  => \@original_samples,
+    });
+
+    my @smoothed_data = $smoother->get_smoothed_data();
+
+    # When the smoothing coefficient is 1 the series is universally equal to the initial unsmoothed value
+    my @expected_values = map { $original_data[0] } 1 .. $smoother->{count};
+    #TEST
+    is_deeply( \@smoothed_data, \@expected_values, 'Max smoothing C=1');
+}
+
+{
+
+    #Test smoothing coeff 0.5
+    my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'weightedExponential',
+           coeff    => 0.5,
+           data     => \@original_data,
+           samples  => \@original_samples,
+    });
+
+    my @smoothed_data = $smoother->get_smoothed_data();
+    my @expected_values = qw/
+                    1
+                    1.33333333333333
+                    2.24242424242424
+                    2.85944551901999
+                    4.0651836704636
+                    4.75526654493058
+                    6.03174342835728
+                    6.7367839208657
+                    8.02706266125788
+                    8.73457937329917
+    /; 
+
+    #TEST
+    is_deeply( \@smoothed_data, \@expected_values, 'Smoothing with C=0.5');
+}
+
+{
+
+    #Test different number of samples and data are not allowed
+    my $smoother = Statistics::Descriptive::Smoother->instantiate({
+           method   => 'weightedExponential',
+           coeff    => 0,
+           data     => [1,2,3,4],
+           samples  => [1,2,3],
+    });
+
+    #TEST
+    is ( $smoother, undef, 'Different number of samples and data');
+}
+
+
+1;