Teraz, gdy wiemy, jak korzystać z kNN, przejdźmy do logiki tworzenia rekomendacji. Jednym ze sposobów, w jaki możemy zacząć przedstawiać rekomendacje, jest znalezienie produktów podobnych do tych, które już lubią nasi użytkownicy, a następnie zastosowanie kNN, które nazwiemy podejściem opartym na przedmiotach. Innym podejściem jest znalezienie elementów popularnych wśród użytkowników, którzy są podobni do użytkownika, dla którego staramy się stworzyć rekomendacje, a następnie zastosować kNN, który nazwiemy podejściem opartym na użytkownikach. Oba podejścia są rozsądne, ale jedno jest prawie zawsze lepsze niż drugie w praktyce. Jeśli masz o wiele więcej użytkowników niż przedmiotów (podobnie jak Netflix ma znacznie więcej użytkowników niż filmów), zaoszczędzisz na obliczeniach i kosztach przechowywania, stosując podejście oparte na przedmiotach, ponieważ wystarczy obliczyć podobieństwa między wszystkimi parami przedmiotów. Jeśli masz o wiele więcej elementów niż użytkowników (co często zdarza się, gdy dopiero zaczynasz zbierać dane), prawdopodobnie spróbuj wypróbować podejście oparte na użytkownikach. W tej części zajmiemy się podejściem opartym na przedmiotach. Zanim jednak omówimy bardziej szczegółowo algorytmy tworzenia rekomendacji, spójrzmy na dane, z którymi będziemy pracować. Zestaw danych, którego użyjemy, to dane, które były dostępne dla uczestników konkursu na rekomendację pakietu R na Kaggle. W tym konkursie udostępniliśmy uczestnikom pełny rekord instalacji pakietu dla około 50 programistów R. Jest to dość mały zestaw danych, ale wystarczyło, aby zacząć uczyć się o popularności różnych pakietów i ich stopniu podobieństwa. Zwycięskie zgłoszenia do konkursu wykorzystywały kNN jako część algorytmu rekomendacji, choć ogólnie był to tylko jeden część wielu dla zwycięskich algorytmów. Innym ważnym algorytmem, który został włączony do większości zwycięskich rozwiązań, jest faktoryzacja macierzy. Nie będziemy szczegółowo opisywać algorytmu, ale każdy, kto buduje system rekomendacji na poziomie produkcyjnym, powinien rozważyć połączenie rekomendacji zarówno z kNN, jak i modeli faktoryzacji macierzowej. W rzeczywistości najlepsze systemy często łączą kNN, faktoryzację macierzy i inne klasyfikatory razem w super-model. Sztuczki łączenia wielu klasyfikatorów są zwykle nazywane metodami zespołowymi. W konkursie R uczestnicy mieli przewidzieć, czy użytkownik zainstaluje pakiet, dla którego wstrzymaliśmy dane instalacyjne, wykorzystując fakt, że wiesz, jakie inne pakiety R zainstalował użytkownik. Podczas prognozowania nowego pakietu można spojrzeć na pakiety najbardziej do niego podobne i sprawdzić, czy zostały zainstalowane. Innymi słowy, było naturalne, że w zawodach zastosowano podejście kNN oparte na przedmiotach. Załadujmy więc zestaw danych i sprawdźmy go trochę. Następnie stworzymy miarę podobieństwa między pakietami. Surowe dane do konkursu nie nadają się idealnie do tego celu, dlatego przygotowaliśmy prostszy zestaw danych, w którym każdy wiersz opisuje parę elementów użytkownika, a trzecia kolumna określa, czy ten użytkownik ma zainstalowany pakiet, czy nie.
installations <- read.csv(‘data/installations.csv’)
head(installations)
# Package User Installed
#1 abind 1 1
#2 AcceptanceSampling 1 0
#3 ACCLMA 1 0
#4 accuracy 1 1
#5 acepack 1 0
#6 aCGH.Spline 1 0
Jak widać, użytkownik 1 w konkursie zainstalował pakiet abind, ale nie pakiet AcceptanceSampling. Ta nieprzetworzona informacja da nam miarę podobieństwa między pakietami po przekształceniu ich w inną formę. Zamierzamy przekształcić dane z „długiej formy” w „szeroką formę” danych, w których każdy wiersz odpowiada użytkownikowi, a każda kolumna odpowiada pakietowi. Możemy to zrobić za pomocą funkcji rzutowania z pakietu przekształcania:
library(‘reshape’)
user.package.matrix <- cast(installations, User ~ Package, value = ‘Installed’)
user.package.matrix[, 1]
# [1] 1 3 4 5 6 7 8 9 11 13 14 15 16 19 21 23 25 26 27 28 29 30 31 33 34
#[26] 35 36 37 40 41 42 43 44 45 46 47 48 49 50 51 54 55 56 57 58 59 60 61 62 63
#[51] 64 65
user.package.matrix[, 2]
# [1] 1 1 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 0 0 1 1 1 1 1 1 1 0 1 0 1 0 1 1 1 1 1 1
#[39] 1 1 1 1 1 1 1 1 0 1 1 1 1 1
row.names(user.package.matrix) <- user.package.matrix[, 1]
user.package.matrix <- user.package.matrix[, -1]
Po pierwsze, użyliśmy obsady do stworzenia naszej matrycy pakietów użytkowników. Po sprawdzeniu pierwszej kolumny zdajemy sobie sprawę, że po prostu przechowuje ona identyfikatory użytkowników, więc usuwamy ją po zapisaniu tych informacji w wierszach. Nazwy naszej matrycy. Teraz mamy odpowiednią macierz pakietów użytkowników, która sprawia, że obliczanie miar podobieństwa jest banalne. Dla uproszczenia wykorzystamy korelację między kolumnami jako miarę podobieństwa. Aby to obliczyć, możemy po prostu wywołać funkcję cor z R:
similarities <- cor(user.package.matrix)
nrow(similarities)
#[1] 2487
ncol(similarities)
#[1] 2487
similarities[1, 1]
#[1] 1
similarities[1, 2]
#[1] -0.04822428
Teraz mamy podobieństwo między wszystkimi parami pakietów. Jak widać, pakiet 1 jest całkowicie podobny do pakietu 1 i nieco odmienny od pakietu 2. Ale kNN nie używa podobieństw; wykorzystuje odległości. Musimy więc przełożyć podobieństwa na odległości. Nasze podejście polega na użyciu jakiejś sprytnej algebry, aby podobieństwo 1 stało się odległością 0, a podobieństwo -1 stało się odległością nieskończoną. Kod, który tu napisaliśmy, robi to. Jeśli nie jest intuicyjnie jasne, dlaczego działa, spróbuj poświęcić trochę czasu na przemyślenie, w jaki sposób algebra przesuwa punkty.
distances <- -log((similarities / 2) + 0.5)
Przy takim przebiegu obliczeniowym mamy naszą miarę odległości i możemy rozpocząć implementację kNN. Użyjemy k = 25 na przykład do celów, ale chcesz wypróbować wiele wartości k w produkcji, aby zobaczyć, która z nich działa najlepiej. Aby przedstawić nasze rekomendacje, oszacujemy prawdopodobieństwo zainstalowania pakietu, po prostu zliczając liczbę zainstalowanych jego sąsiadów. Następnie posortujemy paczki według tej liczby i zasugerujemy paczki z najwyższym wynikiem. Więc przepiszmy naszą funkcję k.nearest.neighbors z wcześniejszej wersji:
k.nearest.neighbors <- function(i, distances, k = 25)
{
return(order(distances[i, ])[2:(k + 1)])
}
Korzystając z najbliższych sąsiadów, przewidzieliśmy prawdopodobieństwo instalacji, po prostu zliczając liczbę zainstalowanych sąsiadów:
installation.probability <- function(user, package, user.package.matrix, distances,
k = 25)
{
neighbors <- k.nearest.neighbors(package, distances, k = k)
return(mean(sapply(neighbors, function (neighbor) {user.package.matrix[user,
neighbor]})))
}
installation.probability(1, 1, user.package.matrix, distances)
#[1] 0.76
Widzimy tutaj, że dla użytkownika 1 pakiet 1 ma prawdopodobieństwo zainstalowania 0,76. Chcielibyśmy znaleźć pakiety, które najprawdopodobniej zostaną zainstalowane, i polecić je. Robimy to, zapętlając wszystkie pakiety, znajdując ich prawdopodobieństwa instalacji i wyświetlając najbardziej prawdopodobne:
most.probable.packages <- function(user, user.package.matrix, distances, k = 25)
{
return(order(sapply(1:ncol(user.package.matrix),
function (package)
{
installation.probability(user,
package,
user.package.matrix,
distances,
k = k)
}),
decreasing = TRUE))
}
user <- 1
listing <- most.probable.packages(user, user.package.matrix, distances)
colnames(user.package.matrix)[listing[1:10]]
#[1] “adegenet” “AIGIS” “ConvergenceConcepts”
#[4] “corcounts” “DBI” “DSpat”
#[7] “ecodist” “eiPack” “envelope”
#[10]”fBasics”
Jedną z zalet tego podejścia jest to, że możemy łatwo uzasadnić nasze prognozy dla użytkowników końcowych. Możemy powiedzieć, że poleciliśmy pakiet P użytkownikowi, ponieważ on już zainstalował pakiety X, Y i Z. Ta przezroczystość może być prawdziwą zaletą w
niektóre aplikacje. Teraz, gdy stworzyliśmy system rekomendacji wykorzystujący tylko miary podobieństwa, czas przejść do budowy silnika, w którym wykorzystujemy informacje społecznościowe w formie struktur sieciowych do formułowania rekomendacji