Q: Ланкастер должен был быть "агрессивным" стеммером, но он работал правильно с replied
. Почему?
Это потому, что реализация Lancaster Stemermer улучшена в https://github.com/nltk/nltk/pull/1654
Если мы посмотрим на https://github.com/nltk/nltk/blob/develop/nltk/stem/lancaster.py#L62, есть суффикс правило, чтобы изменить -ied > -y
default_rule_tuple = (
"ai*2.", # -ia > - if intact
"a*1.", # -a > - if intact
"bb1.", # -bb > -b
"city3s.", # -ytic > -ys
"ci2>", # -ic > -
"cn1t>", # -nc > -nt
"dd1.", # -dd > -d
"dei3y>", # -ied > -y
...)
Функция позволяет пользователям вводить новые правила, и если дополнительные правила не добавляются, то она будет использовать self.default_rule_tuple
в parseRules
, где rule_tuple
будет применено https://github.com/nltk/nltk/blob/develop/nltk/stem/lancaster.py#L196
def parseRules(self, rule_tuple=None):
"""Validate the set of rules used in this stemmer.
If this function is called as an individual method, without using stem
method, rule_tuple argument will be compiled into self.rule_dictionary.
If this function is called within stem, self._rule_tuple will be used.
"""
# If there is no argument for the function, use class' own rule tuple.
rule_tuple = rule_tuple if rule_tuple else self._rule_tuple
valid_rule = re.compile("^[a-z]+\*?\d[a-z]*[>\.]?$")
# Empty any old rules from the rule set before adding new ones
self.rule_dictionary = {}
for rule in rule_tuple:
if not valid_rule.match(rule):
raise ValueError("The rule {0} is invalid".format(rule))
first_letter = rule[0:1]
if first_letter in self.rule_dictionary:
self.rule_dictionary[first_letter].append(rule)
else:
self.rule_dictionary[first_letter] = [rule]
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * default_rule_tuple
* * * * * * * *1025* * * * * * * * * * * * *} * Ланкастер Стеммер https://github.com/nltk/nltk/pull/1661 =)
В: Слово В осталось неизменным в Портере с заглавными буквами В, Почему?
Это супер интересно! И, скорее всего, ошибка.
>>> from nltk.stem import PorterStemmer
>>> porter = PorterStemmer()
>>> porter.stem('In')
'In'
Если мы посмотрим на код, первое, что PorterStemmer.stem()
делает его строчными, https://github.com/nltk/nltk/blob/develop/nltk/stem/porter.py#L651
def stem(self, word):
stem = word.lower()
if self.mode == self.NLTK_EXTENSIONS and word in self.pool:
return self.pool[word]
if self.mode != self.ORIGINAL_ALGORITHM and len(word) <= 2:
# With this line, strings of length 1 or 2 don't go through
# the stemming process, although no mention is made of this
# in the published algorithm.
return word
stem = self._step1a(stem)
stem = self._step1b(stem)
stem = self._step1c(stem)
stem = self._step2(stem)
stem = self._step3(stem)
stem = self._step4(stem)
stem = self._step5a(stem)
stem = self._step5b(stem)
return stem
Но если мы посмотрим в коде все остальное возвращает stem
, который в нижнем регистре, но есть два условия if, которые возвращают некоторую форму исходного word
, который не был в нижнем регистре !!!
if self.mode == self.NLTK_EXTENSIONS and word in self.pool:
return self.pool[word]
if self.mode != self.ORIGINAL_ALGORITHM and len(word) <= 2:
# With this line, strings of length 1 or 2 don't go through
# the stemming process, although no mention is made of this
# in the published algorithm.
return word
В первом предложении if проверяется, находится ли слово внутри self.pool
, которое содержит неправильные слова и их основы.
Второй проверяет, является ли len(word)
<= 2, затем возвращает его исходную форму, которая в случае «In» 2-го предложения if возвращает True, таким образом, возвращается исходная форма без нижнего регистра. </p>
В: Заметьте, что Lancaster удаляет слова, заканчивающиеся на e
в слове "пришел", почему?
Не удивительно, что он также приходит из default_rule_tuple
https://github.com/nltk/nltk/blob/develop/nltk/stem/lancaster.py#L67 есть правило, которое меняет -e > -
=)
В: Как отключить правило -e > -
от default_rule_tuple
?
(К счастью, LancasterStemmer._rule_tuple
) объект является неизменным кортежем, поэтому мы не можем просто удалить один элемент из него, но мы можем переопределить его =)
>>> from nltk.stem import LancasterStemmer
>>> lancaster = LancasterStemmer()
>>> lancaster.stem('came')
'cam'
# Create a new stemmer object to refresh the cache.
>>> lancaster = LancasterStemmer()
>>> temp_rule_list = list(lancaster._rule_tuple)
# Find the 'e1>' rule.
>>> lancaster._rule_tuple.index('e1>')
12
# Create a temporary rule list from the tuple.
>>> temp_rule_list = list(lancaster._rule_tuple)
# Remove the rule.
>>> temp_rule_list.pop(12)
'e1>'
# Override the `._rule_tuple` variable.
>>> lancaster._rule_tuple = tuple(temp_rule_list)
# Et voila!
>>> lancaster.stem('came')
'came'