Sistem rekomendasi untuk Directum Club. Bagian Satu, Kolaboratif

Setiap hari, pengguna di seluruh dunia menerima sejumlah besar surat berbeda - hanya melalui layanan MailChimp setiap hari mengirim satu miliar surat . Dari jumlah tersebut, 20,81% ditemukan.


Setiap bulan, pengguna situs kami menerima buletin dengan materi yang dipilih oleh editor. Sekitar 21% pembaca membuka surat-surat ini.


Untuk menambah angka ini, Anda dapat membuatnya dipersonalisasi. Salah satu caranya adalah dengan menambahkan sistem rekomendasi yang akan mendorong materi yang menarik bagi pembaca tertentu.


Pada artikel ini saya akan berbicara tentang bagaimana menerapkan sistem rekomendasi dari awal berdasarkan penyaringan kolaboratif.


Bagian pertama dari artikel ini berisi dasar teoritis untuk implementasi sistem rekomendasi. Matematika sekolah sudah cukup untuk memahami materi.


Bagian kedua menjelaskan implementasi Python untuk data situs kami.


Sedikit teori penyaringan kolaboratif


Penyaringan kolaboratif mungkin merupakan pendekatan termudah dalam sistem rekomendasi. Ini didasarkan pada gagasan bahwa pengguna yang serupa menyukai objek yang serupa, seperti artikel.


Apakah yang dimaksud dengan "pengguna yang serupa"?


siapa kamu


Bagaimana cara menentukan seberapa mudahnya seperti Ivan atau artikel tentang SQL Server hingga artikel tentang PostgreSQL?


Mari kita lihat sebuah contoh. Katakanlah kita memiliki empat pengguna: Vasily, Ivan, Inna dan Anna. Situs ini memiliki lima artikel: Artikel 1, Pasal 2, Pasal 3, Pasal 4 dan Pasal 5. Dalam tabel di bawah ini, angka di persimpangan pengguna dan artikel adalah peringkat pengguna artikel pada skala lima poin. Nol dalam tabel adalah artikel yang belum diberi peringkat oleh pengguna. Misalnya, Vasily menyukai artikel 1, 3, dan 4.


Tabel 1


Pasal 1Bagian 2Bagian 3Bagian 4Bagian 5
Dengan mudah40550
Ivan00450
Inna42400
Anna55005

Secara intuitif, kita dapat mengasumsikan bahwa jika pengguna menyukai artikel yang sama, maka rasanya sesuai. Bagaimana menurut Anda, minat siapa yang mirip dengan kepentingan Vasily?


Minat Vasily lebih mirip dengan minat Ivan dan Inna dan kurang seperti minat Anna. Mengapa - itu akan diceritakan lebih lanjut.


Untuk pekerjaan lebih lanjut, perlu memformalkan dan mengukur "kesamaan" dari Vasily dan Ivan atau Inna dan Anna.


Cara termudah untuk melakukan ini adalah dengan mempertimbangkan peringkat pengguna sebagai deskripsi profil mereka. Dalam contoh, setiap baris dalam tabel adalah deskripsi satu pengguna. Baris pertama - deskripsi Basil - adalah vektor dari lima angka: [4, 0, 5, 5, 0]; yang kedua - Ivan - [0, 0, 4, 5, 0]; yang ketiga adalah Inna - [4, 2, 4, 0, 0]; yang keempat adalah Anna - [5, 5, 0, 0, 5].


Sekarang Anda dapat memperkenalkan konsep deskripsi pengguna "ukuran kesamaan".


Salah satu cara untuk mengukur "kesamaan" pengguna adalah dengan menghitung jarak kosinus antara vektor yang menggambarkan mereka.



Jarak cosinus dihitung dengan rumus:


1βˆ’cos theta=1βˆ’ fracA cdotB||A|| cdot||B||


dimana Adan B- vektor deskripsi pengguna; A cdotB- produk skalar dari vektor deskripsi; ||A||, ||B||- panjang vektor deskripsi.


Arti jarak cosinus adalah sebagai berikut: jika dua vektor mana Adan B(vektor deskripsi pengguna) adalah "serupa", maka sudut di antara mereka akan cenderung ke nol, dan kosinus dari sudut ini akan cenderung menyatu. Dalam kasus ideal, ketika "minat" kedua pengguna bertepatan, jarak kosinus untuk mereka akan nol.


Jarak cosine antara Vasily dan Ivan:


1βˆ’cos theta=1βˆ’ frac4 cdot0+0 cdot0+5 cdot4+5 cdot5+0 cdot0 sqrt42+02+52+52+02 cdot sqrt02+02+42+52+02=0,1349


