# Nearest Neighbor Item-based Collaborative Filtering

This notebook is a toy implementation of the classic collaborative filtering algorithm. The purpose of this implementation is to provide a small and clear numerical example.

### Detailed Description
See [Introduction to Algorithmic Marketing](https://algorithmicweb.wordpress.com/ ) book

### Data
We use a small rating matrix defined inline. No external datasets are used.


```python
%matplotlib inline
import sympy as sy
import numpy as np
import matplotlib.pyplot as plt
```


```python
# Input rating matrix
# X stands for unknown ratings
X = np.nan
R = np.array([
    [5, 4, X, 1, 2, 1], #  
    [4, X, 3, 1, 1, 2], #
    [X, 5, 5, X, 3, 3], # users
    [2, X, 1, 4, 5, 4], # 
    [2, 2, 2, X, 4, X], #
    [1, 2, 1, X, 5, 4]  #
   #       items 
])
```


```python
# Define common varibales and helper functions
n, m = R.shape

def known(r):
    return not np.isnan(r)

def known_item_ratings(R, i):
    return [r for r in R[:,i] if known(r)]

def item_common_ratings(R, i, j):
    return np.array(list(filter(
        lambda r: all(known(val) for val in r), 
        np.column_stack((R[:,i], R[:,j]))
    )))

def mean_r(R, i):
    return np.mean(known_item_ratings(R, i))
```


```python
# Calculate the matrix of item similarities
def similarity(R, i, j):
    U_ij = item_common_ratings(R, i, j)
    mu_i = mean_r(R, i)
    mu_j = mean_r(R, j)
    return sum([ 
          ((U_ij[u,0] - mu_i)*(U_ij[u,1] - mu_j)) / 
          (np.linalg.norm(U_ij[:,0] - mu_i) * np.linalg.norm(U_ij[:,1] - mu_j)) 
          for u in range(U_ij.shape[0])])

item_similarity = np.array([[
    similarity(R, i, j)
    for i in range(m)] for j in range(m)])
```


```python
# Predict ratings based on the item similarities
k = 2 # neighborhood size

def predict_rating(R, u, i):
    # neighbors sorted by similarity
    all_neighbors = np.argsort(item_similarity[i])[::-1]
    
    # remove neighbors without ratings for u and select top k
    neighbors = list(filter(lambda j: known(R[u,j]) and not i==j, all_neighbors))[:k] 
    score = 0 
    norm = 0
    print("user %s, item %s <- item neighbors %s" % (u, i, neighbors))
    for j in neighbors:
        score = score + item_similarity[i,j]*R[u,j]
        norm = norm + abs(item_similarity[i,j])
    return score/norm

ratings = np.array([[ R[u,i] if known(R[u,i]) else predict_rating(R, u, i)
   for i in range(m)] for u in range(n)])

print("\nComplete rating matrix:")
np.set_printoptions(precision=2)
print(ratings)
```

    user 0, item 2 <- item neighbors [1, 0]
    user 1, item 1 <- item neighbors [2, 0]
    user 2, item 0 <- item neighbors [2, 1]
    user 2, item 3 <- item neighbors [4, 5]
    user 3, item 1 <- item neighbors [2, 0]
    user 4, item 3 <- item neighbors [4, 0]
    user 4, item 5 <- item neighbors [4, 1]
    user 5, item 3 <- item neighbors [4, 5]
    
    Complete rating matrix:
    [[5.   4.   4.5  1.   2.   1.  ]
     [4.   3.49 3.   1.   1.   2.  ]
     [5.   5.   5.   3.   3.   3.  ]
     [2.   1.49 1.   4.   5.   4.  ]
     [2.   2.   2.   1.23 4.   1.81]
     [1.   2.   1.   4.51 5.   4.  ]]



```python

```

54c9b43fa59746726e5498b3d4216aa2cc759e14
ipynb
Jupyter Notebook
recommendations/item-based-cf.ipynb
DeloitteHux/tensor-house
8e9fb7685e33ed159b3bb1ff05eeb3db42dd2ee6
Apache-2.0
2020-02-24T05:11:07.000Z
2022-03-31T01:18:56.000Z
recommendations/item-based-cf.ipynb
pponnada/tensor-house
01950fda7ecfaa7f3fc7d827a14c5c37788a7bf3
Apache-2.0
2020-04-21T16:39:55.000Z
2021-06-15T15:49:40.000Z
recommendations/item-based-cf.ipynb
pponnada/tensor-house
01950fda7ecfaa7f3fc7d827a14c5c37788a7bf3
Apache-2.0
2020-02-27T12:21:42.000Z
2022-03-31T11:15:09.000Z
Qwen/Qwen-72B
1. YES
2. YES