【问题标题】:How to read the data for two consecutive blocks at a time from multiple blocks until the end of file?如何从多个块一次读取两个连续块的数据直到文件末尾?
【发布时间】:2018-01-08 14:24:22
【问题描述】:

如果你能想到一个好的,请更新标题!

我有如下结构的数据:

chr    pos    A_block    A_val
  2     05       7       A,T,C
  2     11       7       T,C,G
  2     15       7       AT,C,G
  2     21       7       C,A,GT
  2     31       7       T,C,CA
  2     42       9       T,C,G
  2     55       9       C,G,GC
  2     61       9       A,GC,T
  2     05       12       AC,TG,G
  2     11       12       A,TC,TG

预期输出:为了学习,我只想重写输出文件,和输入文件一样,但是使用我下面建议的过程。

我想: step 01: 一次只读取两个连续块的值(前 7 和 9)-> step 02: 将该数据存储在字典中,block numbers 为主唯一键 -> step 03: 将该字典返回给预定义函数进行解析。 -> 现在,读取块 (9 & 12) -> 重复相同的过程直到结束。

我在想这样的事情:

import req_packages
from collections import defaultdict

''' make a function that takes data from two blocks at a time '''
def parse_two_blocks(someData):
    for key, vals in someData:
        do ... something 
        write the obtained output
        clear memory  # to prevent memory buildup


''' Now, read the input file'''
with open('HaploBlock_toy.txt') as HaploBlocks:
    header = HaploBlocks.readline()  
    # only reads the first line as header

    ''' create a empty dict or default dict. Which ever is better?'''
    Hap_Dict = {}
    Hap_Dict = defaultdict(list)


    ''' for rest of the lines '''
    for lines in HaploBlocks:
        values = lines.strip('\n').split('\t')

        ''' append the data to the dict for unique keys on the for loop, until the number of unique keys is 2 '''
        Block = values[2]
        Hap_Dict[Block].append(values[3])

        do something to count the number of keys - how?
        if keys_count > 2:
           return parse_two_blocks(Hap_Dict)

        elif keys_count < 2 or no new keys: # This one is odd and won't work I know.
           end the program

因此,当代码执行时,它将从块 7 和 9 中读取数据,直到字典被填满并返回到预定义的函数。解析完成后,它现在可以只保留前一个解析的后一个块中的数据。这样它就只需要读取剩余的块。

