Przejdź do treści

Jaki film obejrzeć?

Kiedyś już pisałem o filmach i danych jakie dawno temu zgromadziłem z Filmwebu. Dzisiaj zajmiemy się polecaniem filmów do obejrzenia. Czyli – systemy rekomendacji.

Dlaczego rekomendacje są ważne

W najprostszym ujęciu chodzi o sprzedaż. Albo dosłowną sprzedaż towarów, albo odsłony (czy też odtworzenia) w serwisach internetowych (i tym samym odsłony reklam). Im więcej ludziom polecisz, tym bardziej będą klikać, z tym większym prawdopodobieństwem kupią coś, czego nie mieli zamiaru kupować. O nic innego nie chodzi. Znalazłem gdzieś informację, że tego typu systemy odpowiadają za

  • w Netflixie – 2/3 oglądanych filmów to wynik rekomendacji
  • w Amazonie – 35% sprzedaży to produkty rekomendowane

Netflix swego (to już jakieś 10 lat… epoka wręcz) organizował konkurs Netflix Prize na poprawę swoich algorytmów.

Typy rekomendacji

Najprostszy podział to dwa rodzaje algorytmów:

  • bazujący na dotychczasowych ocenach produktów
  • bazujący na cechach produktów

Pierwszy z nich to Collaborative Filtering (CF) – bazujemy na założeniu, że podobni do siebie użytkownicy podobnie oceniają produkty. W związku z tym bazujemy na historycznych ocenach i szukamy podobnych użytkowników. A sama rekomendacja to wybranie produktów spełniających określone cechy (na przykład najwyższa średnia ocena wśród podobnych użytkowników). Problemem jest tutaj tak zwany “zimny start” – jeśli nie oceniłeś żadnego produktu to nie wiemy do kogo i jak bardzo jesteś podobny, w związku z tym nie możemy Ci nic polecić. Problem ten Filmweb rozwiązuje zadając na początek (przy zakładaniu konta) pytania o najpopularniejsze filmy – ocenisz kilka, to wpadniesz w jakąś grupę podobnych użytkowników. Jeśli masz niestandardowy gust – możesz nie mieć “podobnych” użytkowników w serwisie i rekomendowane produkty nie muszą dobrze do Ciebie pasować. Tym właśnie algorytmem będziemy się dzisiaj zajmować.

Druga grupa algorytmów to Content/Knowledge-based Filtering (CBF) – rekomendacje bazują na informacji o samym produkcie (content) oraz ewentualnych źródłach zewnętrznych (knowledge), nie biorą pod uwagę opinii innych użytkowników. System rekomendacyjny stara się wybrać produkty podobne do tych, którymi użytkownik był zainteresowany (kupił albo oznaczył, że go interesują czy też odwiedził strony opisujące dany produkt w sklepie). Nie ma w tym przypadku problemu zimnego startu, ale potrzebne są cechy produktów. O ile w przypadku filmów są one z jednego worka (gatunek, reżyseria, scenarzysta, występujący autorzy) o tyle w przypadku sklepów internetowych (albo agregatów typu Allegro czy Ceneo) jest już trudniej – mamy setki kategorii, w każdej inne cechy produktów (wielkość RAMu ma sens w przypadku komputerów czy telefonów, ale w przypadku ciuchów już niekoniecznie). W tym podejściu łatwiej jest podsunąć użytkownikom niestandardowym jakieś produkty. Jakaś wariacja na temat to mój wpis z czerwca, w którym (druga część) jako cech produktów użyłem średnich ocen poszczególnych osób z obsady.

Oczywiście można połączyć wyniki obu narzędzi.

Oceny filmów nadane przez użytkowników

Skoro mamy zająć się algorytmem typu collaborative filtering potrzebujemy ocen produktów. Od ręki są do zdobycia odpowiednie dane – na przykład baza MovieLens albo baza IMDb.com. Ale żeby utrudnić nieco zadanie i zdać się na polski rynek wykorzystamy Filmweb. Trochę też dlatego, że tam sam oceniam filmy i łatwiej będzie mi komentować późniejsze wyniki.

Tylko jak z Filmwebu szybko pobrać informacje o ocenach filmów? Zrobimy małe machniom i sami sobie wygenerujemy oceny. A za listę filmów posłużą nam

rankingi Filmwebu

Na stronie mamy ranking filmów z możliwością podziału go na poszczególne gatunki. I te listy (dla różnych gatunków) weźmiemy. Znowu web scrapping.

Przygotujemy odpowiednią funkcję, która:

  • pobierze stronę z rankingiem dla danego gatunku
  • znajdzie interesujące nas informacje
  • i odda nam to czego chcemy, opakowane ładnie w tabelkę

No to wio:

Teraz tylko potrzebujemy adresów stron z rankingami dla poszczególnych gatunków:

Lista zamieniona na tabelę – ruch może bez sensu, ale bardzo wygodny. Wiele rzeczy w moich kodach jest bez sensu – nie trzymam się konwencji nazw zmiennych czy funkcji, zmieniam typy danych z jednego na drugi bo mi tak wygodniej, używam pętli chociaż można jakieś funkcje z pakietu purrr wykorzystać. To wynik agile’owego sposobu pisania postów ;)

Skoro mamy już dane to pooglądajmy je sobie na szybko.

Najpierw popatrzmy chwilę na dane. Jak zmieniały się oceny topowych filmów w poszczególnych latach?

Widać, że z roku na rok oceny są coraz niższe. Co prawda zmiana jest z prawie 7.6 na nieco mniej niż 7.4, ale tendencja jest wyraźna. Ja mam na ten temat swoją teorię. Otóż kino jest coraz bardziej wtórne. Produkuje się coraz więcej i coraz więcej nowych filmów wpada do rankingów (co widać poniżej)

ale wcale nie znaczy to, że te filmy są coraz lepsze. Osobiście oceniam filmy w kontekście gatunku oraz tego co film wnosi do całej historii kinematografii. Obywatel Kane dostaje ode mnie wyższą ocenę niż Incepcja chociaż technicznie filmy dzieli przepaść.

A czy patrząc poprzez pryzmat gatunku widać jakieś różnice?

To jest ciekawe. Wszystkim właściwie spada (co jest oczywiście zbieżne z wykresem dla całej puli, bez dzielenia na gatunki), ale są gatunki gdzie (według średniego gustu użytkowników Filmwebu) jest coraz lepiej. Oczywiście coraz lepiej to dość względne pojęcie – zmiana o 0.1 (skala dla przypomnienia to 1 do 10) w średniej ocenie to nie jest przecież ogromny sukces. Ale widzimy, że powstają lepsze westerny (Django zrobiło swoje), filmy wojenne (Przełęcz ocalonych), animacje (Twój Vincent zdominował ranking – ze zwiastunów wygląda wspaniale formalnie, ale z recenzji wynika że to taki sobie film pod względem scenariusza. Czy zatem ocena nie jest zawyżona? Bo Zwierzogród zasługuje na wysokie miejsce w rankingu, chociaż formalnie nie wnosi wiele nowego po wszystkich produkcjach Pixara). Mnie cieszy zagięcie w górę przy thrillerach (i znalazłem tutaj coś czego nie widziałem – hiszpańskie Contratiempo z 2016 roku).

Jak wygląda rozkład ocen dla poszczególnych gatunków? To znaczy czy średnio rzecz biorąc horrory są lepsze niż komedie romantyczne?

Najsłabsze są filmy erotyczne (specjalnie dodałem tę kategorię; frapuje mnie tytuł Tureckie owoce, który pierwotnie przeczytałem jako Tureckie owce…) i katastroficzne (i rzeczywiście w porównaniu do słabego w efekty kina lat ’70 XX wieku produkcje z XXI wieku nie powalają scenariuszem – drugie w rankingu Niemożliwe, hello?!)

Dobrze, mamy bazę, możemy na jej podstawie przygotować oceny filmów.

Symulacja ocen użytkowników

Zrobimy sobie funkcję, która dla użytkownika przygotuje listę filmów i ocen. Założenia:

  • każdy user ogląda jakiś fragment każdego z rankingów – w przykładzie poniżej po 1/4 filmów z danego gatunku
  • każdy film oceniony jest losowo, ale rozkład ocen zbliżony jest do średniego rozkładu wszystkich ocen (zobacz wykres we wspomnianym wpisie) – trochę więcej 8 i 9 (w końcu to topowe filmy), a mniej niskich ocen
  • jakiś losowy gatunek jest preferowany – wtedy podbijamy oceny użytkownika dla filmów z tego gatunku o 50%

Teraz jeszcze potrzebujemy losowych użytkowników i nadania przez nich ocen:

Zobaczmy jak średnio losowi użytkownicy oceniają poszczególne gatunki w porównaniu do średniej ocen gatunków zgromadzonych na Filmwebie:

Czerwona kropka to ocena wygenerowana, niebieska – ta pochodząca z Filmwebu.

Widać, że nasze losowanie sprawiło, że w większości przypadków (poza erotykami i filmami katastroficznymi) oceny użytkowników są niższe niż te wynikające z rankingów. To dobrze, że jest taka różnica, która na poziomie użytkowników wygląda jeszcze ciekawiej:

Udało się uzyskać zróżnicowanie użytkowników – niektórzy lepiej niż średnia oceniają poszczególne gatunki, inni gorzej.

Odległość między użytkownikami

Algorytm collaborative filtering polega w pierwszym kroku na znalezieniu podobnych użytkowników. Ten element jest najważniejszy i decyduje o jakości rekomendacji. Trzeba zdefiniować podobieństwo. Mamy użytkownika i bardzo dużo cech go opisujących (wszystkie filmy jakie ocenił, a właściwie wszystkie filmy w bazie). Te cechy to wektor w przestrzeni n-wymiarowej, zatem trzeba znaleźć miarę podobieństwa dwóch wektorów.

