結論
割と大きめのデータ処理をしている時、もっと処理速度を早くしようと思って色々いじっていたら、reduceよりappendの方が断然早かった話
はじめに
実行時間計測に使用するデータはこれで生成
import random
data_list = [random.randint(-2, 2) for _ in range(100000)]
作ったデータをどのように処理したいかというと、
配列のある要素x_nとその要素のひとつ前x_(n-1)を加算した新しい配列を生成したい↓
[1, 2, -1, -2] => [1, 3, 2, 0]
ループ処理
appendメソッドを使う
def append_loop(data):
out_put = [data[0]]
for i in data[1:]:
out_put.append(out_put[-1] + i)
return out_put
# 実行時間: 0.019423961639404297
appendは破壊的メソッドとよばれ、思わぬバグを発生させることが多く。また空の配列を用意しなくてはいけないため、コード量がその分多くなったりするので割と避けていたが速度は非常に早かった。
reduce
def reduce_append(li, elem):
return [elem] if not li else li + [li[-1] + elem]
# 実行時間: 11.915228843688965
reduce(reduce_append, data_list, [])
reduceを使う場合は非常にコード簡潔になるが、速度に関しては大きな差が開いている。およそ600倍の時間がかかっている。
これにはif文があるから実行時間が遅くなった可能性があるので、少々可読性は落ちるが、そのパターンも作成
def reduce_append(li, elem):
return li + [li[-1] + elem]
# 実行時間: 10.55799412727356
reduce(reduce_append, data_list[1:], [data_list[0]])
実行時間は1秒くらいしかかわらなかった。
おまけ
内包表記
[sum(data_list[:i + 1]) for i in range(len(data))]
# 実行時間: 86.43631505966187
一行でかけるが、遅すぎて使い物にならない。sum関数自体にループがあるからしゃーない
再帰関数
@tail_recursion
def recursive_function(result_array, origin_array, index):
if len(result_array) > 0:
result_array.append(result_array[-1] + origin_array[index])
else:
result_array.append(origin_array[0])
if len(origin_array) > index + 1:
return recursive_function(result_array, origin_array, index + 1)
# 実行時間: 0.08165287971496582
recursive_function(result, data_list, 0)
わかりにくいがそこそこはやい。テクニークの練習にはなる。
おわり
append使うのはダサいとか、カッコ悪いとか、初心者とかおもっていたけどちょっと見直しました。まぁ私、初心者なんですが笑
なにか他に良い方法があったら教えてくださいヽ( ◔ ౪ ◔ )ノイッパツデコンパイルトオッタァァァァwwwwww