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

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

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

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

Python

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

Q&A

解決済

3回答

1290閲覧

[Python]forの処理を高速化したい

aiai8976

総合スコア112

最適化

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

Python

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

0グッド

0クリップ

投稿2020/11/06 13:38

編集2020/11/06 13:38

前提・実現したいこと

pythonでndarrayをcsvとして書き込みたいと思っています。
処理自体は回るのですが、処理時間がどうしても長くなってしまいます。
pythonのforは遅いということは知っていましたが、あまりにも遅すぎて何かしらダメな部分があるような気がしています。
高速化について知見がある方、コメントお願いします。

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

ラズパイ→100秒程度
mac→35秒程度

該当のソースコード

#3次元配列(720*1080*3) sample = [[[0,0,0],[0,0,0],[..]..], [..]] def ndarray_to_csv(file_name, ndarray): with open(file_name, 'w') as f: writer = csv.writer(f) for value in ndarray: writer.writerow(value) ndarray_to_csv('sample.csv', sample)

試したこと

mapを使ってみても変化なし

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

python 3.8

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

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

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

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

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

guest

回答3

0

ベストアンサー

np.savetxtは試してみましたか。delimiterを任意に指定できます。
註: 1次元・2次元の場合のみ


テキスト形式で無くても良いならnp.saveが手軽でしょう。

Python

1np.save(f'{file_name}.npy', ndarray)

読み込むときもnp.loadが使えます。

計測

3回ファイル書き出しを行って平均を取ります。

環境

cmd

1C:...>ver 2Microsoft Windows [Version 10.0.18363.1139] 3 4C:...>python --version 5Python 3.7.7

コード

Python

1import csv 2import timeit 3 4import numpy as np 5 6 7def func1(file_name, ndarray): 8 """aiai8976さんの方法""" 9 with open(file_name, 'w') as f: 10 writer = csv.writer(f) 11 for value in ndarray: 12 writer.writerow(value) 13 14def func2(file_name, ndarray): 15 """Moineau26518805さんの方法""" 16 ndarray = "\n".join([",".join([str(n) for n in narray]) for narray in ndarray]) 17 with open(file_name, 'w') as f: 18 f.write(ndarray) 19 20def func3(file_name, ndarray): 21 """toast-uzさんの方法""" 22 sample = np.apply_along_axis(lambda x: f"[{' '.join(x)}]", 2, ndarray.astype(str)) 23 np.savetxt(file_name, sample, delimiter=',', fmt='%s') 24 25def func4(file_name, ndarray): 26 """LouiS0616の方法""" 27 np.save(f'{file_name}.npy', ndarray) 28 29 30if __name__ == '__main__': 31 ndarray = np.random.randint(0, 256, size=(720, 1080, 3)) 32 repeat = 3 33 34 for i, func in enumerate([func1, func2, func3, func4]): 35 print(func.__doc__) 36 print( 37 '\t' + 38 '{}回繰り返した結果: {:.3f}秒かかりました。'.format( 39 repeat, 40 timeit.timeit(lambda: func(f'sample{i}.csv', ndarray), number=repeat) 41 ) 42 )

結果

必要秒数(3回)
aiai8976さんの方法107.394秒
Moineau26518805さんの方法111.174秒
toast-uzさんの方法24.352秒
私の方法(np.save)0.027秒

私の方法が高速なのはバイナリファイルを書き出しているからです。

バイナリ形式にも欠点はありますが、
今回は出力が3次元なのでそもそもCSVの強みを活かせないと考えます。

投稿2020/11/06 13:44

編集2020/11/07 01:57
LouiS0616

総合スコア35660

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

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

LouiS0616

2020/11/06 13:46

あれ、三次元なんですね。 三次元のデータをCSVに吐き出すってどういうイメージなんでしょう。
toast-uz

2020/11/06 23:45 編集

コードを実行してみると、 [0 0 0],[0 0 0],[0 0 0],[0 0 0],[0 0 0],... という行の繰り返しになりますね。各要素がリストになります。
LouiS0616

2020/11/07 00:43

これってCSVと呼べるんですかね。
toast-uz

2020/11/07 01:36

確かに!np.saveが最適説を、私も追記しておきました。
guest

0

魔術的ではありますが、LouiS0616様のアイデアと、Moineau26518805様のアイデアを足して、さらに変換にもnp.apply_along_axisを使ってforループ(リスト内包表現での隠れforループも含む)を避ける、という手法で、約5秒(Mac)を達成しました。

Python

1sample = np.zeros((720, 1080, 3), dtype=int) 2sample = np.apply_along_axis(lambda x: f"[{' '.join(x)}]", 2, sample.astype(str)) 3np.savetxt('sample.csv', sample, delimiter=',', fmt='%s')

なお、元のコードは約26〜27秒、Moineau26518805様のコードもそれと変わらず、という測定結果でした。

また、LouiS0616様のコメントにもありますように、もはやcsvとして役立っているのかは、疑問です。Pythonのndarrayを ファイルに読み書きしたい、というニーズであれば、csvにこだわらないほうがよいでしょう。np.saveを使えば、型情報も保存でき、魔術的な変換も不要で、0.1秒で処理完了します。

投稿2020/11/07 01:06

編集2020/11/07 01:35
toast-uz

総合スコア3266

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

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

0

なるべくForは使わずに、joinなどを使用する方が早いと思いますが、
確認していないのでどれくらい早くなるかはわからないですね

for文での遅延だけでなく、ファイルIOの遅延も考えると、
あらかじめlistをcsv形式のstringに変換しておいて
書き込むことの方が早いです

Python

1import numpy as np 2 3sample = [[[0,0,0],[5,5,5]],[[1,1,1],[2,3,2]]] 4 5def ndarray_to_csv(file_name, ndarray): 6 ndarray = "\n".join([",".join([str(n) for n in narray]) for narray in ndarray]) 7 with open(file_name, 'w') as f: 8 f.write(ndarray) 9 10ndarray_to_csv('sample.csv', sample) 11print(sample)

コードはsampleがlistの場合に動作するので
ndarrayをlistに変換する処理を追加すれば、動作すると思います

投稿2020/11/07 00:30

編集2020/11/07 00:39
Moineau26518805

総合スコア44

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問