将文本文件处理为结构化表的最佳策略?

时间:2019-01-30 01:48:41

标签: python pandas text-files

我的协作者希望我将输入的文本文件处理为结构化表:

原始输入文本文件看起来像

PMID    22224631
Title    -765 G_C and -1195 A_G promoter variants of the cyclooxygenase-2 gene decrease the risk for preeclampsia.
Found 8 gene(s) 
Gene     CRP Mentions
Gene     GC Mentions
Gene     PTGS2 Mentions
Found 1 variant(s)  
Variant  I399V URL
Gene     PTGS1 Mentions
Found 2 variant(s)  
Variant  L255L URL
Variant  V255V URL
Gene     CT49 Mentions
Gene     GAA Mentions
Found 1 variant(s)  
Variant  Q255H URL
Gene     CGA Mentions
Gene     TAT Mentions

PMID    16076618
Title    1166C mutation of angiotensin II type 1 receptor gene is correlated with umbilical blood flow velocimetry in women with preeclampsia.
Found 13 gene(s)    
Gene     AGTR2 Mentions
Gene     QTRT1 Mentions
Gene     SLC25A10 Mentions
Gene     ATM Mentions
Gene     PIH Mentions
Gene     CCL14 Mentions
Gene     AGT Mentions
Gene     REN Mentions
Gene     ASAH1 Mentions
Gene     AGTR1 Mentions
Gene     SSD Mentions
Gene     TAT Mentions
Found 1 variant(s)  
Variant  D389A URL
Gene     ACE Mentions
Found 2 variant(s)  
Variant  D389A URL
Variant  H389P URL

您可以看到,对于每个PMID(科学出版物的ID),都有一些有关基因的信息,对于每个基因,可能都有一些有关变体的信息。输入文本非常类似于“打印”函数输出,而不是表。然后,每个PMID块都由一个空行分隔。

合作伙伴想要的最终表就像一个长格式表(.csv),由三层组成:PMID,基因和变体。 PMID包含基因,而基因包含(或不包含)变体。以上面的输入文件为例:

PMID     |   Gene   |  Variant
22224631 |   CRP    | No
22224631 |   GC     | No
22224631 |   PTGS2  | I399V 
22224631 |   PTGS1  | L255L 
22224631 |   PTGS1  | V255V 
22224631 |   CT49   | No 
22224631 |   GAA    | Q255H
.......  |  .....

我没有用Python处理原始文本文件到表的经验。

我的想法是先使用正则表达式删除多余的单词。我尝试读取此文本文件,它会生成一个很大的字符串列表,其中每个字符串都是输入文件中的一行

with open ("gene and variants.txt", "r") as myfile:
    data=myfile.readlines()

data2 = [x for x in data if not x.startswith('Title') and not 
x.startswith('Found')]
data3 = [x for x in data2 if x != " \t\n"]
data4 = [x.strip(" Mentions\n") for x in data3]
data4 = [x.strip(" URL") for x in data4]
data4 = [x.replace("Gene\t", "Gene") for x in data4]
data4 = [x.replace("PMID\t", "PMID ") for x in data4]
data4 = [x.replace("Variant\t", "Variant") for x in data4]

幸运的是,我能够剥离大多数不必要的信息,最后进入以下字符串列表:

这样的字符串列表:

The list of string like this

然后我被卡住了。...下一步怎么做才能将此字符串列表转换为目标表?我当时在考虑使用Pandas,但似乎只将每个字符串作为数据帧中的一行包含一列。

我在正确的道路上吗?如果是这样,我下一步该怎么做?

如果没有,您对我应该如何解决此问题有任何建议?

3 个答案:

答案 0 :(得分:0)

我对Python没有真正的经验,但是我的方法是创建元组。
第一个手动创建,以创建第一个PMID | Gene | Variant部分,
然后使用正则表达式去除不必要的文本,然后将这些元组添加到单个列表中。
然后使用字符串格式将它们全部打印出来。
或者,您可以列出3个列表,一个用于PMID,一个用于Gene,一个用于Variant。 然后使用forloop对其进行迭代并打印出来以创建该表。
抱歉,无法提供具体提示。
祝一切顺利!

