tag:crieit.net,2005:https://crieit.net/tags/Spark/feed 「Spark」の記事 - Crieit Crieitでタグ「Spark」に投稿された最近の記事 2021-04-05T16:34:35+09:00 https://crieit.net/tags/Spark/feed tag:crieit.net,2005:PublicArticle/16818 2021-04-05T16:27:16+09:00 2021-04-05T16:34:35+09:00 https://crieit.net/posts/MMR-Pyspark MMRアルゴリズムをPysparkで実装する <p>レコメンド結果にMMRを適用して多様性を考慮したかった。<br /> 以下のようにPythonで実装されているコードはあったが、Pysparkで実装れているサンプルがなかったので実装してみた。</p> <p><a target="_blank" rel="nofollow noopener" href="https://yolo-kiyoshi.com/2020/05/08/post-1781/">MMR実装を参考にしたページ</a></p> <h2 id="実装コード"><a href="#%E5%AE%9F%E8%A3%85%E3%82%B3%E3%83%BC%E3%83%89">実装コード</a></h2> <h3 id="モジュールインポート"><a href="#%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E3%82%A4%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%88">モジュールインポート</a></h3> <pre><code class="python">from pyspark.sql import DataFrame as SDF from typing import Set, Callable, List import pyspark.sql.functions as F </code></pre> <h3 id="検索クエリとアイテムリストの類似度結果を取得する関数"><a href="#%E6%A4%9C%E7%B4%A2%E3%82%AF%E3%82%A8%E3%83%AA%E3%81%A8%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0%E3%83%AA%E3%82%B9%E3%83%88%E3%81%AE%E9%A1%9E%E4%BC%BC%E5%BA%A6%E7%B5%90%E6%9E%9C%E3%82%92%E5%8F%96%E5%BE%97%E3%81%99%E3%82%8B%E9%96%A2%E6%95%B0">検索クエリとアイテムリストの類似度結果を取得する関数</a></h3> <pre><code class="python">def sim_func(df: SDF, item_id: int, rec_item_id: int) -> float: min_score = df.filter(F.col('item_id') == item_id).groupBy().min('score').collect()[0][0] try: score = df.filter((F.col('item_id') == item_id) & (F.col('rec_item_id') == rec_item_id)).collect()[0]['score'] except: score = min_score return score </code></pre> <h3 id="選択済みアイテムがオリジナルのアイテムと同じ集合になるまでLOOP"><a href="#%E9%81%B8%E6%8A%9E%E6%B8%88%E3%81%BF%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0%E3%81%8C%E3%82%AA%E3%83%AA%E3%82%B8%E3%83%8A%E3%83%AB%E3%81%AE%E3%82%A2%E3%82%A4%E3%83%86%E3%83%A0%E3%81%A8%E5%90%8C%E3%81%98%E9%9B%86%E5%90%88%E3%81%AB%E3%81%AA%E3%82%8B%E3%81%BE%E3%81%A7LOOP">選択済みアイテムがオリジナルのアイテムと同じ集合になるまでLOOP</a></h3> <pre><code class="python">def mmr(df: SDF, items: Set[int], item_id: int, lambda_: float, sim_func1: Callable[[SDF, int, int], float], sim_func2: Callable[[SDF, int, int]) -> List[int]: def _argmax(keys, f): return max(keys, key=f) selected = [] while set(selected) != items: remaining = items - set(selected) mmr_score = lambda x: labmda_ * sim_func1(df, item_id, x) - (1 - lambda_) * max([sim_func2(df, x, y) for y in set(selected)-{x}] or [0]) next_selected = _argmax(remaining, mmr_score) selected.append(next_selected) return selected </code></pre> <h3 id="MMR実行"><a href="#MMR%E5%AE%9F%E8%A1%8C">MMR実行</a></h3> <pre><code class="python">mmr( df, set(list(df.filter(F.col('item_id') == 12345678).select('rec_item_id').toPandas()['rec_item_id'])), 12345678, 0.8, sim_func, sim_func ) </code></pre> skybee8