Bangun sistem AI untuk merekomendasikan Anda celana paling jazz (atau pakaian lainnya) di planet ini 🩳

Bagaimana jika toko online Anda tahu apa yang diinginkan pelanggan sebelum mereka?

Sebagian besar mesin rekomendasi seperti asisten yang membantu tetapi sedikit tidak tahu apa -apa: Mereka menyarankan item “populer” atau “serupa” berdasarkan data terbatas dan ketinggalan zaman. Mereka berjuang Ketika pengguna baru (masalah awal dingin), dan mereka jarang beradaptasi dengan cukup cepat ketika preferensi pengguna berubah secara real-time.

Tapi bagaimana jika sistem Anda bisa sebenarnya berpikir seperti merchandiser-menggabungkan data produk statis dan perilaku pengguna real-time ke permukaan item yang tepat pada waktu yang tepat?

Panduan ini menuntun Anda dengan membangun mesin rekomendasi modern menggunakan Superlinkedsalah satu yang mengatasi kekurangan tradisional ini dengan mengubah data Anda menjadi profil pengguna yang dapat ditindaklanjuti menggunakan infrastruktur vektor-asli.

(Ingin melompat langsung ke kode? Lihat kode sumber terbuka di GitHub Di Sini. Siap mencoba sistem rekomendasi untuk kasus penggunaan Anda sendiri? Dapatkan demo Di Sini.)

Anda juga dapat mengikuti tutorial dalam browser dengan Colab kami.

Tl; Dr:

Sebagian besar rekomendasi e-commerce terlalu statis (berbasis aturan) atau terlalu hitam (model ML buram). Superlinked menawarkan jalur tengah: rekomendasi fleksibel dan real-time yang dapat beradaptasi dengan pengguna awal yang dingin dengan menggabungkan metadata dengan perilaku langsung-semuanya tanpa melatih kembali model ML.

Mencapai personalisasi meskipun ada tantangan penyematan vektor recsys

Sementara embeddings vektor dapat sangat meningkatkan sistem rekomendasi, secara efektif mengimplementasikannya memerlukan mengatasi beberapa tantangan, termasuk:

  • Kualitas dan relevansi: Proses, arsitektur, dan data pembuatan embedding harus dipertimbangkan dengan cermat.
  • Data yang jarang dan berisik: Embeddings kurang efektif ketika mereka memiliki input yang tidak lengkap atau berisik. Data jarang adalah inti dari masalah awal dingin.
  • Skalabilitas: Metode yang efisien untuk kumpulan data besar diperlukan; Kalau tidak, latensi akan menjadi masalah.

Superlinked memungkinkan Anda mengatasi tantangan ini dengan menggabungkan semua data yang tersedia tentang pengguna dan produk menjadi vektor multimoda yang kaya. Dalam contoh e-commerce recsys kami di bawah ini, kami melakukan ini menggunakan elemen perpustakaan superlink berikut:

  • spasi nomor min_max: Untuk memahami ulasan pelanggan dan informasi harga
  • Ruang Similaritas Teks: Untuk pemahaman semantik tentang informasi produk
  • Skema Acara Dan Efek untuk memodifikasi vektor
  • query time bobots – Untuk mendefinisikan bagaimana Anda ingin data diperlakukan saat Anda menjalankan kueri, memungkinkan Anda mengoptimalkan dan skala tanpa muncul kembali seluruh dataset (latensi)

Dengan menanamkan data spesifik pengguna kami yang awalnya jarang (preferensi produk awal pengguna), kami dapat menangani masalah start dingin. Seperti yang diperoleh perilaku pengguna, kita bisa melangkah lebih jauh, hiper-Perata rekomendasi dengan menanamkan data acara ini, membuat loop umpan balik yang memungkinkan Anda memperbarui vektor dengan preferensi pengguna secara real time. Selain itu, bobot waktu kueri Superlinked memungkinkan Anda menyempurnakan hasil pengambilan Anda, bias untuk mencocokkan preferensi pengguna tertentu.

Mari kita mulai!

Membangun mesin rekomendasi e-commerce dengan superlinked

Pada awal pengembangan, kami memiliki yang berikut ini Data Produk:

Kami juga memiliki yang berikut ini Data tentang pengguna dan produk:

  1. Setiap pengguna memilih salah satu dari tiga produk yang ditawarkan saat mereka mendaftar (yaitu, data preferensi produk)

  2. perilaku pengguna (setelah Pendaftaran) menyediakan data acara tambahan – preferensi untuk karakteristik tekstual produk (deskripsi, nama, kategori)

Juga, ekonomi klasik memberi tahu kita bahwa, rata -rata, semua pengguna ceteris paribus lebih suka produk yang:

  • Biaya lebih murah

  • memiliki banyak ulasan

  • memiliki peringkat yang lebih tinggi

