최근 마르코프 체인을 가지고 놀았는데, 큰 코퍼스에서 무엇을 얻었는지 알기 위해 텍스트를 생성하려고했습니다 (그 중 일부는 상당히 흥미 롭습니다).클로저를 반복자로 사용
텍스트 생성에 필요한 데이터 구조를 구축하는 데는 많은 부분이 n-grams입니다. n = 3
가 될 것이다 "오늘 목요일 3 월 여섯 번째는"예를 들어 N-g : 작은 샘플 텍스트 감안할 때
Today is Thursday
is Thursday March
Thursday March the
March the sixth
# skipped lines that have < 3 words because is isn't enough for a 3-gram
를 텍스트의 크기, 내 코드에 의해 생성 된 N-g의 목록에 따라 수 상당히 크다. 일부 언어에서는 사용자 정의 반복자를 만드는 yield 문을 포함하는 generator이라는 개념이 있지만 Perl은 불행히도 그 중 하나가 아닙니다.
대신 Perl에서 어휘 변수에 대한 클로저를 사용하여 Iterators을 만들 수 있지만 사용시 실제로 얻고있는 것을 이해하는 데 약간의 어려움이 있습니다. 여기
내가 N-그램을 생성하기 위해 만든 반복자 (즉, n은에서 열리는 가정 $자가> 순서) :sub _ngrams {
my ($self, @words) = @_;
return sub {
while(@words) {
my @ngram = @words[0 .. $self->order]; # get $order + 1 words
shift @words; # drop the first word
return @ngram;
}
return; # nothing left to do
};
}
난 정말이 코드의 효율성이 많다는에서 무엇을 얻을 수 있습니까? 단어 목록은 여전히 전체적으로 메모리에 @words
에 있습니다. 내 메모리 사용 공간을 줄일 수있는 대체 구현이 있습니까? 여기
는 반복자가 사전을 생성하는 데 사용되는 방법입니다
는sub seed {
my $self = shift;
my $ngram_it = $self->_ngrams(split /\s+/, $self->text);
GRAM:
while (my @gram = $ngram_it->()) {
next GRAM unless @gram == scalar grep { $_ } @gram;
my $val = pop @gram;
my $key = join ' ', @gram;
if (exists $self->lexicon->{$key}) {
push @{$self->lexicon->{$key}}, $val;
}
else {
$self->lexicon->{$key} = [$val];
}
}
}
모든 입력이 매우 도움이 될 것입니다.
반복기를 사용하면 유연성을 얻을 수 있습니다. 스트림에서 단어를 제공하는 반복기에서 쉽게 바꿀 수 있습니다. (나는 n-gram을 반환하는 반복자가 없을 것이고, 단어를 반환하는 반복자를 가질 것입니다.) – ikegami
@ikegami 그래도이 시나리오에서 작동합니까? N + 1 단어를 가져와야하는 경우 첫 번째 단어 만 제거하십시오. 그런 다음 이전 N 단어를 포함하는 다음 N + 1 단어를 가져옵니다. –
이미 가지고있는 논리를 사용하고 반복자 밖으로 이동하십시오. – ikegami