【问题标题】:Counting unique IDs across several hundred files?计算数百个文件中的唯一 ID?
【发布时间】:2020-04-03 09:16:20
【问题描述】:

我有大约 750 个文件 (.csv),每一行都有一个 UUID 条目。我对这个脚本的目标是计算所有 750 个左右的文件中存在多少唯一 UUID。文件名结构如下:

DATA-20200401-005abf4e3f864dcb83bd9030e63c6da6.csv

如您所见,它有一个日期和一些随机 ID。它们都在同一个目录中,并且都具有相同的文件扩展名。每个文件的格式都是新行分隔的,只有一个 UUID,如下所示:b0d6e1e9-1b32-48d5-b962-671664484616

我尝试合并所有文件,但事情变得一团糟,这大约是 15GB 的数据。

我的最终目标是获得一个输出,以便说明所有文件中唯一 ID 的数量。例如:

文件1:

xxx-yyy-zzz
aaa-bbb-ccc
xxx-yyy-zzz

文件2:

xxx-yyy-zzz
aaa-bbb-ccc
xxx-yyy-zzz

扫描这两个文件后的最终输出是:

The total number of unique ids is: 2

【问题讨论】:

  • 您可以尝试从文件中读取一行并将其添加到集合中。对所有文件执行此操作。如果您的唯一 ID 数量较少,这应该可以工作。不是最好的方法,但应该适用于您的情况。这绝对比一次加载所有文件要好。
  • 一定要用 Python 吗?一个简单的解决方案可能是cat *.csv | sort | uniq | wc -l
  • 我会一次将 ID 添加到排序列表中,如果 ID 已存在于列表中,则不要添加它。唯一 ID 的总数将是完整列表的长度。
  • @jarmod:将sort | uniq 替换为sort -u 以让sort 也进行唯一化(通过减小排序工作集的大小可以更快地运行)。跨度>
  • 我不需要 Python!哈哈,这太棒了。一旦文件从 S3 完全传输到本地,我将运行它并试一试。那么cat *.csv | sort -u | wc -l ?

标签: python


【解决方案1】:

我认为使用Counter 可能是最快的方法:

from collections import Counter

with open(filename) as f:
    c = Counter(f)
    print(sum(c.values()))

计数器提供每个唯一项目的计数。这是使用哈希表实现的,因此对于大量项目应该相当快。

【讨论】:

  • 不要使用.readlines(),只需使用Counter(f).readlines() 强制您一次将整个文件加载为listCounter(f) 将懒惰地读取和计算行数(保持内存成本与唯一项目数成正比,而不是总项目数)。 Counter 仅在您需要重复计数时才需要;听起来他们只需要它是唯一的,计数无关紧要,所以set 就可以了。
  • 啊,这很好。我正在解释这个问题,因为我们需要知道我们拥有的每个独特物品的数量,而不仅仅是独特物品的总数。在这种情况下,一组确实更有意义:)
  • 能不能顺便修改一下所有文件?
  • @Ryan 也许搜索一下如何读取多个文件。这是您自学的机会 :) 或者,如果您可以使用 bash,正如您在 cmets 中提到的,您可以使用 cat *.csv | this.py。修改此代码,以便 f.readlines() 改为从输入中读取。
【解决方案2】:

如果您不必使用 Python,那么一个简单的解决方案可能是命令行:

cat *.csv | sort -u | wc -l   

这会将所有 CSV 文件的内容通过管道传输到 sort -u 中,该sort -u 对重复项进行排序和删除,然后将其传输到 wc -l 中进行行计数。

注意:sort 会根据需要溢出到磁盘,您可以根据需要使用-S size 控制其内存使用情况。

我很想在具有大量 RAM 的强大机器上运行它。

【讨论】:

    【解决方案3】:

    也许这样的事情会起作用:

    from os import listdir
    import re
    import pandas as pd
    
    my_folder_path = "C:\\\\"
    
    # Generic regular expression
    pat = r"DATA-\d{8}-.+\.csv}"
    p = re.compile(pat)
    
    # UUID column in each file (I don't know if this is the case; Adjust accodingly.
    uuid_column = "uuids"
    
    # Empty result dataframe with single column
    result_df = pd.DataFrame(columns=["unique_uuid"])
    
    file_list = [rf"{my_folder_path}\{i}" for i in listdir(my_folder_path)]
    for f in file_list:
        # Check for matching regular expression pattern
        if p.search(f):
    
            # Read file if pattern matches.
            df = pd.read_csv(f, usecols=[uuid_column])
    
            # Append only unique values from the new Series to the dataframe
            (result_df["unique_uuid"]
            .append(list(set(df[uuid_column].values)
            .difference(result_df["unique_uuid"].values)))
            )
    

    【讨论】:

      【解决方案4】:

      连接目录中的所有 csv 文件已在 pretty popular post 中解决,这里唯一的区别是您删除了重复文件。当然,这只有在每个文件中有大量重复项时才会有效(至少足以让所有去重帧都放入内存并执行最终的 drop_duplicates)。

      该链接中还有一些其他建议,例如完全跳过列表。

      import glob
      import pandas as pd
      
      files = glob.glob('./data_path/*.csv')
      
      li = []
      
      for file in files:
          df = pd.read_csv(file, index_col=None, header=None)
          li.append(df.drop_duplicates())
      
      output = pd.concat(li, axis=0, ignore_index=True)
      output = output.drop_duplicates()
      

      【讨论】:

        【解决方案5】:

        读取所有文件并将所有 UUID 添加到一个集合中。集合强制唯一性,因此集合的长度是您找到的唯一 UUID 的数量。大致:

        import csv
        import os
        
        uuids = set()
        for path in os.listdir():
            with open(path) as file:
                for row in csv.reader(file):
                    uuids.update(row)
        print(f"The total number of unique ids is: {len(uuids)}")
        

        这假设您可以将所有唯一的 UUID 存储在内存中。如果不能,那么接下来要尝试在磁盘上构建数据库(例如,将 set 替换为 sqlite db 或类似的东西)。如果您有许多唯一 ID 太大而无法存储任何地方,只要您愿意牺牲一些精度,仍然有解决方案:https://en.wikipedia.org/wiki/HyperLogLog

        【讨论】:

          猜你喜欢
          • 2011-03-29
          • 1970-01-01
          • 1970-01-01
          • 2011-03-17
          • 2022-07-01
          • 2021-03-16
          • 1970-01-01
          • 1970-01-01
          • 2012-11-04
          相关资源
          最近更新 更多