Demikian pula, jarak cosinus antara Vasily dan Anna adalah 0,715. Artinya, minat Vasily lebih seperti minat Ivan daripada Anna.


Bagaimana cara memprediksi peringkat pengguna?


Bagian ini yang paling menarik. Ada banyak opsi berbeda. Di bawah ini kami mempertimbangkan dua opsi sederhana.


Peringkat yang diprediksi - peringkat rata-rata di antara pengguna β€œsejenis”


Opsi termudah untuk menghitung peringkat yang diprediksi adalah untuk melihat peringkat apa yang dimasukkan oleh pengguna "serupa" ke artikel dan mengambil peringkat rata-rata:


ru,i= frac1N sumuβ€² diUruβ€²,i


Dalam rumus ini:


  • ru,iAdalah estimasi yang diperkirakan untuk iartikel dan pengguna u,
  • ruβ€²,i- peringkat pengguna u$untuk iartikel th
  • Uβ€”Banyak pengguna "mirip",
  • N- jumlah pengguna "serupa".

Peringkat yang diprediksi - peringkat rata-rata tertimbang di antara pengguna β€œsejenis”


Opsi yang sedikit lebih rumit adalah dengan mempertimbangkan tingkat kesamaan: peringkat lebih banyak pengguna yang serupa harus mempengaruhi peringkat akhir lebih dari peringkat yang kurang serupa:


ru,i= frac sumuβ€² inU(1βˆ’simil(u,uβ€²))ruβ€²,i sumuβ€² inU|1βˆ’simil(u,uβ€²)|


Dalam rumus ini:


  • ru,iAdalah estimasi yang diperkirakan untuk iartikel dan pengguna u,
  • ruβ€²,i- peringkat pengguna u$untuk iartikel th
  • Uβ€”Banyak pengguna "mirip",
  • simil(u,uβ€²)- "kesamaan" (jarak cosinus) pengguna udan u$.

Bagaimana mengukur kualitas rekomendasi?



Saat membuat sistem rekomendasi, Anda harus menentukan metrik yang dengannya Anda dapat mengevaluasi kualitas model kami - seberapa baik sistem tersebut menawarkan bahan baru kepada pengguna. Sebagai contoh, root mean square error ( RMSE) Apakah akar kuadrat dari kesalahan rata-rata untuk semua peringkat pengguna. Secara formal, ukuran ini dijelaskan oleh rumus:


RMSE= sqrt frac1|D| sumu,i inD( hatru,iβˆ’ru,i)2


Dalam rumus ini


  • D- himpunan semua peringkat pengguna untuk artikel,
  •  hatru,i- prediksi peringkat pengguna uartikel i,
  • ru,i- Peringkat pengguna nyata uartikel i.

Dalam kasus ideal, ketika peringkat yang diprediksi bertepatan dengan milik pengguna RMSEsama dengan nol.


Pertimbangkan sebuah contoh. Dua sistem referensi membuat prediksi untuk Vasily. Hasilnya ada dalam tabel di bawah ini.


Pasal 1Bagian 2Bagian 3Bagian 4Bagian 5
Dengan mudah40550
Sistem pemberi rekomendasi 113522
Sistem pemberi rekomendasi 241530

Secara intuitif jelas bahwa sistem rekomendasi kedua memperkirakan peringkat lebih baik daripada yang pertama. Hitung RMSE:


RMSE(1)= sqrt frac(4βˆ’1)2+(0βˆ’3)2+(5βˆ’5)2+(5βˆ’2)2+(0βˆ’2)25=$2,48


RMSE(2)= sqrt frac(4βˆ’4)2+(0βˆ’1)2+(5βˆ’5)2+(5βˆ’3)2+(0βˆ’0)25=1


Kesalahan untuk evaluasi sistem rekomendasi kedua diharapkan lebih rendah secara signifikan.


Implementasi


Kami memiliki sebagian besar data tentang artikel dan pengguna situs: informasi tentang artikel, tag, suka pengguna, dll.


Untuk menerapkan pemfilteran kolaboratif, peringkat pengguna sudah cukup.


Penafian

Selanjutnya, kode ditulis "di dahi" untuk menunjukkan logika dari sistem rekomendasi. Dalam kehidupan nyata lebih baik menggunakan semua fitur numpy dan pandas .


 import pandas as pd import numpy as np import os ratings_df = pd.read_csv('./input/Ratings.csv') print(' :', ratings_df.shape[0]) print(' :', ratings_df[ratings_df['Rate']].shape[0]) unique_user_ids = ratings_df[ratings_df['Rate']]['UserId'].unique() print(' :', len(unique_user_ids)) ratings_df.head() 

