繁体   English   中英

比较python(numpy)中两个巨大的csv文件的最快方法

[英]Fastest way to compare two huge csv files in python(numpy)

我正在尝试在电话号码的两个非常大的csv文件之间找到intesect子集(一个有60万行,另一个有3亿行)。 我目前正在使用pandas打开两个文件,然后将所需的列转换为一维numpy数组,然后使用numpy相交以获得相交。 有没有更好的方法可以做到这一点,可以使用python或任何其他方法。 谢谢你的帮助

import pandas as pd
import numpy as np

df_dnc = pd.read_csv('dncTest.csv', names = ['phone'])
df_test = pd.read_csv('phoneTest.csv', names = ['phone'])

dnc_phone = df_dnc['phone']
test_phone = df_test['phone']

np.intersect1d(dnc_phone, test_phone)

我将为您提供一些Python伪代码的一般解决方案。 您要在这里解决的是Jon Bentley撰写的“ Programming Pearls”一书中的经典问题。

只需一个简单的位数组就可以非常有效地解决此问题,因此,我的评论是电话号码多长时间(有多少位数字)。

假设电话号码最多为10位数字,而您可以拥有的最大电话号码为: 9 999 999 999 (使用空格可以提高可读性)。 在这里,我们可以使用每个数字1位来标识数字是否设置(分别设置或不设置位),因此我们将使用9 999 999 999位来标识每个数字,即:

  • bits[0]标识数字0 000 000 000
  • bits[193]标识数字0 000 000 193
  • 具有数字659 234-4567的bits[6592344567]将由bits[6592344567]寻址

这样做,我们需要预先分配最初设置为0 9 999 999 999位,即: 9 999 999 999 / 8 / 1024 / 1024 =大约1.2 GB内存。

我认为将数字的交点保留在末尾将比位表示占用更多空间=>最多将存储600k int => 64bit * 600k =约4.6 GB( 实际上int的存储效率不高,可能会使用更多的空间 ),如果它们是字符串,则可能会导致更多的内存需求。

从CSV文件(逐行或缓冲的文件阅读器)中解析电话号码字符串,将其转换为数字,并且比进行固定时间的内存查找要比处理字符串和合并字符串快IMO。 不幸的是,我没有这些电话号码文件可以测试,但是希望听到您的发现。

from bitstring import BitArray


max_number = 9999999999

found_phone_numbers = BitArray(length=max_number+1)


# replace this function with the file open function and retrieving
#  the next found phone number
def number_from_file_iteator(dummy_data):
    for number in dummy_data:
        yield number


def calculate_intersect():
    # should be open a file1 and getting the generator with numbers from it
    #  we use dummy data here
    for number in number_from_file_iteator([1, 25, 77, 224322323, 8292, 1232422]):
        found_phone_numbers[number] = True

    # open second file and check if the number is there
    for number in number_from_file_iteator([4, 24, 224322323, 1232422, max_number]):
        if found_phone_numbers[number]:
            yield number


number_intersection = set(calculate_intersect())

print number_intersection

我使用了位串pip包中的 BitArray ,大约需要2秒钟来初始化整个位串。 之后,扫描文件将使用固定内存。 最后,我使用了一个set来存储项目。

注意1:可以修改此算法以仅使用list 在这种情况下,一旦位数匹配,便必须进行第二次循环,以确保重复项不再匹配。

注意2:set / list中的存储是懒惰的,因为我们在第二个for循环中使用了生成器。 运行时复杂度是线性的,即O(N)

  1. 将60万个电话号码读成一set
  2. 逐行输入较大的文件,并对照集合检查每一行。
  3. 立即将匹配项写入输出文件。

这样,您不必一次将所有数据加载到内存中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM