はてだBlog(仮称)

私的なブログど真ん中のつもりでしたが、気づけばWebサイト系のアプリケーション開発周りで感じたこと寄りの自分メモなどをつれづれ述べています。2020年6月現在、Elasticsearch、pandas、CMSなどに関する話題が多めです。...ですが、だんだんとより私的なプログラムのスニペット置き場になりつつあります。ブログで述べている内容は所属組織で販売している製品などに関するものではなく、また所属する組織の見解を代表するものではありません。

Pandas(もしくはPython)のオレオレイディオム

はじめに

Elasticsearchに取り込むにはそのままではちょっとアレかなという類のデータを手間をかけずにPandasでデータ変換するにはというテーマで考え事をしてみました。

「よくある例」なのかは断言できませんが、ボキャブラリーとして手札にあれば、間に合わせには悪くないのではというもののサンプルコードの例をあげています。

なお、この記事は、次の記事の親戚記事です。

itdepends.hateblo.jp

↑ この記事は、本当にただのシンタックス一覧に過ぎないので、もう少しデータ処理っぽいことのさわりになるようなことをこの記事で補足しました。

itdepends.hateblo.jp

↑ この記事で使っているテクニック(?)を、もっと短めの本記事で少し分解してみたというものになります。

EAVデータ風のデータをJSONらしい体裁にバラす

ストーリー

SQLアンチパターンのEAVパターンをさらにこじらせて、オブジェクトの配列で保持している。 なんぼなんでもと思う面もあるが、このような複数のシステムからなるデータソースのデータを固定のデータフォーマットで永続化してレポジトリに保持しているといった場合にはないわけでもないのではと思ってストーリー設定。

→ このようなデータを、シンプルなJSONオブジェクトに変換する。

※ Pandasというよりは、dict(JSON)データのネスト階層の変換の例。   (是非は別として)この類のメタな処理が、型の扱いが緩めな言語では取り扱いしやすい。(取り扱いしやすい ≒ ひとまず動かすまでのタイプ量が少ない)

DataFrame中のJSON(dict)格納データの重複確認

この例におけるイディオム

  • PandasのDataFrameのある1列にJSON(dict)を保持している場合のグループ化・重複確認
  • ※ 処理の見栄えとしては重複確認だが、ストーリーとしては、おおよそ同一データであるとして「名寄せによるデータ統合・ユニーク化」できるはずだが、そうでないものが混ざっていて、そのようなものを見つけたいという方向性。
  •  ※ Pythonにおいてのdictの比較は、元にしたJSONなどのプロパティの並び順には関係なく(もともと意味がないので当たり前だが)同じものは同じとして比較できるが、Pandasは通常の型であれば重複確認の標準関数があるが、dictの場合は不可なので、別のアイディアを活用。
  • 重複チェック(上記のとおりどちらかといえば、ユニークにできない不明データの存在チェック)時の切り分けフラグ(ここでは、has_cousinというプロパティでラベルづけすることにした)を付与するような論理。
  • 名寄せによるデータ統合を行うが、名寄せ条件に含めないあるカラムの値については、配下のレコードのうち、これこれの値があれば、それを統合データの値とする...のような「生き」の条件をforループを使わずに選定する論理の例。
  • その他、上記のようなユースケースにありがちなちょっとしたクレンジングの小品をいくつか。

関連エンティティ相当のテーブルの情報を重心側のデータを軸にしたJSONデータに変換

ストーリー

多少デフォルメして説明すると、

cust_id product_cd
111 AAA
111 CCC
111 DDD

↑このようなデータを次↓に変換します。

[
  { "cust_id" : 111, "product_cd" : ["AAA", "CCC", "DDD"] },
...
]
 

関連エンティティ相当のテーブルの情報を、1対Nの1側の情報を軸にして、1側をキーとしたJSON情報に非正規化する。

イディオム

  • pd.mergeで、コード値と表示名マスタを結合して、表示名を取得。
  • 列Xでグループ化し、グループしたレコードについて、列Yの値を配列に詰め込みする。→ そのグループ内の列Yの値のバリエーションを得る。
  • 列Xのグループ化の対象とする行は、列Zの値がxxxのもののみ(以下では、SPECIALSという定数で定義)とする、といった条件付きのグループ化とする。

関連エンティティ風のデータの前日と当日の比較

ストーリー

昨日と今日の契約期中の取引情報全件(ただし、関連エンティティ型となっており、顧客単位に名寄せする必要がある)があって、変更があった顧客のリストを抜き出す。

この例で示しているイディオム

  • 昨日と今日それぞれの顧客単位の取引の配列の一覧を作成。
  • 上記を顧客IDで完全外部結合して、左に存在するが右に存在しないものは契約終了の顧客...のように変更検知する。

JSON中のNULL項目についてはプロパティを出力しない(そのような項目を取り除く)

ストーリー

DataFrameは便利だが、項目数が多い場合、いわゆるスパースマトリックスの無駄が発生する。また、項目の中にネストされているようなデータがある場合も何かと無駄が悩ましい。 このような状況において、スパースマトリックスの問題自体は他の場に譲るとして、最終結果をJSONファイルに出力する際に、Nullの項目についてはプロパティ名を出力しないようにすることで、データをコンパクトにする...という例。

※という意味では、andasのイディオムというよりは、dict(JSONと相互変換可能なものに限定されるが、JSONの範囲であれば、ネストが複雑でも再起によってなんとかなる)の再起処理の例に該当。

以上です。