Keluaran [1]

Total data: 15313
Peringkat Positif: 15121
Pengguna aktif: 1007


IdDocumentIdBeri peringkatUserid
011Benar5000
12878Benar2441
231512Benar678
341515Benar678
45877Benar5110
...............

1007 pengguna aktif memberi 15313 "peringkat". Dari jumlah tersebut, 15121 "suka".


Data berisi empat kolom: pengidentifikasi baris dari database (kolom Id ), pengidentifikasi objek (kolom DocumentId ), tanda bahwa pengguna menyukai artikel (kolom Nilai ), dan pengidentifikasi pengguna (kolom UserId ).


Untuk kenyamanan, tambahkan kolom RateInt . 1 pada kolom ini berarti pengguna menyukai artikel tersebut; -1 - itu tidak suka.


 ratings_df['RateInt'] = ratings_df['Rate'].apply(lambda x: 1 if x else -1) ratings_df.head() 

Keluaran [2]
IdDocumentIdBeri peringkatUseridBeri peringkat
011Benar50001
12878Benar24411
231512Benar6781
341515Benar6781
45877Benar51101

Untuk pekerjaan lebih lanjut, diperlukan untuk membagi set data menjadi pelatihan dan tes: pelatihan akan digunakan untuk melatih model, dan tes yang akan menentukan kualitas prediksi.


 from sklearn.model_selection import train_test_split train, test = train_test_split(ratings_df, test_size=0.2) 

Untuk kenyamanan, kami mengubah setiap set menjadi tabel, di mana di baris adalah pengidentifikasi pengguna, dan di kolom adalah pengidentifikasi artikel dengan analogi dengan contoh di awal artikel.


 def create_matrix(df): ratings_per_user = [] post_ids = df['DocumentId'].unique() for user_id in tqdm_notebook(all_users_ids, ''): row = {'user_id': user_id} ratings = df[df['UserId'] == user_id]['DocumentId'].values for post_id in post_ids: row[str(post_id)] = 1 if post_id in ratings else 0 ratings_per_user.append(row) return pd.DataFrame(ratings_per_user) train_df = create_matrix(train) test_df = create_matrix(test) 

Pengguna pencocokan matriks dan artikel favorit akan memungkinkan Anda menghitung jarak cosinus antara pengguna:


 from scipy import spatial def cos_distance(x1, x2): return spatial.distance.cosine(x1, x2) at_least_one_fav_post_users = list(train_valuable_df['user_id'].values) def calculate_distances(df): columns = df.columns[:-1] cp = at_least_one_fav_post_users.copy() data = [] for user_id_1 in tqdm_notebook(at_least_one_fav_post_users, ''): row = {'user_id': user_id_1} for user_id_2 in cp: x1 = df[df['user_id'] == user_id_1][columns].values[0] x2 = df[df['user_id'] == user_id_2][columns].values[0] row[str(user_id_2)] = cos_distance(x1, x2) data.append(row) return pd.DataFrame(data) train_distances = calculate_distances(train_valuable_df) 

Sekarang semuanya sudah siap untuk meminta pengguna artikel yang menurut pendapat mereka akan suka.


Kami menerapkan dua strategi untuk menghitung rekomendasi yang dijelaskan di atas: peringkat rata-rata dan rata-rata tertimbang di antara pengguna yang serupa.


Cara pertama


Kami mengambil 10 pengguna yang paling dekat dengan saat ini dan memperkirakan peringkat sebagai rata-rata untuk pengguna yang serupa untuk artikel:


 from tqdm import tqdm_notebook import heapq def rmse(predicted, actual): return ((predicted - actual) ** 2).mean() ** 0.5 def get_similar(id, n): df = train_distances[train_distances['user_id'] == id] d = df.to_dict('records')[0] top_similar_ids = heapq.nsmallest(n+1, d, key=d.get) top_similar = df[top_similar_ids] return top_similar.to_dict('records')[0] def get_predictions(id, n): top_similar_users = get_similar(id, n) top_similar_users_ids = list([int(x) for x in top_similar_users.keys()]) ratings_for_top_similar = train_df[train_df['user_id'].isin(top_similar_users_ids)] predicted_ratings = {} for article_id in train_df.columns[:-1]: predicted_ratings[article_id] = ratings_for_top_similar[article_id].mean() return predicted_ratings rand_n_users = train_distances.sample(50)['user_id'].values err = 0 for u in tqdm_notebook(rand_n_users): pred = get_predictions(u, 10) err += rmse(test_df[test_df['user_id'] == u][list(pred.keys())].values, pd.DataFrame(pred, index=[0]).values) print(err / len(rand_n_users)) 

