Как разобрать текстовые файлы PubMed? - PullRequest
0 голосов
/ 16 декабря 2018

Я работаю над проектом, в котором мне нужно создать классификаторы SVM для прогнозирования назначений терминов MeSH на основе слов в названии и аннотации статьи.Нам дали gzip-файлы с 1000 PMID, идентифицирующими каждую статью.Ниже приведен пример файла:

PMID- 22997744
OWN - NLM
STAT- MEDLINE
DCOM- 20121113
LR  - 20120924
IS  - 0042-4676 (Print)
IS  - 0042-4676 (Linking)
IP  - 3
DP  - 2012 May-Jun
TI  - [Value of magnetic resonance imaging in the diagnosis of recurrent colorectal
      cancer].
PG  - 28-33
AB  - To diagnose recurrent colorectal cancer is an urgent problem of oncoproctology.
      Eighty patients with suspected recurrent colon tumor were examined. All the
      patients underwent irrigoscopy, colonoscopy, magnetic resonance imaging of the
      abdomen and small pelvis. The major magnetic resonance symptoms of recurrent
      colon tumors were studied; a differential diagnosis of recurrent processes and
      postoperative changes at the site of intervention was made.
FAU - Dan'ko, N A

MH  - Aged
MH  - Colon/pathology/surgery
MH  - Colorectal Neoplasms/*diagnosis/pathology/surgery
MH  - Diagnosis, Differential
MH  - Female
MH  - Humans
MH  - Magnetic Resonance Imaging/*methods
MH  - Male
MH  - Middle Aged
MH  - Neoplasm Recurrence, Local/*diagnosis
MH  - Postoperative Complications/*diagnosis
MH  - Rectum/pathology/surgery
MH  - Reproducibility of Results

Я пытаюсь выяснить, как создать словарь, который будет иметь:

{PMID: {Title (TI): Title words},
       {Abstract (AB): Abstract words},
       {MeSH (MH): MeSH terms}}.

Есть ли простой способ сделать это?Пока я знаю, что приведенный ниже код подходит близко, но он не идеален для него.

class Node:
    def __init__(self, indented_line):
        self.children = []
        self.level = len(indented_line) - len(indented_line.lstrip())
        self.text = indented_line.strip()

    def add_children(self, nodes):
        childlevel = nodes[0].level
        while nodes:
            node = nodes.pop(0)
            if node.level == childlevel: # add node as a child
                self.children.append(node)
            elif node.level > childlevel: # add nodes as grandchildren of the last child
                nodes.insert(0,node)
                self.children[-1].add_children(nodes)
            elif node.level <= self.level: # this node is a sibling, no more children
                nodes.insert(0,node)
                return

    def as_dict(self):
        if len(self.children) > 1:
            return {self.text: [node.as_dict() for node in self.children]}
        elif len(self.children) == 1:
            return {self.text: self.children[0].as_dict()}
        else:
            return self.text

# Problem A [0 points]
def read_data(filenames):
    data = None
    # Begin CODE
    data = {}
    contents = []
    for filename in filenames:
        with gzip.open(filename,'rt') as f:
            contents.append(f.read())

    root = Node('root')
    root.add_children([Node(line) for line in contents[0].splitlines() if line.strip()])
    d = root.as_dict()['root']
    print(d[:50])
    # End CODE
    return data

1 Ответ

0 голосов
/ 16 декабря 2018

Давайте разберем пример до чего-то более простого:

content = """
PMID- 22997744
OWN - NLM
TI  - [Value of magnetic resonance imaging in the diagnosis of recurrent colorectal
      cancer].
PG  - 28-33
AB  - To diagnose recurrent colorectal cancer is an urgent problem of oncoproctology.
      Eighty patients with suspected recurrent colon tumor were examined.
FAU - Dan'ko, N A

MH  - Aged
MH  - Colon/pathology/surgery"""

Вы можете использовать регулярные выражения для сопоставления с шаблоном.Регулярные выражения являются мощным и мощным инструментом:

>>> match = re.search('^PMID- (.*)$', content, re.MULTILINE)

Шаблон ^PMID- (.*)$ соответствует началу строки ^, затем следует PMID-, затем несколько символов ., затем конецлиния $.Скобки (.*) означают, что сопоставление результатов внутри скобок будет помещено в группу.Нам нужно проверить, было ли совпадение:

>>> match is not None
True

Мы можем запросить совпадение:

>>> match.groups()
('22997744',)

Итак, мы можем видеть, что есть одна группа (потому что мы определили только одну группу внаш шаблон), и он соответствует PMID: 22997744.

Мы можем получить значение, запросив значение группы совпадений 1. Группа совпадений 0 - это вся строка, которая соответствует: PMID- 22997744.

>>> pmid = match.group(1)
>>> pmid
'22997744'

Шаблон для сопоставления по нескольким строкам с TI и AB намного сложнее.Я не эксперт, возможно, кто-то еще скинется с чем-то лучшим.Я бы сначала сделал замену текста, чтобы весь текст был в одной строке.Например:

>>> text = """TI  - [Value of magnetic resonance imaging in the diagnosis of recurrent colorectal
...       cancer].

>>> print(text)
TI  - [Value of magnetic resonance imaging in the diagnosis of recurrent colorectal
      cancer].

>>> print(text.replace('\n      ', ' '))
TI  - [Value of magnetic resonance imaging in the diagnosis of recurrent colorectal cancer].

Тогда мы можем сопоставить TI и AB аналогичным образом:

>>> content = content.replace('\n      ', ' ')

>>> match = re.search('^TI  - (.*)$', content, re.MULTILINE)
>>> ti = match.group(1)
>>> ti
'[Value of magnetic resonance imaging in the diagnosis of recurrent colorectal cancer].'

>>> match = re.search('^AB  - (.*)$', content, re.MULTILINE)
>>> ab = match.group(1)
>>> ab
'To diagnose recurrent colorectal cancer is an urgent problem of oncoproctology. Eighty patients with suspected recurrent colon tumor were examined'

Чтобы сопоставить MH, мы хотим найти все совпадения.re.search просто найдет первый матч.re.findall вернет несколько совпадений:

>>> mh = re.findall('^MH  - (.*)$', content, re.MULTILINE)
>>> mh
['Aged', 'Colon/pathology/surgery']

Собрав все это вместе:

data = {}

data[pmid] = {'Title': ti,
              'Abstract': ab,
              'MeSH': mh}

Это дает (используя pprintчтобы он выглядел лучше):

>>> from pprint import pprint
>>> pprint(data)
{'22997744': {'Abstract': 'To diagnose recurrent colorectal cancer is an urgent problem of oncoproctology. Eighty patients with suspected recurrent colon tumor were examined.',
              'MeSH': ['Aged', 'Colon/pathology/surgery'],
              'Title': '[Value of magnetic resonance imaging in the diagnosis of recurrent colorectal cancer].'}}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...