Różne miary odległości

Może to być iloczyn skalarny (wektor razy wektor daje liczbę). Może to być odległość pomiędzy punktami w n-wymiarowej przestrzeni, na przykład euklidesowa (pierwiastek sumy kwadratów różnicy) czy kosinusowa. Może to być też korelacja pomiędzy wartościami ocen i z tego skorzystamy. Nie jest to najlepsze rozwiązanie, ale wybieram je świadomie – przy okazji zobaczymy jakie błędy można popełnić i jak sobie z nimi radzić.

Aby przekształcić otrzymane współczynniki korelacji (z zakresu -1 do 1) na zakres od zera do nieskończoności dodatkowo je logarytmujemy. Dzięki temu dla najbardziej podobnych wektorów (użytkowników) odległość będzie równa zero, a dla najbardziej różnych – nieskończoność. Jeśli chcecie poćwiczyć z innymi miarami – wystarczy odpowiednio zmodyfikować poniższą funkcję:

Ważna sprawa dotycząca wydajności i ograniczeń pamięci. Funkcja cor() buduje macierz kwadratową, która swoje rozmiary ma i odpowiednio dużo zajmuje (zarówno miejsca w pamięci jak i czasu na wygenerowanie). W naszym przypadku 20 losowych użytkowników jest to macierz 20×20 elementów. Jeśli mamy miliony użytkowników jest to szalenie nieefektywne pamięciowo i trzeba szukać innych metod. Można spróbować w pętli policzyć korelację dla kolejnych par (każdy z każdym) i dane trzymać w długiej tabeli (zamiast kwadratowej macierzy) na przykład w bazie danych. W takim przypadku odpowiednio trzeba zmodyfikować funkcję powyżej oraz kolejną (GetRecommendedMovies() która będzie za moment).

Zobaczmy jeszcze co wyszło nam w macierzy podobieństwa: którzy userzy są podobni do siebie? Im bardziej czerwony tym bliższa siebie para (mniejsza odległość).

Widzimy tutaj różne odcienie czerwieni, jest więc różnorako :) Dodatkowo – generujemy losowe oceny losowym filmom, tak więc jeśli ćwiczysz to w domu to wyniki raczej nie będą powtarzalne. Można próbować ustawić generator losowy (set.seed() – ja ustawiłem go na 123456) na określoną wartość na początku. W rzeczywistości dane (oceny) się nie zmieniają (dla uruchomienia tego samego działania w bliskich odstępach czasu) i ten problem nie istnieje.

Sprawdźmy jeszcze na dendogramie jak grupują się użytkownicy i którzy są sobie najbliżsi:

Porównajmy oba rysunki: widać podobieństwo pomiędzy parami: User_04-User_16, User_06-User_10, User_07-User_11. Zarówno są w jednej gałęzi dendrogramu jak i na heatmapie mają najbardziej czerwone kolory.

Rekomendacje

Proces wyboru produktów rekomendowanych polega na:

  • wybraniu określonej liczby podobnych użytkowników, im większa ich liczba tym teoretycznie lepsze rekomendacje
  • wybraniu spośród ocenianych przez nich produktów tych, które mają na przykład najwyższą ocenę (średnią ocen wśród podobnych użytkowników)
  • w drugim punkcie warto odrzucić produkty, które użytkownik dla którego przygotowujemy rekomendację już ocenił (po co polecać coś, co ktoś już zna?)

Przygotujemy do tego funkcję, która znajdzie podobnych użytkowników (tych, których odległości są najmniejsze) i na tej podstawie przygotuje rekomendacje, ale nie tylko. Co się dzieje wewnątrz opisują komentarze, ale też dalszy tekst. W kodzie funkcji wszystkie kroki są rozbite i liczone od początku. Można wszystko zrobić na jednej tabeli, ale chciałem zachować czytelność działań.

Używając tej funkcji możemy przeanalizować przykładowego losowego usera – weźmy pod lupę User_04 i zobaczmy jak działa nasza funkcja. Zobaczmy co dostaniemy w wyniku dla User_04 przy 5 podobnych użytkownikach:

Funkcja na początku wybiera k najbardziej podobnych użytkowników. W drugim kroku szuka filmów ocenionych przez tych podobnych i pozostawia te, które widzieli wszyscy. Dla każdego z filmu liczy średnią ocenę wystawioną przez podobnych. Efekt:

Wspólnie oceniane

Gatunek Tytuł Rok produkcji Średnia ocena podobnych użytkowników Ocena z Filmweb
KomediaObyczajowa Życie 1999 4.6 7.34
Thriller Karmazynowy przypływ 1995 5.3 7.54

Im więcej podobnych użytkowników będziemy brać pod uwagę tym ta lista będzie krótsza – prawdopodobnieństwo, że wszyscy widzieli dany film maleje z liczbą owych wszystkich. Oczywiście w realnym świecie są filmy, które widziało i oceniło bardzo dużo użytkowników.

Rekomendacje

Kolejny krok funkcji to wybór filmów, które użytkownik już ocenił – ich nie będziemy rekomendować, więc odrzucamy je z listy wszystkich ocenionych filmów. Dla całej reszty liczymy średnią z ocen podobnych użytkowników oraz liczymy jaki procent podobnych oceniło dany film (im więcej tym rekomendacja powinna być pewniejsza).

Co zatem jest rekomendowane dla użytkownika?

Gatunek Tytuł Rok produkcji Średnia ocena podobnych użytkowników Liczba ocen podobnych użytkowników
Akcja Brat 1997 9.750000 0.8
Animacja Starsza pani i gołębie 1998 9.500000 0.4
Biograficzny Jak zostać królem 2010 9.500000 0.4
Dokumentalny Takiego pięknego syna urodziłam 1999 9.000000 0.4
Dramat Piękny umysł 2001 9.000000 0.4
Dramat Ray 2004 9.000000 0.4
Dreszczowiec Wetherby 1985 7.000000 0.4
Erotyczny Nigdy nie rozmawiaj z nieznajomym 1995 9.333333 0.6
Horror Obcy 3 1992 9.500000 0.4
Katastroficzny Epicentrum 2002 10.000000 0.4
Komedia Gorączka złota 1925 9.500000 0.4
KomediaKryminalna Kingsman: Tajne służby 2014 9.500000 0.4
KomediaKryminalna 8 kobiet 2002 9.500000 0.4
KomediaKryminalna Trailer Park Boys: Countdown to Liquor Day 2009 9.500000 0.4
KomediaObyczajowa Grzeszny żywot Franciszka Buły 1980 9.000000 0.4
KomediaRomantyczna Cocktail 2012 9.000000 0.4
Kryminał 25. godzina 2002 9.000000 0.4
Kryminał Infernal Affairs: Piekielna gra 2002 9.000000 0.4
Kryminał Do utraty tchu 1960 9.000000 0.4
Obyczajowy Światła sceny 2000 9.333333 0.6
Psychologiczny Przekleństwa niewinności 1999 9.000000 0.4
Psychologiczny Salto 1965 9.000000 0.4
Psychologiczny Służący 1963 9.000000 0.4
SciFi Gwiezdne wojny: Część III – Zemsta Sithów 2005 9.000000 0.4
Sensacyjny Wydział pościgowy 1998 9.000000 0.4
Sensacyjny Firma 1993 9.000000 0.4
Sensacyjny Diamenty są wieczne 1971 9.000000 0.4
Sensacyjny Bullitt 1968 9.000000 0.4
Thriller Blue Velvet 1986 10.000000 0.4
Western Człowiek zwany Koniem 1970 8.500000 0.4
Western Samuraje i kowboje 1971 8.500000 0.4
Wojenny Eroica 1957 8.500000 0.4
Wojenny Lawrence z Arabii 1962 8.500000 0.4
Wojenny Na Zachodzie bez zmian 1930 8.500000 0.4

Przewidywanie oceny

Ostatni krok to policzenie przewidywanej oceny. Najprościej jest wziąć filmy, które widzieli użytkownicy podobni, policzyć średnią ważoną ich ocen gdzie wagą jest miara podobieństwa do użytkownika dla którego wykonujemy predykcję.

Gatunek Tytuł Rok produkcji Przewidywana ocena Ocena na Filmweb
Akcja Baby Driver 2017 10.000000 7.29
Animacja Stalowy gigant 1999 9.256047 7.66
Biograficzny Jak zostać królem 2010 9.784397 7.79
Dokumentalny Kokainowi kowboje 2006 8.778561 7.80
Dokumentalny Międzynarodowe Centrum Szczęśliwych Ludzi 1998 8.778561 7.42
Dramat Wołyń 2016 9.507961 7.94
Dreszczowiec Krzyk strachu 1961 6.665182 6.83
Erotyczny Nigdy nie rozmawiaj z nieznajomym 1995 9.221439 6.31
Horror Kara no Kyokai: Tsukaku Zanryu 2008 9.335684 7.26
Katastroficzny Epicentrum 2002 10.000000 5.54
Komedia Gorączka złota 1925 9.745070 7.79
Komedia Forrest Gump 1994 9.745070 8.55
KomediaKryminalna 8 kobiet 2002 10.000000 7.05
KomediaKryminalna Szajka z Lawendowego Wzgórza 1951 10.000000 7.02
KomediaObyczajowa Grzeszny żywot Franciszka Buły 1980 9.000000 7.02
KomediaRomantyczna Wiele hałasu o nic 1993 9.000000 7.48
KomediaRomantyczna Cocktail 2012 9.000000 6.86
KomediaRomantyczna Jak stracić chłopaka w 10 dni 2003 9.000000 6.79
Kryminał Zagadka zbrodni 2003 10.000000 7.54
Obyczajowy Zabić drozda 1962 10.000000 7.87
Obyczajowy Dobry rok 2006 10.000000 7.25
Obyczajowy Dobosz 2002 10.000000 6.95
Psychologiczny Noc 1961 9.490139 7.52
SciFi Gwiezdne wojny: Część III – Zemsta Sithów 2005 9.854983 7.64
Sensacyjny Bułgarski pościkk 2001 10.000000 7.19
Thriller Blue Velvet 1986 10.000000 7.56
Thriller Obłęd 2005 10.000000 7.55
Thriller Gra 1997 10.000000 7.88
Thriller Zaginiona dziewczyna 2014 10.000000 7.81
Western Człowiek zwany Koniem 1970 10.000000 7.14
Wojenny Życie jest cudem 2004 9.709966 7.62

