จะอ่านไฟล์ขนาดใหญ่ทีละบรรทัดได้อย่างไร?


536

ฉันต้องการวนซ้ำทุกบรรทัดของไฟล์ทั้งหมด วิธีหนึ่งในการทำเช่นนี้คือการอ่านไฟล์ทั้งหมดบันทึกลงในรายการจากนั้นข้ามสายที่น่าสนใจ วิธีนี้ใช้หน่วยความจำจำนวนมากดังนั้นฉันกำลังมองหาทางเลือกอื่น

รหัสของฉัน:

for each_line in fileinput.input(input_file):
    do_something(each_line)

    for each_line_again in fileinput.input(input_file):
        do_something(each_line_again)

device activeการดำเนินการนี้จะช่วยให้รหัสข้อผิดพลาด:

ข้อเสนอแนะใด ๆ

จุดประสงค์คือการคำนวณความคล้ายคลึงกันของสตริงคู่ที่ชาญฉลาดซึ่งมีความหมายสำหรับแต่ละบรรทัดในไฟล์ฉันต้องการคำนวณระยะทาง Levenshtein กับเส้นอื่น ๆ


4
ทำไมคุณต้องอ่านไฟล์ทั้งหมดอีกครั้งสำหรับแต่ละบรรทัด? บางทีถ้าคุณบอกว่าคุณกำลังพยายามทำให้สำเร็จใครบางคนอาจสามารถแนะนำวิธีการที่ดีกว่า
JJJ

คำตอบ:


1269

วิธีที่ถูกต้องและครบถ้วนสำหรับการอ่านไฟล์ต่อไปนี้:

with open(...) as f:
    for line in f:
        # Do something with 'line'

withคำสั่งจับเปิดและปิดไฟล์รวมทั้งถ้ายกเว้นจะเติบโตในบล็อกภายใน การfor line in fปฏิบัติต่อวัตถุไฟล์fเป็น iterable ซึ่งใช้ I / O บัฟเฟอร์และการจัดการหน่วยความจำโดยอัตโนมัติดังนั้นคุณไม่ต้องกังวลเกี่ยวกับไฟล์ขนาดใหญ่

ควรมีอย่างใดอย่างหนึ่ง - และดีกว่าเพียงหนึ่ง - วิธีที่ชัดเจนที่จะทำ


14
ใช่นี่เป็นรุ่นที่ดีที่สุดด้วย python 2.6 ขึ้นไป
Simon Bergot

3
ฉันชอบเครื่องกำเนิดไฟฟ้า & coroutines สำหรับการจัดการกับ data pipelines
jldupont

4
สิ่งที่จะเป็นกลยุทธ์ที่ดีที่สุดหากไฟล์เป็นไฟล์ข้อความขนาดใหญ่ แต่มีหนึ่งบรรทัดและความคิดคือการประมวลผลคำ?
mfcabrera

4
มีคนอธิบายfor line in f:ได้ไหมว่าทำงานอย่างไร ฉันหมายความว่ามันวนซ้ำวัตถุไฟล์เป็นไปได้อย่างไร
haccks

11
ถ้าคุณวนซ้ำวัตถุ Python จะค้นหารายการวัตถุที่เรียกว่าพิเศษ__iter__ซึ่งจะบอกสิ่งที่ต้องทำ วัตถุไฟล์กำหนดวิธีพิเศษนี้เพื่อส่งกลับตัววนซ้ำบนบรรทัด (ประมาณ.)
Katriel

130

วิธีที่มีประสิทธิภาพของหน่วยความจำสองวิธีในการจัดอันดับ (อันดับแรกดีที่สุด) -

  1. การใช้งานwith- สนับสนุนจาก python 2.5 ขึ้นไป
  2. ใช้yieldถ้าคุณต้องการควบคุมว่าจะอ่านมากแค่ไหน

1. การใช้ with

withเป็นวิธี pythonic ที่ดีและมีประสิทธิภาพในการอ่านไฟล์ขนาดใหญ่ ข้อดี - 1) วัตถุไฟล์ถูกปิดโดยอัตโนมัติหลังจากออกจากwithบล็อกการดำเนินการ 2) การจัดการข้อยกเว้นภายในwithบล็อก 3) forวนหน่วยความจำวนซ้ำผ่านfวัตถุไฟล์ทีละบรรทัด ภายในจะบัฟเฟอร์ IO (เพื่อเพิ่มประสิทธิภาพในการดำเนินงาน IO ค่าใช้จ่าย) และการจัดการหน่วยความจำ

