Python Dashによりデータ分析結果の共有を効率化する取り組み

ogp

はじめに

こんにちは、検索基盤部の伊澤です。検索基盤部では普段から、ZOZOTOWNの検索機能に関するデータ分析や、データ分析を踏まえた検索性能の改善に取り組んでいます。

検索に関するデータ分析では、検索クエリの傾向把握や課題のあるクエリの特定のために、検索クエリごとの検索結果のクリック率やコンバージョン率といったパフォーマンス指標を評価しています。

本記事では、検索クエリごとのデータ分析に関する情報共有を効率化するため、ウェブフレームワークの「Dash」で開発したダッシュボードを活用した事例を紹介します。

目次

検索クエリごとのデータ分析の重要性

ZOZOTOWNでは、ユーザーが欲しい商品を見つけやすくするために、以下のような検索機能を提供しています。

  • ユーザーが検索クエリを入力した際に、入力の続きを補完したキーワードを提示するサジェスト機能
  • 検索結果の並び順を最適化するおすすめ順検索
  • 検索の絞り込みクエリ提案機能

サジェスト機能の詳細は以下の記事をご参照ください。

techblog.zozo.com

おすすめ順検索については以下の記事をご参照ください。

techblog.zozo.com

ZOZOTOWNの検索の絞り込みクエリ提案機能は、以下の赤枠内に設置されています。ここで表示されているキーワードをクリックすることで、そのキーワードにより検索をさらに絞り込むことができます。

絞り込みクエリ提案機能

これら検索関連の機能の改善を進めるために、検索全体の商品クリック率やコンバージョン率だけではなく、検索クエリごとの指標を評価して効果的な検索クエリとそうでない検索クエリを把握することも必要です。これにより、適切な検索結果が表示されない検索クエリを特定し、改善の余地を見つけることができます。

例えば、おすすめ順検索においては、検索回数に対して商品クリック数やコンバージョン数が少ないような検索クエリを把握できれば、ランキングが効果的でない検索クエリを特定できます。

サジェスト機能や絞り込みクエリ提案機能では、検索クエリごとのパフォーマンス指標から、次に提案すべきクエリの示唆を得ることができます。

このように、「検索クエリごと」のパフォーマンス指標を把握することも重要となります。検索基盤部では、検索クエリごとのパフォーマンス指標を把握し、チーム内で共有して次の施策の改善案や優先順位を検討しています。

分析結果のチーム内共有時の課題

データ分析結果のチーム内共有時には、以下のような課題がありました。

  • 膨大な検索クエリパターン:検索クエリごとの分析といってもそのパターンは膨大であり、それらを一覧で見て判断することは困難。そのため、検索回数の上位数十件に焦点を当てた限定的な範囲での結果の共有となってしまう。
  • ファッション業界の季節性:ファッションの世界では、季節性によって検索されるクエリは日々更新されるため、検索クエリごとの分析結果も日々変化する。そのため分析も高頻度で行うことになるが、共有のためのグラフやテーブルをその都度作り直すことには非常に大きな手間がかかる。
  • チーム内での検索クエリへの関心の違い:チームメンバーの関心のある検索クエリが異なる場合、共有時のグラフに含まれない検索クエリはその場で確認できないことになる。

こうした課題を解決し、効率的な分析と共有を可能にするため、共有時にチームメンバーがインタラクティブに確認できるような状況を整える必要があります。

Dashを用いたダッシュボードの開発

上述の問題を解決するために、各検索クエリに関する商品クリック率やコンバージョン率をインタラクティブに可視化するダッシュボードを開発しました。

ダッシュボードの開発にあたっては、Pythonのウェブフレームワークである「Dash」を用いました。

Dashとは

Dashは、Pythonでデータアプリケーションを開発できるウェブフレームワークです。少ないプログラムコード(Low-Code)で、様々なグラフや表を表示するダッシュボードを開発できます。

dash.plotly.com

以下にサンプルコードとサンプルアプリケーションのイメージを示します。サンプルコードは、公式のA Minimal Dash Appを参考にしています。

from dash import Dash, dcc, html, callback, Output, Input
import plotly.express as px
import pandas as pd

# サンプルデータを作成
data = {
    'category': ['tops', 'tops', 'tops', 'bottoms', 'bottoms', 'bottoms'],
    'sub_category': ['t-shirt', 'polo', 'knit', 'denim', 'cargo', 'chino'],
    'value': [10, 20, 15, 25, 20, 30]
}
df = pd.DataFrame(data)

# Dashアプリを作成
app = Dash(__name__)