Zwróćcie uwagę na coś ciekawego: w ramach Dramatów rekomendowany były Piękny umysł oraz Ray (średnia ocena podobnych użytkowników to w obu przypadkach 9, 40% z nich oceniło każdy z filmów). A najwyższą przewidywaną ocenę ma Wołyń. Dlaczego tak się dzieje? Przecież na zdrowy rozum w obu przypadkach na pierwszym miejscu powinien być ten sam film. Spróbujmy to wyjaśnić.

Zaczniemy od sprawdzenia jakie informacje o tych filmach zwraca nam funkcja w obu tabelach.

Rekomendacje:

Tytuł Gatunek User_03 User_12 User_14 User_16 User_20 Średnia ocena podobnych użytkowników Liczba ocen podobnych użytkowników
Piękny umysł Dramat 9 9 9.000000 0.4
Piękny umysł Biograficzny 9 9.000000 0.2
Ray Dramat 9 9 9.000000 0.4
Wołyń Dramat 9 5 9 7.666667 0.6
Wołyń Wojenny 10 10.000000 0.2

Przewidywane oceny:

Gatunek Tytuł Przewidywana ocena Liczba ocen podobnych użytkowników
Dramat Piękny umysł 9.000000 0.4
Dramat Piękny umysł 9.000000 0.2
Biograficzny Piękny umysł 9.000000 0.4
Biograficzny Piękny umysł 9.000000 0.2
Dramat Ray 9.000000 0.4
Dramat Wołyń 9.507961 0.6
Dramat Wołyń 9.507961 0.2
Wojenny Wołyń 9.507961 0.6
Wojenny Wołyń 9.507961 0.2

Widzicie gdzie jest problem? Piękny umysł i Wołyń należą jednocześnie do dwóch gatunków. W związku z tym gdzieś po drodze są liczone oddzielnie, trochę jak dwa różne filmy. Widać to szczególnie w przypadku filmu Smarzowskiego – raz ma średnią ocenę wśród podobnych 7.66 a innym razem 10.

Dzieje się to w funkcji GetRecommendedMovies(), tam gdzie powstaje tabelka wybrane_filmy. Tabelka ta ma więcej wierszy niż wybranych filmów – w przypadku naszej trójki filmów powstaje pięć wierszy zamiast trzech. Należy odpowiednio przebudować ten fragment, tak aby funkcja spread dostała tylko trzy kolumny: film (jego tytuł, a bezpieczniej ID filmu – tytuły mogą się powtórzyć), nazwę użytkownika oraz jego ocenę. Poprawiona wersja wygląda tak (w komentarzach oznaczyłem zmiany):

Jak teraz wyglądają rekomendacje i przewidywane oceny dlanaszej trójki?

Rekomendacje:

User_03 User_12 User_14 User_16 User_20 Średnia ocena podobnych użytkowników Liczba ocen podobnych użytkowników Tytuł Gatunek
9 9 9 9.00 0.6 Piękny umysł Dramat
9 9 9 9.00 0.6 Piękny umysł Biograficzny
9 9 9.00 0.4 Ray Dramat
9 9 9.00 0.4 Ray Biograficzny
9 5 10 9 8.25 0.8 Wołyń Wojenny
9 5 10 9 8.25 0.8 Wołyń Dramat

Przewidywane oceny:

Gatunek Tytuł Przewidywana ocena Liczba ocen podobnych użytkowników
Dramat Piękny umysł 9.000000 0.6
Biograficzny Piękny umysł 9.000000 0.6
Dramat Ray 9.000000 0.4
Dramat Wołyń 9.507961 0.8
Wojenny Wołyń 9.507961 0.8

Dalej filmy są rozbite na gatunki, ale liczby im towarzyszące już są stale takie same. Wołyń nadal nie będzie rekomendowany – średnia ocena wśród podobnych użytkowników jest mniejsza niż ta dla Pięknego umysłu czy Raya. Średnia ocena nie jest oceną ważoną, a jedynie arytmetyczną.

Przewidywana ocena zależy zaś od podobieństwa użytkowników – widocznie piątka od User_14 nie ma tak wielkiego wpływu jak 10 od User_16. I rzeczywiście tak jest: najbardziej podobnym do naszego badanego User_04 był właśnie User_16, tak więc jego ocena ma największą wagę.

