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

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

新規登録して質問してみよう
ただいま回答率
85.31%
Jupyter

Jupyter (旧IPython notebook)は、Notebook形式でドキュメント作成し、プログラムの記述・実行、その実行結果を記録するツールです。メモの作成や保存、共有、確認などもブラウザ上で行うことができます。

Python 3.x

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

Q&A

3回答

594閲覧

リストの中身をfor文を使わずに抽出したい

J.F

総合スコア1

Jupyter

Jupyter (旧IPython notebook)は、Notebook形式でドキュメント作成し、プログラムの記述・実行、その実行結果を記録するツールです。メモの作成や保存、共有、確認などもブラウザ上で行うことができます。

Python 3.x

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

0グッド

0クリップ

投稿2023/11/08 04:11

実現したいこと

  • 以下のような,「リストを与えたら,中身を順番に返してくれる」という作業を,for抜きで行いたい.

python

1import numpy as np 2list_1 = [1, 2, 3, 4, 5] 3list_2 = [6, 7, 8, 9, 10] 4for i in range(len(list)): 5 print(list_1[i] + list_2[2]) 6 7#実行結果 8#7 9#9 10#11 11#13 12#15

前提

卒論で使うプログラムを組んでいたのですが,何も考えずforを使いまくった結果,とても長いうえにものすごい重いプログラムになってしまいました.少しでも時間短縮をしたいのですが,知識不足でなかなか良い案が思い浮かびませんでした(『実現したいこと』のプログラムはその一部を切り出して簡略化したものです.本来なら元のプログラムをアップすべきかとは思ったのですが,本当に長いうえにcsvファイルなども使うため,断念いたしました.一応参考情報として,こちらで頂いた知識を活かしたいパートを一番下に貼っておきます).

試したこと

自作関数を作る,numpyを使った処理などについても調べたり,その他for文の代わりになるようなことを色々試してみたりしたのですが,大体の場合でリストに入ってひと塊で返ってきてしまい,イメージしたようなものができませんでした.ご助力いただければ幸いです.

参考情報

こちらで頂いた知識を活かしたいパートです.https://ide-research.net/papers/2016_Iwanami_Ide.pdfの11ページ(27)の異常度を算定する式になります.
もともと参考にしたプログラムはこちらhttps://github.com/ytakashina/notebooks/tree/master/glassoになります.

for p in range(test.shape[0]):#各行→#このあたりに適用したい row = [] for q in range(test.shape[1]):#各列↓#このあたりに適用したい acc = 0 for r in range(test.shape[1]):#各列↓#このあたりに適用したい if not math.isnan(test[test.columns[r]][test.index[p]]): acc += prec_diag_zero[q][r] * (test[test.columns[r]][test.index[p]] - test[test.columns[r]].mean()) acc = (test[test.columns[r]][test.index[p]] - (test[test.columns[q]].mean() - (1/prec_[q][q])*acc))**2#☑ score = -0.5 * math.log(prec_[q][q]/(2*math.pi)) + 0.5 * prec_[q][q] * acc#☑異常度の算定式 row.append(score) df_scores.loc[p] = row

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

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

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

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

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

bsdfan

2023/11/08 11:04

test は Dataframe ですか? 同じ for ループでも、ndarray に変えるだけでそこそこ改善するはずです。 またループの中で何度も同じ mean を計算しているのも無駄に時間がかかってます。
guest

回答3

0

for ループを使わない方法を示していないので御参考です。

質問へのコメントの

同じ for ループでも、ndarray に変えるだけでそこそこ改善するはずです。

には同意見だったので実際に確かめてみました。

あくまで,下記のふたつのコードを「MacOS(M1) 13.6.1, Python 3.11.6, numpy 1.26.1」(私の環境)で実行した場合にはなりますが,処理時間は<オリジナル>が約 45秒だったのに対して<改善案>では約 10秒でした。

なお,式の意味を理解しているわけではありませんが,<オリジナル>の24行目は r ではなく q ではないかと思い変更しています。

<オリジナル>

Python

1import pandas as pd 2import numpy as np 3from numpy import random 4import math 5 6N, M = 100, 200 7rng = random.default_rng(103) 8 9prec_ = np.array(rng.random(M * M).reshape(M, M)) 10prec_diag_zero = prec_ - np.diag(np.diag(prec_)) 11 12test = pd.DataFrame(rng.random(N * M).reshape(N, M)) 13df_scores = pd.DataFrame(np.empty_like(test)) 14 15for p in range(test.shape[0]): 16 row = [] 17 for q in range(test.shape[1]): 18 acc = 0 19 for r in range(test.shape[1]): 20 if not math.isnan(test[test.columns[r]][test.index[p]]): 21 acc += (prec_diag_zero[q][r] 22 * (test[test.columns[r]][test.index[p]] 23 - test[test.columns[r]].mean())) 24 acc = (test[test.columns[q]][test.index[p]] 25 - (test[test.columns[q]].mean() 26 - (1/prec_[q][q]) * acc))**2 27 score = (-0.5 * math.log(prec_[q][q]/(2 * math.pi)) 28 + 0.5 * prec_[q][q] * acc) 29 row.append(score) 30 df_scores.iloc[p] = row 31 32print(df_scores) 33# 0 1 2 ... 197 198 199 34# 0 15.967284 11.300599 10.289985 ... 9.177044 5.273374 3.993757 35# 1 30.356535 25.223625 14.959857 ... 37.244809 19.037071 17.883623 36# 2 20.163732 25.146996 8.948390 ... 7.535858 9.392445 26.143601 37# 3 24.453619 1.481159 1.398596 ... 2.389492 10.123730 4.762429 38# 4 17.849431 22.829211 3.040402 ... 1.325447 4.508241 7.728260 39# .. ... ... ... ... ... ... ... 40# 95 4.672619 1.595823 1.401191 ... 1.654326 1.691618 1.297010 41# 96 7.553522 6.044351 2.154869 ... 2.220435 1.291333 3.721267 42# 97 10.679974 26.306743 13.505873 ... 21.988895 8.507998 20.977496 43# 98 5.983548 3.172999 3.922773 ... 1.883454 2.108250 2.091508 44# 99 3.986986 1.896011 15.165940 ... 1.468343 2.619154 2.027559 45# 46# [100 rows x 200 columns]