Kami dapat mengatur ruang kami untuk memperhitungkan data ini, sehingga recsys kami berfungsi dalam skenario cold -start – merekomendasikan item untuk pengguna yang sangat sedikit kami kenal. Setelah recsys kami berjalan dan berjalan, kami juga akan memiliki data perilaku: pengguna akan mengklik produk tertentu, membeli produk tertentu, dll. Kami dapat menangkap dan menggunakan data acara ini untuk membuat loop umpan balik, memperbarui vektor kami untuk mencerminkan preferensi pengguna dan meningkatkan kualitas rekomendasi.

Menyiapkan superlink

Pertama, kita perlu menginstal pustaka yang sangat dikaitkan dan mengimpor kelas.

%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)

Kami juga mendefinisikan kumpulan data kami, dan membuat konstanta untuk menyimpan 10 item teratas – lihat sel 3 di notebook.

Sekarang setelah perpustakaan diinstal, kelas diimpor, dan lokasi dataset diidentifikasi, kita dapat melihat dataset kita untuk menginformasikan cara kita mengatur ruang kita. Awalnya, kami memiliki data dari pendaftaran pengguna – IE,. Manakah dari tiga produk user_1 dan user_2 memilih. Kami akan menggunakan data ini untuk menyelesaikan masalah awal dingin.

# 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

Produk Pengguna Pref pada saat pendaftaranProduk Pengguna Pref pada saat pendaftaran

Kami juga dapat mengatur pemeriksaan dekat data distribusi produk kami – lihat sel 5. Ini memberi Anda gambaran tentang berapa banyak produk yang ada pada titik harga yang berbeda, memiliki jumlah ulasan yang berbeda, dan memiliki peringkat yang berbeda (termasuk di mana sebagian besar produk terletak pada rentang ini).

Jumlah Produk vs Harga, Hitungan Tinjauan, dan Distribusi PeringkatJumlah Produk vs Harga, Hitungan Tinjauan, dan Distribusi Peringkat

Bins harga untuk produk sebagian besar di bawah titik harga $ 1000. Kami mungkin ingin mengatur rentang ruang menjadi 25-1000 untuk membuatnya representatif, tidak terdistorsi oleh nilai-nilai outlier. Hitungan tinjauan produk didistribusikan secara merata, dan peringkat peninjauan yang relatif merata, sehingga tidak diperlukan pengobatan tambahan. Lihat Sel 7-9.

Perpustakaan Superlinked berisi serangkaian blok bangunan inti yang kami gunakan untuk membangun indeks dan mengelola pengambilan. Anda dapat membaca tentang blok bangunan ini secara lebih rinci di sini.

Mari kita taruh blok bangunan perpustakaan ini untuk digunakan di eComm recsys kami. Pertama Anda perlu Tentukan skema Anda untuk memberi tahu sistem tentang data Anda.

# 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()

Selanjutnya, Anda menggunakan ruang untuk mengatakan bagaimana Anda ingin memperlakukan setiap bagian data saat menanamkan. Dalam definisi ruang, kami menjelaskan cara menyematkan input sehingga mereka mencerminkan hubungan semantik dalam data kami. Setiap ruang dioptimalkan untuk menanamkan data sehingga dapat mengembalikan kualitas tertinggi dari hasil pengambilan. Ruang mana yang digunakan tergantung pada tipe data Anda.

# 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])

Sekarang setelah Anda mendapatkan data yang didefinisikan dalam ruang, Anda siap bermain dengan data Anda dan mengoptimalkan hasilnya. Mari pertama kali menampilkan apa yang bisa kita lakukan tanpa acara – Solusi Cold-Start kami.

Menangani masalah recsys cold-start

Di sini, kami mendefinisikan kueri pengguna yang hanya mencari dengan vektor preferensi pengguna. Kami memiliki kontrol konfigurasi atas kepentingan (bobot) dari setiap jenis input (ruang).

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()

Hasil kueri ini mencerminkan fakta bahwa USER_1 memilih tas tangan ketika mereka pertama kali mendaftar di situs eComm kami.

Pengguna 1 Pendaftaran Produk Berbasis Pilihan ProdukPengguna 1 Pendaftaran Produk Berbasis Pilihan Produk

Juga dimungkinkan untuk merekomendasikan produk ke user_1 umumnya Menarik – yaitu, berdasarkan harganya rendah, dan memiliki banyak ulasan bagus. Hasil kami sekarang akan mencerminkan pilihan produk User_1 saat pendaftaran Dan Popularitas umum produk. (Kami juga dapat bermain -main dengan bobot ini untuk condong hasil ke arah satu ruang atau lainnya.)

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() 

Rec berbasis fitur produk umumRec berbasis fitur produk umum

