♪もしあなたのオンラインショップが顧客が何を求めているかを知っていたら?
♪
もしあなたのオンラインショップが顧客が何を求めているかを知っていたら?
Most recommendation engines are like helpful but slightly clueless assistants:有限で時代遅れのデータに基づいて「人気」または「類似」の項目を提案する。struggleユーザーが新しい場合(冷たいスタートの問題)で、ユーザーの好みがリアルタイムで変更された場合に適応することは稀です。
もし、あなたのシステムが、実際に考えるマーチャンダーのように、静的な製品データとリアルタイムのユーザー行動を表面に組み合わせる正しい項目正しいタイミングで?
実際に考える
This guide walks you through building a modern recommendation engine利用Superlinkedこれらの伝統的な欠点を克服し、データをベクトルネイティブインフラストラクチャを使用して動作可能で進化可能なユーザープロファイルに変換します。
(コードに直接ジャンプしたいですか? ここでGitHubのオープンソースコードをチェックしてください. あなた自身の使用例のために推奨システムを試してみる準備ができていますか? ここでデモを取得してください.)
ここここここここ
You can also follow along with the tutorial in-browser with ourコラボ
ドクター:
ほとんどの電子商取引の推奨業者は、あまりにも静的(ルールベース)またはあまりにもブラックボックス(曖昧なMLモデル)である。Superlinkedは、MLモデルを再訓練することなく、メタデータとライブ行動を組み合わせることによって、冷たいスタートユーザーに適応できる柔軟でリアルタイムの推奨方法を提供しています。
RecSys vector embeddingの課題にもかかわらず、パーソナライズ化を達成
ベクトル埋め込みは、勧告システムを大幅に改善することができるが、効果的に実装するには、以下を含むいくつかの課題に対処する必要がある。
- ♪
- 品質と関連性:埋め込み生成プロセス、アーキテクチャ、データは慎重に考慮する必要があります。 ♪
- Sparse and noisy data: Embeddings are less effective when they have incomplete or noisy input. Sparse data is the crux of the cold-start problem. Sparse and noisy data: Embeddings are less effective when they have incomplete or noisy input. Sparse data is the crux of the cold-start problem. Sparse data is the crux of the cold-start problem. ♪
- スケーラビリティ: 大規模なデータセットのための効率的な方法が必要ですが、そうでないと、遅延は問題になります。 ♪
Superlinked では、ユーザーや製品に関するすべてのデータを豊富な多様なベクターに組み合わせることで、これらの課題に対処できます。
- ♪
- min_max 数スペース:顧客レビューと価格情報を理解するために ♪
- text-similarity Space: for semantic understanding of product information テキスト-類似性 スペース: 製品情報のセマンティックな理解のために ♪
- Event Scheme and Effects to Modify Vectors エクスペリエンス ♪
- query time weights - to define how you want the data to be treated when you run the query, allowing you to optimize and scale without re-embedding the entire dataset (latency) クエリを実行するときにデータがどのように処理されるかを定義する ♪
当初はわずかなユーザー特有のデータ(ユーザーの初期の製品好み)を組み込むことで、冷たいスタートの問題に対処することができます。ハイパーこのイベントデータを埋め込み、リアルタイムでユーザーの好みを含むベクターを更新できるフィードバックループを作成することにより、推奨事項をパーソナライズする。
Let's get started!
Superlinked で電子商取引推奨エンジンを構築する
開発の初期段階では、次のようなものがあります。product data: :
- ♪
- レビュー数 ♪
- 製品評価 ♪
- テキスト説明 ♪
- 製品名(通常はブランド名を含む) ♪
- カテゴリ ♪
私たちはまた、次のdata about users and products: :
- ♪
- 各ユーザーは、登録時に3つの製品のうちの1つを選択します(すなわち、製品好みのデータ) ♪
- ユーザーの行動(登録後)は、追加のイベントデータを提供します - 製品のテキスト特性(記述、名前、カテゴリ)の好み ♪
また、古典的な経済学は、平均的に、すべてのユーザーがceteris paribusが以下のような製品を好むことを示しています。
- ♪
- コスト 少ない ♪
- たくさんのレビューが ♪
- より高い評価を得る ♪
私たちは、このデータを考慮に入れるようにスペースを設定し、RecSysが冷たいスタートシナリオで動作するようにします - 私たちがほとんど知らないユーザーにアイテムを推奨します. RecSysが起動すると、ユーザーは特定の製品をクリックし、特定の製品を購入します。
スーパーリンクの設定
まず、Superlinked ライブラリをインストールし、クラスをインポートする必要があります。
%pip install superlinked==6.0.0
import altair as alt
import os
import pandas as pd
import sys
from superlinked.framework.common.embedding.number_embedding import Mode
from superlinked.framework.common.schema.schema import schema
from superlinked.framework.common.schema.event_schema import event_schema
from superlinked.framework.common.schema.schema_object import String, Integer
from superlinked.framework.common.schema.schema_reference import SchemaReference
from superlinked.framework.common.schema.id_schema_object import IdField
from superlinked.framework.common.parser.dataframe_parser import DataFrameParser
from superlinked.framework.dsl.executor.in_memory.in_memory_executor import (
InMemoryExecutor,
InMemoryApp,
)
from superlinked.framework.dsl.index.index import Index
from superlinked.framework.dsl.index.effect import Effect
from superlinked.framework.dsl.query.param import Param
from superlinked.framework.dsl.query.query import Query
from superlinked.framework.dsl.source.in_memory_source import InMemorySource
from superlinked.framework.dsl.space.text_similarity_space import TextSimilaritySpace
from superlinked.framework.dsl.space.number_space import NumberSpace
alt.renderers.enable(get_altair_renderer())
pd.set_option("display.max_colwidth", 190)
また、データセットを定義し、トップ10の項目を保存するための常数を作成します。セル3ノートに
図書館がインストールされ、クラスがインポートされ、データセットの場所が特定されているので、当社のスペースを設定する方法についてデータセットを調べることができます。
# the user preferences come from the user being prompted to select a product out of 3 - those will be the initial preferences
# this is done in order to give somewhat personalised recommendations
user_df: pd.DataFrame = pd.read_json(USER_DATASET_URL)
user_df
我々はまた、我々の製品の配布データの詳細な調査を設定することができます - 参照セル5これは、いくつかの製品が異なる価格点にあり、異なるレビュー数を持っているか、異なる評価を持っているかを示します(製品の大部分がこれらの範囲内にある場所を含む)。
製品の価格は、主に1000ドルの価格ポイントの下にあります。当社はスペースの範囲を25〜1000に設定して、外部値によって歪曲されずに代表的なものにしたい場合があります。製品のレビュー数は均等に分布し、レビュー評価は比較的均等に分布しますので、追加の処理は必要ありません。バッテリー 7-9で。
ベクター検索のためのインデックスの構築
Superlinkedのライブラリには、インデックスを構築し、検索を管理するために使用するコアビルドブロックのセットが含まれています。ここで。
この図書館のビルドブロックを EComm RecSys で使用しましょう。define your Schemaあなたのデータについてシステムに伝える
# schema is the way to describe the input data flowing into our system - in a typed manner
@schema
class ProductSchema:
description: String
name: String
category: String
price: Integer
review_count: Integer
review_rating: Integer
id: IdField
@schema
class UserSchema:
preference_description: String
preference_name: String
preference_category: String
id: IdField
@event_schema
class EventSchema:
product: SchemaReference[ProductSchema]
user: SchemaReference[UserSchema]
event_type: String
id: IdField
# we instantiate schemas as follows
product = ProductSchema()
user = UserSchema()
event = EventSchema()
次に、スペースを使用して、埋め込む際にデータの各部分をどのように扱いたいかを示します。スペース定義では、入力を埋め込む方法を説明しますので、データのセマンティックな関係を反映します。
# textual inputs are embedded in a text similarity space powered by a sentence_transformers model
description_space = TextSimilaritySpace(
text=[user.preference_description, product.description],
model="sentence-transformers/all-distilroberta-v1",
)
name_space = TextSimilaritySpace(
text=[user.preference_name, product.name],
model="sentence-transformers/all-distilroberta-v1",
)
category_space = TextSimilaritySpace(
text=[user.preference_category, product.category],
model="sentence-transformers/all-distilroberta-v1",
)
# NumberSpaces encode numeric input in special ways to reflect a relationship
# here we express relationships to price (lower the better), or ratings and review counts (more/higher the better)
price_space = NumberSpace(
number=product.price, mode=Mode.MINIMUM, min_value=25, max_value=1000
)
review_count_space = NumberSpace(
number=product.review_count, mode=Mode.MAXIMUM, min_value=0, max_value=100
)
review_rating_space = NumberSpace(
number=product.review_rating, mode=Mode.MAXIMUM, min_value=0, max_value=4
)
# create the index using the defined spaces
product_index = Index(
spaces=[
description_space,
name_space,
category_space,
price_space,
review_count_space,
review_rating_space,
]
)
# parse our data into the schemas - not matching column names can be conformed to schemas using the mapping parameter
product_df_parser = DataFrameParser(schema=product)
user_df_parser = DataFrameParser(
schema=user, mapping={user.preference_description: "preference_desc"}
)
# setup our application
source_product: InMemorySource = InMemorySource(product, parser=product_df_parser)
source_user: InMemorySource = InMemorySource(user, parser=user_df_parser)
executor: InMemoryExecutor = InMemoryExecutor(
sources=[source_product, source_user], indices=[product_index]
)
app: InMemoryApp = executor.run()
# load the actual data into our system
source_product.put([products_df])
source_user.put([user_df])
Spaces でデータを定義した後、データと遊び、結果を最適化する準備ができています。イベントなしでできること冷たいスタートのソリューション
RecSys Cold-Start 問題の解決
ここでは、ユーザーの好みベクターのみで検索するユーザクエリを定義します.We have configuration control over the importance (weights) of each input type (Space).
user_query = (
Query(
product_index,
weights={
description_space: Param("description_weight"),
name_space: Param("name_weight"),
category_space: Param("category_weight"),
price_space: Param("price_weight"),
review_count_space: Param("review_count_weight"),
review_rating_space: Param("review_rating_weight"),
},
)
.find(product)
.with_vector(user, Param("user_id"))
.limit(Param("limit"))
)
# simple recommendations for our user_1
# these are based only on the initial product the user chose when first entering our site
simple_result = app.query(
user_query,
user_id="user_1",
description_weight=1,
name_weight=1,
category_weight=1,
price_weight=1,
review_count_weight=1,
review_rating_weight=1,
limit=TOP_N,
)
simple_result.to_pandas()
このクエリの結果は、 user_1 が最初に ecomm サイトに登録したときにハンドバッグを選択したという事実を反映しています。
また、ユーザー_1 に製品を推薦することも可能です。一般魅力的な - すなわち、価格が低く、良いレビューがたくさんあることに基づいて、当社の結果は登録時に user_1 の両方の製品選択を反映します。そして製品の一般的な人気(私たちはまた、これらの重量で遊ぶことができ、1つの空間または別の方向に結果を曲げることができます。
general_result = app.query(
user_query,
user_id="user_1",
description_weight=0,
name_weight=0,
category_weight=0,
price_weight=1,
review_count_weight=1,
review_rating_weight=1,
limit=TOP_N,
)
general_result.to_pandas()
新しいユーザーの検索では、クエリテキストを推薦結果の入力として入力します。セル 20で。
私たちの例では、 user_1 が「女性の服装ジャケット」を検索しました。additional weight to the category space(※)category_weight = 10
「女性の服」の商品をもっとお勧めします。
women_cat_result = app.query(
search_query,
user_id="user_1",
query_text="women clothing jackets",
description_weight=1,
name_weight=1,
category_weight=10,
price_weight=1,
review_count_weight=1,
review_rating_weight=1,
limit=TOP_N,
)
women_cat_result.to_pandas()
私たちの追加カテゴリの重みは、より多くの女性の服の結果を生み出します。
我々はまた、トップ評価の製品に我々の推奨を偏見することができる(review_rating_weight=5
), より高いカテゴリの重量をバランスをとる. 結果は、ユーザー_1 が一般に人気のあるハンドバッグやアイテムに対する初期の好みを反映し、低評価の製品は完全に削除されます. 参照セル 22で。
イベントデータを使用して、パーソナライズされた体験を作成する
私たちのユーザーは私たちのプラットフォームと相互作用しました - user_1 more, user_2 less so. We can now utilize our users'behavioral data(以下を参照)、イベントとして表される:
- ♪
- オリジナル&レジャー製品に興味のあるユーザー(user_2) ♪
- エレガントな製品に興味のあるユーザーは、外出や正式な仕事の機会に(user_1) ♪
events_df = (
pd.read_json(EVENT_DATASET_URL)
.reset_index()
.rename(columns={"index": "id"})
.head(NROWS)
)
events_df = events_df.merge(
products_df[["id"]], left_on="product", right_on="id", suffixes=("", "r")
).drop("idr", axis=1)
events_df = events_df.assign(created_at=1715439600)
events_df
特定の製品に対するユーザーの関心のレベルを記録するための特定のアクションを重視し、リハビリを実行する際にイベントを考慮に入れるようにセットアップを調整しましょう。
event_weights = {
"clicked_on": 0.2,
"buy": 1,
"put_to_cart": 0.5,
"removed_from_cart": -0.5,
}
# adjust the setup to events
product_index_with_events = Index(
spaces=[
description_space,
category_space,
name_space,
price_space,
review_count_space,
review_rating_space,
],
effects=[
Effect(
description_space,
event.user,
event_weight * event.product,
event.event_type == event_type,
)
for event_type, event_weight in event_weights.items()
]
+ [
Effect(
category_space,
event.user,
event_weight * event.product,
event.event_type == event_type,
)
for event_type, event_weight in event_weights.items()
]
+ [
Effect(
name_space,
event.user,
event_weight * event.product,
event.event_type == event_type,
)
for event_type, event_weight in event_weights.items()
],
)
event_df_parser: DataFrameParser = DataFrameParser(schema=event)
source_event: InMemorySource = InMemorySource(schema=event, parser=event_df_parser)
executor_with_events: InMemoryExecutor = InMemoryExecutor(
sources=[source_product, source_user, source_event],
indices=[product_index_with_events],
)
app_with_events: InMemoryApp = executor_with_events.run()
現在、ユーザーのイベントを考慮するための新しいインデックスを作成し、それぞれのユーザーへの推薦を適切にカスタマイズします。
# for a new index, all data has to be put into the source again
source_product.put([products_df])
source_user.put([user_df])
source_event.put([events_df])
# a query only searching with the user's vector the preferences are now much more personalised thanks to the events
personalised_query = (
Query(
product_index_with_events,
weights={
description_space: Param("description_weight"),
category_space: Param("category_weight"),
name_space: Param("name_weight"),
price_space: Param("price_weight"),
review_count_space: Param("review_count_weight"),
review_rating_space: Param("review_rating_weight"),
},
)
.find(product)
.with_vector(user, Param("user_id"))
.limit(Param("limit"))
)
We can observe the impact of incorporating events in our RecSys by weighing personalization. 私たちは、パーソナライズ化を重視することによって、イベントをRecSysに組み込むことの影響を観察することができます。わずかにまたは重いまず、これらの(行動データ)イベントによって影響を受けるスペースの重量化の効果(ベースラインと比較)を見てみましょう。
# with small weight on event-affected spaces, we mainly just alter the results below position 4
general_event_result = app_with_events.query(
personalised_query,
user_id="user_1",
description_weight=1,
category_weight=1,
name_weight=1,
price_weight=1,
review_count_weight=1,
review_rating_weight=1,
limit=TOP_N,
)
general_event_result.to_pandas().join(
simple_result.to_pandas(), lsuffix="", rsuffix="_base"
)[["description", "id", "description_base", "id_base"]]
イベントによって影響を受けるスペースに非常に少ない重さがあるため、前回の結果(右側の「id_base」)と比較して、主にトップ10の後半にのみ変化を観察します。
しかし、イベントに影響を与えたスペースをより重く重視すると、私たちは勧告リストに完全に新しい項目を表します。
# with larger weight on the the event-affected spaces, more totally new items appear in the TOP10
event_weighted_result = app_with_events.query(
personalised_query,
user_id="user_1",
query_text="",
description_weight=5,
category_weight=1,
name_weight=1,
price_weight=1,
review_count_weight=1,
review_rating_weight=1,
limit=TOP_N,
)
event_weighted_result.to_pandas().join(
simple_result.to_pandas(), lsuffix="", rsuffix="_base"
)[["description", "id", "description_base", "id_base"]]
当然ながら、私たちは、特定のユーザーの行動(イベントデータ)に基づいて私たちの勧告をパーソナライズするために、重量を使用することもできます。同時に、他の製品の特性を優先する。たとえば、価格(見る)セル 31( )
結論
Superlinked ライブラリの eComm RecSys 実装 (上記) では、ユーザー クエリと行動データのセマンティックな意味を組み込むことで、ベクトル インベーディングのパワーを実現する方法を示しています. Using our min_max number and text-similarity Spaces, Events Scheme and Effects, and query time weights, you can address the cold-start, quality and relevance, and scalability challenges of RecSys and provide highly accurate, user-personalized recommendations in production.
今度は君の番だ!Superlinked Library を私たちのノートブックを使用して実装してみてください。で。
Try It Yourself – Get the Code & Demo!
Try It Yourself - Get the Code & Demo!- ♪
- コードを取得:ここでGitHubのレポで完全な実装をチェックしてください.Fork it, tweak it, and make it your own! ♪
- See It in Action: リアルワールドのセットアップでこの機能を見たいですか? 早速デモを予約し、Superlinked がお勧めをどのようにアップロードできるかを探索してください。 ♪
Recommendation engines are shaping the way we discover content. 人気のパンツ、音楽、またはその他の製品であろうと、vector search is the future―そして今、あなたはあなた自身を構築するためのツールを持っています。