with open("x.txt") as f:
    for line in f:
        do something with data

2. การใช้ yield

บางครั้งคนเราอาจต้องการการควบคุมที่ละเอียดยิ่งขึ้นเกี่ยวกับจำนวนการอ่านในแต่ละรอบ ในกรณีที่ใช้เราเตอร์และอัตราผลตอบแทน หมายเหตุด้วยวิธีนี้จะต้องปิดไฟล์อย่างชัดเจนในตอนท้าย

def readInChunks(fileObj, chunkSize=2048):
    """
    Lazy function to read a file piece by piece.
    Default chunk size: 2kB.
    """
    while True:
        data = fileObj.read(chunkSize)
        if not data:
            break
        yield data

f = open('bigFile')
for chuck in readInChunks(f):
    do_something(chunk)
f.close()

ข้อผิดพลาดและเพื่อความสมบูรณ์ - วิธีการด้านล่างไม่ดีหรือไม่หรูหราสำหรับการอ่านไฟล์ขนาดใหญ่ แต่โปรดอ่านเพื่อทำความเข้าใจ

ใน Python วิธีทั่วไปในการอ่านบรรทัดจากไฟล์คือทำสิ่งต่อไปนี้:

for line in open('myfile','r').readlines():
    do_something(line)

เมื่อทำสิ่งนี้เสร็จแล้วreadlines()ฟังก์ชั่น (ใช้กับread()ฟังก์ชั่นเดียวกัน) จะโหลดไฟล์ทั้งหมดลงในหน่วยความจำจากนั้นวนซ้ำมัน วิธีที่ดีกว่าเล็กน้อย (สองวิธีแรกที่กล่าวถึงดีที่สุด) สำหรับไฟล์ขนาดใหญ่คือการใช้fileinputโมดูลดังต่อไปนี้:

import fileinput

for line in fileinput.input(['myfile']):
    do_something(line)

การfileinput.input()โทรจะอ่านบรรทัดตามลำดับ แต่ไม่เก็บไว้ในหน่วยความจำหลังจากที่อ่านหรือแม้กระทั่งเรื่องนี้เพราะfileในไพ ธ อนนั้นสามารถทำซ้ำได้

อ้างอิง

  1. Python พร้อมคำสั่ง

9
-1 for line in open(...).readlines(): <do stuff>มันเป็นพื้นไม่เคยมีความคิดที่ดีที่จะทำ ทำไมต้องเป็นคุณ! คุณเพิ่งสูญเสียผลประโยชน์ทั้งหมดของ Python Buffer iterator ที่ฉลาดอย่างไม่มีประโยชน์
Katriel

5
@Srikar: มีเวลาและสถานที่สำหรับการแก้ปัญหาที่เป็นไปได้ทั้งหมด การสอนผู้เริ่มต้นว่าจะป้อนไฟล์อย่างไรไม่ได้ การมีคำตอบที่ถูกต้องฝังอยู่ที่ด้านล่างของโพสต์ยาวที่เต็มไปด้วยคำตอบที่ผิดนั้นไม่ได้เป็นการสอนที่ดี
Katriel

6
@Srikar: คุณสามารถทำให้โพสต์ของคุณดีขึ้นอย่างมีนัยสำคัญโดยใส่วิธีการที่ถูกต้องที่ด้านบนแล้วพูดถึงreadlinesและอธิบายว่าทำไมการทำสิ่งที่ไม่ดี (เพราะอ่านไฟล์ในหน่วยความจำ) จากนั้นอธิบายสิ่งที่fileinputโมดูลทำ อาจต้องการใช้มากกว่าวิธีอื่น ๆ จากนั้นอธิบายวิธีที่การทำให้ไฟล์เป็นก้อนทำให้ IO ดีขึ้นและให้ตัวอย่างของฟังก์ชันการ chunking (แต่พูดถึงว่า Python ทำสิ่งนี้ให้คุณแล้วดังนั้นคุณไม่จำเป็นต้องทำ) แต่เพียงแค่ให้ห้าวิธีในการแก้ปัญหาอย่างง่ายสี่วิธีที่ผิดในกรณีนี้ไม่ดี
Katriel

2
สิ่งที่คุณเพิ่มเพื่อความสมบูรณ์ให้เพิ่มครั้งสุดท้ายไม่ใช่อันดับแรก แสดงวิธีที่เหมาะสมก่อน
m000

