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