# レイアウトを定義
app.layout = html.Div([
    html.H1('Sample Dash App'),
    dcc.Dropdown(df.category.unique(), 'tops', id='dropdown'),
    dcc.Graph(
        id='bar-chart',
        figure=px.bar(df, x='sub_category', y='value', title='Sample Bar Chart')
    )
])

# コールバックを定義
@callback(
    Output('bar-chart', 'figure'),
    Input('dropdown', 'value')
)
def update_bar_chart(value):
    dff = df[df.category == value]
    return px.bar(dff, x='sub_category', y='value', title='Sample Bar Chart')

if __name__ == '__main__':
    app.run_server(debug=True)

サンプルコードでは、レイアウトとコールバック関数を定義しています。レイアウト内のDropdownコンポーネントにidを付与し、コールバック関数内のInputにDropdownコンポーネントのidを指定しています。これにより、Dropdownコンポーネントの値が変化した時にコールバック関数が呼び出され、コールバック関数のOutputに指定したグラフの値を更新できます。

上記のコードだけで、以下のようなアプリケーションを立ち上げることができます。

サンプルアプリケーション

その他、公式のサイトにサンプルアプリケーションが豊富にあります。Dashでどんなことができるか知りたい方は、以下を参照してください。

plotly.com

Dashを選定した理由

今回、検索クエリごとのパフォーマンス指標のダッシュボードを作成するにあたっては、以下の理由からDashを選定しました。

  • Low-Codeでクイックにダッシュボードを開発できる
  • Plotly」のグラフをダッシュボードに統合できる
  • コンポーネントが豊富にありレイアウトのカスタマイズ性が高い

Low-Codeでクイックに開発ができる点は、上記で見たように、レイアウトとコールバック関数を定義するだけでインタラクティブなダッシュボードを作成できることから明らかです。

Plotlyは、様々なグラフを描画するPythonのライブラリです。Plotlyで作成したグラフに対しては、グラフ上でデータポイントをホバーして詳細を表示する、ズームする、グラフ内の範囲を選択するなどのインタラクティブな操作が可能です。Dashでは、dcc.Graphモジュールを使って、Plotlyのグラフをアプリケーション内で表示できます。Plotlyのグラフに対するレイアウトやスタイルのカスタマイズも可能です。

さらに、Dashには、入力フォーム、ドロップダウン、ボタン、テーブルなど、オープンソースのコンポーネントが豊富にあります。これらのコンポーネントを組み合わせて、用途に応じたダッシュボードを作成できます。

Dashのほかにも、Low-Codeのウェブフレームワークとしては、Streamlitがあります。Streamlitを使っても、データ処理と可視化を一貫して行うことができます。しかし、Dashと比べてレイアウトのカスタマイズに制限があります。今回のダッシュボードについては、テーブルとグラフを水平方向に並べる際、レイアウトの微調整を必要としました。StreamlitではCSSを用いたスタイルの適用は困難ですが、Dashでは各コンポーネントモジュールにstyleを指定することでレイアウトの微調整が可能であるため、Dashを用いることとしました。

検索クエリごとのパフォーマンス指標のダッシュボード

今回作成した、検索クエリごとの商品クリック数、コンバージョン数(または率)を可視化したダッシュボードを紹介します。

ダッシュボードは、パラメータに分解した検索クエリを格納したテーブルと、各検索クエリに対応するパフォーマンス指標を表示するグラフで構成されています。

以下はダッシュボードのイメージです(グラフには適当な値を入れています)。

ダッシュボードイメージ

今回のダッシュボードには、以下の要素が含まれています。

  1. 検索クエリごとのパフォーマンス指標のテーブル(左下)
  2. 検索クエリごとのパフォーマンス指標のグラフ(右下)
  3. テーブルやグラフを操作するコントローラー(上部)

これらの要素を順に説明します。

1. 検索クエリごとのパフォーマンス指標のテーブル

ダッシュボードの左下にあるテーブル(下図)では、検索クエリを各パラメータ(ショップ、ブランド、カテゴリー等)をそれぞれのカラムに分割して表示しています。このテーブルは公式ドキュメントの「DataTable Interactivity」を参考に作成しました。

テーブル

このテーブルには、ソート機能、フィルタ機能、ページング機能があります。ソート機能は、カラム名の横の三角形をクリックすることで使用でき、そのカラム内の値でテーブル全体をソートできます。また、フィルタ機能では、指定したフィルタの条件でデータを絞り込むことができます。紹介したイメージでは、platformがPCの検索クエリに絞って表示しています。さらに、ここでは1ページに20件の検索クエリを表示していますが、テーブル下部のページング機能から次の20件のデータを表示できます。

