【问题标题】:CSV file - count distinct, group by, sumCSV 文件 - 计数不同、分组依据、总和
【发布时间】:2018-05-23 18:45:42
【问题描述】:

我有一个如下所示的文件;

- Visitor ID,Revenue,Channel,Flight
- 1234,100,Email,BA123
- 2345,200,PPC,BA112
- 456,150,Email,BA456

我需要生成一个包含;

The count of distinct Visitor IDs (3)
The total revenue (450)
The count of each Channel
Email 2
PPC 2
The count of each Flight
BA123 1
BA112 1
BA456 1

到目前为止,我有以下代码,但是在 350MB 文件上执行此代码时,它需要的时间太长,并且在某些情况下会破坏 memory limit。因为我必须在multiple columns 上运行这个function,所以它会多次遍历文件。理想情况下,我需要在一个文件传递中执行此操作。

$file = 'log.txt'

function GroupBy($columnName)
{
    $objects = Import-Csv -Delimiter "`t" $file | Group-Object $columnName |
       Select-Object @{n=$columnName;e={$_.Group[0].$columnName}}, Count

      for($i=0;$i -lt $objects.count;$I++) {
     $line += $columnName +"|"+$objects[$I]."$columnName" +"|Count|"+ $objects[$I].'Count' + $OFS

    }
    return $line
}

$finalOutput += GroupBy "Channel"
$finalOutput += GroupBy "Flight"


Write-Host $finalOutput

任何帮助将不胜感激。

谢谢,

克雷格

【问题讨论】:

标签: powershell


【解决方案1】:

您正在为每一列再次导入 CSV,这一事实正在扼杀您的脚本。尝试加载一次,然后重新使用数据。例如:

$data = Import-Csv .\data.csv

$flights = $data | Group-Object Flight -NoElement | ForEach-Object {[PsCustomObject]@{Flight=$_.Name;Count=$_.Count}}
$visitors = ($data | Group-Object "Visitor ID" | Measure-Object).Count
$revenue = ($data | Measure-Object Revenue -Sum).Sum
$channel = $data | Group-Object Channel -NoElement | ForEach-Object {[PsCustomObject]@{Channel=$_.Name;Count=$_.Count}}

你可以这样显示数据:

"Revenue : $revenue"
"Visitors: $visitors"
$flights | Format-Table -AutoSize
$channel | Format-Table -AutoSize

【讨论】:

  • 感谢您的回复 - 我确实在 350MB 文件上尝试了您的代码。现在有 12 GB 的内存被使用,我只能想象会发生大量的分页。 Powershell 一直这么糟糕吗?!
  • PowerShell 基于 .NET Framework,它有自己的在后台运行的垃圾收集。对象并不总是立即被处理掉(从而释放内存)。您现在可以使用 [GC]::Collect() 强制 .NET 进行垃圾收集,尽管它是 isn't usually recommended
  • 当我遇到大量数据时,我发现 Group-By 可能会很慢并且会消耗内存。在这些情况下,我通常只使用哈希映射来获得我正在寻找的内容。
  • 抛出了“System.OutOfMemoryException”类型的异常。在 C:\Users\fitches\Documents\Clients\TUI\GMP Data Summary\gmp.ps1:19 char:1 + $visitors = ($data | Group-Object "CMid Visitor" | Measure-Object).Co .. . + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : OperationStopped: (:) [], OutOfMemoryException + FullyQualifiedErrorId : System.OutOfMemoryException
【解决方案2】:

这可能会起作用 - 使用哈希图。

  • 优点:它会更快/使用更少的内存。
  • 缺点:可读性较差 远远超过Group-Object,并且需要更多代码。
  • 减少内存占用:逐行读取 CSV 文件

    $data = Import-CSV -Path "C:\temp\data.csv" -Delimiter ","
    $DistinctVisitors = @{}
    $TotalRevenue = 0
    $ChannelCount = @{}
    $FlightCount = @{}
    
    $data | ForEach-Object {
        $DistinctVisitors[$_.'Visitor ID'] = $true
        $TotalRevenue += $_.Revenue
    
        if (-not $ChannelCount.ContainsKey($_.Channel)) {
            $ChannelCount[$_.Channel] = 0
        }
        $ChannelCount[$_.Channel] += 1
    
        if (-not $FlightCount.ContainsKey($_.Flight)) {
            $FlightCount[$_.Flight] = 0
        }
        $FlightCount[$_.Flight] += 1
    }
    
    $DistinctVisitorsCount = $DistinctVisitors.Keys | Measure-Object | Select-Object -ExpandProperty Count
    
    Write-Output "The count of distinc Visitor IDs $DistinctVisitorsCount"
    Write-Output "The total revenue $TotalRevenue"
    Write-Output "The Count of each Channel"
    $ChannelCount.Keys | ForEach-Object {
        Write-Output "$_ $($ChannelCount[$_])"
    }
    Write-Output "The count of each Flight"
    $FlightCount.Keys | ForEach-Object {
        Write-Output "$_ $($FlightCount[$_])"
    }
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-25
    • 2011-07-17
    • 1970-01-01
    • 1970-01-01
    • 2018-07-28
    相关资源
    最近更新 更多