Cały ten wywód był po to, aby pokazać jak nawet drobne zmiany (albo przeoczenia) wpływają na wynik rekomendacji. Który z trzech filmów polecić User_04 do obejrzenia? Patrząc na najlepsze według niego dramaty:

Tytuł Rok produkcji Ocena użytkownika
Amarcord 1973 9
Kasyno 1995 9
Krótki film o zabijaniu 1987 9
Leon zawodowiec 1994 9
Przesłuchanie 1982 9
Rękopis znaleziony w Saragossie 1964 9
Ścieżki chwały 1957 9
Bulwar Zachodzącego Słońca 1950 8
Dawno temu w Ameryce 1984 8
Dom z małych kostek 2008 8
Filadelfia 1993 8
Lista Schindlera 1993 8
Nietykalni 2011 8
Pętla 1957 8
Skazani na Shawshank 1994 8
Tam, gdzie rosną poziomki 1957 8

w pierwszej kolejności poleciłbym jednak to co wyszło z rekomendacji (Piękny umysł i Ray), a Wołyń… to zależy od oceny Idź i patrz (dlaczego akutat ten film? trzeba go zobaczyć i porównać z Wołyniem) oraz pozostałych filmów Smarzowskiego:

Tytuł Rok produkcji Ocena użytkownika
Idź i patrz 1985 6
Drogówka 2013 9

Wyliczone 9.5 to chyba za dużo…

Pamiętajmy jednak, że to tylko symulacja.

Dane rzeczywiste

Bardziej sensowne i prawdopodobne wyniki wyjdą nam, kiedy na warsztat weźmiemy dane rzeczywiste i tym samym rzeczywisty gust poszczególnych osób. Tylko skąd pobrać dane o ocenach rzeczywistych użytkowników?

Rozwiązania są dwa. Jedno w R, drugie z użyciem mechanizmów oddzielnych.

W R po prostu wczytamy sobie stronę i wyciągniemy z niej informacje. Niestety – bez zalogowania dostaniemy tylko kilkadziesiąt ostatnich ocen danego użytkownika. Funkcja wygląda tak jak poniżej i jako parametru potrzebuje ciągu z nickiem:

Ja jakiś czas temu skorzystałem ze skryptu, jaki znalazłem na forum Filmwebu, pobrałem dane o kilku użytkownikach i wpakowałem do pliku CSV. Ten plik i wszystkie przygotowane wcześniej funkcje za chwilę wykorzystamy.

Przy okazji: jeśli używacie IMDB i tam oceniacie filmy to jest też ciekawa wtyczka do Chrome

Wyniki dla danych rzeczywistych

Zobaczmy jakie moje oceny znajdziemy, może same 10-tki (wszystkich moich ocen w tym archiwum jest 598, a jest to może 1/3 aktualnego stanu – ten plik jest bardzo stary…):

Gatunek Tytuł Ocena użytkownika
Akcja Batman 10
Dramat Dawno temu w Ameryce 10
Dramat Ojciec chrzestny 10
Dramat Ojciec chrzestny II 10
Dramat Skazani na Shawshank 10
Horror Dziecko Rosemary 10
Horror Lśnienie 10
Komedia Kawa i papierosy 10
Komedia Kawa i papierosy III 10
Komedia Zelig 10
Komedia Żywot Briana 10
KomediaObyczajowa Annie Hall 10
Kryminał Dzikość serca 10
Obyczajowy Ziemia obiecana 10
Psychologiczny Lot nad kukułczym gniazdem 10
Psychologiczny Nóż w wodzie 10
Psychologiczny Truposz 10
Psychologiczny Wstręt 10
SciFi 2001: Odyseja kosmiczna 10
SciFi Metropolis 10
Thriller 21 gramów 10
Thriller Fargo 10
Thriller Lokator 10
Thriller Urodzeni mordercy 10
Thriller Zagubiona autostrada 10

Potrzebujemy oczywiście macierzy podobieństw:

Mało jest podobnych do mnie użytkowników w tej bazie. Z dendrogramu

wynika, że MalwinaG powinna być najbliżej. Znam Malwinę i znam jej oceny – zgadza się.

Zobaczmy co rekomenduje maszyneria:

Tytul Rok produkcji Średnia ocena podobnych użytkowników Ocena na Filmweb
Święci z Bostonu 1999 8.666667 7.84
Imperium Słońca 1987 8.333333 7.80
Gran Torino 2008 7.833333 8.21
Sugar Man 2012 7.666667 7.74
Człowiek w ogniu 2004 7.250000 7.90
Helikopter w ogniu 2001 7.250000 7.79
W pogoni za szczęściem 2006 7.000000 8.10
Gwiezdne wojny: Przebudzenie Mocy 2015 7.000000 7.47
Tańczący z wilkami 1990 6.666667 7.76
Monachium 2005 6.666667 7.40
To właśnie miłość 2003 6.666667 7.60
Wszystko za życie 2007 6.333333 7.92

Wśród powyższych rekomendowanych filmów część widziałem i nie były to gnioty, nie jest więc źle. A co z proponowanymi ocenami?

