🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Python

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

Q&A

解決済

2回答

1076閲覧

python 処理速度を上げるためにこのコードのどこを改善すれば良いでしょうか?

tanukichipon

総合スコア14

Python

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

0グッド

0クリップ

投稿2019/10/27 02:25

17GBの分かち書き済txtファイルを読み込み、n_gram処理をしているファイルです。処理が非常に遅く心配です。以下のコードを処理速度を上げるために改善できる箇所はあるでしょうか?
教えていただけるととても嬉しいです。

Python

1import pandas as pd 2import sys 3import csv 4from collections import Counter 5 6cmd, infile = sys.argv 7termFreq = {} 8 9n = 0 10for wordArray in open(infile, errors='ignore'): 11 wordArray = wordArray.split() 12 if wordArray == []: 13 continue 14 15 ngram_list = ([(wordArray[i], wordArray[i+1], wordArray[i+2]) for i in range(len(wordArray)-2)]) 16 17 18 for n_word in ngram_list: 19 if n_word in termFreq: 20 termFreq[n_word] += 1 21 else: 22 termFreq[n_word] = 1 23 print(n) 24 n += 1 25 26 27 28 29 30term_list = [] 31count_list = [] 32for term, count in termFreq.items(): 33 term_list.append(term) 34 count_list.append(count) 35 36s = pd.DataFrame({ 37 'Count':count_list, 38 'List':term_list 39 }) 40 41s = s.sort_values('Count', ascending=False) 42 43 44print(s.shape) 45 46s.to_csv('./effect_3.csv', index=False) 47

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

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

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

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

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

meg_

2019/10/27 02:32

実行環境を質問に追記してください。(OSとかPCのスペックとか)
meg_

2019/10/27 02:36 編集

to_csv()はデータが大きいと時間がかかります。その前までの処理は遅いですか?具体的に今何分かかっていますか?
tanukichipon

2019/10/27 02:53

コメントしていただきありがとうございます プロセッサ:2.7 GHz Intel Core i5 メモリ:8 GB 1867 MHz DDR3 OS: MacOS Mojava 4700万行のうち1時間で600万行です。 to_csvより前の処理 for wordArrayの箇所が遅いです。
meg_

2019/10/27 03:59

・皆さんの目に触れるように、回答は「質問に追記」してください。 ・メモリに対してファイルサイズが大きいため時間がかかっているかと思われます。(マルチプロセス処理が可能であれば早くなる可能性はあります。メモリ不足なので効果があるかは分かりませんが。)
guest

回答2

0

ベストアンサー

私の知っている範囲で最速のn-gramの関数と、それを使った処理を挙げておきます。

python

1def ngram(seq, n): 2 return zip(*map(islice, tee(seq, n), count(0), repeat(None))) 3 4termFreq = Counter(chain.from_iterable(ngram(line.rstrip().split(), 3) for line in open(infile, errors='ignore')))

100Mぐらいのファイルを作って計測してるソースと結果です。

  1. 質問のコード
  2. 質問のコードから冗長なループを解消したコード
  3. 上のコード

を比べてみました。

python

1import random 2from collections import Counter 3from datetime import datetime 4from itertools import chain, count, islice, repeat, tee 5 6infile = 'a.csv' 7 8 9def question_code(): 10 termFreq = {} 11 12 for wordArray in open(infile, errors='ignore'): 13 wordArray = wordArray.split() 14 if wordArray == []: 15 continue 16 17 ngram_list = [(wordArray[i], wordArray[i + 1], wordArray[i + 2]) for i in range(len(wordArray) - 2)] 18 19 for n_word in ngram_list: 20 if n_word in termFreq: 21 termFreq[n_word] += 1 22 else: 23 termFreq[n_word] = 1 24 return termFreq 25 26 27def remove_redundant_loop(): 28 termFreq = {} 29 30 for line in open(infile, errors='ignore'): 31 wordArray = line.rstrip().split() 32 if wordArray == []: 33 continue 34 35 for i in range(len(wordArray) - 2): 36 n_word = wordArray[i], wordArray[i + 1], wordArray[i + 2] 37 if n_word in termFreq: 38 termFreq[n_word] += 1 39 else: 40 termFreq[n_word] = 1 41 return termFreq 42 43 44def ngram(seq, n): 45 return zip(*map(islice, tee(seq, n), count(0), repeat(None))) 46 47 48def use_itertools(): 49 return Counter(chain.from_iterable(ngram(line.rstrip().split(), 3) for line in open(infile, errors='ignore'))) 50 51 52if __name__ == '__main__': 53 with open(infile, 'w') as w: 54 for i in range(100000): 55 print(' '.join(map(str, [random.randint(0, 10) for j in range(0, 500)])), file=w) 56 57 start = datetime.now() 58 print(question_code()[('0', '0', '0')]) 59 print(datetime.now() - start) 60 61 start = datetime.now() 62 print(remove_redundant_loop()[('0', '0', '0')]) 63 print(datetime.now() - start) 64 65 start = datetime.now() 66 print(use_itertools()[('0', '0', '0')]) 67 print(datetime.now() - start)

