簡體   English   中英

如何在Python中以不同的順序有效地讀取大文本文件的行:a)每次隨機行,b)從中間開始...?

[英]How to efficiently read lines of large text file in Python in different orders: a) random line each time, b) starting in middle…?

我有一個大文本文件 (500萬到1000萬行)。 每行包含10到5,000個字母數字項,它們之間用空格或逗號分隔。 每一行都以換行符結束 行數在運行時之前是已知的,文本文件在運行時不會更改。

每次運行代碼時,都會傳遞50-200個搜索列表 ,每個搜索列表包含2-10個項目(單詞)。 對於這些搜索列表中的每一個,我想在文本文件中找到x ,其中包含該列表中的至少一個項目 行數x的范圍為5-10行,並在運行時設置。 匹配不區分大小寫,並且必須精確地在單詞邊界上(例如,“foo”匹配“,foo”但不匹配“foobar”)。

每個搜索列表都有三種搜索順序策略之一

  • 正常 從第一行開始,按連續順序逐行搜索,直到找到x行數或到達最后一行。

  • 隨機 從文本文件中隨機選取行。 繼續前進,直到找到x行或已完成每行的搜索。

  • 鏟斗范圍 首先搜索最高優先級的行,然后搜索下一個最高優先級的行,然后搜索下一行等。例如,搜索范圍優先級可能是首先查看行1,000,000到1,499,999,然后行0到999,999,然后行1,500,000至2,199,999等。可以有3至20個鏟斗,每個鏟斗的行程范圍為100,000至5,000,000。 在運行時給出桶和行號范圍的數量。 在每個范圍內,連續搜索。 搜索直到找到x行數或到達最后一個桶的末尾。

這是我為“普通搜索”編寫的內容[此測試代碼將所有行檢查到文件末尾,而不是在x行后停止; 在最終版本中,在找到搜索列表的x匹配后,它將停止並轉到下一個搜索列表]:

import re
textFile = "bigTextFile.txt"
searchItems = ["foo","bar","anotherfoo","anotherbar","etc"]
searchStrategy = "normal" #could be "normal", "random", "bucket"; this code is just for "normal"
results = []
with open(textFile) as inFile:
    for line in inFile:
        regex = re.compile('(' + '|'.join('\\b'+item+'\\b' for item in searchItems) +')', re.IGNORECASE)
        match = regex.search(line)  
        if match is not None:
            analysisResult = analyze_the_match(line)
            results.append(analysisResult)

這個代碼用於“普通搜索”。 我試過的,它似乎是最快的,但我是Python的新手,我猜想必須有一個更好的方法(速度/效率)來做到這一點。

[ 更新以回應評論以更好地解釋不同搜索策略的原因 ]這些項目高度傾斜 使用數據,我發現大約一半的搜索將在10,000行之前完成,40%可能需要幾百萬行才能找到足夠的匹配,10%將在整個文本文件中找不到足夠的匹配。 每行中的項目與它們所在的行沒有關系,但行的范圍相似(即行100,000-500,000是相關的,1,500,000-1,750,000是相關的,等等)。 代碼可以針對給定的搜索列表運行多次,並且對於每次運行,優先級可以是關注於不同的行范圍。 如果整個文本文件只有x行包含特定搜索列表中的項目,那么結果將始終是那些x行。 但對於許多搜索列表,有2x10x100,000x線匹配,在不同的時間,我想選擇不同的線。 在某些時候,特定范圍可能是優先考慮的,有時候隨機抽樣是最好的,有時只是從頭開始找到前x行很好,因此是“正常”,“隨機”和“桶”搜索策略。

我真的很感激“隨機”和“桶”的任何想法,因為我不確定如何最有效地接近它們。 我玩了linecacheitertools islicereadlines (在這個答案中每個@Martin Thoma, readlines非常快),以及修改上面的代碼,但我對“隨機”和“桶”的嘗試都是笨重,低效,我知道我不知道什么可能是最好的:)。

有什么建議么? 謝謝。

對於隨機搜索和存儲桶搜索,您可以對文件進行線性掃描並構建候選結果列表,如果列表已滿並且出現更好的候選項,則從列表中替換候選項。

對於隨機選擇,您只需計算候選人在列表中的幾率,並使用隨機數來確定候選人是否被列入列表。

對於存儲桶選擇,如果候選者的存儲桶排名優於現有項的排名,則候選者將替換現有列表成員。

隨機選擇:

import random
candidates = []
n = 0
with open(textFile) as inFile:
    for line in inFile:
        if valid_candidate(line): # use regex here
            n += 1
            if n <= x:
                candidates.append(line)
            else:
                i = random.randrange(n)
                if i < x:
                    candidates[i] = line
results = []
for line in candidates:
    analysisResult = analyze_the_match(line)
    results.append(analysisResult)

對於鏟斗選擇:

import bisect
candidates = []
n = 0
with open(textFile) as inFile:
    for line in inFile:
        n += 1
        if valid_candidate(line): # use regex here
            rank = get_rank(n) # use n to determine the bucket and assign a rank, lower numbers are higher rank
            bisect.insort(candidates, (rank, n, line))
results = []
for rank, n, line in candidates[:x]:
    analysisResult = analyze_the_match(line)
    results.append(analysisResult)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM