【问题标题】:Read data in chunks and keep one row for each ID in Python分块读取数据并在 Python 中为每个 ID 保留一行
【发布时间】:2016-10-26 22:00:08
【问题描述】:

假设我们有一个大文件,其中行如下

ID     value     string
1      105       abc 
1      98        edg
1      100       aoafsk
2      160       oemd
2      150       adsf 
...

假设文件名为 file.txt 并由制表符分隔。

我想为每个 ID 保留最大值。预期的输出是

ID     value     string
1      105       abc 
2      160       oemd
...

如何分块读取并处理数据?如果我以块的形式读取数据,如何确保在每个块的末尾,每个 ID 的记录都是完整的?

【问题讨论】:

    标签: python data-manipulation bigdata


    【解决方案1】:

    在这种格式的字典中跟踪数据:

    data = {
        ID: [value, 'string'],
    }
    

    当您从文件中读取每一行时,请查看该 ID 是否已在字典中。如果没有,添加它;如果是,并且当前ID更大,则在dict中替换它。

    最后,你的 dict 应该有每个最大的 ID。

    # init to empty dict
    data = {}
    
    # open the input file
    with open('file.txt', 'r') as fp:
    
        # read each line
        for line in fp:
    
              # grab ID, value, string
              item_id, item_value, item_string = line.split()
    
              # convert ID and value to integers
              item_id = int(item_id)
              item_value = int(item_value)
    
              # if ID is not in the dict at all, or if the value we just read
              # is bigger, use the current values
              if item_id not in data or item_value > data[item_id][0]:
                  data[item_id] = [item_value, item_string]
    
    for item_id in data:
        print item_id, data[item_id][0], data[item_id][1]
    

    字典不强制对其内容进行任何特定排序,因此在程序结束时,当您从字典中取回数据时,它可能与原始文件的顺序不同(即您可能会看到首先是 ID 2,然后是 ID 1)。

    如果这对您很重要,您可以使用OrderedDict,它会保留元素的原始插入顺序。

    (当您说“按块读取”时,您是否有特定的想法?如果您的意思是特定数量的字节,那么如果块边界碰巧落入,您可能会遇到问题一个单词的中间......)

    【讨论】:

    • 您的回答正常。一个问题。哪一个更有效:逐行处理或逐块读取并逐块处理或读取文件并立即处理它们(如果内存允许)?我仍然对这些块如何工作感到好奇。所以我会把这个问题留一会儿。如果没有更好的答案,将采取你的。谢谢。
    • 我怀疑会有很大的不同,因为操作系统已经在后台进行输入缓冲。
    【解决方案2】:

    代码

    import csv
    import itertools as it
    import collections as ct
    
    
    with open("test.csv") as f:                                
        reader = csv.DictReader(f, delimiter=" ")              # 1
        for k, g in it.groupby(reader, lambda d: d["ID"]):     # 2
            print(max(g, key=lambda d: float(d["value"])))     # 3
    
    # {'value': '105', 'string': 'abc', 'ID': '1'}
    # {'value': '160', 'string': 'oemd', 'ID': '2'}
    

    详情

    with 块确保安全打开和关闭文件 f。该文件是可迭代的,允许您对其进行循环或理想地应用itertools

    1. 对于f 的每一行,csv.DictReader 拆分数据并将标题行信息维护为字典的键值对,例如[{'value': '105', 'string': 'abc', 'ID': '1'}, ...

    2. 此数据是可迭代的并传递给groupby,该ID 将所有数据分块。见this post from more details on how groupby works

    3. max() 内置函数与特殊键函数相结合,返回具有最大 "value" 的字典。见this tutorial for more details on the max() function

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-02
      • 1970-01-01
      • 2020-04-30
      • 2017-01-14
      • 1970-01-01
      • 1970-01-01
      • 2010-11-27
      相关资源
      最近更新 更多