Tytuł Rok produkcji Przewidywana ocena Ocena na Filmweb
Święci z Bostonu 1999 8.799850 7.84
Gran Torino 2008 8.562072 8.21
Imperium Słońca 1987 8.439186 7.80
Wszystko za życie 2007 7.505476 7.92
Sugar Man 2012 7.272766 7.74
W pogoni za szczęściem 2006 7.000000 8.10
To właśnie miłość 2003 6.930428 7.60
Człowiek w ogniu 2004 6.768800 7.90
Helikopter w ogniu 2001 6.545532 7.79
Tańczący z wilkami 1990 6.300580 7.76
Monachium 2005 6.132817 7.40
Gwiezdne wojny: Przebudzenie Mocy 2015 5.775787 7.47

Z tego co widziałem i pamiętam w tym momencie:

  • Gran Torino mnie wynudził, nie przepadam za filmami Eastwooda i zawsze oceniam niżej niż znajomi
  • To właśnie miłość – prawie siódemka… tak, zgadzam się – dałbym temu filmowi 7/10, bo to dobrze zrobiona komedia romantyczna (chociaż prosta w konstrukcji)
  • Helikopter w ogniu – chyba nie obejrzałem do końca, ale byłaby to co najmniej 7/10
  • Tańczący z wilkami – ten film widziałem tak bardzo dawno temu, że nie podejmuję się go oceniać w tym momencie
  • Monachium z nieco ponad 6? Pamiętam, że mnie wcale nie wzięło, wynudziłem się. Byłaby to 5 albo 6
  • Przebudzenie Mocy – to te przeodstatnie? Bardziej piątka niż szóstka. Ale wielkim fanem Star Wars nie jestem, a jeśli już to wolę pierszą (w kolejności kręcenia) trylogię
  • Święci z Bostonu – tego filmu nie widziałem i kiedyś wreszcie muszę nadrobić, bo często ten tytuł się przewija przed moimi oczami jako pasujący do mojego gustu

Warto przeczytać

Na koniec dwa linki, które warto prześledzić jeśli chcecie dowiedzieć się czegoś więcej o systemach rekomendacyjnych (oba dotyczą problemu rekomendacji filmów).

  • Pierwszy to nieprzebrane źródło wiedzy jakim jest Kaggle.com – jest tam zestaw danych The Movies Dataset i kernele do niego podczepione opisują co i jak – zarówno w R jak i w Pythonie.
  • Drugi, według mnie bardzo ciekawy wpis to Silnik rekomendacji filmów na blogu Mateusza Grzyba. Mateusz zaprezentował opisany materiał na Meetupie, z którego materiały znajdziecie tutaj.

