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

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

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

Elasticsearchは、クラウド向けに構築された、RESTful な API を提供する分散型のサーチエンジンアプリケーションです。

Python 3.x

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

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

Q&A

解決済

2回答

4848閲覧

pandas.dataframeのiterrowsが遅すぎる

zenji0705

総合スコア69

Elasticsearch

Elasticsearchは、クラウド向けに構築された、RESTful な API を提供する分散型のサーチエンジンアプリケーションです。

Python 3.x

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

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

pandas

Pandasは、PythonでRにおけるデータフレームに似た型を持たせることができるライブラリです。 行列計算の負担が大幅に軽減されるため、Rで行っていた集計作業をPythonでも比較的簡単に行えます。 データ構造を変更したりデータ分析したりするときにも便利です。

0グッド

0クリップ

投稿2020/05/20 22:45

編集2020/05/20 22:47

閲覧ありがとうございます。

dataframe型に格納されているデータをElasticSearchにbulk insertしようと考えております。

一旦、dataframeの中をiterrowsでループしながら、ElasticSearchのbulk insert用に成形してESに登録したのですが、50万件登録するのに5分くらいかかってしまうので、速度を改善したいです。

iterrowsはもともと遅いってことが文献にのっていたのですが、代替案(mapを使う、不要なインスタンスを作らないコーディング等)を調べたのですが、知識不足で実装することが困難です。

下記にソースを記載しますので、改善策をアドバイスいただけると助かります。

python3

1def es_doc_generator(df): 2 """ 3 ES登録ドキュメント生成  4 """ 5 # パフォーマンスチューニング中 6 doc = [] 7 for d in df.iterrows(): 8 doc = [{key: d[1][key] for key in d[1].keys()}] 9 10 # イメージ:log-20200725 11 tdatetime = datetime.datetime.strptime(doc[0]['eventTimestamp'], '%Y-%m-%d %H:%M:%S') 12 index = "log-" + str(tdatetime.year) + str(tdatetime.month) + str(tdatetime.day) 13 yield { 14 "_index": index, 15 "_id": doc[0]['SeqNo'], 16 "_type": "_doc", 17 "_source": doc[0], 18 } 19 20def es_insert(df): 21 #- Elasticsearch定義ファイル読み込み 22 __es_dict = read_es_conf(ES) 23 24 #- Elasticsearch接続 25 __esCon = es_connect(__es_dict) 26 27 # ESデータをbulk投入 28 helpers.bulk(__esCon,es_doc_generator(df)) 29 30if __name__ == "__main__": 31 # df 32 33 df = pd.DataFrame({'A': ['A1', 'A2', '2020/05/21 12:00:00','001'], 34 'B': ['B1', 'B2', '2020/05/22 12:00:00','002'], 35 'C': ['C1', 'C2', '2020/05/22 13:00:00','003']}, 36 index=['ONE', 'TWO', 'eventTimestamp','Seq']) 37  es_insert(df) 38

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

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

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

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

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

guest

回答2

0

ベストアンサー

メモリ的に問題ないのであれば、先に DataFrameをDataFrame.to_dict() を使って 行ごとにdict化したリストデータを作成しておき、そのリストをループするとよいのではないでしょうか。

動作確認

Python

1import pandas as pd 2import datetime 3 4def es_doc_generator(df): 5 # 行毎にdict化しておく 6 sources = df.to_dict('record') 7 # eventTimestamp列より indexのリストを作成しておく 8 indexes = pd.to_datetime(df['eventTimestamp']).dt.strftime('log-%Y%m%d').values 9 # SeqNo列より idのリストを作成しておく 10 ids = df['SeqNo'].values 11 # 上記で作成した データを纏めてループで回す 12 for index, id, source in zip(indexes, ids, sources): 13 yield { 14 "_index": index, 15 "_id": id, 16 "_type": "_doc", 17 "_source": source, 18 } 19 20df = pd.DataFrame([['A1', 'A2', '2020/05/21 12:00:00','001'], 21 ['B1', 'B2', '2020/05/22 12:00:00','002'], 22 ['C1', 'C2', '2020/05/22 13:00:00','003']], 23 columns=['ONE', 'TWO', 'eventTimestamp','SeqNo']) 24 25for data in es_doc_generator(df): 26 print(data)

上記のコードを実行した結果は以下のようになります

Text

1{'_index': 'log-20200521', '_id': '001', '_type': '_doc', '_source': {'ONE': 'A1', 'TWO': 'A2', 'eventTimestamp': '2020 2/05/21 12:00:00', 'SeqNo': '001'}} 3{'_index': 'log-20200522', '_id': '002', '_type': '_doc', '_source': {'ONE': 'B1', 'TWO': 'B2', 'eventTimestamp': '2020 4/05/22 12:00:00', 'SeqNo': '002'}} 5{'_index': 'log-20200522', '_id': '003', '_type': '_doc', '_source': {'ONE': 'C1', 'TWO': 'C2', 'eventTimestamp': '2020 6/05/22 13:00:00', 'SeqNo': '003'}}

次にダミーの50万件のデータを作成して、速度を測ってみます

import pandas as pd import time def es_doc_generator(df): sources = df.to_dict('record') indexes = pd.to_datetime(df['eventTimestamp']).dt.strftime('log-%Y%m%d').values ids = df['SeqNo'].values for index, id, source in zip(indexes, ids, sources): yield { "_index": index, "_id": id, "_type": "_doc", "_source": source, } # 50万件のダミーを作成 N = 500000 df = pd.DataFrame({ 'ONE': [f'{d:03d}' for d in range(N)], 'TWO': [f'{d:03d}' for d in range(N)], 'eventTimestamp': ['2000-01-01 00:00:00'] * N, 'SeqNo': [f'{d:03d}' for d in range(N)] }) # 50万件のループ処理の時間を計測する st = time.time() for d in es_doc_generator(df): pass print(f'elapsed_time: {time.time() - st:.3f} sec')

結果

elapsed_time: 3.606 sec

3秒そこそこで完了しますので、こちらの処理がボトルネックになることはないのではないでしょうか。

投稿2020/05/21 02:37

magichan

総合スコア15898

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

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

zenji0705

2020/05/21 22:19

コメントありがとうございました。ご指摘いただいた処理内容で実行したところ、数秒で対応することができました。あとはElasticSearchのバルクインサートもparallel_bulkによる分散登録もできるようなので、もっと早く処理できそうです。助かりました。
guest

0

mapを使わずに簡単に出来る範囲でという事ですか?

python

1loop=df.shape[0] 2for idx in range(loop): 3 print(df.loc[idx, 'columnname'])

でもmapで出来る事ならやはりmapを理解して使った方がいいです

投稿2020/05/20 22:59

hentaiman

総合スコア6426

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

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

zenji0705

2020/05/21 22:21

ご指摘ありがとうございます。mapを理解するよう意識します。locによる配列の座標のループも考えたんですが、あんまり早くならなかったのでうーん・・と唸っていた次第です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問