6
@katrielalex กลับมาคำตอบของฉันและพบว่ามันรับประกันการปรับโครงสร้าง ฉันสามารถดูว่าคำตอบก่อนหน้านี้อาจทำให้เกิดความสับสน หวังว่านี่จะทำให้ชัดเจนสำหรับผู้ใช้ในอนาคต
Srikar Appalaraju

37

หากต้องการตัดบรรทัดใหม่:

with open(file_path, 'rU') as f:
    for line_terminated in f:
        line = line_terminated.rstrip('\n')
        ...

ด้วยการสนับสนุนการขึ้นบรรทัดใหม่สากลทุกสายแฟ้มข้อความจะดูเหมือนจะสิ้นสุดลงด้วย'\n'สิ่งที่จุดสิ้นสุดในแฟ้ม'\r', หรือ'\n''\r\n'

แก้ไข -เพื่อระบุการสนับสนุนบรรทัดใหม่สากล:

  • Python 2 บน Unix - open(file_path, mode='rU')- ต้องมี[ขอบคุณ@Dave ]
  • Python 2 บน Windows - open(file_path, mode='rU')- ตัวเลือก
  • Python 3 - open(file_path, newline=None)- ตัวเลือก

newlineพารามิเตอร์การสนับสนุนเฉพาะในหลาม 3 Noneและค่าเริ่มต้น modeพารามิเตอร์ค่าเริ่มต้น'r'ในทุกกรณี Uจะเลิกในหลาม 3. ในหลาม 2 บน Windows บางกลไกอื่น ๆ ที่ปรากฏในการแปลไป\r\n\n

เอกสาร:

ในการคงตัวเทอร์มิเนลไลน์ดั้งเดิม:

with open(file_path, 'rb') as f:
    with line_native_terminated in f:
        ...

โหมด Binary inยังสามารถแยกไฟล์ลงในเส้นที่มี แต่ละบรรทัดจะมีเทอร์มินัลอะไรก็ตามที่อยู่ในไฟล์

ขอขอบคุณที่@katrielalex 's คำตอบ , งูใหญ่เปิด () doc และIPythonทดลอง


1
ใน Python 2.7 ฉันต้องopen(file_path, 'rU')เปิดใช้งานบรรทัดใหม่สากล
เดฟ

17

นี่เป็นวิธีที่เป็นไปได้ในการอ่านไฟล์ในไพ ธ อน:

f = open(input_file)
for line in f:
    do_stuff(line)
f.close()

มันไม่ได้จัดสรรรายการเต็มรูปแบบ มันวนซ้ำเหนือเส้น


2
ในขณะที่ใช้งานได้มันไม่ได้เป็นที่ยอมรับอย่างแน่นอน with open(input_file) as f:วิธีที่ยอมรับคือการใช้กระดาษห่อบริบทเช่น สิ่งนี้ช่วยให้คุณประหยัดf.close()และทำให้แน่ใจว่าคุณจะไม่ลืมที่จะปิดมันโดยไม่ตั้งใจ ป้องกันการรั่วไหลของหน่วยความจำและทั้งหมดค่อนข้างสำคัญเมื่ออ่านไฟล์
เสา

1
ดังที่ @Mast กล่าวว่านั่นไม่ใช่วิธีที่เป็นที่ยอมรับดังนั้นโปรดลงคะแนนเพื่อสิ่งนั้น
azuax

12

บริบทบางอย่างล่วงหน้าว่าฉันมาจากไหน ตัวอย่างรหัสอยู่ที่ท้าย

เมื่อฉันสามารถฉันชอบที่จะใช้เครื่องมือโอเพนซอร์สเช่น H2O เพื่ออ่านไฟล์ CSV ขนานประสิทธิภาพสูงเป็นพิเศษ แต่เครื่องมือนี้มีข้อ จำกัด ในชุดคุณลักษณะ ฉันสิ้นสุดการเขียนรหัสจำนวนมากเพื่อสร้างท่อวิทยาศาสตร์ข้อมูลก่อนที่จะส่งไปยังกลุ่ม H2O สำหรับการเรียนรู้ภายใต้การดูแลที่เหมาะสม

