【问题标题】:Filter large file using python, using contents of another使用python过滤大文件,使用另一个的内容
【发布时间】:2012-06-21 05:22:16
【问题描述】:

我有一个约 1GB 的数据条目文本文件和另一个我想用来过滤它们的名称列表。遍历每个条目的每个名称将非常缓慢。在 python 中执行此操作的最有效方法是什么?如果名称嵌入在条目中,是否可以使用哈希表?我可以使用名称部分一致放置的事实吗?

示例文件:

Entries 文件 -- 条目的每个部分都用制表符分隔,直到名称为止

246   lalala   name="Jack";surname="Smith"
1357   dedada   name="Mary";surname="White"
123456  lala   name="Dan";surname="Brown"
555555   lalala   name="Jack";surname="Joe"

名称文件 -- 每个都在换行符

Jack
Dan
Ryan

所需的输出 -- 仅在名称文件中具有名称的条目

246   lalala   name="Jack";surname="Smith"
123456  lala   name="Dan";surname="Brown"
555555   lalala   name="Jack";surname="Joe"

【问题讨论】:

    标签: python optimization filter compare


    【解决方案1】:

    您可以使用set 数据结构来存储名称——它提供了高效的查找,但如果名称列表非常大,那么您可能会遇到内存问题。

    一般的想法是遍历所有名称,将它们添加到set,然后检查数据文件中每一行的每个名称是否包含在set 中。由于条目的格式没有变化,您应该能够使用简单的正则表达式提取名称。

    如果您在名称set 的大小方面遇到问题,您可以从名称文件中读取 n 行,并对每组名称重复该过程,除非您需要排序。

    【讨论】:

    • 谢谢。有没有更有效的方法来存储数据条目,或者只是一个 datafile.readlines() 列表尽可能好?例如,将每个条目存储为一个列表,由 tabs[246, lalala, name="Jack";surname="Smith" 分割
    • 并用 " 分割得到 [246, lalala, name=", Jack, ";surname="Smith"],然后检查 list[4] ("Jack") 是否在名称中设置?
    • 不要使用readlines——相反,只需遍历文件(即for line in datafile)——这将逐行读取文件,而不是将整个内容读入内存。跨度>
    【解决方案2】:

    我的第一个直觉是制作一个以名称为键的字典,假设使用字典中键的哈希查找名称是最有效的。

    鉴于@rfw 的答案,使用名称的set,我编辑了如下代码并针对两种方法进行了测试,使用名称的dictset

    我构建了一个包含超过 40 M 条记录和超过 5400 个名称的虚拟数据集。使用这个数据集,set 方法在我的机器上始终具有优势。

    import re
    from collections import Counter
    import time
    
    # names file downloaded from http://www.tucows.com/preview/520007
    # the set contains over 5400 names
    f = open('./names.txt', 'r')
    names = [ name.rstrip() for name in f.read().split(',') ]
    name_set = set(names) # set of unique names
    names_dict = Counter(names) # Counter ~= dict of names with counts
    
    # Expect: 246   lalala   name="Jack";surname="Smith"
    pattern = re.compile(r'.*\sname="([^"]*)"')
    
    def select_rows_set():
        f = open('./data.txt', 'r')
        out_f = open('./data_out_set.txt', 'a')
        for record in f.readlines():
            name = pattern.match(record).groups()[0]
            if name in name_set:
                out_f.write(record)
        out_f.close()
        f.close()
    
    def select_rows_dict():
        f = open('./data.txt', 'r')
        out_f = open('./data_out_dict.txt', 'a')
        for record in f.readlines():
            name = pattern.match(record).groups()[0]
            if name in names_dict:
                out_f.write(record)
        out_f.close()
        f.close()
    
    if __name__ == '__main__':
        # One round to time the use of name_set
        t0 = time.time()
        select_rows_set()
        t1 = time.time()
        time_for_set = t1-t0
        print 'Total set: ', time_for_set
    
        # One round to time the use of names_dict
        t0 = time.time()
        select_rows_dict()
        t1 = time.time()
        time_for_dict = t1-t0
        print 'Total dict: ', time_for_dict
    

    我假设Counter 本质上是一个字典,并且更容易从数据集构建,不会增加访问时间的任何开销。如果我遗漏了什么,很高兴得到纠正。

    【讨论】:

    • 哇,感谢您为这两个选项计时并为该过程提供了解释清楚的代码!
    • 我的荣幸。很高兴你喜欢它。
    【解决方案3】:

    您的数据以表格的形式清晰地呈现出来,因此这可能是适用的。 Data structure for maintaining tabular data in memory?

    【讨论】:

      【解决方案4】:

      您可以使用自己的“按名称搜索”功能创建自定义数据结构。那将是某种字典的列表。这应该比文本文件的大小占用更少的内存,因为它会删除每行上的重复信息,例如“姓名”和“姓氏”,这将是字典键。如果你懂一点 SQL(这里几乎不需要),那么请使用Filter large file using python, using contents of another

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-14
        • 2013-02-03
        • 2015-11-07
        • 2020-11-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多