ファイル全体の各行を繰り返したい。これを行う1つの方法は、ファイル全体を読み取り、それをリストに保存してから、目的の行に移動することです。この方法は大量のメモリを使用するため、代替手段を探しています。
私のコードはこれまでのところ:
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距離を計算したいです。
ファイルを読み取るための正しい、完全にPythonicの方法は以下のとおりです。
with open(...) as f:
for line in f:
# Do something with 'line'
with
ステートメントは、内部ブロックで例外が発生した場合も含めて、ファイルの開閉を処理します。 for line in f
はファイルオブジェクトf
をイテラブルとして扱います。これは自動的にバッファされたI/Oとメモリ管理を使うので、大きなファイルを心配する必要はありません。
それを行うには、明白な方法が1つ(できれば1つだけ)あるべきです。
ランク付けされた順序で2つのメモリ効率的な方法(最初が最善です) -
with
の使用 - python 2.5以降からサポートされていますyield
を使用します。with
の使用with
は、大きなファイルを読むための素晴らしい効率的なPythonicの方法です。利点 - 1)ファイルオブジェクトはwith
実行ブロックから出た後に自動的に閉じられます。 2)with
ブロック内での例外処理3)memory for
ループは、f
ファイルオブジェクトを1行ずつ繰り返します。内部的にはバッファリングされたIO(コストのかかるIO操作に最適化されています)およびメモリ管理を行います。
with open("x.txt") as f:
for line in f:
do something with data
yield
の使用各反復で読み取る量をもっときめ細かく制御したい場合があります。その場合は iter & 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()
関数にも同じ)がファイル全体をメモリにロードしてから繰り返します。大きなファイルのための少し良い方法(最初に述べた2つの方法が最善です)は、以下のようにfileinput
モジュールを使うことです:
import fileinput
for line in fileinput.input(['myfile']):
do_something(line)
fileinput.input()
呼び出しは行を順番に読み込みますが、それらが読み込まれた後、あるいは単にそうさえしてもそれらをメモリに保持しません。なぜなら、pythonではfile
は繰り返し可能だからです。
with open(file_path, 'rU') as f:
for line_terminated in f:
line = line_terminated.rstrip('\n')
...
ユニバーサル改行サポートを使用する ファイル内のターミネータが'\n'
、'\r'
、'\n'
のいずれであっても、すべてのテキストファイル行は'\r\n'
で終了するようです。
EDIT - ユニバーサル改行サポートを指定するには:
open(file_path, mode='rU')
- 必須 [ありがとう @Dave ]open(file_path, mode='rU')
- オプションopen(file_path, newline=None)
- オプションnewline
パラメータはPython 3でのみサポートされ、デフォルトはNone
です。 mode
パラメータは、デフォルトで'r'
になります。 U
はPython 3では推奨されません。Windows上のPython 2では、\r\n
を\n
に変換するための他のメカニズムがあります。
ドキュメント:
with open(file_path, 'rb') as f:
with line_native_terminated in f:
...
バイナリモードでも、ファイルをin
の行に解析できます。各行には、ファイル内の終端文字がすべて含まれます。
@katrielalex の answer 、Pythonの open() doc、および iPython 実験のおかげで
これはpythonでファイルを読むための可能な方法です:
f = open(input_file)
for line in f:
do_stuff(line)
f.close()
全リストは割り当てられません。それは行を繰り返します。
私がどこから来たのかについてのいくつかの文脈。コードスニペットは最後にあります。
可能であれば、私はH2Oのようなオープンソースのツールを使って超高性能の並列CSVファイル読み込みをすることを好むが、このツールは機能セットが限られている。教師付き学習を適切に行うためにH2Oクラスターにフィードする前に、データサイエンスパイプラインを作成するためのコードをたくさん書くことになります。
私は、UCIレポからの8GB HIGGSデータセットのようなファイルや、マルチプロセシングライブラリのプールオブジェクトとマップ機能を使った並列処理を追加することにより、データサイエンス目的で40GBのCSVファイルさえもかなり速く読みました。たとえば、最近傍検索によるクラスタリングや、DBSCANおよびマルコフのクラスタリングアルゴリズムでは、メモリや壁時計の深刻な問題を回避するために、ある程度の並列プログラミングの技巧が必要です。
私は通常、最初にgnuツールを使ってファイルを行ごとに分割し、次にそれらすべてをglob-filemaskしてpythonプログラムでそれらを並行して見つけて読むのが好きです。私は一般的に1000以上の部分ファイルのようなものを使います。これらのトリックを行うことは、処理速度とメモリ制限に非常に役立ちます。
パンダdataframe.read_csvはシングルスレッドなので、並列実行のためにmap()を実行することによってパンダをかなり速くするためにこれらのトリックをすることができます。 htopを使って、普通のシーケンシャルパンダdataframe.read_csvでは、たった1つのコア上の100%cpuがpd.read_csvの実際のボトルネックであり、ディスクではないことがわかります。
SATA6バスで回転するHDではなく、高速ビデオカードバスでSSDを使用し、さらに16個のCPUコアを使用します。
また、私が発見した別のテクニックは、1つの大きなファイルを多数のパーツファイルに事前に分割するのではなく、並列CSVファイルが1つの巨大ファイル内ですべて読み取り、各ワーカーをファイルにオフセットすることです。それぞれの並列ワーカーでpythonのファイルseek()およびtell()を使用して、ビッグテキストファイルを、ビッグファイル内の異なるバイトオフセットの開始バイト位置と終了バイト位置で、同時に同時に読み取ります。あなたはそのバイトに対して正規表現のfindallを行い、改行の数を返すことができます。これは部分的な合計です。ワーカーが終了した後にマップ関数が戻ったときに、最後に部分的な合計を合計してグローバル合計を取得します。
以下は、パラレルバイトオフセットトリックを使用したベンチマークの例です。
私は2つのファイルを使います:HIGGS.csvは8 GBです。それはUCI機械学習リポジトリからです。 all_bin .csvは40.4 GBで、私の現在のプロジェクトからのものです。私は2つのプログラムを使います:Linuxに付属するGNU wcプログラムと私が開発した純粋な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 /秒、つまり45 Gbpsのファイル整理速度です。それは回転するハードディスクではない、私の友人。それは実際にはSamsung Pro 950 SSDです。
以下は、純粋なCコンパイル済みプログラムであるgnu wcによってラインカウントされている同じファイルの速度ベンチマークです。
素晴らしいのは、この場合、私の純粋なpythonプログラムがgnu wcでコンパイルされたCプログラムの速度と本質的に一致しているのを見ることができるということです。 Pythonは解釈されますがCはコンパイルされますので、これはかなり面白いスピードの妙技です、私はあなたが同意すると思います。もちろん、wcは実際には並列プログラムに変更する必要があり、それからそれは私のpythonプログラムから離れてしまいます。しかし今日のように、gnu wcは単なる順次プログラムです。あなたはあなたができることをします、そしてpythonは今日平行してすることができます。 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
結論:純粋なpythonプログラムは、Cプログラムと比べて速度が速いです。ただし、少なくともラインカウントの目的で、純粋なpythonプログラムをCプログラムよりも使用するのは十分ではありません。一般的にこのテクニックは他のファイル処理にも使えるので、このPythonコードはまだ良いです。
質問:正規表現を1回だけコンパイルしてすべての作業者に渡すと、速度が向上しますか?回答:正規表現のプリコンパイルは、このアプリケーションでは役に立ちません。その理由は、すべてのワーカーに対するプロセスのシリアル化と作成のオーバーヘッドが支配的であることにあると思います。
もう一つ。 CSVファイルの並列読み取りも役に立ちますか?ディスクがボトルネックなのか、それともCPUなのか。 stackoverflowに関する多くのいわゆるトップクラスの回答には、ファイルを読み込むために1つのスレッドしか必要としないという一般的な開発者の知恵が含まれています。彼らは確かですか?
確認してみましょう:
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 pythonプログラムの主な部分:
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
PartitionDataToWorkersのdefは、通常のシーケンシャルコードです。他の誰かが並列プログラミングがどのようなものであるかについていくらかの練習を得たいと思うならば私はそれを省略しました。私はあなたの学習の利益のために、より困難な部分を無料で譲渡しました。
おかげで:ArnoとCliffによるオープンソースのH2Oプロジェクト、そしてH2Oスタッフによる素晴らしいソフトウェアと説明ビデオ。これらの純粋なpythonの高性能パラレルバイトオフセットリーダーにインスピレーションを与えてくれました。 H2OはJavaを使用して並列ファイル読み取りを行い、pythonおよびRプログラムによって呼び出すことができます。そして、巨大なCSVファイルを読み取ることで、地球上のものよりも速く、速くなります。
Katrielalexは1つのファイルを開いて読む方法を提供しました。
しかしながら、あなたのアルゴリズムが進む方法では、ファイルの各行についてファイル全体を読み込みます。つまり、ファイル内の行数がNであれば、ファイルの読み取り全体の量、および Levenshtein距離の計算 - は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、または再利用のための中間結果のキャッシュ.
#Using a text file for the example
with open("yourFile.txt","r") as f:
text = f.readlines()
for line in text:
print line
たとえば、10を超える長さで特定の行をチェックしたい場合は、すでに使用可能なものを使用してください。
for line in text:
if len(line) > 10:
print line
デフォルトのファイルロードは非常に遅いので使用しないことを強くお勧めします。あなたは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)
データをチャンク単位でロードしてから行列演算を行う方が、要素ごとにデータを処理するよりもはるかに高速です。
fileinput 。input()のPythonドキュメントから:
これは
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)
詳細については ここ を参照してください。