Untuk pendekatan pertama, kami mendapat kesalahan sama dengan 0,855.


Rekomendasi untuk pengguna biasa
ArtikelPeringkat yang diprediksi
DIRECTUM 5.6. Pencarian teks lengkap baru0,6364
DIRECTUM 5.6 - lebih banyak opsi untuk pekerjaan yang nyaman0,6364
Pengembangan alat pengembangan dalam DIRECTUM 5.50,6364
DIRECTUM Memperkenalkan DirectumRX0,5455
Rilis tahunan DIRECTUM sekarang adalah 5.1!0,5455
A hingga K. DIRECTUM 5.0 diperbarui lagi0,5455
DIRECTUM Jazz - solusi mobile baru dari perusahaan DIRECTUM0,5455
Sudahkah Anda memperbarui DIRECTUM?0,5455
DIRECTUM 5.6. Super Kolom dan Tindakan Folder0,5455
Penyorotan sintaksis GitLab ISBL0,5455

Cara kedua


Metode kedua memperhitungkan tingkat kesamaan pengguna. Implementasinya hampir identik dengan yang pertama:


 def get_predictions(id, n): similar_users = get_similar(u, 10) prediction = {} user_ids = list(similar_users.keys()) user_similarities = [] for user_id in user_ids: user_similarities.append(similar_users[user_id]) predicted_ratings = {} for article_id in train_df.columns[:-1]: prediction_for_article = 0 numerator = 0 denominator = 0 for user_id in user_ids: rating = train_df[train_df['user_id'] == int(user_id)][article_id].values[0] numerator += rating * (1 - similar_users[user_id]) denominator += np.abs(similar_users[user_id]) predicted_ratings[article_id] = numerator / denominator return predicted_ratings err = 0 for u in tqdm_notebook(rand_n_users): pred = get_predictions(u, 10) err += rmse(test_df[test_df['user_id'] == u][list(pred.keys())].values, pd.DataFrame(pred, index=[0]).values) print(err / len(rand_n_users)) 

Dalam hal ini, mereka mendapat kesalahan 0,866. Kesalahannya sedikit lebih besar dari pada kasus pertama.


Rekomendasi untuk pengguna acak yang sama
ArtikelPeringkat
DIRECTUM 5.6. Pencarian teks lengkap baru0,3095
DIRECTUM 5.6 - lebih banyak opsi untuk pekerjaan yang nyaman0,3095
Pengembangan alat pengembangan dalam DIRECTUM 5.50,3095
Banyak Layanan DIRECTUM - Satu Alat Administrasi0,2833
A hingga K. DIRECTUM 5.0 diperbarui lagi0,2809
Rilis tahunan DIRECTUM sekarang adalah 5.1!0,2784
DIRECTUM Memperkenalkan DirectumRX0,2778
Sudahkah Anda memperbarui DIRECTUM?0,2778
DIRECTUM 5.6. Super Kolom dan Tindakan Folder0,2758
DIRECTUM Ario - solusi cerdas baru0,2732

Hasilnya dapat digunakan dalam berbagai skenario. Misalnya, dalam buletin artikel baru per bulan atau tambahkan di situs bagian "Anda mungkin tertarik."


Ringkasan


Pada artikel ini, saya mencoba secara detail, menggunakan contoh tugas nyata, untuk menganalisis bagaimana membuat sistem rekomendasi berdasarkan penyaringan kolaboratif.


Keuntungan dari pendekatan ini adalah fleksibilitasnya - rekomendasi tidak mempertimbangkan objek mana yang direkomendasikan. Satu sistem dapat digunakan untuk artikel blog dan produk di toko online.


Kerugiannya termasuk yang berikut ini:


  • dalam kasus sejumlah besar objek untuk rekomendasi, matriks objek-pengguna menjadi jarang, dan menjadi lebih sulit untuk menemukan pengguna yang cukup serupa (lebih sedikit pasangan objek-pengguna yang cocok)
  • masalah mulai dingin - tidak mungkin bagi pengguna baru untuk menemukan pengguna yang serupa (ada strategi untuk menghindari batasan ini, tetapi mereka bukan obat mujarab)
  • sistem yang berdasarkan pada filter kolaboratif cenderung merekomendasikan objek populer, karena sebagian besar pengguna akan menghargai objek tersebut.

Pada artikel selanjutnya, pendekatan lain akan dipertimbangkan - berdasarkan pada analisis objek itu sendiri.

Source: https://habr.com/ru/post/id463609/


All Articles