<改善案>

Python

1import pandas as pd 2import numpy as np 3from numpy import random 4import math 5 6N, M = 100, 200 7rng = random.default_rng(103) 8 9prec_ = np.array(rng.random(M * M).reshape(M, M)) 10prec_diag_zero = prec_ - np.diag(np.diag(prec_)) 11 12test = pd.DataFrame(rng.random(N * M).reshape(N, M)) 13df_scores = pd.DataFrame(np.empty_like(test)) 14 15test_np = test.to_numpy() 16 17for p in range(test.shape[0]): 18 row = [] 19 for q in range(test.shape[1]): 20 acc = 0 21 for r in range(test.shape[1]): 22 if not np.isnan(test_np[p, r]): 23 acc += (prec_diag_zero[q, r] 24 * (test_np[p, r] - test_np[:, r].mean())) 25 acc = (test_np[p, q] 26 - (test_np[:, q].mean() - (1/prec_[q, q]) * acc))**2 27 score = (-0.5 * math.log(prec_[q, q]/(2 * math.pi)) 28 + 0.5 * prec_[q, q] * acc) 29 row.append(score) 30 df_scores.iloc[p] = row 31 32print(df_scores) 33# 0 1 2 ... 197 198 199 34# 0 15.967284 11.300599 10.289985 ... 9.177044 5.273374 3.993757 35# 1 30.356535 25.223625 14.959857 ... 37.244809 19.037071 17.883623 36# 2 20.163732 25.146996 8.948390 ... 7.535858 9.392445 26.143601 37# 3 24.453619 1.481159 1.398596 ... 2.389492 10.123730 4.762429 38# 4 17.849431 22.829211 3.040402 ... 1.325447 4.508241 7.728260 39# .. ... ... ... ... ... ... ... 40# 95 4.672619 1.595823 1.401191 ... 1.654326 1.691618 1.297010 41# 96 7.553522 6.044351 2.154869 ... 2.220435 1.291333 3.721267 42# 97 10.679974 26.306743 13.505873 ... 21.988895 8.507998 20.977496 43# 98 5.983548 3.172999 3.922773 ... 1.883454 2.108250 2.091508 44# 99 3.986986 1.896011 15.165940 ... 1.468343 2.619154 2.027559 45# 46# [100 rows x 200 columns]

投稿2023/11/15 13:54

編集2023/11/15 14:23
little_street

総合スコア437

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

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

0

例えば、数値1000個のリストの中の最大値を求める場合、Pythonのforで1要素ずつ比較するのと、max関数を使うのだとループ回数はどちらも1000回ですが、maxはCで書かれているので、個数が多いと10倍くらいは速いはずです。
これは、forやwhile等でPythonレベルでループするのでなく、NumPy等の関数を使うことで同じように、同じ繰返し回数でもCレベルでループさせることで10倍くらいは速くなるかと思います。

ということで、

自作関数を作る,numpyを使った処理などについても調べたり,その他for文の代わりになるようなことを色々試してみたりしたのですが,大体の場合でリストに入ってひと塊で返ってきてしまい,イメージしたようなものができませんでした.

頑張ってNumPyかPandasを学びましょう。

また、三重ループだとデータ個数の三乗のループ回数だったりしますが、これをアルゴリズムを工夫することで個数の二乗回のループで済ませることが出来ると、データが数千件・数万件だと、数千倍・数万倍速くなるかも知れません。これについては「こうやれば出来る」という単純な話ではないので、個別ケース毎に考えるということになるかと思います。ただし、そもそもそんな改善は不可能というケースが多いかと思います。

投稿2023/11/09 01:19

otn

総合スコア86295

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

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

0

python

1import numpy as np 2 3list_1 = [1, 2, 3, 4, 5] 4list_2 = [6, 7, 8, 9, 10] 5 6arr_1 = np.array(list_1) 7arr_2 = np.array(list_2) 8sum_arr = arr_1 + arr_2 9 10print(*sum_arr, sep='\n') 11 12#7 13#9 14#11 15#13 16#15

投稿2023/11/08 04:19

melian

総合スコア21118

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問