比較的長めの文章(txtで40MB,おそらく80万行ほど)から1行ごとにre.finditerで特定の文字列を取り出し、
numpyの2次元配列に結合する、というコードを書きました。
序盤は対象配列を抽出、クリーニング、arrayに結合 まで0.01sec程度で終わっていたのですが
次第に遅くなり、0.1sec、0.3secと遅くなり続けています。
python
1for string in re.finditer(("some_regex"),txt, re.MULTILINE): 2 get = string.group() 3 get_2 = string.group(1) 4 ##re split subなどで整形 5 cleaned_data = [datax,datay,dataz] 6 array = np.vstack((array,cleaned_data))
このようなコードです。
遅くなる原因としてarrayのデータ量が大きくなっていきvstackの際に時間がかかっているのでは
と考えました。
そのため、for内部にカウンターを設置しカウンターが1000になるまでは一時保存配列に整形データを格納、
1000を超えたらarrayに格納、というようにすればarrayの呼び出し回数が減り処理速度の遅延も回避できるかと思ったのですが
他になにか良い方法があれば教えていただきたいです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答3件
0
1行が50byteの文章のデータで80万行ということであれば、Numpy ではなくて Pandas を使った方が便利です。データの内容が質問の中にないので詳しいことは書けませんが、以下のコードで基本的なところの処理はできて、残りの処理は str アクセサーを使えばできると思います。
import pandas as pd df = pd.read_csv(filepath, header=None) df = df[0].str.extract("some_regex")
パフォーマンスは、通常の python の処理とあまり変わらないと思いますが、コードは分かり易くなります。また、Numpy を使いたいのであれば、Pandas の Series から変換すればいいです。
文章がどういうデータになっているかを質問に追記してもらえれば、もう少し詳しコードを書くことが可能です。
投稿2019/06/07 04:42
編集2019/06/07 04:44総合スコア584
0
すでにquiquiさんの回答されている通り、np.appendはただでさえ遅い操作であり、更に文字列をnumpy配列に格納するとデフォルトでは固定長フォーマットで取り扱われるためメモリ効率も悪くなります。
基本的にはlistで取り扱うことを推奨しますが、どうしてもnumpy配列に格納したい場合は、object型を使えば固定長フォーマットになる問題だけは解消し、pythonのstr(※python3前提)をlistに格納したのと同等になります。
この場合はpythonの演算子を使った基本的な文字列操作を一括で適用できるほか、indexingなどnumpy配列のリッチな機能も使えるので、用途によってはありかもしれません(コードが書きやすいというだけで、パフォーマンス自体は愚直にループなどを使って書くのと大差ないはずです)。
python
1>>> import numpy as np 2>>> a = ["hoge", "fuga", "piyo", "hogehoge", "fugafuga", "piyopiyo"] 3>>> np.array(a) 4array(['hoge', 'fuga', 'piyo', 'hogehoge', 'fugafuga', 'piyopiyo'], 5 dtype='<U8') 6>>> np.array(a, dtype=object) 7array(['hoge', 'fuga', 'piyo', 'hogehoge', 'fugafuga', 'piyopiyo'], 8 dtype=object) 9>>> a = np.array(a, dtype=object) 10>>> a + "!" 11array(['hoge!', 'fuga!', 'piyo!', 'hogehoge!', 'fugafuga!', 'piyopiyo!'], 12 dtype=object) 13>>> a * 2 14array(['hogehoge', 'fugafuga', 'piyopiyo', 'hogehogehogehoge', 15 'fugafugafugafuga', 'piyopiyopiyopiyo'], dtype=object) 16>>> a[[1,3]] 17array(['fuga', 'hogehoge'], dtype=object)
投稿2019/06/06 18:06
編集2019/06/06 18:09総合スコア30939
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
ベストアンサー
numpy.ndarrayは固定の大きさの配列を効率よく操作するためのデータ構造ですから……。
単純なタプルのリストでいいのではないですか。
どうしてもnumpy.ndarrayが欲しいなら最後にnumpy.ndarrayにすればいいかと。
In [1]: import numpy as np In [2]: def arr(n): : a = np.array([['', '']]) : for i in range(n): : data = [(str(i), str(i+1))] : a = np.vstack((a, data)) : return len(a) : : In [3]: def list_append(n): : """ひとつのリストに追加していく""" : a = [('', '')] : for i in range(n): : data = [(str(i), str(i+1))] : a.append(data) : return len(a) : In [4]: def list_new(n): : """連結したリストを都度新しく作る""" : a = [('', '')] : for i in range(n): : data = [(str(i), str(i+1))] : a = a + data : return len(a) : In [5]: %timeit arr(10000) == 10001 245 ms ± 56.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) In [6]: %timeit list_append(10000) == 10001 8.12 ms ± 978 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) In [7]: %timeit list_new(10000) == 10001 241 ms ± 48.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
このコード片だけだとdtypeがわかりませんが、numpy.ndarrayは固定の大きさの配列を背後に持っている以上、
配列の大きさ×(入っている文字列の最大長×α)
のメモリを使います。
In [1]: import numpy as np In [2]: np.array([['0', 'a']]) Out[2]: array([['0', 'a']], dtype='<U1') In [3]: np.vstack((np.array([['0', 'a']]), [['bbbbb', 'ccccc']])) Out[3]: array([['0', 'a'], ['bbbbb', 'ccccc']], dtype='<U5') In [4]: np.array([['0', 'a']]).nbytes Out[4]: 8 In [5]: np.array([[['0', 'a'], ['b', 'c']]]).nbytes Out[5]: 16 In [6]: np.array([[['0', 'a'], ['bbbbb', 'ccccc']]]).nbytes Out[6]: 80
vstackによって、もともとの「入っていた文字列の最大長」より長い文字列を追加するとdtypeが変わっているのが分かりますか。
固定の配列の大きさがdtypeの変化に見合った分大きくなっているのが分かりますか。
質問のソースはnumpy.ndarrayを使うメリットを捨てて、デメリットばかりを背負っているように見えます。
(再度ですが、このコード片だけで想像できる範囲の話です。「dtypeがobjectにしてる」とか、「そういったことが起きないように注意を払っている」なら後半は無視していただいてかまわないのですが、この質問が出るということはそうではないだろうとも想像します)
投稿2019/06/06 03:18
編集2019/06/06 03:20総合スコア11299
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。