【问题标题】:Find the statistical mode(s) of a dataset in PowerShell在 PowerShell 中查找数据集的统计模式
【发布时间】:2019-11-06 21:08:17
【问题描述】:

这个自我回答的问题是this question 的后续问题:

如何确定给定数据集的(数组)statistical mode,即最常出现的一个值或一组值?

例如,在数组1, 2, 2, 3, 4, 4, 5 中有两种模式,24,因为它们是出现频率最高的值。

【问题讨论】:

    标签: powershell statistics


    【解决方案1】:

    使用Group-ObjectSort-Objectdo ... while 循环的组合:

    # Sample dataset.
    $dataset = 1, 2, 2, 3, 4, 4, 5
    
    # Group the same numbers and sort the groups by member count, highest counts first.
    $groups = $dataset | Group-Object | Sort-Object Count -Descending
    
    # Output only the numbers represented by those groups that have 
    # the highest member count.
    $i = 0
    do { $groups[$i].Group[0] } while ($groups[++$i].Count -eq $groups[0].Count)
    

    上面产生24,这是两种模式(出现频率最高的值,在这种情况下每个两次),按升序排序(因为Group-Object按分组标准排序,Sort-Object的排序算法是稳定的)。

    注意:虽然此解决方案在概念上很简单,但大型数据集的性能可能是一个问题;有关某些输入可能的优化,请参阅底部部分。

    说明:

    • Group-Object 按相等对所有输入进行分组。

    • Sort-Object -Descending 按成员计数以降序方式对结果组进行排序(最常出现的输入优先)。

    • do ... while 语句遍历已排序的组,并输出每个组表示的输入,只要组成员和因此出现计数(频率)最高,正如第一个组的成员计数所暗示的那样。


    性能更好的解决方案,包含字符串和数字:

    如果输入元素都是简单的数字或字符串(与复杂的对象相反),则可以进行优化:

    • Group-Object-NoElement 禁止收集每个组中的单个输入。

    • 每个组的.Name 属性反映了分组值,但作为字符串,因此必须将其转换回其原始数据类型。

    # Sample dataset.
    # Must be composed of all numbers or strings.
    $dataset = 1, 2, 2, 3, 4, 4, 5
    
    # Determine the data type of the elements of the dataset via its first element.
    # All elements are assumed to be of the same type.
    $type = $dataset[0].GetType()
    
    # Group the same numbers and sort the groups by member count, highest counts first.
    $groups = $dataset | Group-Object -NoElement | Sort-Object Count -Descending
    
    # Output only the numbers represented by those groups that have 
    # the highest member count.
    # -as $type converts the .Name string value back to the original type.
    $i = 0
    do { $groups[$i].Name -as $type } while ($groups[++$i].Count -eq $groups[0].Count)
    

    【讨论】:

    • 我可能对此有误(并欢迎更正),但如果您只是使用 where 子句来退出模式,这难道不会更简单吗? $排序 = $数据集 |组对象 | sort-object -property count -descending 然后 ($sorted | ? {$_.Count -eq $sorted[0].Count}).Name
    • 谢谢,@Ryan - 确实有改进的潜力:我最初认为单个管道可以避免收集内存中的所有对象,但这种逻辑是错误的,因为分组和排序都需要反正。因此,两步法是可行的,并且在概念上更简单。但是,Where-Object 解决方案总是会遍历 所有 组,这应该避免 - 请参阅我的更新,它现在使用 do ... while 循环。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 2011-03-06
    • 2022-01-22
    • 1970-01-01
    • 2012-02-10
    相关资源
    最近更新 更多