代码之家  ›  专栏  ›  技术社区  ›  user977828

简化文件结尾的处理

  •  0
  • user977828  · 技术社区  · 4 年前

    我有以下文件:

    chr11_pilon3.g3568.t1   transcript:OIS96097 82.2    168 30
    chr11_pilon3.g3568.t2   transcript:OIS96097 82.2    169 30
    gene.100079.0.5.p3  transcript:OIS96097 82.2    169 30
    gene.100079.0.3.p1  transcript:OIS96097 82.2    169 30
    gene.100079.0.0.p1  transcript:OIS96097 82.2    169 35
    gene.100080.0.3.p1  transcript:OIS96097 82.2    169 40
    gene.100080.0.0.p1  transcript:OIS96097 82.2    169 40
    

    我得到以下输出:

    chr11_pilon3.g3568.t1   transcript:OIS96097 82.2    168 30
    chr11_pilon3.g3568.t2   transcript:OIS96097 82.2    169 30
    gene.100079.0.0.p1  transcript:OIS96097 82.2    169 35
    gene.100080.0.3.p1  transcript:OIS96097 82.2    169 40
    gene.100080.0.0.p1  transcript:OIS96097 82.2    169 40
    

                try:
                    lineParts = line.rstrip().split('\t')
                except IndexError:
                    continue
    

            if dataStorage:  # check if Dict is **not** empty
                output(tmp_id, dataStorage, out_fn)
    

    ?

    def output(tmp_id, dataDict, out_fn):
        for isoformID in dataDict.keys():
            mx = max(dataDict[isoformID], key=lambda x: int(x[4]))[4]
            mx_values = [d for d in dataDict[isoformID] if d[4] == mx]
            for mx_value in mx_values:
                out_fn.write('\t'.join(mx_value) + '\n')
    
        del dataDict[isoformID]
        dataDict[tmp_id].append(lineParts)
        return dataDict
    
    dataStorage = defaultdict(list)
    
    with open("data/datap-bigcov.tsv") as data_fn, open("data/datap-bigcov-out.tsv", 'w') as out_fn:
        for line in data_fn:
            try:
                lineParts = line.rstrip().split('\t')
            except IndexError:
                continue
            if lineParts[0].startswith("gene"):
                split_id = lineParts[0].split('.')
                tmp_id = split_id[0] + "." + split_id[1]
            else:
                tmp_id = lineParts[0]
    
            if not dataStorage:  # check if Dict is empty
                dataStorage[tmp_id].append(lineParts)
            elif tmp_id in dataStorage:
                dataStorage[tmp_id].append(lineParts)
            else:
                dataStorage = output(tmp_id, dataStorage, out_fn)
        if dataStorage:  # check if Dict is **not** empty
            output(tmp_id, dataStorage, out_fn)
    
    1 回复  |  直到 4 年前
        1
  •  1
  •   Grismar    4 年前

    您已经在这里处理文件的结尾:

    for line in data_fn:
        ...
    

    for line in data_fn:
        line = line.rstrip()
        if not line:
            break
        ...
    

    或者,如果你不喜欢使用/滥用 '' False

    for line in data_fn:
        if line == '\n':
            break
        ...
    

    另一种方法是简单地跳过空行(允许文件中间的空行):

    for line in data_fn:
        line = line.rstrip()
        if line:
            ...
    

    data_fn ,因为名称表明这是文件名,但实际上是对文件的引用。

    所以 data_f f data

    您在评论中提出了一个后续问题:“谢谢,您将如何替换此条件以保证最后一个id写入文件: if blastStorage: output(tmp_id, blastStorage, out_fn) “-我可以试着回答这个问题,但我觉得还有更多的问题要问。你的代码中有相当多的编程和风格错误,单独解决这些问题有点太过分了。

    您的总体问题是,您的代码比需要的要复杂一些。通常情况下,如果你曾经解决过一个问题,那么退一步决定你现在是否对这个问题有足够的了解,从而编写出一个更好(更简单)的解决方案是有帮助的。

    你要解决的问题是:你有一个记录的输入文件;每一条记录都有一个相关的标识符(第一列的前两部分在不同的时间段内分开);您希望为输入文件中的每个标识符创建一个输出文件,其中所有记录的某个值等于具有该标识符的所有记录的最大相同值。您似乎希望在一次过程中处理该文件(一个更简单但可能较慢的解决方案可以执行双过程)。

    您的代码似乎表明您希望具有匹配标识符的记录是连续的,因此您不必为以后的匹配保留数据。从你处理最大值的方式来看

    with open("data/datap-bigcov.tsv") as f_in, open("data/datap-bigcov-out.tsv", 'w') as f_out:
        current = ('', 0)
        max_lines = []
        for line in f_in:
            line_parts = line.rstrip().split()
            rec_id = '.'.join(line_parts[0].split('.')[:2])
            value = int(line_parts[4])
            # id and value match, just add it
            if (rec_id, value) == current:
                max_lines.append(line)
            else:
                # id doesn't match
                if rec_id != current[0]:
                    # whatever was collected so far should be written first
                    f_out.writelines(max_lines)
                # value doesn't match (and is greater)
                elif value > current[1]:
                    # if rec_id matches, but value doesn't and isn't greater, just skip it
                    continue
                # in both other cases, rec_id and value are the values we're after for now
                current = (rec_id, value)
                # start a new set with the greater max
                max_lines = [line]
        f_out.writelines(max_lines)
    

    声明 f_out.writelines(max_lines) 在那里有两次,以确保最终的id也被写入文件,但我认为整个代码非常简单,所以重复调用实际上并不重要。

    还要注意的是,第一次调用它时,会使用空 max_lines

    只有17行Python代码,而不牺牲清晰度和速度。

    最后一点注意:这种类型的东西通常由 pandas 图书馆这里有一个解决您的问题的方法,只需使用 :

    from pandas import read_csv
    
    df = read_csv('data/datap-bigcov.tsv', sep='\t', header=None)
    df['id'] = df.apply(lambda rec: '.'.join(rec[0].split('.')[:2]), axis=1)
    result = df[df[4] == df.groupby(by='id')[4].transform('max')]
    result.to_csv('data/datap-bigcov-out.tsv', sep='\t', header=None)
    

    我觉得用 熊猫 是否牺牲了清晰性(至少它需要对 熊猫