答案 1 :(得分:0)

您可以使用词典。

例如:

fileDict =  {Gene : [], Variant: [], PMID: []}

遍历列表,检查是否是Gene,Variant或PMID并附加值。

您可以随后喜欢

for x in fileDict['Gene']:
    print(x)

答案 2 :(得分:0)

您可以按照以下步骤将文本文件转换为具有所需格式的Pandas数据框:

  1. 使用read_csv()导入文本文件。为了进行测试,我将上面粘贴的原始输入文本复制到一个新的文本文件中,并将其另存为raw_input.txt
df = pd.read_csv('raw_input.txt', header=-1)

数据框将包含一排这样的行:

    0
0   PMID 22224631
1   Title -765 G_C and -1195 A_G promoter varia...
2   Found 8 gene(s)
3   Gene CRP Mentions
4   Gene GC Mentions
5   Gene PTGS2 Mentions
6   Found 1 variant(s)
7   Variant I399V URL
8   Gene PTGS1 Mentions
...
  1. 下一步是创建一个字典,用于存储每个PMID的信息:
# Get the indices of each row that has a new PMID header
pmid_idxs = df[df[0].str.contains('PMID')].index

# Now construct the dictionary, using each PMID as a key and 
# filling the entry for each key with the PMID's gene info.
pmid_dict = {}
for i, val in enumerate(pmid_idxs.values):
    if pmid_idxs.values[-1] != val:
        nxt_pmid_idx = pmid_idxs.values[i+1]
        pmid_dict[df[0].iloc[val]] =  df[0].iloc[val+1:nxt_pmid_idx].reset_index(drop=True)
    else: # if last PMID
        pmid_dict[df[0].iloc[val]] =  df[0].iloc[val+1:].reset_index(drop=True)
  1. 现在是主要部分-这是一种逻辑,它将循环遍历字典中的每个条目,将每个PMID的基因信息提取并格式化为一个小的数据框,然后将该数据框添加到列表中:
df_list = []

for key, value in pmid_dict.items():
    pmid_num = ''.join(c for c in key if c not in 'PMID ')
    series = value
    next_rows = series.shift(-1).fillna('placeholder')
    df_dict = {'PMID': [],
               'Gene': [],
               'Variant': []}
    gene = ''
    variant = ''
    for i, row in series.iteritems():
        if 'Gene' in row:
            gene = row[4:-9].strip(' ')
            if i <= (len(series)) and 'variant' not in next_rows.iloc[i].lower():
                df_dict['PMID'].append(pmid_num)
                df_dict['Gene'].append(gene)
                df_dict['Variant'].append('No')
            elif i == len(series) + 1:
                df_dict['PMID'].append(pmid_num)
                df_dict['Gene'].append(gene)
                df_dict['Variant'].append('No')
        if 'Variant' in row:
            variant = row[8:-4].strip(' ')
            df_dict['PMID'].append(pmid_num)
            df_dict['Gene'].append(gene)
            df_dict['Variant'].append(variant)

    df = pd.DataFrame(df_dict)
    df_list.append(df)
  1. 最终的输出数据帧将仅仅是我们上面创建的每个小数据帧的串联:
output_df = pd.concat(df_list).reset_index(drop=True)

就是这样。输出数据帧看起来像这样,我相信这是您想要的格式:

    PMID        Gene      Variant
0   22224631    CRP       No
1   22224631    GC        No
2   22224631    PTGS2     I399V
3   22224631    PTGS1     L255L
4   22224631    PTGS1     V255V
5   22224631    CT49      No
6   22224631    GAA       Q255H
7   22224631    CGA       No
8   22224631    TAT       No
9   16076618    AGTR2     No
10  16076618    QTRT1     No
11  16076618    SLC25A10  No
12  16076618    ATM       No
13  16076618    PIH       No
14  16076618    CCL14     No
15  16076618    AGT       No
16  16076618    REN       No
17  16076618    ASAH1     No
18  16076618    AGTR1     No
19  16076618    SSD       No
20  16076618    TAT       D389A
21  16076618    ACE       D389A
22  16076618    ACE       H389P