预期输出: 我现在的主要问题是能够一次读取两个块。我不想在 `parse_two_blocks(someData)' 中添加关于如何解析信息的内在细节 - 这个只是另一个问题。但是,让我们尝试重写与输入相同的输出。

【问题讨论】:

  • 你能举例说明你想要得到的结果吗?
  • @ComradeAndrew:我试图以这种方式解析数据,因为我必须一次读取两个块 -> 然后,进行适当的计算并写入值?为了我的学习和暂时将问题最小化,我只想编写与输入相同的输出文件。我可以自己操作。主要问题是一次读取两个块。
  • 每个块是否包含 4 个条目的倍数?我建议您尝试创建所有行的列表,并使用双索引为它们行走,其中第一个索引在第一个块中,第二个在第二个块中移位 4。
  • 不,它没有。它会有所不同。那只是一个巧合。对不起。我刚刚更新了数据
  • 编写一个返回块列表的函数。然后编写另一个成对迭代该列表的函数。然后编写一个函数,使用块号作为键从列表中创建数据库。一些“功能”可能是单行列表推导。

标签: python list dictionary for-loop defaultdict


【解决方案1】:

将输入解析为块的动态列表(生成器)。迭代这些对。这一切都应该在您评估配对时完成。也就是说,这些行都不应该一次读取或存储整个 csv 文件。

#!/usr/bin/env python3

data = """chr   pos A_block A_val
2   05  7   A,T,C
2   11  7   T,C,G
2   15  7   AT,C,G
2   21  7   C,A,GT
2   31  7   T,C,CA
2   42  9   T,C,G
2   55  9   C,G,GC
2   61  9   A,GC,T
2   05  12  AC,TG,G
2   11  12  A,TC,TG"""

import csv
import io
import itertools
import collections
import operator
from pprint import pprint

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = itertools.tee(iterable)
    next(b, None)
    return zip(a, b)

def one():
    # read rows as tuples of values
    c = csv.reader(io.StringIO(data), dialect=csv.excel_tab)
    # read header row
    keys = next(c)
    block_index = keys.index('A_block')
    # group rows by block numbers
    blocks = itertools.groupby(c, key=operator.itemgetter(block_index))
    # extract just the row values for each block
    row_values = (tuple(v) for k, v in blocks)
    # rearrange the values by column
    unzipped_values = (zip(*v) for v in row_values)
    # create a dictionary for each block
    dict_blocks = (dict(zip(keys, v)) for v in unzipped_values)
    yield from pairwise(dict_blocks)


def two():
    c = csv.DictReader(io.StringIO(data), dialect=csv.excel_tab)
    blocks = itertools.groupby(c, key=lambda x: x['A_block'])
    yield from pairwise((k, list(v)) for k, v in blocks)


for a, b in one():
        pprint(a)
        pprint(b)
        print()

输出(one):

{'A_block': ('7', '7', '7', '7', '7'),
 'A_val': ('A,T,C', 'T,C,G', 'AT,C,G', 'C,A,GT', 'T,C,CA'),
 'chr': ('2', '2', '2', '2', '2'),
 'pos': ('05', '11', '15', '21', '31')}
{'A_block': ('9', '9', '9'),
 'A_val': ('T,C,G', 'C,G,GC', 'A,GC,T'),
 'chr': ('2', '2', '2'),
 'pos': ('42', '55', '61')}

{'A_block': ('9', '9', '9'),
 'A_val': ('T,C,G', 'C,G,GC', 'A,GC,T'),
 'chr': ('2', '2', '2'),
 'pos': ('42', '55', '61')}
{'A_block': ('12', '12'),
 'A_val': ('AC,TG,G', 'A,TC,TG'),
 'chr': ('2', '2'),
 'pos': ('05', '11')}

io.StringIO(string)

获取一个字符串并返回一个包含字符串内容的类文件对象。

csv.DictReader(file_object, dialect) 来自csv module

为每一行返回一个有序的字典,其中取自第一行的字段名称用作字段值的字典键。

groupby(iterable, key_function)

创建一个迭代器,从 可迭代的。键是为每个元素计算键值的函数。

lambda x: x['A_block']

一个临时函数,接受名为 x 的输入并返回键 'A_block' 的值

(k, list(v)) for k, v in blocks

groupby() 为值返回一个迭代器(只能使用一次)。这会将迭代器转换为列表。

pairwise(iterable) recipe

"s -> (s0,s1), (s1,s2), (s2, s3), ..."

【讨论】:

  • 非常感谢哈维。我要试试这个,你能补充一些解释吗?但是,如果有数百万行和数百列,您不认为这会占用大量内存吗?
  • 也许我误解了,但我认为你想要字典中的所有数据(所以没有内存限制)。通过一些额外的工作可以避免内存存储。
  • 我想一次只读取两个块的原因 - 处理它 - 写入输出只是为了节省内存积累。对于这个问题,for 循环是否太糟糕了?
  • 被解析的两个块应该有block values作为主要索引来解析块之间的信息。喜欢{'7': defaultdict(&lt;class 'list'&gt;, {'chr': ['7', '7', '7', '7', '7'], 'pos': ['05', '11', '15', '21', '31'], 'A_val': ['ATC', 'TCG', .... ]}), '9': defaultdict(&lt;class 'list'&gt;, {'chr': ['2', '2', .... ], 'pos': ['42', '55', '61'], 'A_val': ['T,C,G', 'C,G,GC', .... ]}))}。此外,我们只在有两个唯一键之前读取。
  • 我不明白你的评论。那么你是否将一个块的所有行组合在一起?如果您确实将它们分组,并且只希望它们采用不同的格式,则可以这样做。那么,一旦您有两个不同的块号,您就停止读取文件?即示例中永远不会读取第 12 块?
猜你喜欢
  • 1970-01-01
  • 2013-10-26
  • 1970-01-01
  • 2020-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-21
相关资源
最近更新 更多