2017-02-21 29 views
4

Сформировать биграммы слова в Джулию, я мог бы просто пронестись через исходный список и список, который падает на первый элемент, например:Сформировать ngrams с Юлией

julia> s = split("the lazy fox jumps over the brown dog") 
8-element Array{SubString{String},1}: 
"the" 
"lazy" 
"fox" 
"jumps" 
"over" 
"the" 
"brown" 
"dog" 

julia> collect(zip(s, drop(s,1))) 
7-element Array{Tuple{SubString{String},SubString{String}},1}: 
("the","lazy") 
("lazy","fox") 
("fox","jumps") 
("jumps","over") 
("over","the") 
("the","brown") 
("brown","dog") 

Чтобы сгенерировать триграмму я мог бы использовать один и те же collect(zip(...)) идиома, чтобы получить:

julia> collect(zip(s, drop(s,1), drop(s,2))) 
6-element Array{Tuple{SubString{String},SubString{String},SubString{String}},1}: 
("the","lazy","fox") 
("lazy","fox","jumps") 
("fox","jumps","over") 
("jumps","over","the") 
("over","the","brown") 
("the","brown","dog") 

Но я должен вручную добавить в 3-й список, чтобы пронестись через, есть идиоматическое способ таким образом, что я могу сделать любой заказ п -gram?

например. Я хотел бы избежать этого, чтобы извлечь 5-грамм:

julia> collect(zip(s, drop(s,1), drop(s,2), drop(s,3), drop(s,4))) 
4-element Array{Tuple{SubString{String},SubString{String},SubString{String},SubString{String},SubString{String}},1}: 
("the","lazy","fox","jumps","over") 
("lazy","fox","jumps","over","the") 
("fox","jumps","over","the","brown") 
("jumps","over","the","brown","dog") 

ответ

4

Вот чистый однострочный вкладыш для n-граммов любой длины.

ngram(s, n) = collect(zip((drop(s, k) for k = 0:n-1)...)) 

Он использует генератор понимание перебрать числа элементов, k к drop. Затем, используя оператор splat(), он распаковывает Drop s в zip и, наконец, collect с Zip в Array.

julia> ngram(s, 2) 
7-element Array{Tuple{SubString{String},SubString{String}},1}: 
("the","lazy") 
("lazy","fox") 
("fox","jumps") 
("jumps","over") 
("over","the") 
("the","brown") 
("brown","dog") 

julia> ngram(s, 5) 
4-element Array{Tuple{SubString{String},SubString{String},SubString{String},SubString{String},SubString{String}},1}: 
("the","lazy","fox","jumps","over") 
("lazy","fox","jumps","over","the") 
("fox","jumps","over","the","brown") 
("jumps","over","the","brown","dog") 

Как вы можете видеть, это очень похоже на ваше решение - только простое понимание было добавлено перебрать числа элементов drop, так что длина может быть динамическим.

+0

О, круто! Спасибо @HarrisonGrodin, не знал, что 'drop (s, 0)' возможно =) – alvas

+1

@alvas Нет проблем! Кроме того, в случае, когда 'drop (s, 0)' не удалось, будет работать следующее. :) 'zip (s, (drop (s, k) для k = 1: n-1) ...)' –

5

Другой способ заключается в использовании Iterators.jl «s partition():

ngram(s,n) = collect(partition(s, n, 1)) 
4

При незначительном изменении выходного сигнала и с помощью SubArray сек вместо Tuple с, немного теряется, но можно избежать распределения и копирования памяти. Если базовый список слов статичен, все в порядке и быстрее (в моих тестах тоже). Код:

ngram(s,n) = [view(s,i:i+n-1) for i=1:length(s)-n+1] 

и выход:

julia> ngram(s,5) 
SubString{String}["the","lazy","fox","jumps","over"] 
SubString{String}["lazy","fox","jumps","over","the"] 
SubString{String}["fox","jumps","over","the","brown"] 
SubString{String}["jumps","over","the","brown","dog"] 

julia> ngram(s,5)[1][3] 
"fox" 

Для большего слова перечислены требования к памяти существенно меньше, также.

Также обратите внимание, что генератор позволяет обрабатывать ngrams один за другим быстрее и с меньшим объемом памяти и может быть достаточным для желаемого кода обработки (считая что-то или проходящий через некоторый хеш). Например, используя решение @ Gnimuc без collect, то есть только partition(s, n, 1).