Pencarian pengguna baru memperkenalkan teks kueri sebagai input untuk hasil rekomendasi kami – lihat sel 20.

Dalam kasus contoh kami, User_1 mencari “jaket pakaian wanita”. Kami dapat mengoptimalkan hasil kami dengan memberi bobot tambahan untuk ruang kategori (category_weight = 10), untuk merekomendasikan lebih banyak produk “jaket pakaian wanita”.

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()

Bobot Kategori Tambahan kami menghasilkan lebih banyak hasil pakaian wanita.

Pengguna 1 kueri untuk Pengguna 1 kueri untuk

Kami juga dapat bias rekomendasi kami untuk produk berperingkat teratas (review_rating_weight=5), menyeimbangkan peningkatan pembobotan kategori kami. Hasilnya sekarang mencerminkan preferensi awal USER_1 untuk tas dan item yang umumnya populer, sementara produk dengan peringkat rendah dihapus sama sekali. Lihat sel 22.

Menggunakan data acara untuk membuat pengalaman yang dipersonalisasi

Maju cepat sebulan. Pengguna kami telah berinteraksi dengan platform kami – user_1 lebih, user_2 lebih sedikit begitu. Kami sekarang dapat memanfaatkan pengguna kami data perilaku (Lihat di bawah), diwakili sebagai acara:

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

Acara PenggunaAcara Pengguna

Mari kita bobot tindakan spesifik untuk mendaftarkan tingkat minat pengguna pada produk tertentu, dan menyesuaikan pengaturan untuk memperhitungkan peristiwa saat melakukan pengambilan.

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()

Sekarang kami membuat indeks baru untuk memperhitungkan acara pengguna, dan kemudian mempersonalisasikan rekomendasi untuk setiap pengguna yang sesuai. Bahkan pertanyaan hanya berdasarkan vektor pengguna sekarang jauh lebih personal daripada sebelumnya.

# 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"))
)

Kita dapat mengamati dampak dari menggabungkan peristiwa dalam recsys kita dengan menimbang personalisasi sedikit saja atau sangat berat. Pertama, mari kita lihat efeknya (dibandingkan dengan baseline) bobot ruang yang dipengaruhi oleh peristiwa (data perilaku) ini.

# 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"]]

Dengan sangat sedikit bobot yang ditempatkan pada spasi yang dipengaruhi oleh peristiwa, kami mengamati perubahan tetapi terutama hanya pada paruh kedua dari 10 teratas kami, dibandingkan dengan hasil sebelumnya (“ID_Base”, di sebelah kanan).

Ruang-ruang yang terkena peristiwa yang sedikit tertimbang vs baselineRuang-ruang yang terkena peristiwa yang sedikit tertimbang vs baseline

Tetapi jika kita menimbang ruang yang terkena dampak peristiwa lebih berat, kita memunculkan item yang sepenuhnya baru dalam daftar rekomendasi kami.

# 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"]]

Ruang-ruang yang lebih tertimbang yang dipengaruhi oleh peristiwa vs baselineRuang-ruang yang lebih tertimbang yang dipengaruhi oleh peristiwa vs baseline

Kami juga dapat, tentu saja, menggunakan bobot untuk mempersonalisasi rekomendasi kami berdasarkan perilaku pengguna tertentu (data acara) dan secara bersamaan memprioritaskan atribut produk lainnya – Misalnya, harga (lihat sel 31).

Kesimpulan

Implementasi ECOMM Recsys dari perpustakaan superlink (di atas) menunjukkan kepada Anda bagaimana mewujudkan kekuatan embeddings vektor dengan memasukkan makna semantik dari kueri pengguna dan data perilaku. Menggunakan angka Min_max kami dan ruang-ruang-similaritas kami, skema dan efek acara, dan bobot waktu kueri, Anda dapat mengatasi tantangan recsys, kualitas dan relevansi yang dingin, dan skalabilitas dari Recsys dan memberikan rekomendasi yang sangat akurat dan dipersonalisasi dalam produksi dalam produksi.

Sekarang giliranmu! Coba implementasikan sendiri perpustakaan superlink menggunakan buku catatan kami.

Cobalah sendiri – dapatkan kode & demo!

  • 💾 ambil kode: Lihat implementasi lengkap dalam repo github kami Di Sini.Fork It, tweak, dan buat milik Anda sendiri!
  • 🚀 melihatnya beraksi: Ingin melihat ini bekerja dalam pengaturan dunia nyata? Pesan cepat demo, dan jelajahi caranya Superlinked dapat menambah rekomendasi Anda. Dapatkan demo sekarang!

Mesin rekomendasi membentuk cara kami menemukan konten. Apakah itu celana populer, musik, atau produk lainnya, Pencarian vektor adalah masa depan—Dan sekarang Anda memiliki alat untuk membangun sendiri.