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

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

新規登録して質問してみよう
ただいま回答率
85.35%
最適化

最適化とはメソッドやデザインの最適な処理方法を選択することです。パフォーマンスの向上を目指す為に行われます。プログラミングにおける最適化は、アルゴリズムのスピードアップや、要求されるリソースを減らすことなどを指します。

Python

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

Q&A

解決済

1回答

2416閲覧

Python 実行速度を高速化したいです!

obahaya

総合スコア1

最適化

最適化とはメソッドやデザインの最適な処理方法を選択することです。パフォーマンスの向上を目指す為に行われます。プログラミングにおける最適化は、アルゴリズムのスピードアップや、要求されるリソースを減らすことなどを指します。

Python

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

1グッド

1クリップ

投稿2021/10/10 04:15

編集2021/10/18 00:31

Python 実行速度を高速化し、時間短縮したいです!

今の書き方では、何日待っても終わらないため、
もっと早く終わるように高速化(最適化)したいです!

【追記】
やっていることは、
①(AからN列・1から6362行)のcsvファイルを読み込む
②CからN列の値を用いて、【Cが〇以下かつDが○以下かつ・・・Nが○○以下】と条件を指定し、その条件を満たす行(データ)のみを抽出する
③抽出した行(データ)におけるA列の合計値を求める
(「〇以下」の〇の値を一つずつ変えて全通りの条件において、A列の合計値を求める)
④Aの合計値が23を超える場合のみ、その条件と値を出力する

発生している問題・エラーメッセージ

今の処理を高速化したいです!

該当のソースコード

Python

1import numpy 2from numba import jit, prange 3 4score = numpy.loadtxt('sample.csv', delimiter=',', encoding='utf_8') 5 6@jit(nopython=True, parallel=True) 7def hello(): 8 for c in prange(0, 11): 9 for d in prange(0, 4): 10 for e in prange(0, 4): 11 for f in prange(0, 12): 12 for g in prange(0, 12): 13 for h in prange(0, 19): 14 for i in prange(0, 334): 15 for j in prange(0, 235): 16 for k in prange(0, 552): 17 for l in prange(0, 25): 18 for m in prange(0, 32): 19 for n in prange(0, 43): 20 score1 = score[(score[:, 2] <= c) & (score[:, 3] <= d) & (score[:, 4] <= e) & (score[:, 5] <= f) & (score[:, 6] <= g) & (score[:, 7] <= h) & (score[:, 8] <= i) & (score[:, 9] <= j) & (score[:, 10] <= k) & (score[:, 11] <= l) & (score[:, 12] <= m) & (score[:, 13] <= n)] 21 if numpy.sum(score1[:, 0]) > 23: 22 score2 = numpy.sum(score1[:, 0]) 23 print(c, d, e, f, g, h, i, j, k, l, m, n, score2) 24hello()

試したこと

Cythonを試しましたが、処理速度はnumbaの方が速かったです。
またpythonよりも実行速度が速いC++やGoやJavaで実現しようとしましたが、pythonのようなデータフレーム機能が見当たらなかったため実現できませんでした。

補足情報(FW/ツールのバージョンなど)

pythonでなくても今と同じ結果が得られるのであれば手段は問いません。pythonでの高速化もしくは他の言語での実現について、ご教授いただけると幸いです。何卒よろしくお願いいたします。

退会済みユーザー👍を押しています

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

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

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

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

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

y_waiwai

2021/10/10 04:58

なにをするコードなんでしょうか。 質問文を編集して、そこらへんの詳しい説明を追記しましょう
退会済みユーザー

退会済みユーザー

2021/10/10 05:00

numbaは検討しましたか? pythonのforは遅いのでなるべく外したいところです。実際にやらないとどこまで早くなるかわからないのでコメントだけですが…
obahaya

2021/10/10 05:30

コメントありがとうございます! 何をやっているか質問文を編集しました! numbaは検討しておりませんでした。試してみます!
episteme

2021/10/10 06:02

JavaとC++とGo のtagはなんのため?
obahaya

2021/10/10 06:15

コメントありがとうございます! 「python 実行速度 改善」などで調べたところ C++やGo、Javaが速いと書いてあったため、 C++やGo、Javaで同じ処理ができたら良いなと思いタグつけしました!
shiketa

2021/10/10 06:59

for文のrange()の値がナニを意味しているのかわかりませんが、dtemp=の文が実行される回数は、11*4*4*12*...*43で、717696139640832000回。C++でもGoでもJavaでも、とてもとても早くなりそうにはありませんけど...
obahaya

2021/10/10 07:26

コメントありがとうございます! やはりそうですか。。! range()の範囲を小さくすることで、 100万通りなら今のままでもある程度の時間で終わったのですが、 3500万通りの場合は何日待っても計算が終わりませんでした。。! そのため717696139640832000回ではなく3500万回程度の場合で良いので、 少しでも早く終わらせる方法が知りたいです!
episteme

2021/10/10 08:16 編集

マルチスレッドで速くするってんならGILの縛りがないC++/Java/Goを選ぶことになるかな...どれ選ぶかとなると、やっぱnativeなC++が他のよりマシでしょうかね(Goもnativeやけど)
obahaya