plain

137156 20:00:19.557652 337156 40:00:19.402147 537156 60:00:09.168290

冗長なループが実行速度上は問題にならないことが分かります。


実はコードなんかよりもずっとずっと大事なことがあります。
作成している辞書が実メモリを超えないかどうかです。
辞書が実メモリを超えるようならコードをどんなに工夫しても速くなりません。低頻度語を捨てるなどの割り切りや、分割統治が必要になる問題です。

投稿2019/10/27 11:48

quickquip

総合スコア11231

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

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

tanukichipon

2019/10/29 00:35

本当に勉強になります。すごく助かりました。ありがとうざいます。
guest

0

速度改善には、ループを並列処理させるのが手っ取り早いですが、環境によってできたりできなかったりしますので、アルゴリズム的に冗長な箇所をご指摘します。

python

1ngram_list = ([(wordArray[i], wordArray[i+1], wordArray[i+2]) for i in range(len(wordArray)-2)]) 2 3 4 for n_word in ngram_list: 5 if n_word in termFreq: 6 termFreq[n_word] += 1 7 else: 8 termFreq[n_word] = 1

こちらですが、ngram_listを定義している内包表記のループと、そのあとのifでカウントしているループ、同時に処理できるはずです。
ngram_listをそもそも定義する必要がなく、直接
termFreqをカウントアップしていけると思います。

ただし、どの箇所が処理に時間が掛かっているのか、実際にtime関数やtqdmなどを使って計測してみて、その箇所について詰めていくのがよいとおもいます。


追記

python

1for i in range(len(wordArray)-2)): 2 n_word = wordArray[i], wordArray[i+1], wordArray[i+2] 3 if n_word in termFreq: 4 termFreq[n_word] += 1 5 else: 6 termFreq[n_word] = 1

投稿2019/10/27 02:53

編集2019/10/27 03:38
qax

総合スコア622

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

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

tanukichipon

2019/10/27 03:07

回答していただきありがとうございます。自分で調べてみたのですが内包リストがうまく記述できませんでした。厚かましいお願いなのですか後学のためにも上記の内包リストの記述仕方を教えていただけないでしょうか。どうかよろしくお願いいたします。
qax

2019/10/27 03:39

内包する必要はありません。 追記のように、ngram_listの定義をやめ、下のループと統合することで、 冗長に2回同じループをしていたのを、1つのループに統合します。
quickquip

2019/10/27 03:55

冗長と言っているのがどういう意味なのか、 >ngram_listをそもそも定義する必要がなく、直接termFreqをカウントアップしていけると思います。 というのがどういう意味でそれでどう速くなるのか、 私にはわかりませんでした。
qax

2019/10/27 04:01

冗長というのは、同じような処理を何回も繰り返しているということです。 ご提示のコードでは、 (1) wordArrayからn_gramを生成(ngram_listの行) (2) ngram_listを参照してtermFreqをカウントアップ していますね。 これは、ngram_listを生成する部分をカットして、 (1) wordArrayを参照してtermFreqをカウントアップ とすれば、同様の処理が実現でき、ngram_listを生成する分の処理がカットされるため、 速度が向上するという考えです。
tanukichipon

2019/10/27 07:30

教えていただきありがとうございます。やはり扱っているファイル自体が大きいためか、そこまで大きく速度改善はしませんでした。しかしながらコードの書き方等大変参考になりました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問