Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在大型表上操作:使用python一次操作一组行_Python - Fatal编程技术网

在大型表上操作:使用python一次操作一组行

在大型表上操作:使用python一次操作一组行,python,Python,我有一个巨大的表文件,如下所示。为了处理单个产品(名称),我尝试使用pandas groupby,但它似乎将整个表(~10G)放在内存中,这是我无法负担的 name index change A Q QQ A Q QQ A Q QQ B L LL C Q QQ C L LL C LL LL C Q QQ C L LL C LL LL “名称”列的排序很好,我一次只关心一个名称。我希望在“更改”列上使用以下标准

我有一个巨大的表文件,如下所示。为了处理单个产品(名称),我尝试使用pandas groupby,但它似乎将整个表(~10G)放在内存中,这是我无法负担的

name    index   change
A   Q   QQ
A   Q   QQ
A   Q   QQ
B   L   LL
C   Q   QQ
C   L   LL
C   LL  LL
C   Q   QQ
C   L   LL
C   LL  LL
“名称”列的排序很好,我一次只关心一个名称。我希望在“更改”列上使用以下标准来筛选每个名称:

  • 检查“QQ”的数量是否超过“LL”的数量。基本上,如果包含“QQ”的行数减去包含“LL”>=2的行数,则从现在起放弃/忽略此名称的“LL”行。如果“LL”压倒了“QQ”,那么用QQ丢弃行。(例如,A有3个QQ和0个LL,C有4个LL和2个QQ。它们都很好。)
  • 结果表:

    name    index   change
    A   Q   QQ
    A   Q   QQ
    A   Q   QQ
    C   L   LL
    C   LL  LL
    C   L   LL
    C   LL  LL
    
    name    index   change
    A   Q   QQ
    A   Q   QQ
    A   Q   QQ
    
  • 将“更改”与“索引”进行比较,如果未发生任何更改(例如,两列中都有LL),则该行无效。此外,对于有效的更改,剩余的QQ或LL必须连续>=3次。因此C只有2个有效的更改,它将被过滤掉
  • 结果表:

    name    index   change
    A   Q   QQ
    A   Q   QQ
    A   Q   QQ
    C   L   LL
    C   LL  LL
    C   L   LL
    C   LL  LL
    
    name    index   change
    A   Q   QQ
    A   Q   QQ
    A   Q   QQ
    

    我想知道是否有一种方法可以按名称处理表名,并在每个名称后释放内存。(而且不必一步一步地做这两个标准。)任何提示或建议都将不胜感激

    因为文件是按“名称”排序的,所以您可以逐行读取文件:

    def process_name(name, data, output_file):
        group_by = {}
        for index, change in data:
            if index not in group_by:
                group_by[index] = []
            group_by[index].append(change)
    
        # do the step 1 filter logic here
    
        # do the step 2 filter logic here
        for index in group_by:
            if index == group_by[index]:
                # Because there is at least one "no change" this 
                # whole "name" can be thrown out, so return here.
                return
    
        output = []
        for index in group_by:
            output_file.write("%s\t%s\t%s\n" % (name, index, group_by[index]))
    
    current_name = None
    current_data = []
    
    input_file = open(input_filename, "r")
    output_file = open(output_filename, "w")
    header = input_file.readline()
    for row in input_file:
        cols = row.strip().split("\t")
        name = cols[0]
        index = cols[1]
        change = cols[2]
        if name != current_name:
            if name != None:
                process_name(current_name, current_data, output_file)
            current_name = name
            current_data = []
    
        current_data.append((index, change))
    
    # process what's left in the buffer
    if current_name is not None:
        process_name(current_name, current_data, output_file)
    
    input_file.close()
    output_file.close()
    

    我不完全理解你在#1中解释的逻辑,所以我把它留白了。我还觉得您可能希望首先执行步骤2,因为这将很快排除整个“名称”的可能性。

    因为您的文件已排序,并且您似乎只按名称对子段进行操作,也许只需使用Python并在运行时为每个名称段创建一个表:

    from itertools import groupby
    import pandas as pd
    
    with open('/tmp/so.csv') as f:
        header=next(f).split()
        for k, segment in groupby(f, key=lambda line: line.split()[0]):
            seg_data={k:[] for k in header}
            for e in segment:
                for key, v in zip(header, e.split()):
                    seg_data[key].append(v)
    
            seg_fram=pd.DataFrame.from_dict(seg_data)
            print k
            print seg_fram
            print
    
    印刷品:

    A
      change index name
    0     QQ     Q    A
    1     QQ     Q    A
    2     QQ     Q    A
    
    B
      change index name
    0     LL     L    B
    
    C
      change index name
    0     QQ     Q    C
    1     LL     L    C
    2     LL    LL    C
    3     QQ     Q    C
    4     LL     L    C
    5     LL    LL    C
    
    然后,您将拥有的最大内存将由最大的连续组决定,而不是由文件大小决定

    通过逐行追加到数据帧,而不是构建中间dict,可以使用该方法的1/2内存:

    with open('/tmp/so.csv') as f:
        header=next(f).split()
        for k, segment in groupby(f, key=lambda line: line.split()[0]):
            seg_data={k:[] for k in header}
            seg_fram=pd.DataFrame(columns=header)
            for idx, e in enumerate(segment):
                 df=pd.DataFrame({k:v for k, v in zip(header, e.split())}, index=[idx])
                 seg_fram=seg_fram.append(df)
    
    (可能会慢一些…)


    如果不起作用,请考虑使用磁盘数据库。 设法把规则编成法典。逐行读取文件,逐行累加,直到名称更改。在文件中保存该位置。处理已累积的行,应用规则,将结果附加到新文件。重复你在文件中留下的开始部分。考虑使用Awesome-非常感谢。我对我的问题做了一些修改,希望第一步更清楚——但现在不要担心,让我先回家消化一下你的代码。对于规则1,你是在谈论“索引”还是“更改”中的值?Q、L、QQ和LL是唯一可能的值吗?谢谢@georgeoflages的帮助。在仔细阅读了您的代码之后,我解决了这个问题-我认为关键是使用字典和键的概念,这是我还没有练习过的。不要担心规则1:)谢谢你@dawg!对不起,我迟了答复。我喜欢你关于使用1/2内存的想法,我很快就会尝试一下。我感谢你的帮助。