2021/10/11 03:54

コメントありがとうございます! C++にもこれから挑戦しようと思います!
obahaya

2021/10/11 21:39 編集

pandas < numpy < numbaという速度ですかね!
退会済みユーザー

退会済みユーザー

2021/10/11 22:40 編集

pandasはエクセルのような表計算データを扱うイメージ(インターフェイス?)で、その後ろではNumpyが走っていると思います。何をするかに寄りますし試してもいませんが、恐らくほぼ同じか少しnumpyが早いくらいと思います。 numpy<numbaは(ほぼ)例外なく間違いないと思います。from numba import jit とした上で関数の前に@jitとするだけで早くなります。 ※Numbaが解釈できるもの(Numbaが裏側でPythonではなくC++として解釈できるもの)が@jit以降にある場合に限ります。解釈できないものがあるとエラー(解釈不可)をはきます。Numbaのエラーを無視する(解釈できない=普通のPythonと変わらなくてもいい)のであれば@jit(nopython=True)としてください。早くないと困る!であれば、Numbaが解釈できる形に解釈できなかった関数(たとえばpandasの)機能を分解して自前で書き換えないといけません。Numbaが解釈できるのは、Numpyのうち比較的シンプルな計算ができる部分ですので、例えばnp.einsumみたいな変態関数は解釈できません。ご注意ください。
obahaya

2021/10/12 00:32

コメントありがとうございます! pandasからnumpyに変更すると実行速度が一気に速くなりました!またnumbaに変更することでさらに速くなりました! 最初、pandasを用いたまま@jitとしていたため、エラーになっていたのですが、詳しく解説していただいたおかげでnumbaを使用することができました! 本当にありがとうございます!
obahaya

2021/10/12 01:29

for文・多重ループを高速化する方法(for文を使わずに同じ処理をする方法)が知りたいです!
ArMigELo

2021/10/12 05:18

Cythonを使うか、Rayを使う方法に変えるのはどうでしょうか? python Cython , python ray で出てくると思います。
ArMigELo

2021/10/12 05:21

早くは出来ませんが from tqdm.notebook import tqdm tqdmを使うとかかる時間もある程度可視化できます。 最初のforのところにつけます。
obahaya

2021/10/12 07:46

コメントありがとうございます! from tqdm import tqdm、最初のforにtqdmをつけてみました! どこまで進んでいるか可視化できるため、とても助かります! Rayは並列処理が可能になるんですね! Ray以外にもmultiprocessingやconcurrent.futuresなども勉強してみたのですが、今回のソースコードへの適用の仕方が分かってないです。。! Cython勉強してみます!
退会済みユーザー

退会済みユーザー

2021/10/12 10:18 編集

@obahayaさん 一回できたところまでで回答を書いてはいかがでしょうか? ほかのアイデアも教えてもらえるかもしれません。
obahaya

2021/10/12 17:27 編集

コメントありがとうございます! 今記載しているソースコード(numba)が最速になります! Cythonを試してみたのですが、numpyを用いたfor文のためcdefで定義できず、よってCythonよりもnumbaの方が実行速度が速いという結果になりました! Rayやmultiprocessing、concurrent.futuresなど並列処理は今回のソースコードへどのように適用すればよいかまだ分かっていないです。。! よろしくお願いいたします!
guest

回答1

0

ベストアンサー

Rayやmultiprocessing、concurrent.futuresなど並列処理は今回のソースコードへどのように適用すれば

Rayは便利そうですが、使ったことがないのでconcurrent.futuresで書きます。

超シンプルなサンプル

Python3

1import time 2import numpy as np 3from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor 4 5def something_func(value): 6 ans = 0 7 for i in range(len(value)): 8 for j in range(10): 9 ans = ans + np.power(value[i],j) 10 return ans 11 12def executor(values,bool_TPE,num_workers): 13 14 timer = time.time() 15 16 if bool_TPE: 17 print("TPE","Workers:",num_workers,end=" ") 18 with ThreadPoolExecutor(max_workers=num_workers) as tpe: 19 ans = tpe.map(something_func, values) 20 else: 21 print("PPE","Workers:",num_workers,end=" ") 22 with ProcessPoolExecutor(max_workers=num_workers) as ppe: 23 ans = ppe.map(something_func, values) 24 25 print( time.time() - timer ,"[sec]") 26 return ans 27 28 29VALUES = np.asarray((1,2,3,4,5,6,7,8,9,10)) 30 31ans = executor(VALUES,bool_TPE=True,num_workers=2) 32ans = executor(VALUES,bool_TPE=True,num_workers=5) 33 34ans = executor(VALUES,bool_TPE=False,num_workers=2) 35ans = executor(VALUES,bool_TPE=False,num_workers=5) 36

TPEはスレッドを複数走らせてFor文を処理します。
PPEはプロセスを複数走らせてFor文を処理します。

