mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Standard deviation implementation on Measure-Object (#6238)
Implement iterative standard deviation algorithm for Measure-Object
This commit is contained in:
committed by
Sergei Vorobev
parent
339e4533e7
commit
80d5df55c2
@@ -34,7 +34,7 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
public GenericMeasureInfo()
|
||||
{
|
||||
Average = Sum = Maximum = Minimum = null;
|
||||
Average = Sum = Maximum = Minimum = StandardDeviation = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,6 +71,11 @@ namespace Microsoft.PowerShell.Commands
|
||||
///
|
||||
/// </summary>
|
||||
public double? Minimum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Standard Deviation of property values.
|
||||
/// </summary>
|
||||
public double? StandardDeviation { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -90,7 +95,7 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
public GenericObjectMeasureInfo()
|
||||
{
|
||||
Average = Sum = null;
|
||||
Average = Sum = StandardDeviation = null;
|
||||
Maximum = Minimum = null;
|
||||
}
|
||||
|
||||
@@ -128,6 +133,11 @@ namespace Microsoft.PowerShell.Commands
|
||||
///
|
||||
/// </summary>
|
||||
public object Minimum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Standard Deviation of property values.
|
||||
/// </summary>
|
||||
public double? StandardDeviation { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -225,6 +235,8 @@ namespace Microsoft.PowerShell.Commands
|
||||
|
||||
// Generic/Numeric statistics
|
||||
internal double sum = 0.0;
|
||||
internal double sumPrevious = 0.0;
|
||||
internal double variance = 0.0;
|
||||
internal object max = null;
|
||||
internal object min = null;
|
||||
|
||||
@@ -263,6 +275,24 @@ namespace Microsoft.PowerShell.Commands
|
||||
|
||||
#endregion Common parameters in both sets
|
||||
|
||||
/// <summary>
|
||||
/// Set to true if Standard Deviation is to be returned.
|
||||
/// </summary>
|
||||
[Parameter(ParameterSetName = GenericParameterSet)]
|
||||
public SwitchParameter StandardDeviation
|
||||
{
|
||||
get
|
||||
{
|
||||
return _measureStandardDeviation;
|
||||
}
|
||||
set
|
||||
{
|
||||
_measureStandardDeviation = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _measureStandardDeviation;
|
||||
|
||||
/// <summary>
|
||||
/// Set to true is Sum is to be returned
|
||||
/// </summary>
|
||||
@@ -525,7 +555,7 @@ namespace Microsoft.PowerShell.Commands
|
||||
AnalyzeString(strValue, stat);
|
||||
}
|
||||
|
||||
if (_measureAverage || _measureSum)
|
||||
if (_measureAverage || _measureSum || _measureStandardDeviation)
|
||||
{
|
||||
double numValue = 0.0;
|
||||
if (!LanguagePrimitives.TryConvertTo(objValue, out numValue))
|
||||
@@ -708,8 +738,19 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
private void AnalyzeNumber(double numValue, Statistics stat)
|
||||
{
|
||||
if (_measureSum || _measureAverage)
|
||||
if (_measureSum || _measureAverage || _measureStandardDeviation)
|
||||
{
|
||||
stat.sumPrevious = stat.sum;
|
||||
stat.sum += numValue;
|
||||
}
|
||||
if (_measureStandardDeviation && stat.count > 1)
|
||||
{
|
||||
// Based off of iterative method of calculating variance on
|
||||
// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm
|
||||
double avgPrevious = stat.sumPrevious / (stat.count - 1);
|
||||
stat.variance *= (stat.count - 2.0) / (stat.count - 1);
|
||||
stat.variance += (numValue - avgPrevious) * (numValue - avgPrevious) / stat.count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -790,6 +831,7 @@ namespace Microsoft.PowerShell.Commands
|
||||
{
|
||||
double? sum = null;
|
||||
double? average = null;
|
||||
double? StandardDeviation = null;
|
||||
object max = null;
|
||||
object min = null;
|
||||
|
||||
@@ -797,8 +839,14 @@ namespace Microsoft.PowerShell.Commands
|
||||
{
|
||||
if (_measureSum)
|
||||
sum = stat.sum;
|
||||
|
||||
if (_measureAverage && stat.count > 0)
|
||||
average = stat.sum / stat.count;
|
||||
|
||||
if (_measureStandardDeviation)
|
||||
{
|
||||
StandardDeviation = Math.Sqrt(stat.variance);
|
||||
}
|
||||
}
|
||||
|
||||
if (_measureMax)
|
||||
@@ -835,6 +883,7 @@ namespace Microsoft.PowerShell.Commands
|
||||
gmi.Count = stat.count;
|
||||
gmi.Sum = sum;
|
||||
gmi.Average = average;
|
||||
gmi.StandardDeviation = StandardDeviation;
|
||||
if (null != max)
|
||||
{
|
||||
gmi.Maximum = (double)max;
|
||||
@@ -887,7 +936,7 @@ namespace Microsoft.PowerShell.Commands
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not a numeric conversion error occurred.
|
||||
/// If true, then average/sum will not be output.
|
||||
/// If true, then average/sum/standard deviation will not be output.
|
||||
/// </summary>
|
||||
private bool _nonNumericError = false;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
Describe "Measure-Object" -Tags "CI" {
|
||||
BeforeAll {
|
||||
$testObject = 1,3,4
|
||||
$testObject2 = 1..100
|
||||
}
|
||||
|
||||
It "Should be able to be called without error" {
|
||||
@@ -17,6 +18,51 @@ Describe "Measure-Object" -Tags "CI" {
|
||||
$($testObject | Measure-Object).Count | Should Be $testObject.Length
|
||||
}
|
||||
|
||||
It "Should calculate Standard Deviation" {
|
||||
$actual = ($testObject | Measure-Object -StandardDeviation)
|
||||
# We check this way since .StandardDeviation returns a double value
|
||||
# 1.52752523165195 was calculated outside powershell using formula from
|
||||
# http://mathworld.wolfram.com/StandardDeviation.html
|
||||
[Math]::abs($actual.StandardDeviation - 1.52752523165195) | Should -BeLessThan .00000000000001
|
||||
}
|
||||
|
||||
|
||||
It "Should calculate Standard Deviation" {
|
||||
$actual = ($testObject2 | Measure-Object -StandardDeviation)
|
||||
# We check this way since .StandardDeviation returns a double value
|
||||
# 29.011491975882 was calculated outside powershell using formula from
|
||||
# http://mathworld.wolfram.com/StandardDeviation.html
|
||||
[Math]::abs($actual.StandardDeviation - 29.011491975882) | Should -BeLessThan .0000000000001
|
||||
}
|
||||
|
||||
It "Should calculate Standard Deviation with -Sum" {
|
||||
$actual = ($testObject | Measure-Object -Sum -StandardDeviation)
|
||||
# We check this way since .StandardDeviation returns a double value
|
||||
$actual.Sum | Should Be 8
|
||||
# 1.52752523165195 was calculated outside powershell using formula from
|
||||
# http://mathworld.wolfram.com/StandardDeviation.html
|
||||
[Math]::abs($actual.StandardDeviation - 1.52752523165195) | Should -BeLessThan .00000000000001
|
||||
}
|
||||
|
||||
It "Should calculate Standard Deviation with -Average" {
|
||||
$actual = ($testObject | Measure-Object -Average -StandardDeviation)
|
||||
# We check this way since .StandardDeviation returns a double value
|
||||
[Math]::abs($actual.Average - 2.66666666666667) | Should -BeLessThan .00000000000001
|
||||
# 1.52752523165195 was calculated outside powershell using formula from
|
||||
# http://mathworld.wolfram.com/StandardDeviation.html
|
||||
[Math]::abs($actual.StandardDeviation - 1.52752523165195) | Should -BeLessThan .00000000000001
|
||||
}
|
||||
|
||||
It "Should calculate Standard Deviation with -Sum -Average" {
|
||||
$actual = ($testObject2 | Measure-Object -Sum -Average -StandardDeviation)
|
||||
# We check this way since .StandardDeviation returns a double value
|
||||
$actual.Sum | Should Be 5050
|
||||
$actual.Average | Should Be 50.5
|
||||
# 29.011491975882 was calculated outside powershell using formula from
|
||||
# http://mathworld.wolfram.com/StandardDeviation.html
|
||||
[Math]::abs($actual.StandardDeviation - 29.011491975882) | Should -BeLessThan .0000000000001
|
||||
}
|
||||
|
||||
It "Should be able to count using the Property switch" {
|
||||
$expected = $(Get-ChildItem $TestDrive).Length
|
||||
$actual = $(Get-ChildItem $TestDrive | Measure-Object -Property Length).Count
|
||||
|
||||
Reference in New Issue
Block a user