在文件中添加常用值awk内存有效的解决方案

时间:2016-09-10 04:41:50

标签: awk

我有一个包含值和频率的文件。我使用以下命令awk {a [$ 1] + = $ 2} END  添加具有相同值的列的频率。但是,该文件包含3GB的数据,我需要一个内存有效的解决方案。所以我首先对文件进行了排序,并尝试添加连续的列,如果它们相同,但我没有这样做,

5 个答案:

答案 0 :(得分:1)

如果您先排序数据并在之后处理,那该怎么办:

$ cat > assumed_data.txt
VALUE1 1
VALUE2 2
VALUE1 3
VALUE2 4
$ sort assumed_data.txt|awk 'NR>1 && prev != $1 {print prev, sum; sum=0} {sum+=$2; prev=$1} END {print prev, sum}'
VALUE1 4
VALUE2 6

答案 1 :(得分:0)

...或计数并分批打印出来,例如处理1000行并将它们打印到另一个文件,接下来的1000行并附加到同一个文件中:

$ cat divisum.awk
NR % 1000 ==0 {
    for(i in sum) 
        print i, sum[i]
    delete sum
} 
{
    sum[$1]+=$2
} 
END {
    for(i in sum) 
        print i, sum[i]
}
$ awk -f divisum.awk assumed_data.txt > summedsome.txt

然后:

$ awk -f divisum.awk summedsome.txt > summedsomore.txt

......等等。不知道你所有1000的数据可能是也可能不是很多行。如果您的文件正好均匀分布了1000个不同的值,则一次1000行不能解决您的问题。

答案 2 :(得分:0)

如果您确实遇到了内存问题,因为您可以在文件上运行sort,我不相信您这样做了,那么您需要这样的内容来解决它:

awk '
    !full {
        if ( ($1 > prevMax) || (NR == FNR) ) {
            sum[$1] += $2
            if ( length(sum) == 1000000 ) {
                full = 1
                for ( i in sum ) {
                    min = ( $1<min ? $1 : min)
                    max = ( $1>max ? $1 : max)
                }
            }
        }
        next
    }
    ($1 >= min) && ($1 =< max) {
        sum[$1] += $2
    }
    ENDFILE {
        if ( length(sum) > 0 ) {
            for ( i in sum ) {
                print i, sum[i]
            }
            ARGV[ARGC] = FILENAME
            ARGC++
            delete sum
            full = 0
            prevMax = max
        }
    }
' file

检查数学/逻辑,但希望您能够一次计算最多1000000个唯一值,并继续将输入文件添加回ARGV列表,直到不再有唯一值。按摩1000000以适应。

以上使用GNU awk作为ENDFILE,其他awks你必须使用文件中的行数或使用FNR == 1和退出或类似。

答案 3 :(得分:0)

您经常可以将RAM换成磁盘,因此请通过文件一次性将其按值分成文件 - 因此所有VALUE1个频率都会放入文件f.VALUE1和所有VALUE2个频率进入档案f.VALUE2

awk '{print $2 > "f." $1}' yourFile

然后,你需要总计每个f.*中的数字。此解决方案一次只能在内存中保存一行: - )

答案 4 :(得分:0)

另一种解决方法是使用 GNU Parallel 。它可以将文件分块为任意大小的块,并为您并行处理它们。它只会分成整行 - 除非你做其他我不建议的东西,所以不存在分裂的风险。

因此,假设我在awk中使用您的script.awk脚本,如下所示:

{a[$1]+=$2}
END{for(i in a)print i,a[i]}

并假设您的文件名为data,我可以将 GNU Parallel 块文件分成10MB块并将它们与CPU并行传递给尽可能多的awk有核心:

parallel -a data --pipepart --block 10m awk -f ./script.awk

现在只要在任何10MB块中有重复值,这将减少您的数据。你可以明显地使块更大并且它将会有更大的减少,因为你将有更好的参考局部性,你也可以通过改变块大小来测试你的缺乏记忆的理论。您也可以反复应用上述内容,直到文件大小小于内存,这意味着您可以将内存全部放入内存中。我的意思是:

parallel -a data  --pipepart --block 10m awk -f ./script.awk > part1
parallel -a part1 --pipepart --block 10m awk -f ./script.awk > part2

正如Ed所说,问题是您拥有多少唯一值,而不是您有多少值。您拥有的唯一值越少,它们在文件中的距离越近,此方法收敛的速度就越快。