バクっとしてますが、シンプルなものはTPE向けですし、複雑な処理はPPE向けです。
早くなると思ったらシングルスレッドが一番早かった!もよくある話ですし、
いろいろな並列処理をまぜこぜにすると次亜塩素酸ナトリウムに酸性の液体を混ぜるようなことになります。オーバーヘッドが大きすぎて遅くなるだけなのでやめた方がイイです。
num_workersはCPUの(論理)コア数に合わせてあげてください。task managerで確認できるはずです。
うまくいけばコア数の倍数分だけ早くなります。

hello()について

データがないので試せませんが、

  1. def executor(values,bool_TPE,num_workers):のvaluesをけずって、
  2. something_func(value)をhello()にして、
  3. .map(something_func, values)を.map(hello)

にしたら行けると思います。

構文エラー系が出たら適当に直してください :)

投稿2021/10/14 13:04

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

obahaya

2021/10/14 21:39 編集

ご回答ありがとうございます! 1. def executor(values,bool_TPE,num_workers):のvaluesをけずって、 2. something_func(value)をhello()にして、 3. .map(something_func, values)を.map(hello) にしたのですが、うまくいきません。。! concurrent.futuresの使い方が理解できてなくて、申し訳ないです。。! 以下のコードで実行しました! import time import numpy as np from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor score = np.loadtxt('sample.csv', delimiter=',', encoding='utf_8') def hello(): for c in range(0, 11): for i in range(140, 180): for j in range(50, 85): for n in range(0, 25): score1 = score[(score[:, 2] <= c) & (score[:, 8] <= i) & (score[:, 9] <= j) & (score[:, 13] <= n)] if np.sum(score1[:, 0]) > 15: score2 = np.sum(score1[:, 0]) print(c, i, j, n, score2) def executor(bool_TPE,num_workers): timer = time.time() if bool_TPE: print("TPE","Workers:",num_workers,end=" ") with ThreadPoolExecutor(max_workers=num_workers) as tpe: ans = tpe.map(hello) else: print("PPE","Workers:",num_workers,end=" ") with ProcessPoolExecutor(max_workers=num_workers) as ppe: ans = ppe.map(hello) print( time.time() - timer ,"[sec]") return ans ans = executor(bool_TPE=True,num_workers=2) ans = executor(bool_TPE=True,num_workers=5) ans = executor(bool_TPE=False,num_workers=2) ans = executor(bool_TPE=False,num_workers=5) 以下が出力されました! TPE Workers: 2 0.0 [sec] TPE Workers: 5 0.0 [sec] PPE Workers: 2 0.0049970149993896484 [sec] PPE Workers: 5 0.0 [sec] 上の出力ではなく、以下の出力になって欲しいです! 10 145 77 14 15.056999999999348 10 149 62 14 15.245999999999889 10 149 62 15 15.07199999999986 10 150 77 13 15.353999999999573 10 157 77 13 15.131999999999401 10 158 77 13 15.594999999999374 よろしくお願いいたします!
退会済みユーザー

退会済みユーザー

2021/10/15 12:29

小さくていいのでダミーデータをください。
退会済みユーザー

退会済みユーザー

2021/10/16 06:50

あー、 ans = executor(略) のように計算はしているのですが、肝心の計算結果を出力していないんですね。 ans = executor(略) print(ans) とすれば計算結果が見えるはずです。
obahaya

2021/10/18 00:24

コメントありがとうございます! 計算できました! .map(hello)ではなく.map(hello())にしなければいけないのを忘れていました。。! task managerでCPUの(論理)コア数を確認すると2でしたので、 num_workers=2にしました! TPE、PPEどちらも試したのですが、 numbaを用いた時とほぼ同等の処理速度となりました! ①@njit def hello() ②@njit def hello()+def executor ①②の速度はほぼ同じでした! ①以上に処理速度を上げることは難しくて、 ①の速度がPython(インタプリタ言語)の限界ですかね!
退会済みユーザー

退会済みユーザー

2021/10/18 10:22

そのように思います。 もし今のデータ数がかなり少ない状態で検証しただけであれば、 forで処理するデータ数が多くなってくると細かい差が大きくなってくる可能性も捨てきれません。 1を基軸に、データ数が10か100倍くらい違うもので2(のTPEとPPEの両方)も 試した方がイイかもしれません。
obahaya

2021/10/19 06:07

ほんとその通りですね! 100秒程度で終わる処理で計算時間を比較していました! もっと計算数を増やして比較してみます! ありがとうございます!
退会済みユーザー

退会済みユーザー

2021/10/19 09:16

エクセルの散布図で様子を見ると良いと思います。条件ごとに大体直線に乗ってくる傾向が見えるはずです。本番で計算したいデータ量がどれくらいの量かによって最適な方法が変わると思います。 縦軸:かかった秒数、横軸:データ量 手法を生、TPE、PPEといった具合です。
obahaya

2021/10/21 10:13

なるほど!! 「大体直線に乗ってくる」→ほぼ比例するのですね! そうすると、その散布図から逆算でき、 寝ている間の8時間で最大限に計算を回そうとしたとき どのくらいの計算量なら計算が無事終わる目処がつきますね! ありがとうございます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問