Использование ключевых аргументов в функции, чтобы сделать генерацию n-грамм необязательной
Пример того, как выглядит мой XML-файл:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="folia.xsl"?>
<FoLiA xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://ilk.uvt.nl/folia" xml:id="untitled" generator="libfolia-v0.10">
<metadata type="native">
<annotations>
<token-annotation annotator="ucto" annotatortype="auto" datetime="2017-04-17T14:50:04" set="tokconfig-nl"/>
<pos-annotation annotator="frog-mbpos-1.0" annotatortype="auto" datetime="2017-04-17T14:50:04" set="http://ilk.uvt.nl/folia/sets/frog-mbpos-cgn"/>
<lemma-annotation annotator="frog-mblem-1.1" annotatortype="auto" datetime="2017-04-17T14:50:04" set="http://ilk.uvt.nl/folia/sets/frog-mblem-nl"/>
<chunking-annotation annotator="frog-chunker-1.0" annotatortype="auto" datetime="2017-04-17T14:50:04" set="http://ilk.uvt.nl/folia/sets/frog-chunker-nl"/>
<entity-annotation annotator="frog-mwu-1.0" annotatortype="auto" datetime="2017-04-17T14:50:04" set="http://ilk.uvt.nl/folia/sets/frog-mwu-nl"/>
<entity-annotation annotator="frog-ner-1.0" annotatortype="auto" datetime="2017-04-17T14:50:04" set="http://ilk.uvt.nl/folia/sets/frog-ner-nl"/>
<morphological-annotation annotator="frog-mbma-1.0" annotatortype="auto" datetime="2017-04-17T14:50:04" set="http://ilk.uvt.nl/folia/sets/frog-mbma-nl"/>
<dependency-annotation annotator="frog-depparse-1.0" annotatortype="auto" set="http://ilk.uvt.nl/folia/sets/frog-depparse-nl"/>
</annotations>
</metadata>
<text xml:id="untitled.text">
<p xml:id="untitled.p.1">
<s xml:id="untitled.p.1.s.1">
<w xml:id="untitled.p.1.s.1.w.1" class="WORD">
<t>De</t>
<pos class="LID(bep,stan,rest)" confidence="0.999701" head="LID">
<feat class="bep" subset="lwtype"/>
<feat class="stan" subset="naamval"/>
<feat class="rest" subset="npagr"/>
</pos>
<lemma class="de"/>
<morphology>
<morpheme>
<t offset="0">de</t>
</morpheme>
</morphology>
</w>
Я делаю функцию для генерации слов uni-, bi- и trigram из xml-файла. Я хочу сделать n-грамм необязательным, чтобы вы могли выбрать, хотите ли вы все н-граммы или, например, только униграммы. Результатом моей функции является векторизованная относительная частота слова n-грамм. Я попробовал это, используя ключевые аргументы в моих параметрах (используя True и False). Я получаю пустой словарь, поэтому я, должно быть, делаю что-то не так. Вот что у меня есть. Может кто-нибудь сказать мне, что я делаю не так?
import re
import xml.etree.ElementTree as ET
def word_ngrams(frogged_xmlfile, unigrams=True, bigrams=True, trigrams=True):
vector = {}
tree = ET.parse(frogged_xmlfile) #enter the xml tree
root = tree.getroot()
tokens = []
words = []
regex = re.compile(r'[^0-9] |[^(\.|\,|\?|\:|\;|\!)]')
for node in root.iter('w'):
for w in node.findall('t'):
tokens.append(w.text)
for word in tokens:
if regex.search(word):
words.append(word)
if (unigrams):
for n in [1]: #unigrams
grams = ngrams(words, n)
fdist = FreqDist(grams)
total = sum(c for g,c in fdist.items())
for gram, count in fdist.items():
vector['w'+str(n)+'+'+' '.join(gram)] = count/total
if (bigrams):
for n in [2]: #bigrams
grams = ngrams(tokens, n)
fdist = FreqDist(grams)
total = sum(c for g,c in fdist.items())
for gram, count in fdist.items():
vector['w'+str(n)+'+'+' '.join(gram)] = count/total
if (trigrams):
for n in [3]: #trigrams
grams = ngrams(tokens, n)
fdist = FreqDist(grams)
total = sum(c for g,c in fdist.items())
for gram, count in fdist.items():
vector['w'+str(n)+'+'+' '.join(gram)] = count/total
return vector
print(word_ngrams('romanfragment_frogged.xml', unigrams = True, bigrams = False, trigrams = False))
1 ответ
Ваш поиск игнорирует пространство имен документа по умолчанию, поэтому он никогда не находит совпадающие теги.
Ваше регулярное выражение действительно ужасно -
"[^0-9] " # not-a-digit, followed by space "|" # OR "[^(\.|\,|\?|\:|\;|\!)]" # bad syntax, but I think you mean not one of .,?:;!
Он будет принимать любую пунктуацию, за которой следует пробел (как не цифра), или любая цифра или другой символ или пробел (как не пунктуация)! По сути, единственное, что ему не соответствует, это "строка, состоящая исключительно из знаков препинания".
Я собираюсь догадаться, что вы действительно хотели "строку, содержащую хотя бы одну букву и не состоящую из букв", но не стесняйтесь меня поправлять.
Ваш код не включает
ngrams()
или жеFreqDist()
поэтому я не могу проверить это.Отступ
for gram, count ...
выглядит некорректно - думаю, стоит отступить еще на один уровень.У вас много ненужного дублированного кода.
Попробуй это:
# import re
import xml.etree.ElementTree as ET
FOLIA_NAMESPACE = {
'default': 'http://ilk.uvt.nl/folia',
'xlink': 'http://www.w3.org/1999/xlink'
}
def is_word(s):
return s.isalpha()
# as a regex:
# return re.match("[A-Za-z]+$", s) is not None
def load_words(folia_xml_file, is_word=is_word, namespace=FOLIA_NAMESPACE):
root = ET.parse(folia_xml_file).getroot()
tokens = root.findall(".//default:w/default:t", namespace)
return [t.text for t in tokens if is_word(t.text)]
def make_ngram_vectors(words, n_values=[1,2,3]):
vectors = {}
for n in n_values:
grams = ngrams(words, n)
fdist = FreqDist(grams)
total = sum(count for gram,count in fdist.items())
for gram,count in fdist.items():
key = "w{}+{}".format(n, " ".join(gram))
vectors[key] = count / total
return vectors
def main():
words = load_words("romanfragment_frogged.xml")
vectors = make_ngram_vectors(words, [1])
print(vectors)
if __name__ == "__main__":
main()
Изменить: если вы посмотрите в <FoLiA>
тег в верхней части вашего XML-файла, вы увидите xmlns=
(ссылка, определяющая пространство имен документа по умолчанию, т.е. какие теги доступны) и xmlns:xlink=
(альтернативное пространство имен XLink, которое определяет такие теги, как xlink:href
а также xlink:show
- см. https://www.w3schools.com/xml/xml_xlink.asp).
ElementTree любит расширять встроенные пространства имен, чтобы ваши теги выглядели как {http://ilk.uvt.nl/folia}w
, Передача dict пространства имен позволяет нам использовать более удобочитаемое форматирование, например default:w
вместо.
Чтобы получить те же форматы ввода / вывода, что и в исходной функции, вы можете использовать функцию-оболочку, например:
def word_ngrams(folia_xml_file, unigrams=True, bigrams=True, trigrams=True):
# condense parameters into n_values
n_values = []
if unigrams:
n_values.append(1)
if bigrams:
n_values.append(2)
if trigrams:
n_values.append(3)
words = load_words(folia_xml_file)
return make_ngram_vectors(words, n_values)