ฉันได้อ่านไฟล์เช่นชุดข้อมูล 8GB HIGGS จาก UCI repo และแม้แต่ไฟล์ CSV ขนาด 40GB สำหรับวัตถุประสงค์ด้านวิทยาศาสตร์ข้อมูลได้เร็วขึ้นอย่างมากโดยการเพิ่มความขนานจำนวนมากด้วยฟังก์ชั่นพูลออบเจ็กต์และแผนที่ของมัลติโปรเซสเซอร์ ตัวอย่างเช่นการจัดกลุ่มที่มีการค้นหาเพื่อนบ้านที่ใกล้ที่สุดและอัลกอริทึมการจัดกลุ่ม DBSCAN และ Markov ต้องใช้กลวิธีการเขียนโปรแกรมแบบขนานบางอย่างเพื่อหลีกเลี่ยงปัญหาหน่วยความจำที่ท้าทายอย่างมากและเวลาของนาฬิกาแขวนผนัง

ฉันมักจะชอบแบ่งไฟล์แถวที่ฉลาดออกเป็นส่วน ๆ โดยใช้เครื่องมือ gnu ก่อนจากนั้น glob-filemask พวกเขาทั้งหมดเพื่อค้นหาและอ่านพวกเขาในแบบคู่ขนานในโปรแกรมหลาม ฉันใช้บางอย่างเช่นไฟล์บางส่วนมากกว่า 1,000 ไฟล์ การทำเทคนิคเหล่านี้ช่วยอย่างมากกับการประมวลผลความเร็วและขีด จำกัด ของหน่วยความจำ

pandas dataframe.read_csv เป็นเธรดเดี่ยวดังนั้นคุณสามารถใช้เทคนิคเหล่านี้เพื่อทำให้แพนด้าเร็วขึ้นโดยใช้แผนที่ () สำหรับการประมวลผลแบบขนาน คุณสามารถใช้ htop เพื่อดูว่าด้วยดาต้าต่อเนื่องแบบเก่า ๆ ดาต้าดาต้าสแตร็กซีซี 100% ซีพียูเพียงแกนเดียวคือคอขวดจริงใน pd.read_csv ไม่ใช่ดิสก์เลย

ฉันควรเพิ่มฉันใช้ SSD บนบัสการ์ดแบบเร็วไม่ใช่ HD ที่หมุนได้บนบัส SATA6 บวกกับคอร์ CPU 16 คอร์

อีกเทคนิคหนึ่งที่ฉันค้นพบใช้งานได้ดีในบางแอพพลิเคชั่นคือไฟล์ CSV แบบขนานอ่านทั้งหมดภายในไฟล์ขนาดยักษ์หนึ่งไฟล์โดยเริ่มจากคนงานแต่ละคนที่ออฟเซ็ตต่างกันลงในไฟล์แทนที่จะแยกไฟล์ขนาดใหญ่หนึ่งไฟล์ ใช้ไฟล์ python หา () และ tell () ในแต่ละคนทำงานแบบขนานเพื่ออ่านไฟล์ข้อความขนาดใหญ่ในแถบที่ไบต์ออฟเซ็ตออฟเซตไบต์เริ่มต้นและไบต์สิ้นสุดที่แตกต่างกันในไฟล์ขนาดใหญ่ทั้งหมดในเวลาเดียวกันพร้อมกัน คุณสามารถทำ regex findall บนไบต์และส่งกลับจำนวนของ linefeeds นี่คือผลรวมบางส่วน ในที่สุดก็สรุปผลรวมบางส่วนเพื่อให้ได้ผลรวมทั่วโลกเมื่อฟังก์ชันแผนที่ส่งคืนหลังจากคนงานเสร็จสิ้น

ต่อไปนี้เป็นตัวอย่างมาตรฐานที่ใช้เคล็ดลับออฟเซ็ตไบต์ขนาน:

ฉันใช้ 2 ไฟล์: HIGGS.csv คือ 8 GB มันมาจากแหล่งเก็บข้อมูลการเรียนรู้ของเครื่อง UCI all_bin .csv คือ 40.4 GB และมาจากโครงการปัจจุบันของฉัน ฉันใช้ 2 โปรแกรม: โปรแกรม GNU wc ซึ่งมาพร้อมกับ Linux และโปรแกรม python fastread.py บริสุทธิ์ที่ฉันพัฒนาขึ้น

HP-Z820:/mnt/fastssd/fast_file_reader$ ls -l /mnt/fastssd/nzv/HIGGS.csv
-rw-rw-r-- 1 8035497980 Jan 24 16:00 /mnt/fastssd/nzv/HIGGS.csv

HP-Z820:/mnt/fastssd$ ls -l all_bin.csv
-rw-rw-r-- 1 40412077758 Feb  2 09:00 all_bin.csv

