2017-06-08 60 views
0

我試圖找到兩個非常大的csv文件 電話號碼(一個有600k行,另一個有300mil)的intesect子集。我目前使用熊貓來打開這兩個文件,然後將所需的列轉換爲1d numpy數組,然後使用numpy相交來獲得相交。有沒有更好的方法來做到這一點,無論是使用Python或任何其他方法。感謝您的幫助在python(numpy)中比較兩個巨大的csv文件的最快方法

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) 
+0

您的CSV文件在結構上是否相同? (即你在尋找相同的行還是相同的CSV字段)? – zwer

+1

每一步目前需要多少時間?哪一步是瓶頸?目前的總運行時間是多少?您的目標總運行時間是多少?順便說一句,你可以設置'squeeze = True'來直接獲得一個Series,並跳過'dnc_phone = df_dnc ['phone']'部分。 –

+0

@ zwer,是的,有相同的結構和比較相同的csv領域。這是電話號碼 – TimCodes

回答

3

我會給你一些Python僞代碼的一般解決方案。你在這裏試圖解決的是"Programming Pearls" by Jon Bentley這本書中的經典問題。

這可以非常有效地解決,只需要一個簡單的位陣列,因此我的評論,電話號碼有多長(有多少位數)。

假設電話號碼長度至多爲10位數字,最大電話號碼可以是:9 999 999 999(空格用於提高可讀性)。這裏我們可以使用1位每號來識別該號碼是否在設定與否(位被設置或不分別設置),因此,我們將使用9 999 999 999比特來標識每個數字,即:

  • bits[0]識別數0 000 000 000
  • bits[193]標識具有數659 234-4567將由bits[6592344567]

來解決我們這樣做會東東的數量0 000 000 193

  • d預先分配9 999 999 999位,最初設置爲0,即:9 999 999 999/8/1024/1024 =大約1.2 GB的內存。

    我認爲持有數字在最後將使用更多的空間比位表示=>最多600k整數將被存儲=>64bit * 600k =大約4.6 GB(actually int is not stored that efficiently and might use much more),如果這些是字符串,你會可能以更多的內存需求結束。

    從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 
    

    我用BitArraybitstring pip package,它需要約2秒,以初始化整個比特串。之後,掃描文件將使用常量內存。最後,我用set來存儲這些項目。

    注1:該算法可以修改爲只使用list。在這種情況下,只要位號匹配該位,第二個循環必須重置,以便重複次數不再匹配。

    注2:set/list中存儲會發生懶惰,因爲我們在第二個for循環中使用生成器。運行時複雜度是線性的,即O(N)

  • 1
    1. 閱讀600K電話號碼爲set
    2. 逐行輸入較大的文件,按照設置檢查每一行。
    3. 立即將匹配寫入輸出文件。

    這樣你就不必一次加載所有的數據。

    +0

    與使用Pandas和NumPy中提供的編譯代碼設施相比,這會帶來災難性的性能。 –

    +0

    其他事情當然是平等的。但它最大限度地減少了內存佔用。如果OP已經獲得了不錯的表現,那麼就不需要嘗試,我同意。 (不幸的是,這個問題沒有解釋需要解決什麼問題。) – alexis