質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

5回答

4917閲覧

要素比較の高速化について

cho

総合スコア23

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2015/11/20 06:37

二つのファイルの要素を比較しています.
ファイルAはとにかく大きい(10GB前後),ファイルBは400件程度の要素が存在します.
Aには要素の被りがありますが,Bにはありません.
Aの中からBを探し,Bが出現頻度を算出することが目的です.

現在,どちらのファイルもl読み込み,比較していき,
要素が一致すれば出力(ファイルに書き出し)という手順で行っています.
出現頻度は後から・・と考えています.

python

1 2sys.stdout=open('hoge.txt','w') 3for row in csv.reader(open('B.csv','r'),delimiter='\t'): 4 for row2 in csv.reader(open('A.csv','r'),delimiter='\t'): 5 if (row[0]==row2[0]): 6 print(row2[0]+'\t'+row2[2]+'\t'+row2[4]); 7sys.stdout.close() 8sys.stdout=sys.__stdout__

これで動いてはいるのですが非常に時間がかかり困っています.
高速化する方法はないでしょうか.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答5

0

頻度を数えることも同時にやってしまって、出力は頻度のみでOKということであれば、

python

1sys.stdout=open('hoge.txt','w') 2rows=[row[0] for row in csv.reader(open('B.csv','r'),delimiter='\t')] 3counts=[0]*len(rows) 4for row2 in csv.reader(open('A.csv','r'),delimiter='\t'): 5 if row2[0] in rows: 6 counts[rows.index(row2[0])]+=1 7for row,count in zip(rows,counts): 8 print(row,count) 9sys.stdout.close() 10sys.stdout=sys.__stdout__

とすれば、出力として
row[0] 頻度
というのが並んだファイルが作られます。

投稿2015/11/20 07:07

hiro-k

総合スコア902

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

  1. 小さい方のファイルを全部読み込む。csvreader を介し、先頭カラムだけリストに格納する。row
  2. デカイ方のファイルを 1000 行単位で読み込む。csvreader を介さず、1 行まるごと読み込む。row2
  3. 2つの配列で、小さい方を外、大きい方を内側の2重ループで検索する。row2 行の最初のタブまでの文字列を抽出して比較、同一ならば、row2 だけ出力用リストに格納する。出力用リストが100件溜まったら、ファイルにしゅつりょくする、0,2,4カラムを抽出してcsv形式にせいけいする。

これを延々くり返す。ディスクアクセスは、HDDの場合、1/1000秒以下のアクセスは無理なので、なるべくアクセスを避ける。出力用リストも、メモリやヒープサイズとの兼ね合いもありますが、何度も試行して、最適な出力のしきい値を求める。100じゃなくて、余裕あれば10000とかにするだけで、結果が50000件なら、500回のアクセスを5回に大幅削減できます。また、csv出力も、1行作ってファイル書き込みではなくて、100行繋げて一辺に書き込むとかするだけで、ディスクヘッドの移動時間のオーバーヘッドとかも回避できるかもしれません。10000文字書き込んで、10000文字が連続した領域に書き込まれるのかは運次第ですが。

結局メインループは、大きいファイル依存で物凄い回数まわるので、その部分はなるべくpythonのロジックだけが動作するように工夫するのがベターだと思います。

投稿2015/11/20 07:16

ipadcaron

総合スコア1693

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

もし、出力の順番が変わっては困るということだと、全部の探索が終わった後に出力する必要があります。

python

1sys.stdout=open('hoge.txt','w') 2rows=[row[0] for row in csv.reader(open('B.csv','r'),delimiter='\t')] 3outputs=[[] for n in xrange(len(rows))] 4for row2 in csv.reader(open('A.csv','r'),delimiter='\t'): 5 if row2[0] in rows: 6 outputs[rows.index(row2[0])].append(row2[0]+'\t'+row2[2]+'\t'+row2[4]) 7for output in outputs: 8 for o in output: 9 print(o) 10sys.stdout.close() 11sys.stdout=sys.__stdout__

というように、まずは全ての出力をoutputs に貯めて、最後に出力することになります。
この場合「10GBのほとんどが出力対象」などのように出力量が多いと、沢山のメモリが必要になります。

投稿2015/11/20 06:55

編集2015/11/20 06:59
hiro-k

総合スコア902

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

1.Aのデータを一度先に走査し、要素名をファイル名としたファイルにその要素が存在するごとにカウントを増やしていく。
2.1.のデータがあればBの各行の出現頻度は要素名のファイルを開けばわかる。

という感じにすれば、Aのデータの走査が一回だけで済んでそれなりに高速になると思いますが如何でしょうか?

投稿2015/11/20 06:51

tanat

総合スコア18709

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

遅い問題は、10GB前後もあるファイルを400回程度も繰り返し読んでいることに起因します。
なので、10GBのファイルを1回読めば良いように変更すれば速くなります。

たとえば、出力の順番が変わっても良いなら、

python

1sys.stdout=open('hoge.txt','w') 2rows=[row[0] for row in csv.reader(open('B.csv','r'),delimiter='\t')] 3for row2 in csv.reader(open('A.csv','r'),delimiter='\t'): 4 if row2[0] in rows: 5 print(row2[0]+'\t'+row2[2]+'\t'+row2[4]); 6sys.stdout.close() 7sys.stdout=sys.__stdout__

というのは如何でしょうか?
rows という B.csv の各行 の最初の要素(row[0])が入った list を作ります。
その後A.csv の各行の最初の要素(rows[2])が rowsに含まれていれば出力します。

投稿2015/11/20 06:49

hiro-k

総合スコア902

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問