📘 Computing standard deviation using Perl 6

For the given data, calculate the standard deviation value (sigma).

Standard deviation is a statistical term that shows how compact data distribution is. The formula is the following:

where N is the number of elements in the array x; is the average value (see Task 56, Average on an array).

Let’s use some test data from Wikipedia and take the straightforward approach using reduction operations and avoiding explicit loops:

my @data = 727.7, 1086.5, 1091.0, 1361.3, 1490.5, 1956.1;

my $avg = ([+] @data) / @data.elems;
my $sigma = sqrt(
    ([+] map * ** 2, map * - $avg, @data) /
    (@data.elems - 1)
);

say $sigma; # 420.962489619523

Inside the sqrt function, the [+] reduction operator gets the array that is formed by the two nested runs of map. First, the constant shift has been removed by applying * - $avg to each element. Second, a square of each item has been calculated: * ** 2.

In both cases, the WhateverCode is used. It is usually more expressive but may lead to constructs like * ** 2, which look a bit cryptic.

The two maps can be merged into one:

my $sigma = sqrt(
    ([+] map (* - $avg) ** 2, @data)  / (@data.elems - 1)
);

Now, let’s explore the second approach that gets the same result using feed operators. In Perl 6, there are feed operators of both directions: <== and  ==>. Their shape indicates the direction of data flow, so here is another version of the program.

my @data = 727.7, 1086.5, 1091.0, 1361.3, 1490.5, 1956.1;

my $avg = ([+] @data) / @data.elems;
@data
    ==> map * - $avg
    ==> map * ** 2
    ==> reduce * + *
    ==> my @σ;
say sqrt(@σ[0] / (@data.elems - 1)); # 420.962489619523

The data flow is clearly visible now. The @data array passes the two maps, and then, it is reduced using the + operation. The call of reduce * + * is equivalent to using the reduction operator in the form of [+].

Notice how the  array is defined, not only the fact that a Unicode name is used but mostly the fact that the my declaration is placed at the end of the feed chain. An array is used here because the feed operator does not return a scalar value, although we only need one element.

To make the code even closer to the original mathematical formula, you may choose a different name for the variable holding the average value (and remove the elemscall):

my $x̄= ([+] @data) / @data;

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s