Saya perlu mendapatkan jumlah baris file besar (ratusan ribu baris) dengan python. Apa cara paling efisien baik dari segi memori maupun waktu?
Saat ini saya lakukan:
def file_len(fname):
with open(fname) as f:
for i, l in enumerate(f):
pass
return i + 1
Apakah mungkin melakukan yang lebih baik?
python
text-files
line-count
SilentGhost
sumber
sumber
enumerate(f, 1)
dan pariti + 1
?Jawaban:
Anda tidak bisa mendapatkan yang lebih baik dari itu.
Bagaimanapun, solusi apa pun harus membaca seluruh file, mencari tahu berapa banyak yang
\n
Anda miliki, dan mengembalikan hasilnya.Apakah Anda memiliki cara yang lebih baik untuk melakukannya tanpa membaca seluruh file? Tidak yakin ... Solusi terbaik akan selalu I / O-terikat, terbaik yang dapat Anda lakukan adalah memastikan Anda tidak menggunakan memori yang tidak perlu, tetapi sepertinya Anda memiliki yang tertutup.
sumber
Satu baris, mungkin cukup cepat:
sumber
Saya percaya bahwa file yang dipetakan memori akan menjadi solusi tercepat. Saya mencoba empat fungsi: fungsi yang diposting oleh OP (
opcount
); iterasi sederhana di atas baris dalam file (simplecount
); readline dengan memori yang dipetakan diajukan (mmap) (mapcount
); dan solusi baca buffer yang ditawarkan oleh Mykola Kharechko (bufcount
).Saya menjalankan setiap fungsi lima kali, dan menghitung rata-rata run-time untuk file teks 1,2 juta-baris.
Windows XP, Python 2.5, RAM 2GB, prosesor AMD 2 GHz
Inilah hasil saya:
Sunting : angka untuk Python 2.6:
Jadi strategi membaca buffer tampaknya menjadi yang tercepat untuk Windows / Python 2.6
Ini kodenya:
sumber
wccount()
adalah gist.github.com/0ac760859e614cd03652Saya harus memposting ini pada pertanyaan yang sama sampai skor reputasi saya melonjak sedikit (terima kasih kepada siapa pun yang menabrak saya!).
Semua solusi ini mengabaikan satu cara untuk membuat ini berjalan jauh lebih cepat, yaitu dengan menggunakan antarmuka (mentah) unbuffered, menggunakan bytearrays, dan melakukan buffering Anda sendiri. (Ini hanya berlaku dalam Python 3. Dalam Python 2, antarmuka mentah mungkin atau mungkin tidak digunakan secara default, tetapi dalam Python 3, Anda akan default ke Unicode.)
Menggunakan versi modifikasi dari alat penghitung waktu, saya percaya kode berikut ini lebih cepat (dan sedikit lebih pythonic) daripada salah satu solusi yang ditawarkan:
Menggunakan fungsi generator terpisah, ini menjalankan smidge lebih cepat:
Ini dapat dilakukan sepenuhnya dengan ekspresi generator secara in-line menggunakan itertools, tetapi terlihat sangat aneh:
Inilah waktu saya:
sumber
wccount
di tabel ini untukwc
alat shell subprocess ?rawincount
solusi terlihat kurang aneh dengan menggunakanbufgen = iter(partial(f.raw.read, 1024*1024), b'')
alih-alih menggabungkantakewhile
danrepeat
.Anda dapat menjalankan subproses dan menjalankannya
wc -l filename
sumber
Berikut ini adalah program python untuk menggunakan pustaka multiprocessing untuk mendistribusikan penghitungan baris di seluruh mesin / inti. Pengujian saya meningkatkan penghitungan file baris 20 juta dari 26 detik hingga 7 detik menggunakan server 8 core windows 64. Catatan: tidak menggunakan pemetaan memori membuat segalanya lebih lambat.
sumber
Solusi bash satu baris yang mirip dengan jawaban ini , menggunakan
subprocess.check_output
fungsi modern :sumber
wc -l
membutuhkan waktu ~ 5 detik.shell=True
buruk untuk keamanan, lebih baik menghindarinya.Saya akan menggunakan metode objek file Python
readlines
, sebagai berikut:Ini membuka file, membuat daftar baris dalam file, menghitung panjang daftar, menyimpannya ke variabel dan menutup file lagi.
sumber
xreadlines
telah ditinggalkan sejak 2.3, karena hanya mengembalikan iterator.for line in file
adalah pengganti yang disebutkan. Lihat: docs.python.org/2/library/stdtypes.html#file.xreadlinessumber
Inilah yang saya gunakan, sepertinya cukup bersih:
UPDATE: Ini sedikit lebih cepat daripada menggunakan python murni tetapi dengan biaya penggunaan memori. Subprocess akan melakukan proses baru dengan jejak memori yang sama dengan proses induk saat menjalankan perintah Anda.
sumber
:-)
Ini adalah hal tercepat yang saya temukan menggunakan python murni. Anda dapat menggunakan jumlah memori berapa pun yang Anda inginkan dengan mengatur buffer, meskipun 2 ** 16 tampaknya menjadi sweet spot di komputer saya.
Saya menemukan jawabannya di sini. Mengapa membaca baris dari stdin jauh lebih lambat di C ++ daripada Python? dan men-tweak sedikit saja. Ini adalah bacaan yang sangat baik untuk memahami cara menghitung garis dengan cepat, meskipun
wc -l
masih sekitar 75% lebih cepat dari yang lainnya.sumber
Saya mendapat peningkatan kecil (4-8%) dengan versi ini yang menggunakan kembali buffer konstan sehingga harus menghindari memori atau overhead GC:
Anda dapat bermain-main dengan ukuran buffer dan mungkin melihat sedikit peningkatan.
sumber
Jawaban Kyle
mungkin yang terbaik, alternatif untuk ini
Berikut ini perbandingan kinerja keduanya
sumber
Solusi satu baris:
Cuplikan saya:
sumber
os.system()
ke variabel dan mempostingnya lagi.Hanya untuk melengkapi metode di atas saya mencoba varian dengan modul fileinput:
Dan melewati file 60mil baris ke semua metode yang disebutkan di atas:
Ini sedikit mengejutkan bagi saya bahwa fileinput adalah yang buruk dan skala jauh lebih buruk daripada semua metode lain ...
sumber
Bagi saya varian ini akan menjadi yang tercepat:
alasan: buffering lebih cepat daripada membaca baris demi baris dan
string.count
juga sangat cepatsumber
Kode ini lebih pendek dan lebih jelas. Itu mungkin cara terbaik:
sumber
Saya telah memodifikasi kasing buffer seperti ini:
Sekarang juga kosongkan file dan baris terakhir (tanpa \ n) dihitung.
sumber
Bagaimana dengan ini
sumber
count = max(enumerate(open(filename)))[0]
sumber
enumerate()
adalah mulai menghitung menurut docs.python.org/2/library/functions.html#enumeratesumber
sumber
Jika seseorang ingin mendapatkan jumlah baris murah di Python di Linux, saya merekomendasikan metode ini:
file_path dapat berupa path file abstrak atau path relatif. Semoga ini bisa membantu.
sumber
Bagaimana dengan ini?
sumber
Bagaimana dengan one-liner ini:
Membutuhkan 0,003 detik menggunakan metode ini untuk menghitung waktu pada file baris 3900
sumber
sumber
Metode sederhana:
1)
2)
3)
sumber
hasil dari pembukaan file adalah iterator, yang dapat dikonversi ke urutan, yang memiliki panjang:
ini lebih ringkas daripada loop eksplisit Anda, dan menghindari
enumerate
.sumber
Anda dapat menggunakan
os.path
modul dengan cara berikut:, di mana
Filename
jalur absolut file.sumber
os.path
?Jika file tersebut dapat masuk ke dalam memori, maka
sumber