ga@ga-HP-Z820:/mnt/fastssd$ time python fastread.py --fileName="all_bin.csv" --numProcesses=32 --balanceFactor=2
2367496

real    0m8.920s
user    1m30.056s
sys 2m38.744s

In [1]: 40412077758. / 8.92
Out[1]: 4530501990.807175

นั่นคือ 4.5 GB / s หรือ 45 Gb / s ความเร็วของไฟล์ slurping เพื่อนของฉันก็ไม่ได้หมุนฮาร์ดดิสก์เลย นั่นเป็น Samsung Pro 950 SSD จริงๆ

ด้านล่างเป็นเกณฑ์มาตรฐานความเร็วสำหรับไฟล์เดียวกันกับการนับบรรทัดโดย gnu wc ซึ่งเป็นโปรแกรมที่คอมไพล์ด้วย C บริสุทธิ์

อะไรที่เจ๋งมากคือคุณสามารถเห็นโปรแกรมหลามบริสุทธิ์ของฉันตรงกับความเร็วของโปรแกรม C ที่คอมไพล์แล้วในกรณีนี้ Python ตีความได้ แต่ C ถูกคอมไพล์ดังนั้นนี่เป็นเพลงที่น่าสนใจเรื่องความเร็วฉันคิดว่าคุณคงเห็นด้วย แน่นอนว่า wc จำเป็นต้องเปลี่ยนเป็นโปรแกรมคู่ขนานแล้วมันจะเอาชนะถุงเท้าออกจากโปรแกรมไพ ธ อนของฉัน แต่ ณ วันนี้ gnu wc เป็นเพียงโปรแกรมต่อเนื่อง คุณทำสิ่งที่คุณทำได้และหลามสามารถทำขนานกันวันนี้ การรวบรวม Cython อาจช่วยฉันได้ (บางครั้ง) ไฟล์หน่วยความจำที่แมปยังไม่ได้รับการสำรวจ

HP-Z820:/mnt/fastssd$ time wc -l all_bin.csv
2367496 all_bin.csv

real    0m8.807s
user    0m1.168s
sys 0m7.636s


HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000

real    0m2.257s
user    0m12.088s
sys 0m20.512s

HP-Z820:/mnt/fastssd/fast_file_reader$ time wc -l HIGGS.csv
11000000 HIGGS.csv

real    0m1.820s
user    0m0.364s
sys 0m1.456s

สรุป: ความเร็วนั้นดีสำหรับโปรแกรมหลามบริสุทธิ์เมื่อเทียบกับโปรแกรม C อย่างไรก็ตามมันไม่ดีพอที่จะใช้โปรแกรมหลามบริสุทธิ์เหนือโปรแกรม C อย่างน้อยก็เพื่อจุดประสงค์ในการนับจำนวน โดยทั่วไปแล้วเทคนิคนี้สามารถใช้สำหรับการประมวลผลไฟล์อื่น ๆ ดังนั้นรหัสไพ ธ อนนี้จึงยังดี

คำถาม: การรวบรวม regex เพียงครั้งเดียวและส่งให้คนงานทุกคนจะช่วยเพิ่มความเร็วหรือไม่ คำตอบ: การรวบรวมข้อมูลล่วงหน้าของ Regex ไม่ได้ช่วยในแอปพลิเคชันนี้ ฉันคิดว่าเหตุผลก็คือค่าใช้จ่ายในการจัดลำดับกระบวนการและการสร้างสำหรับคนงานทั้งหมดที่มีอำนาจเหนือ

อีกหนึ่งสิ่ง. การอ่านไฟล์ CSV แบบขนานช่วยได้หรือไม่ ดิสก์เป็นคอขวดหรือเป็น CPU หรือไม่ คำตอบที่ได้รับความนิยมสูงสุดใน stackoverflow มีคำสั่ง dev ทั่วไปที่คุณต้องการเพียงหนึ่งเธรดเพื่ออ่านไฟล์ที่ดีที่สุดที่คุณสามารถทำได้พวกเขาพูด พวกเขาแน่ใจเหรอ

ลองดู:

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=16 --balanceFactor=2
11000000

real    0m2.256s
user    0m10.696s
sys 0m19.952s

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=1
11000000

real    0m17.380s
user    0m11.124s
sys 0m6.272s

โอ้ใช่แล้วใช่ การอ่านไฟล์แบบขนานนั้นทำได้ค่อนข้างดี เอาล่ะคุณไปกันแล้ว!

ps ในกรณีที่คุณอยากรู้ว่าถ้า balanceFactor เป็น 2 เมื่อใช้กระบวนการผู้ปฏิบัติงานเดียว ก็น่ากลัว:

HP-Z820:/mnt/fastssd/fast_file_reader$ time python fastread.py --fileName="HIGGS.csv" --numProcesses=1 --balanceFactor=2
11000000

real    1m37.077s
user    0m12.432s
sys 1m24.700s

ส่วนสำคัญของโปรแกรมหลาม fastread.py:

fileBytes = stat(fileName).st_size  # Read quickly from OS how many bytes are in a text file
startByte, endByte = PartitionDataToWorkers(workers=numProcesses, items=fileBytes, balanceFactor=balanceFactor)
p = Pool(numProcesses)
partialSum = p.starmap(ReadFileSegment, zip(startByte, endByte, repeat(fileName))) # startByte is already a list. fileName is made into a same-length list of duplicates values.
globalSum = sum(partialSum)
print(globalSum)


def ReadFileSegment(startByte, endByte, fileName, searchChar='\n'):  # counts number of searchChar appearing in the byte range
    with open(fileName, 'r') as f:
        f.seek(startByte-1)  # seek is initially at byte 0 and then moves forward the specified amount, so seek(5) points at the 6th byte.
        bytes = f.read(endByte - startByte + 1)
        cnt = len(re.findall(searchChar, bytes)) # findall with implicit compiling runs just as fast here as re.compile once + re.finditer many times.
    return cnt

def สำหรับ PartitionDataToWorkers เป็นเพียงรหัสต่อเนื่องธรรมดา ฉันทิ้งมันไว้ในกรณีที่คนอื่นต้องการฝึกหัดเกี่ยวกับการเขียนโปรแกรมแบบขนาน ฉันแจกส่วนที่ยากขึ้นฟรี: โค้ดทดสอบที่ทำงานและขนานได้เพื่อประโยชน์ในการเรียนรู้ของคุณ

ขอบคุณ: โครงการ H2O แบบโอเพ่นซอร์สโดย Arno และ Cliff และเจ้าหน้าที่ H2O สำหรับซอฟต์แวร์และวิดีโอการเรียนการสอนที่ยอดเยี่ยมของฉันซึ่งเป็นแรงบันดาลใจให้ฉันสำหรับเครื่องอ่าน python ขนานประสิทธิภาพสูงขนานแท้ดังที่แสดงไว้ด้านบน H2O ทำการอ่านไฟล์แบบขนานโดยใช้จาวาสามารถเรียกใช้โดยโปรแกรมหลามและ R และเร็วอย่างบ้าคลั่งเร็วกว่าทุกอย่างในโลกที่อ่านไฟล์ CSV ขนาดใหญ่


ชิ้นขนานคือสิ่งนี้โดยทั่วไป นอกจากนี้ฉันคาดว่า SSD และ Flash เป็นอุปกรณ์จัดเก็บข้อมูลที่รองรับด้วยเทคนิคนี้เท่านั้น Spinning HD ไม่น่าจะเข้ากันได้
Geoffrey Anderson

1
คุณบัญชีไฟล์แคชของระบบปฏิบัติการได้อย่างไร
JamesThomasMoon1979

5

Katrielalex ให้วิธีเปิดและอ่านไฟล์เดียว

อย่างไรก็ตามวิธีการที่อัลกอริทึมของคุณจะอ่านไฟล์ทั้งหมดสำหรับแต่ละบรรทัดของไฟล์ นั่นหมายถึงจำนวนโดยรวมของการอ่านไฟล์ - และคำนวณระยะทาง Levenshtein - จะทำ N * N หาก N คือจำนวนบรรทัดในไฟล์ เนื่องจากคุณกังวลเกี่ยวกับขนาดไฟล์และไม่ต้องการเก็บไว้ในหน่วยความจำฉันกังวลเกี่ยวกับรันไทม์สมการกำลังสองที่เกิดขึ้น อัลกอริทึมของคุณอยู่ในคลาส O (n ^ 2) ของอัลกอริทึมซึ่งสามารถปรับปรุงได้ด้วยความเชี่ยวชาญ

ฉันสงสัยว่าคุณรู้ถึงการแลกเปลี่ยนของหน่วยความจำกับรันไทม์ที่นี่แล้ว แต่บางทีคุณอาจต้องการตรวจสอบว่ามีวิธีที่มีประสิทธิภาพในการคำนวณระยะทางหลายระดับของ Levenshtein พร้อมกันหรือไม่ ถ้าอย่างนั้นมันจะน่าสนใจที่จะแบ่งปันทางออกของคุณที่นี่