4 komentarze do “Jaki film obejrzeć?”

  1. Napisałem sobie kiedyś rekomendacje dla serwisu książkowego i algorytm był mniej więcej podobny. :) Ale jest parę pułapek, na które trzeba uważać.

    1. Jeśli użytkownik ocenił wszystkie filmy na tą sama ocenę (np. tylko 10, albo tylko 1), to nie da się policzyć korelacji z nim. Z drugiej strony taki użytkownik jest mało wiarygodny i pewnie nic nie wnosi do rekomendacji. Nie jest to jednak przypadek wydumany. W bazie widziałem użytkowników, którzy książki pewnych kategorii hurtowo oceniali na MIN lub MAX. Najczęściej była to kategoria „religijne”.
    2. Zero ma wartość liczbową i mocno psuje liczenie korelacji. Przykład:
    User_01”, który ocenił 10 filmów (przyjmijmy, że filmów jest 100) ma lepszą korelację z użytkownikiem, „User_02”, który ocenił te same 10 filmów zupełnie inaczej, niż z użytkownikiem „User_03”, który ocenił 90 filmów, w tym wszystkie 10 tak samo jak „User_01”
    Korelację warto by liczyć tylko dla wspólnie ocenionych filmów i jeszcze wprowadzić jakieś minimum. Pewnie nie da się tego zrobić jedna zgrabną instrukcją, ale zawsze możne pętlą. Próbowałem nieocenione ustawiać na NA i różnych argumentów „use” dla funkcji cor(), ale to chyba nie pomoże.

    3. Korelacja daje czasami nieintuicyjne wyniki.
    Np. jeśli „User_01” oceni tylko jeden film np. na 1, a „User_02” oceni tylko ten jeden film na 10, to korelacja jest 1. (Takich użytkowników jest sporo. Wpadnie na chwilę, oceni kilka pozycji i już nie wraca)
    Inny przykład dla 10 filmów:
    „User_01” ocenił filmy kolejno na 1 3 1 2 0 0 0 9 8 9
    „User_02” ocenił filmy kolejno na 8 10 8 9 1 2 2 0 0 0
    Korelacja na podstawie pierwszych czterech jest 1. Czy to źle? Nie! Bo zgodnie oceniają film 2 najlepiej, a filmy 1 i 3 najgorzej. Ale dla jednego są to filmy najgorsze, a dla drugiego najlepsze. Taka korelacja niesie nam sporo informacji, ale pewnie trzeba by to jakoś sensownie użyć. Na oko wydaje się, że przy liczeniu korelacji należy uwzględniać tylko wspólnie ocenione filmy, ale odchylenie liczyć od średniej ze wszystkich ocen użytkownika.

    4. Nie musimy liczyć korelacji każdy z każdym. Jeśli liczymy rekomendacje dla „User_01” to wystarczy policzyć N-1 korelacji z użytkownikami „User_02”-„User_N”. Być może pełna macierz korelacji była by przydatna jeśli liczenie korelacji jest kosztowne. Dla serwisu książkowego liczenie na żądanie korelacji jednego użytkownika z pozostałymi(>50000) przy ograniczeniu tylko do wspólnie ocenionych książek było bardzo szybkie. (średnio wspólne było około kilkanaście-kilkadziesiąt książek z bazy ponad 100000)

    5. Przy wyliczaniu przewidywanych ocen warto wziąć też pod uwagę jaka jest średnia ocen osoby, która nam poleca filmy. Np. 10 od osoby, której średnia jest około 7, może oznaczać film dla niej wybitny, z kolei u osoby której średnia ocen jest około 9, ocena 10 dla filmu jest pewnie prawie normą. (Ale tez może się okazać, że ta pierwsza jest krytykiem filmowym, który zawodowo musi oglądać wiele gniotów ;) ). W moim algorytmie podciągałem oceny o procentowe odchylenie oceny filmu od średniej dla tej osoby. W efekcie przewidywana ocena czasami wyskakiwała ponad MAX, ale informacja, że dany film będzie się podobał na 11,5 też jest interesująca.

    6. Wiem, że dla czytelności są pewne uproszczenia, ale też nigdy nie zaszkodzi przypomnieć, że gdyby ktoś chciał pociągnąć temat to technicznie lepiej w tabelach mieć identyfikatory filmów i użytkowników, zamiast ciągnąć ze sobą pełne tytuły i nazwy. Być może R sobie poradzi z wydajnością operacji na takich pełnych tabelach, ale nigdy nie zaszkodzi samemu oszczędzić na pamięci. (to takie moje skrzywienie dotyczące optymalizacji i trzeciej postaci normalnej ;) )

    W moim algorytmie dałem trzy parametry. Minimalna liczba wspólnie ocenionych książek, minimalne podobieństwo osób branych pod uwagę i minimalna liczba podobnych osób polecających daną pozycję. Żonglując wartościami można dostosować specyfikę algorytmu, np. żeby polecał książki w sposób bardziej bezpieczny (duże podobieństwo, dużo poleceń), lub bardziej ryzykancki (mniej wspólnych ocen, mniej poleceń, duże podobieństwo). Wyniki były całkiem ciekawe. :) Niestety taki algorytm jest jednak dosyć prosty i nie zawsze dobrze działa. Daje radę dla użytkowników z rozsądnie niewielką liczbą ocen i dla bardziej bezpiecznych ustawień. (Ale równie dobrze można by wtedy brać topowe pozycje z rankingów). Dla maniaków z tysiącami ocen i specyficznym guście już jest gorzej. Chciałem kiedyś poprawić i przepisać algorytm (z C). R wygląda całkiem nieźle do tego celu, tylko muszę się jeszcze trochę podszkolić.

    1. Dzięki za świetny komentarz – wszystko się zgadza, a dotyczy głównie korelacji jako miary podobieństwa. Tak jak napisałem w poście – nie jest to najlepsza miara, lepszą jest chociażby odległość kosinusowa.

      Swoją drogą – odnośnie punktu 3:

      > User_01 = c(1, 3, 1, 2, 0, 0, 0, 9, 8, 9)
      > User_02 = c(8, 10, 8, 9, 1, 2, 2, 0, 0, 0)
      > cor(User_01, User_02) # korelacja
      [1] -0.4706835
      > lsa::cosine(User_01, User_02) # odległość kosinusowa
      [,1]
      [1,] 0.2311841

      ;)

      Jeśli chodzi o wydajność – R jest wolny. Lepsze efekty są w Pythonie. Oczywiście masz rację – wystarczą same IDki filmów. Liczenie całych macierzy odległości dla użytkowników każdy z każdym też jest wątpliwe, ale… może się okazać lepszym rozwiązaniem przeliczenie całości raz na dobę zamiast w locie.
      Filmweb pokazuje procent, że dany film mi się spodoba – tego nie może robić w locie, maszyny by umarły. Swoją drogą średnią ocenę filmu też przeliczają co jakiś czas (badałem jak się ona zmienia w czasie i są wyraźne skoki)

    2. Uwielbiam oglądać filmy i z chęcią bym sobie teraz coś włączyła, ale niestety nie mam jeszcze kupionych złącz antenowych. Gdy tylko je zamówię to w końcu będę mogła oglądać telewizję, a jest to moja ulubiona rozrywka.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *