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

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

詳細はこちら
NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python 3.x

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

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

Python

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

2回答

2295閲覧

Python3.6 numpyを使ってループのネストを解消したい

Purindle

総合スコア7

NumPy

NumPyはPythonのプログラミング言語の科学的と数学的なコンピューティングに関する拡張モジュールです。

Python 3.x

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

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

Python

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2019/12/24 11:44

編集2019/12/25 10:03

前提・実現したいこと

以下を実現したいのですが、ループのネストをせずに実現することは可能でしょうか。
※目的は処理の高速化です。

numpyをうまく使えば高速に行えるのではないかと考えているのですが、
妙案が浮かばず。。。
お力をお貸しいただけないでしょうか。

  • 増減する数の配列において「各インデックスの値」と「そのインデックス以降の値」を比較して、

各インデックスの値の状態を取得する。

得たい結果

各インデックスの値とそのインデックス以降の値を比較して、

  • 10以上になった後、10以下になった場合、

 または、10以下になった後、10以上になった場合、
または、どの条件にも該当しない場合:0

  • 10以下に一度もなっていない状態で、20以上になった場合:1
  • 10以上に一度もなっていない状態で、20以下がった場合:2
入力1

[10, 0, 20, 9, 9, 9, 0, 29]

出力1

[0, 1, 2, 1, 1, 1, 1, 0]

入力2

[25, 36, 14, 50, 0]

出力2

[0, 2, 1, 2, 0]

入力3

[25, 24, 24, 24, 24]

出力3

[0, 0, 0, 0, 0]

該当のソースコード

python3.6

1import numpy as np 2 3arr = np.array([25, 36, 14, 50, 0]) 4result = [0] * len(arr) 5for i, target in enumerate(arr) : 6 is_up = False 7 is_down = False 8 for i_inner in range(i+1, len(arr)) : 9 diff = arr[i_inner] - target 10 if diff <= -10 : 11 is_down = True 12 elif diff >= 10 : 13 is_up = True 14 if is_up and is_down : 15 break 16 elif is_down == False and diff >= 20 : 17 result[i] = 1 18 break 19 elif is_up == False and diff <= -20 : 20 result[i] = 2 21 break 22 23print(result) # [0, 1, 2, 1, 1, 1, 1, 0]

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

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

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

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

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

meg_

2019/12/24 13:23

ロジックを簡単に言葉で説明いただけないでしょうか?
shiracamus

2019/12/24 13:57 編集

10以上、10以下という条件はすべての比較に当てはまることになりませんか? arr最初の10は、どれと比較してどんな差になって、どれを最優先に選んで出力0になったのですか? [30, 0, 60] というデータが与えられたら、どんな結果を期待しますか?
Purindle

2019/12/25 09:59

コメントありがとうございます。 得たい結果について加筆いたしました。 何卒、お力添えお願いいたします。 ・10以上になった後、10以下になった場合、  または、10以下になった後、10以上になった場合、  または、どの条件にも該当しない場合:0 ・10以下に一度もなっていない状態で、20以上になった場合:1 ・10以上に一度もなっていない状態で、20以下がった場合:2
guest

回答2

0

ベストアンサー

コードを見る限りだと、一定数ではない数の後続要素を見ないと状態が確定しないようなので、numpyのベクトル演算にはあまり向かないと思います。最適化が必要な場合、numbaなど高速にループを回せるようにする方向性でしょう。

投稿2019/12/24 18:07

hayataka2049

総合スコア30935

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

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

0

教えて頂いた通りnumbaを使ってみました。
結果に記載の通り、処理速度が改善しました。
ありがとうございました。

検証用コード

python3.6

1import numpy as np 2import time 3from numba import njit 4 5def original(arr): 6 result = [0] * len(arr) 7 for i, target in enumerate(arr) : 8 is_up = False 9 is_down = False 10 for i_inner in range(i+1, len(arr)) : 11 diff = arr[i_inner] - target 12 if diff <= -10 : 13 is_down = True 14 elif diff >= 10 : 15 is_up = True 16 if is_up and is_down : 17 break 18 elif is_down == False and diff >= 20 : 19 result[i] = 1 20 break 21 elif is_up == False and diff <= -20 : 22 result[i] = 2 23 break 24 return result 25 26@njit 27def original_njit(arr): 28 result = [0] * len(arr) 29 for i, target in enumerate(arr) : 30 is_up = False 31 is_down = False 32 for i_inner in range(i+1, len(arr)) : 33 diff = arr[i_inner] - target 34 if diff <= -10 : 35 is_down = True 36 elif diff >= 10 : 37 is_up = True 38 if is_up and is_down : 39 break 40 elif is_down == False and diff >= 20 : 41 result[i] = 1 42 break 43 elif is_up == False and diff <= -20 : 44 result[i] = 2 45 break 46 return result 47 48arr = (np.random.rand(10000000) * 100).astype(int) 49 50start = time.time() 51result = original(arr) 52end = time.time() 53print("[original]", end - start) 54 55start = time.time() 56result = original_njit(arr) 57end = time.time() 58print("[original_njit]", end - start)

結果

[original] 18.820305824279785
[original_njit] 0.5157194137573242

投稿2019/12/29 02:18

Purindle

総合スコア7

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問