{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Getting Started\n", "\n", "This notebook gets you started with a brief nDCG evaluation with LensKit for Python.\n", "\n", "This notebook is also available on [Google Collaboratory](https://colab.research.google.com/drive/1ym040cKkQf85epu80VtIkMXy3LpfYQky?usp=sharing) and [nbviewer](https://nbviewer.jupyter.org/github/lenskit/lkpy/blob/master/doc/GettingStarted.ipynb)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup\n", "\n", "We first import the LensKit components we need:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from lenskit import batch, topn, util\n", "from lenskit import crossfold as xf\n", "from lenskit.algorithms import Recommender, als, knn\n", "from lenskit.data import from_interactions_df\n", "from lenskit.data.movielens import load_movielens_df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And Pandas is very useful:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import pandas as pd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `pyprojroot` package makes it easy to find input data:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "from pyprojroot.here import here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loading Data\n", "\n", "We're going to use the ML-100K data set:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
useritemratingtimestamp
01962423.0881250949
11863023.0891717742
2223771.0878887116
3244512.0880606923
41663461.0886397596
\n", "
" ], "text/plain": [ " user item rating timestamp\n", "0 196 242 3.0 881250949\n", "1 186 302 3.0 891717742\n", "2 22 377 1.0 878887116\n", "3 244 51 2.0 880606923\n", "4 166 346 1.0 886397596" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ml100k = load_movielens_df(here('data/ml-100k.zip'))\n", "ml100k.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Defining Algorithms\n", "\n", "Let's set up two algorithms:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "algo_ii = knn.ItemItem(20)\n", "algo_als = als.BiasedMF(50)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Running the Evaluation\n", "\n", "In LensKit, our evaluation proceeds in 2 steps:\n", "\n", "1. Generate recommendations\n", "2. Measure them\n", "\n", "If memory is a concern, we can measure while generating, but we will not do that for now.\n", "\n", "We will first define a function to generate recommendations from one algorithm over a single partition of the data set. It will take an algorithm, a train set, and a test set, and return the recommendations.\n", "\n", "**Note:** before fitting the algorithm, we clone it. Some algorithms misbehave when fit multiple times.\n", "\n", "**Note 2:** our algorithms do not necessarily implement the `Recommender` interface, so we adapt them. This fills in a default candidate selector.\n", "\n", "The code function looks like this:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "def eval(aname, algo, train, test):\n", " fittable = util.clone(algo)\n", " fittable = Recommender.adapt(fittable)\n", " fittable.fit(from_interactions_df(train))\n", " users = test.user.unique()\n", " # now we run the recommender\n", " recs = batch.recommend(fittable, users, 100)\n", " # add the algorithm name for analyzability\n", " recs['Algorithm'] = aname\n", " return recs" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, we will loop over the data and the algorithms, and generate recommendations:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/Users/mde48/LensKit/lkpy/lenskit/lenskit/data/dataset.py:628: UserWarning: Sparse CSR tensor support is in beta state. If you miss a functionality in the sparse tensor support, please submit a feature request to https://github.com/pytorch/pytorch/issues. (Triggered internally at /Users/runner/miniforge3/conda-bld/libtorch_1719361060788/work/aten/src/ATen/SparseCsrTensorImpl.cpp:55.)\n", " return torch.sparse_csr_tensor(\n" ] } ], "source": [ "all_recs = []\n", "test_data = []\n", "for train, test in xf.partition_users(ml100k[['user', 'item', 'rating']], 5, xf.SampleFrac(0.2)):\n", " test_data.append(test)\n", " all_recs.append(eval('ItemItem', algo_ii, train, test))\n", " all_recs.append(eval('ALS', algo_als, train, test))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With the results in place, we can concatenate them into a single data frame:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
itemscoreuserrankAlgorithm
014494.99497521ItemItem
113984.86685122ItemItem
25114.84539923ItemItem
315124.80541324ItemItem
415944.78846825ItemItem
\n", "
" ], "text/plain": [ " item score user rank Algorithm\n", "0 1449 4.994975 2 1 ItemItem\n", "1 1398 4.866851 2 2 ItemItem\n", "2 511 4.845399 2 3 ItemItem\n", "3 1512 4.805413 2 4 ItemItem\n", "4 1594 4.788468 2 5 ItemItem" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "all_recs = pd.concat(all_recs, ignore_index=True)\n", "all_recs.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To compute our analysis, we also need to concatenate the test data into a single frame:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "test_data = pd.concat(test_data, ignore_index=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We analyze our recommendation lists with a `RecListAnalysis`. It takes care of the hard work of making sure that the truth data (our test data) and the recoommendations line up properly.\n", "\n", "We do assume here that each user only appears once per algorithm. Since our crossfold method partitions users, this is fine." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
nrecsndcg
Algorithmuser
ItemItem21000.081186
61000.288946
81000.082112
101000.364167
141000.182636
\n", "
" ], "text/plain": [ " nrecs ndcg\n", "Algorithm user \n", "ItemItem 2 100 0.081186\n", " 6 100 0.288946\n", " 8 100 0.082112\n", " 10 100 0.364167\n", " 14 100 0.182636" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rla = topn.RecListAnalysis()\n", "rla.add_metric(topn.ndcg)\n", "results = rla.compute(all_recs, test_data)\n", "results.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we have nDCG values!" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Algorithm\n", "ALS 0.132649\n", "ItemItem 0.096963\n", "Name: ndcg, dtype: float64" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "results.groupby('Algorithm').ndcg.mean()" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "results.groupby('Algorithm').ndcg.mean().plot.bar()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.9" } }, "nbformat": 4, "nbformat_minor": 2 }