ไฟล์ของคุณมีไฟล์กี่บรรทัดและอัลกอริธึมของคุณต้องรันและชนิดของเครื่อง (พลัง mem & cpu) และประเภทใดที่รันไทม์ที่ยอมรับได้

รหัสจะมีลักษณะดังนี้:

with f_outer as open(input_file, 'r'):
    for line_outer in f_outer:
        with f_inner as open(input_file, 'r'):
            for line_inner in f_inner:
                compute_distance(line_outer, line_inner)

แต่คำถามคือคุณจะจัดเก็บระยะทาง (เมทริกซ์ได้อย่างไร) และคุณจะได้รับประโยชน์จากการเตรียมเช่น outer_line สำหรับการประมวลผลหรือแคชผลลัพธ์ระดับกลางเพื่อนำมาใช้ซ้ำ


ประเด็นของฉันคือโพสต์นี้ไม่มีคำตอบสำหรับคำถาม แต่มีคำถามเพิ่มอีก! IMO มันจะเหมาะกว่าเป็นความคิดเห็น
Katriel

1
@katriealex: เออ แปลก. คุณเห็นลูปซ้อนกันขยายคำตอบของคุณเองเพื่อให้เหมาะกับคำถามจริงหรือไม่? ฉันสามารถลบคำถามออกจากคำตอบได้ที่นี่และมีเนื้อหาเพียงพอที่จะรับประกันได้ว่านี่เป็นคำตอบ ฉันสามารถยอมรับได้หากคุณต้องการแก้ไขคำตอบของคุณเองเพื่อรวมตัวอย่างลูปซ้อนกัน - ซึ่งคำถามถูกถามอย่างชัดเจน - จากนั้นฉันสามารถลบคำตอบของฉันเองอย่างมีความสุข แต่ downvote เป็นสิ่งที่ฉันไม่ได้รับเลย
cfi

ยุติธรรมเพียงพอ ฉันไม่เห็นการสาธิตการซ้อนกันของลูปเป็นคำตอบสำหรับคำถาม แต่ฉันคิดว่ามันเป็นเป้าหมายที่ค่อนข้างแรงสำหรับผู้เริ่มต้น ลบโหวตแล้ว
Katriel

3
#Using a text file for the example
with open("yourFile.txt","r") as f:
    text = f.readlines()
for line in text:
    print line
  • เปิดไฟล์ของคุณเพื่ออ่าน (r)
  • อ่านไฟล์ทั้งหมดและบันทึกแต่ละบรรทัดในรายการ (ข้อความ)
  • วนซ้ำผ่านรายการที่พิมพ์แต่ละบรรทัด

ตัวอย่างเช่นหากคุณต้องการตรวจสอบสายเฉพาะสำหรับความยาวที่มากกว่า 10 ให้ทำงานกับสิ่งที่คุณมีอยู่แล้ว

for line in text:
    if len(line) > 10:
        print line

1
ไม่ดีที่สุดสำหรับคำถามนี้ แต่รหัสนี้มีประโยชน์เป็นหลักในกรณีที่สิ่งที่คุณกำลังมองหาคือ "slurping" (อ่านไฟล์ทั้งหมดพร้อมกัน) นั่นคือกรณีของฉันและ google ทำให้ฉันมาที่นี่ +1 นอกจากนี้สำหรับอะตอมมิกหรือหากคุณใช้เวลาในการประมวลผลในลูปอาจทำให้การอ่านไฟล์ทั้งหมดจบลงเร็วขึ้น
ntg

1
และปรับปรุงรหัสเล็กน้อย: 1. ไม่จำเป็นต้องปิดหลังจากด้วย: ( docs.python.org/2/tutorial/inputoutput.htmlค้นหา "มันเป็นวิธีปฏิบัติที่ดีที่จะใช้กับคำหลัก ... ") 2 . ข้อความสามารถประมวลผลได้หลังจากอ่านไฟล์แล้ว (ouside of with loop .... )
ntg

2

จากเอกสารไพธ อนสำหรับfileinput .input ():

iterates นี้ผ่านสายของไฟล์ทั้งหมดที่ระบุไว้ในsys.argv[1:], ผิดนัดsys.stdinถ้ารายการว่างเปล่า

เพิ่มเติมนิยามของฟังก์ชั่นคือ:

fileinput.FileInput([files[, inplace[, backup[, mode[, openhook]]]]])

อ่านระหว่างบรรทัดนี่บอกฉันว่าfilesสามารถเป็นรายการเพื่อให้คุณมีสิ่งที่ชอบ:

for each_line in fileinput.input([input_file, input_file]):
  do_something(each_line)

ดูที่นี่สำหรับข้อมูลเพิ่มเติม


2

ฉันขอแนะนำอย่างยิ่งให้ไม่ใช้การโหลดไฟล์เริ่มต้นเนื่องจากมันช้าอย่างน่ากลัว คุณควรตรวจสอบฟังก์ชัน numpy และฟังก์ชัน IOpro (เช่น numpy.loadtxt ())

http://docs.scipy.org/doc/numpy/user/basics.io.genfromtxt.html

https://store.continuum.io/cshop/iopro/

จากนั้นคุณสามารถแบ่งการดำเนินการตามลำดับของคุณออกเป็นชิ้น ๆ :

import numpy as np
import math

lines_total = n    
similarity = np.zeros(n,n)
lines_per_chunk = m
n_chunks = math.ceil(float(n)/m)
for i in xrange(n_chunks):
    for j in xrange(n_chunks):
        chunk_i = (function of your choice to read lines i*lines_per_chunk to (i+1)*lines_per_chunk)
        chunk_j = (function of your choice to read lines j*lines_per_chunk to (j+1)*lines_per_chunk)
        similarity[i*lines_per_chunk:(i+1)*lines_per_chunk,
                   j*lines_per_chunk:(j+1)*lines_per_chunk] = fast_operation(chunk_i, chunk_j) 

มันเกือบจะเร็วกว่ามากในการโหลดข้อมูลเป็นชิ้น ๆ จากนั้นทำการเมทริกซ์บนมันมากกว่าที่จะทำองค์ประกอบโดยองค์ประกอบ !!


0

ต้องการอ่านไฟล์ขนาดใหญ่บ่อยๆจากการอ่านตำแหน่งสุดท้ายหรือไม่

ฉันสร้างสคริปต์ที่ใช้เพื่อตัดไฟล์ access.log ของ Apache หลายครั้งต่อวัน ดังนั้นผมจึงจำเป็นในการตั้งค่าเคอร์เซอร์ตำแหน่งในบรรทัดสุดท้ายแยกวิเคราะห์ระหว่างการดำเนินการที่ผ่านมา ด้วยเหตุนี้ฉันใช้file.seek()และfile.seek()วิธีการที่ช่วยให้การจัดเก็บเคอร์เซอร์ในไฟล์

รหัสของฉัน:

ENCODING = "utf8"
CURRENT_FILE_DIR = os.path.dirname(os.path.abspath(__file__))

# This file is used to store the last cursor position
cursor_position = os.path.join(CURRENT_FILE_DIR, "access_cursor_position.log")

# Log file with new lines
log_file_to_cut = os.path.join(CURRENT_FILE_DIR, "access.log")
cut_file = os.path.join(CURRENT_FILE_DIR, "cut_access", "cut.log")

# Set in from_line 
from_position = 0
try:
    with open(cursor_position, "r", encoding=ENCODING) as f:
        from_position = int(f.read())
except Exception as e:
    pass

# We read log_file_to_cut to put new lines in cut_file
with open(log_file_to_cut, "r", encoding=ENCODING) as f:
    with open(cut_file, "w", encoding=ENCODING) as fw:
        # We set cursor to the last position used (during last run of script)
        f.seek(from_position)
        for line in f:
            fw.write("%s" % (line))

    # We save the last position of cursor for next usage
    with open(cursor_position, "w", encoding=ENCODING) as fw:
        fw.write(str(f.tell()))

-2

วิธีที่ดีที่สุดในการอ่านไฟล์ขนาดใหญ่ทีละบรรทัดคือการใช้ฟังก์ชั่นการแจกแจงแบบหลาม

with open(file_name, "rU") as read_file:
    for i, row in enumerate(read_file, 1):
        #do something
        #i in line of that line
        #row containts all data of that line

3
เหตุใดการใช้แจกแจงจึงดีกว่า ประโยชน์เพียงอย่างเดียวของคำตอบที่ยอมรับคือคุณได้รับดัชนีซึ่ง OP ไม่ต้องการและคุณกำลังทำให้โค้ดอ่านน้อยลง
fuyas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.