2. 検索クエリごとのパフォーマンス指標のグラフ

右下のグラフ(下図)は、テーブルの検索クエリごとの検索回数、商品クリック数、コンバージョン数を表示しています。テーブルのunique_idとグラフのunique_idによって、テーブル内の行とグラフ内のバーが対応しています。グラフの描画にはPlotlyを使っているため、ホバーやズーム等の操作ができます。

グラフ

このグラフはテーブルの内容と連動しており、テーブルへの操作が行われるとコールバック関数が呼ばれてグラフも更新されるようになっています。

以下に、コールバック関数update_graphの内容を説明します。Input("table", "data")としており、これによりid"table"であるコンポーネントのdataが変わった時にupdate_graph関数が呼ばれます。update_graph関数は、変更されたデータを受け取って新しいグラフを作成し、新しいグラフを格納したコンポーネントを返します。update_graph関数から返ってきた内容で、Outputに指定したid="graph-container"を持つhtml.Divの中身が置き換えられ、表示されるグラフが更新されます。

# レイアウトを定義
app.layout = html.Div(
  [
    ...
      html.Div(
        dash_table.DataTable(
          id="table",
          ...
        )
      ),
      ...
      html.Div(id="graph-container"),
    ...
  ]
)

@app.callback(
  Output("graph-container", "children"),
  Input("table", "data"),
  Input("radio-button", "value"),
)
def update_graph(queries: list[dict], radio-option: str) -> html.Div:
  fig = go.Figure()
  # データの更新処理およびグラフの作成処理
  ...
  # 更新したグラフを格納したコンポーネントを返す
  return dcc.Graph(
    id="bar-chart",
    figure=fig
  )

3. テーブルやグラフを操作するコントローラー

上部のコントローラーには、データを検索クエリのパラメータでグルーピングするドロップダウン(下図左)と、グラフの表示データを切り替えるラジオボタン(下図右)を配置しています。

コントローラー

検索クエリのパラメータでのグルーピングには、先ほどのサンプルアプリケーションでも使用していたDropdownコンポーネントを使用しています。Dropdownコンポーネントでmulti=Trueとすることで、複数のオプションから選択できるようになります。このドロップダウンからパラメータを選択すると、選択したパラメータでデータがグルーピングされ、その結果がテーブルに反映されます。

dcc.Dropdown(
  id="multi-select-dropdown",
  options=dropdown_options,
  value=dropdown_options,
  multi=True,
)

ラジオボタンでは、グラフの数と率の表示を切り替えることができます。以下のラジオボタンのコードでは、inputStyleでコンポーネントに適用するスタイルを指定しています。これはRadioButtonに限らず、そのほかのコンポーネントでも同様にスタイルを指定できます。

dcc.RadioItems(
  radio_options,
  "absolute",
  id="radio-button",
  inline=True,
  inputStyle={
      "margin-left": "15px",
      "margin-right": "5px",
  },
)

今回作成したダッシュボードによって、表示するデータの範囲やパラメータの種類などをインタラクティブに操作しながら、検索クエリごとのパフォーマンス指標を可視化できるようになりました。

ダッシュボードによる情報共有の効果

今回のダッシュボードを用いるようになったことで、データ分析結果の情報共有時に以下の効果が得られました。

まず、効率的に共有が行えるようになりました。従来、データ分析のたびに、グラフやテーブルを作成してそれらをドキュメントにまとめる作業が必要でした。ファッション業界の季節性もありデータ分析結果の共有の頻度も高く、そのたびに新たなドキュメントを作成する手間が発生していました。今回のダッシュボードの導入により、共有のためのグラフやテーブルを手動で作り直す手間を軽減できました。これにより、定型作業から解放されたことで、分析や洞察に集中することが可能となりました。

さらに、インタラクティブな情報共有が可能になりました。これまでは、情報が一方的に共有されるだけであり、チームメンバーが共有された検索クエリ以外に関心がある場合はその場で確認することが困難でした。今回のダッシュボードにより、報告者以外のメンバーもデータを操作し、必要な情報を自由に探索できるようになりました。これにより、共有時のミーティングが対話的なものとなり、意見交換や意思決定が円滑に行えるようになりました。

まとめ

本記事では「Dash」を用いて検索クエリごとのパフォーマンス指標をインタラクティブに可視化した事例を紹介しました。

今後は、このダッシュボードを拡張させ、検索に関するそのほかのデータも可視化することで、さらに課題抽出や意思決定を加速化していきたいと考えています。

ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。

corp.zozo.com

カテゴリー