我正在分析句子中一起出现的词组的出现频率。
每组由 3 个单词组成,我们必须计算它们的频率。
示例:这是聚会的好时机,因为这是假期。
预期输出:
this is a - 2
is a good - 1
a good time - 1
等等。
我编写了一个运行良好的脚本,它打印频率并按降序对其进行排序。
它的工作原理是一次从文件中读取一行。对于每一行,它会将它们转换为小写,将其拆分为单独的单词,然后从中形成一个数组。
然后,我们从左边开始一次选择 3 个单词,并不断形成一个哈希来存储出现次数。完成后,我们移动数组中最左边的元素并重复,直到我们的数组包含超过 3 个单词。
问题已更新:
问题是我想在包含超过 1000 万行的文件上使用此脚本。
在运行一些测试后,我观察到如果输入文件中的行数超过 400K,它将无法工作。
我怎样才能让这个脚本更有内存效率?
感谢 fxzuz 的建议,但现在我想让这个脚本处理更大的文件:)
#!/usr/bin/perl
use strict;
use warnings;
print "Enter the File name: ";
my $input = <STDIN>;
chomp $input;
open INPUT, '<', $input
or die("Couldn't open the file, $input with error: $!\n");
my %c;
while (my $line = <INPUT>) {
chomp $line;
my @x = map lc, split /\W+/, join "", $line;
while (@x>3) {
$c{"@x[0..2]"}++;
shift @x;
}
}
foreach $key (sort {$c{$b} <=> $c{$a}} keys %c) {
if($c{$key} > 20) {
print $key." - ".$c{$key}."\n";
}
}
close INPUT;
这很好用,它会按频率降序打印单词组。它只会打印出现次数超过 20 次的词组。
现在,我如何在包含超过 100 万或 1000 万行的文件上执行此操作?
我还在 Linux 中使用 top 命令运行此脚本时检查了 perl 的内存和 CPU 使用情况,并观察到当脚本在 400K 组成的文件上运行时,CPU 使用率达到 100%,内存使用率接近 90%行。
因此,要使其与包含 100 万行的文件一起工作是不可行的。因为perl进程会挂掉。
如何使这段代码的内存效率更高?
最佳答案
显然,您的代码编写正确并且可以运行,但前提是您的数据集不是很大。如果您有大量输入数据(并且看起来确实如此),排序阶段可能会由于内存不足而失败。如果您无法增加内存,唯一的解决方案是将数据写入磁盘 - 以文本或数据库格式。
文本格式:您可以在进入文本文件时简单地写下您的三元组,每个三元组一行。这样做会将输出大小增加 3 倍,但它仍然是可管理的。然后,您可以简单地使用命令行 gnu sort 和 uniq 工具来获得您想要的计数,如下所示:
text2triplet.pl <input.txt | sort | uniq -c | sort -r | head -10000
(您可能希望将用于排序的输出存储到一个文件中,如果它非常大则不要通过管道传输)数据库格式:使用 DBD::SQLite 并像这样创建表:
CREATE TABLE hash (triplet VARCHAR, count INTEGER DEFAULT 0);
CREATE INDEX idx1 ON hash (triplet);
CREATE INDEX idx2 ON hash (count);
INSERT
将您的三胞胎放入该表中,并增加重复项的数量。处理数据后,只需
SELECT * FROM hash
WHERE count > 20
ORDER BY count DESC
然后打印出来。
然后你可以DROP
您的哈希表或干脆删除整个 SQLite 数据库。
这两种方法都应该允许您扩展到几乎磁盘的大小,但数据库方法可能更灵活。
关于perl - 在 Perl 中对巨大的哈希进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13043083/