Basic Content Based Recommendation#

[4]:
import numpy as np
import tensorflow as tf
[5]:
users = [ 'user1', 'user2', 'user3', 'user4' ]
movies = [ 'movie1', 'movie2', 'movie3', 'movie4', 'movie5', 'movie6']
features = [ 'action', 'drama', 'scifi', 'comedy', 'animated']

n_users = len(users)
n_movies = len(movies)
n_features = len(features)

References#

Strategy#

  1. create a user-item matrix.

  2. create a item-feature matrix.

  3. multiplying user-item and item-feature, to create user-feature matrix.

  4. normalize user-feature matrix.

  5. create a user and non-interacted item matrix, to only recommend non-interacted items to users.

  6. elementwise multiplication of user-item and user-non_interacted_item matrix to get only ratings of non interacted items.

  7. get indexes of top k rated non interacted items, k number of recommendations.

user-item matrix#

sparse matrix for user and items rating matrix.

          items
       +-------------+
       |             |
users  |             |
       |             |
       |             |
       |             |
       +-------------+

shape \((n_{users}, n_{items})\)

[6]:
users, movies
[6]:
(['user1', 'user2', 'user3', 'user4'],
 ['movie1', 'movie2', 'movie3', 'movie4', 'movie5', 'movie6'])
[7]:
user_movies = tf.constant([
    [5, 6, 8, 0, 0, 1],
    [0, 0, 10, 10, 0, 5],
    [0, 9, 5, 5, 0, 0],
    [1, 5, 0, 0, 0, 5]
], dtype=tf.float32)

item-feature martix#

k-hot encoded matrix of item and feature matrix.

          features
       +-------------+
       |             |
items  |             |
       |             |
       |             |
       |             |
       +-------------+

shape : \((n_{items}, n_{features})\)

[8]:
movies, features
[8]:
(['movie1', 'movie2', 'movie3', 'movie4', 'movie5', 'movie6'],
 ['action', 'drama', 'scifi', 'comedy', 'animated'])
[9]:
movie_features = tf.constant([
    [1, 0, 1, 0 ,0],
    [0, 1, 0, 1, 0],
    [0, 1, 0, 1, 1],
    [1, 1, 0, 0, 1],
    [0, 0, 1, 0, 1],
    [0, 0, 1, 1, 1]
], dtype=tf.float32)

user-feature matrix#

\((n_{users}, n_{items}) \times (n_{items}, n_{features})\)

          items                      features                    features
       +-------------+            +-------------+             +-------------+
       |             |            |             |             |             |
users  |             |      items |             |      users  |             |
       |             |    X       |             |  =          |             |
       |             |            |             |             |             |
       |             |            |             |             |             |
       +-------------+            +-------------+             +-------------+
                                         ___
                                          |
         item_1   item_2   item_3         |            feature_1   feature_2   feature_3
       +---------------------------+      |           +-----------------------------------------+
user_1 |                                  |   item_1  |
       |      represents user             |           |     individual features for different
user_2 |      and items relation          |   item_2  |           items
       |                                  |           |
                                          |   item_3  |
                                          |           |
                                          |
                                          |
[10]:
user_feaures = user_movies @ movie_features
user_feaures
[10]:
<tf.Tensor: shape=(4, 5), dtype=float32, numpy=
array([[ 5., 14.,  6., 15.,  9.],
       [10., 20.,  5., 15., 25.],
       [ 5., 19.,  0., 14., 10.],
       [ 1.,  5.,  6., 10.,  5.]], dtype=float32)>

normalizing the matrix

[11]:
user_features_norm = user_feaures / tf.reduce_sum(user_feaures, axis=0, keepdims=True)
user_features_norm
[11]:
<tf.Tensor: shape=(4, 5), dtype=float32, numpy=
array([[0.23809524, 0.2413793 , 0.3529412 , 0.2777778 , 0.18367347],
       [0.47619048, 0.3448276 , 0.29411766, 0.2777778 , 0.5102041 ],
       [0.23809524, 0.3275862 , 0.        , 0.25925925, 0.20408164],
       [0.04761905, 0.0862069 , 0.3529412 , 0.18518518, 0.10204082]],
      dtype=float32)>

user feature preference#

get top k values from the user-feature matrix.

tensorflow’s function to get top k values.

[12]:
tf.nn.top_k(user_features_norm, k=1)
[12]:
TopKV2(values=<tf.Tensor: shape=(4, 1), dtype=float32, numpy=
array([[0.3529412],
       [0.5102041],
       [0.3275862],
       [0.3529412]], dtype=float32)>, indices=<tf.Tensor: shape=(4, 1), dtype=int32, numpy=
array([[2],
       [4],
       [1],
       [2]], dtype=int32)>)
[13]:
top_values, top_feature_idx = tf.nn.top_k(user_features_norm, k=n_features)
[14]:
top_values
[14]:
<tf.Tensor: shape=(4, 5), dtype=float32, numpy=
array([[0.3529412 , 0.2777778 , 0.2413793 , 0.23809524, 0.18367347],
       [0.5102041 , 0.47619048, 0.3448276 , 0.29411766, 0.2777778 ],
       [0.3275862 , 0.25925925, 0.23809524, 0.20408164, 0.        ],
       [0.3529412 , 0.18518518, 0.10204082, 0.0862069 , 0.04761905]],
      dtype=float32)>
[15]:
top_feature_idx
[15]:
<tf.Tensor: shape=(4, 5), dtype=int32, numpy=
array([[2, 3, 1, 0, 4],
       [4, 0, 1, 2, 3],
       [1, 3, 0, 4, 2],
       [2, 3, 4, 1, 0]], dtype=int32)>
[16]:
for i in range(n_users):
    print(users[i]," : ", [features[index] for index in top_feature_idx[i]])
user1  :  ['scifi', 'comedy', 'drama', 'action', 'animated']
user2  :  ['animated', 'action', 'drama', 'scifi', 'comedy']
user3  :  ['drama', 'comedy', 'action', 'animated', 'scifi']
user4  :  ['scifi', 'comedy', 'animated', 'drama', 'action']

Get movie recommendations#

[17]:
user_ratings = user_features_norm @ tf.transpose(movie_features)

user_ratings
[17]:
<tf.Tensor: shape=(4, 6), dtype=float32, numpy=
array([[0.59103644, 0.5191571 , 0.70283055, 0.66314805, 0.53661466,
        0.81439245],
       [0.77030814, 0.6226054 , 1.1328094 , 1.3312222 , 0.80432177,
        1.0820996 ],
       [0.23809524, 0.58684546, 0.7909271 , 0.7697631 , 0.20408164,
        0.46334088],
       [0.40056023, 0.27139208, 0.3734329 , 0.23586676, 0.454982  ,
        0.6401672 ]], dtype=float32)>
[18]:
user_movies
[18]:
<tf.Tensor: shape=(4, 6), dtype=float32, numpy=
array([[ 5.,  6.,  8.,  0.,  0.,  1.],
       [ 0.,  0., 10., 10.,  0.,  5.],
       [ 0.,  9.,  5.,  5.,  0.,  0.],
       [ 1.,  5.,  0.,  0.,  0.,  5.]], dtype=float32)>
[19]:
unseen_movies = tf.equal(user_movies, tf.zeros_like(user_movies))
unseen_movies
[19]:
<tf.Tensor: shape=(4, 6), dtype=bool, numpy=
array([[False, False, False,  True,  True, False],
       [ True,  True, False, False,  True, False],
       [ True, False, False, False,  True,  True],
       [False, False,  True,  True,  True, False]])>
[20]:
ignore_matrix = tf.zeros_like(user_movies)
ignore_matrix
[20]:
<tf.Tensor: shape=(4, 6), dtype=float32, numpy=
array([[0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0.]], dtype=float32)>
[21]:
new_ratings = tf.where(condition=unseen_movies, x=user_ratings, y=ignore_matrix)

new_ratings
[21]:
<tf.Tensor: shape=(4, 6), dtype=float32, numpy=
array([[0.        , 0.        , 0.        , 0.66314805, 0.53661466,
        0.        ],
       [0.77030814, 0.6226054 , 0.        , 0.        , 0.80432177,
        0.        ],
       [0.23809524, 0.        , 0.        , 0.        , 0.20408164,
        0.46334088],
       [0.        , 0.        , 0.3734329 , 0.23586676, 0.454982  ,
        0.        ]], dtype=float32)>

2 movie recommendations#

[22]:
top_movies_idx = tf.nn.top_k(user_ratings, k = 2)[1]
[23]:
for i in range(n_users):
    print(users[i], [movies[index] for index in top_movies_idx[i]])
user1 ['movie6', 'movie3']
user2 ['movie4', 'movie3']
user3 ['movie3', 'movie4']
user4 ['movie6', 'movie5']

Building Reco system with movie data#

[24]:
import pandas as pd
[25]:
ratings = pd.read_csv('/opt/datasetsRepo/RecommendationData/ratings.csv')
ratings.head()
[25]:
userId movieId rating timestamp
0 1 1 4.0 964982703
1 1 3 4.0 964981247
2 1 6 4.0 964982224
3 1 47 5.0 964983815
4 1 50 5.0 964982931
[26]:
ratings.shape
[26]:
(100836, 4)
[27]:
movies = pd.read_csv("/opt/datasetsRepo/RecommendationData/movies.csv")
movies.head()
[27]:
movieId title genres
0 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy
1 2 Jumanji (1995) Adventure|Children|Fantasy
2 3 Grumpier Old Men (1995) Comedy|Romance
3 4 Waiting to Exhale (1995) Comedy|Drama|Romance
4 5 Father of the Bride Part II (1995) Comedy
[28]:
movies.shape
[28]:
(9742, 3)

mappers#

though here movie id’s and user id’s are integer. In real scenarios they aren’t. For a quick fix we can create mappers to convert id’s to indexes. these mappers generally helps creating sparse matrix.

[29]:
idx_to_movieid_mapper = dict(enumerate(movies.movieId.unique()))
[30]:
movieid_to_idx_mapper = dict(zip(idx_to_movieid_mapper.values(), idx_to_movieid_mapper.keys()))
[31]:
idx_to_userid_mapper = dict(enumerate(ratings.userId.unique()))
[32]:
userid_to_idx_mapper = dict(zip(idx_to_userid_mapper.values(), idx_to_userid_mapper.keys()))

apply mappers#

[33]:
movies['movie_idx'] = movies['movieId'].map(movieid_to_idx_mapper)

movies.head()
[33]:
movieId title genres movie_idx
0 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy 0
1 2 Jumanji (1995) Adventure|Children|Fantasy 1
2 3 Grumpier Old Men (1995) Comedy|Romance 2
3 4 Waiting to Exhale (1995) Comedy|Drama|Romance 3
4 5 Father of the Bride Part II (1995) Comedy 4
[34]:
ratings['user_idx'] = ratings['userId'].map(userid_to_idx_mapper)
ratings['movie_idx'] = ratings['movieId'].map(movieid_to_idx_mapper)
ratings.head()
[34]:
userId movieId rating timestamp user_idx movie_idx
0 1 1 4.0 964982703 0 0
1 1 3 4.0 964981247 0 2
2 1 6 4.0 964982224 0 5
3 1 47 5.0 964983815 0 43
4 1 50 5.0 964982931 0 46

user movie sparse rating matrix#

[35]:
user_movies_sparse_matrix = tf.sparse.SparseTensor(
    indices=ratings[['user_idx', 'movie_idx']],
    values=ratings['rating'],
    dense_shape=[len(idx_to_userid_mapper), len(idx_to_movieid_mapper)]
)
[36]:
n_users, n_movies = user_movies_sparse_matrix.get_shape()

movies features(genere) k hot matrix#

[37]:
movies['genres_arr'] = movies['genres'].apply(lambda x: x.split("|"))
movies.head()
[37]:
movieId title genres movie_idx genres_arr
0 1 Toy Story (1995) Adventure|Animation|Children|Comedy|Fantasy 0 [Adventure, Animation, Children, Comedy, Fantasy]
1 2 Jumanji (1995) Adventure|Children|Fantasy 1 [Adventure, Children, Fantasy]
2 3 Grumpier Old Men (1995) Comedy|Romance 2 [Comedy, Romance]
3 4 Waiting to Exhale (1995) Comedy|Drama|Romance 3 [Comedy, Drama, Romance]
4 5 Father of the Bride Part II (1995) Comedy 4 [Comedy]
[38]:
movies_tmp = movies[['movie_idx','genres_arr']].explode('genres_arr').drop_duplicates()
movies_tmp.head()
[38]:
movie_idx genres_arr
0 0 Adventure
0 0 Animation
0 0 Children
0 0 Comedy
0 0 Fantasy
[39]:
movies_tmp.insert(loc=0, value=1, column='cnt')

movie_features_sparse_matrix =  movies_tmp.pivot_table(index='movie_idx', columns='genres_arr', values='cnt', aggfunc='count').fillna(0)

movie_features_sparse_matrix.head()
[39]:
genres_arr (no genres listed) Action Adventure Animation Children Comedy Crime Documentary Drama Fantasy Film-Noir Horror IMAX Musical Mystery Romance Sci-Fi Thriller War Western
movie_idx
0 0.0 0.0 1.0 1.0 1.0 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
1 0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
2 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0
3 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0
4 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
[40]:
features = movie_features_sparse_matrix.columns
features
[40]:
Index(['(no genres listed)', 'Action', 'Adventure', 'Animation', 'Children',
       'Comedy', 'Crime', 'Documentary', 'Drama', 'Fantasy', 'Film-Noir',
       'Horror', 'IMAX', 'Musical', 'Mystery', 'Romance', 'Sci-Fi', 'Thriller',
       'War', 'Western'],
      dtype='object', name='genres_arr')
[41]:
n_movies, n_features = movie_features_sparse_matrix.shape

user features matrix#

[42]:
user_feaures_matrix = tf.sparse.to_dense(user_movies_sparse_matrix) @ movie_features_sparse_matrix
[43]:
user_feaures_normalized_matrix = user_feaures_matrix / tf.reduce_sum(user_feaures_matrix, axis=0, keepdims=True)
user_feaures_normalized_matrix
[43]:
<tf.Tensor: shape=(610, 20), dtype=float64, numpy=
array([[0.        , 0.0036827 , 0.00440006, ..., 0.00246712, 0.00535005,
        0.00433714],
       [0.        , 0.00041182, 0.00014746, ..., 0.00040037, 0.00024318,
        0.000506  ],
       [0.        , 0.00047335, 0.00035389, ..., 0.0003138 , 0.0001351 ,
        0.        ],
       ...,
       [0.        , 0.0087334 , 0.00687731, ..., 0.00991176, 0.00367478,
        0.00419257],
       [0.        , 0.00032188, 0.00037749, ..., 0.00049775, 0.00075657,
        0.00057829],
       [0.        , 0.017623  , 0.01167256, ..., 0.01972072, 0.00959226,
        0.01785456]])>

get user genre preferences#

[44]:
top_values, top_feature_idx = tf.nn.top_k(user_feaures_normalized_matrix, k=n_features)
[45]:
top_feature_idx
[45]:
<tf.Tensor: shape=(610, 20), dtype=int32, numpy=
array([[13,  4,  3, ...,  0,  7, 12],
       [ 7, 12,  6, ...,  9, 10, 13],
       [11, 16,  1, ..., 10, 12, 19],
       ...,
       [11, 17, 16, ..., 18, 12,  0],
       [ 7, 18, 19, ..., 10, 13, 14],
       [11, 12, 17, ...,  7, 13,  0]], dtype=int32)>
[46]:
for i in range(10):
    print(idx_to_userid_mapper[i]," : ", [features[index.numpy()] for index in top_feature_idx[i]])
1  :  ['Musical', 'Children', 'Animation', 'War', 'Fantasy', 'Adventure', 'Western', 'Action', 'Crime', 'Sci-Fi', 'Mystery', 'Comedy', 'Horror', 'Thriller', 'Drama', 'Romance', 'Film-Noir', '(no genres listed)', 'Documentary', 'IMAX']
2  :  ['Documentary', 'IMAX', 'Crime', 'Western', 'Drama', 'Action', 'Thriller', 'Mystery', 'Sci-Fi', 'War', 'Comedy', 'Adventure', 'Horror', 'Romance', '(no genres listed)', 'Animation', 'Children', 'Fantasy', 'Film-Noir', 'Musical']
3  :  ['Horror', 'Sci-Fi', 'Action', 'Adventure', 'Fantasy', 'Thriller', 'Mystery', 'War', 'Children', 'Animation', 'Drama', 'Comedy', 'Romance', 'Musical', 'Crime', '(no genres listed)', 'Documentary', 'Film-Noir', 'IMAX', 'Western']
4  :  ['Western', 'Film-Noir', 'Musical', 'Romance', 'Mystery', 'Comedy', 'Drama', 'Documentary', 'Fantasy', 'Crime', 'Thriller', 'War', 'Adventure', 'Children', 'Animation', 'Action', 'Horror', 'Sci-Fi', 'IMAX', '(no genres listed)']
5  :  ['Musical', 'Children', 'Animation', 'Western', 'Crime', 'IMAX', 'Fantasy', 'Drama', 'War', 'Romance', 'Comedy', 'Thriller', 'Adventure', 'Action', 'Mystery', 'Horror', 'Sci-Fi', '(no genres listed)', 'Documentary', 'Film-Noir']
6  :  ['Western', 'Children', 'Romance', 'Musical', 'Drama', 'Comedy', 'Horror', 'Thriller', 'War', 'Animation', 'Fantasy', 'Action', 'Adventure', 'Mystery', 'Crime', 'Film-Noir', 'Sci-Fi', 'IMAX', '(no genres listed)', 'Documentary']
7  :  ['Musical', 'Sci-Fi', 'War', 'Adventure', 'Action', 'Film-Noir', 'Animation', 'IMAX', 'Fantasy', 'Mystery', 'Thriller', 'Children', 'Crime', 'Romance', 'Comedy', 'Drama', 'Horror', 'Western', '(no genres listed)', 'Documentary']
8  :  ['Western', 'Romance', 'Thriller', 'IMAX', 'War', 'Comedy', 'Crime', 'Children', 'Drama', 'Adventure', 'Mystery', 'Horror', 'Action', 'Musical', 'Fantasy', 'Sci-Fi', 'Animation', '(no genres listed)', 'Documentary', 'Film-Noir']
9  :  ['Film-Noir', 'Western', 'Drama', 'Adventure', 'Mystery', 'Comedy', 'Sci-Fi', 'Horror', 'War', 'Crime', 'Thriller', 'Romance', 'Fantasy', 'Action', 'Musical', 'IMAX', 'Animation', 'Children', '(no genres listed)', 'Documentary']
10  :  ['Romance', 'IMAX', 'Animation', 'Musical', 'Comedy', 'Children', 'Drama', 'Fantasy', 'Adventure', 'Action', 'War', 'Crime', 'Thriller', 'Mystery', 'Sci-Fi', 'Horror', '(no genres listed)', 'Documentary', 'Film-Noir', 'Western']

generate recommendations#

[47]:
user_ratings = user_feaures_normalized_matrix @ tf.transpose(movie_features_sparse_matrix)

user_ratings
[47]:
<tf.Tensor: shape=(610, 9742), dtype=float64, numpy=
array([[2.34144663e-02, 1.53672983e-02, 4.44799682e-03, ...,
        2.00917829e-03, 9.04420830e-03, 2.68566046e-03],
       [3.59281959e-04, 1.47455218e-04, 2.82634898e-04, ...,
        4.30538205e-04, 4.11818724e-04, 2.11826741e-04],
       [9.07153696e-04, 7.60220830e-04, 1.07425032e-04, ...,
        7.82796737e-05, 5.52200554e-04, 6.80871667e-05],
       ...,
       [3.59375662e-02, 2.18269162e-02, 1.21645861e-02, ...,
        6.27868216e-03, 1.54944158e-02, 7.34963138e-03],
       [9.33293364e-04, 6.41024279e-04, 4.25762873e-04, ...,
        4.17491593e-04, 4.40149850e-04, 1.74000537e-04],
       [5.30641013e-02, 3.13114209e-02, 1.85877015e-02, ...,
        1.21072562e-02, 2.77743850e-02, 1.16012967e-02]])>
[48]:
unseen_movies = tf.equal(tf.sparse.to_dense(user_movies_sparse_matrix),
                         tf.zeros_like(tf.sparse.to_dense(user_movies_sparse_matrix)))
unseen_movies
[48]:
<tf.Tensor: shape=(610, 9742), dtype=bool, numpy=
array([[False,  True, False, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       [ True,  True,  True, ...,  True,  True,  True],
       ...,
       [False, False, False, ...,  True,  True,  True],
       [False,  True,  True, ...,  True,  True,  True],
       [False,  True,  True, ...,  True,  True,  True]])>
[49]:
ignore_matrix = tf.zeros_like(tf.sparse.to_dense(user_movies_sparse_matrix))
ignore_matrix
[49]:
<tf.Tensor: shape=(610, 9742), dtype=float64, numpy=
array([[0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       ...,
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 0., 0.]])>
[50]:
new_ratings = tf.where(condition=unseen_movies, x=user_ratings, y=ignore_matrix)

new_ratings
[50]:
<tf.Tensor: shape=(610, 9742), dtype=float64, numpy=
array([[0.00000000e+00, 1.53672983e-02, 0.00000000e+00, ...,
        2.00917829e-03, 9.04420830e-03, 2.68566046e-03],
       [3.59281959e-04, 1.47455218e-04, 2.82634898e-04, ...,
        4.30538205e-04, 4.11818724e-04, 2.11826741e-04],
       [9.07153696e-04, 7.60220830e-04, 1.07425032e-04, ...,
        7.82796737e-05, 5.52200554e-04, 6.80871667e-05],
       ...,
       [0.00000000e+00, 0.00000000e+00, 0.00000000e+00, ...,
        6.27868216e-03, 1.54944158e-02, 7.34963138e-03],
       [0.00000000e+00, 6.41024279e-04, 4.25762873e-04, ...,
        4.17491593e-04, 4.40149850e-04, 1.74000537e-04],
       [0.00000000e+00, 3.13114209e-02, 1.85877015e-02, ...,
        1.21072562e-02, 2.77743850e-02, 1.16012967e-02]])>
[51]:
top_movies_idx = tf.nn.top_k(user_ratings, k = 5)[1]
[52]:
def get_movie_name(movie_id):
    return movies[movies['movieId'] == movie_id].title.iloc[0]
[53]:
for i in range(15):
    print(idx_to_userid_mapper[i],
          [get_movie_name(idx_to_movieid_mapper[index.numpy()]) for index in top_movies_idx[i]])
1 ['Enchanted (2007)', 'All Dogs Go to Heaven 2 (1996)', 'Return of Jafar, The (1994)', 'Rubber (2010)', 'Who Framed Roger Rabbit? (1988)']
2 ['From the Earth to the Moon (1998)', 'T-Rex: Back to the Cretaceous (1998)', 'Everest (1998)', 'Michael Jordan to the Max (2000)', 'Africa: The Serengeti (1994)']
3 ['Pulse (2006)', 'Cave, The (2005)', 'Night Watch (Nochnoy dozor) (2004)', 'Rogue (2007)', 'Phantasm II (1988)']
4 ['Rubber (2010)', 'Song of the Thin Man (1947)', 'Lost Highway (1997)', 'Mulan (1998)', 'Patlabor: The Movie (Kidô keisatsu patorebâ: The Movie) (1989)']
5 ['Tangled (2010)', 'Beauty and the Beast (1991)', 'Enchanted (2007)', 'Mulan (1998)', 'Lion King, The (1994)']
6 ['Rubber (2010)', 'Mulan (1998)', 'Enchanted (2007)', 'Tangled (2010)', 'Rango (2011)']
7 ['Rubber (2010)', 'Patlabor: The Movie (Kidô keisatsu patorebâ: The Movie) (1989)', 'Mars Needs Moms (2011)', 'Aqua Teen Hunger Force Colon Movie Film for Theaters (2007)', 'Robots (2005)']
8 ['Rubber (2010)', 'Osmosis Jones (2001)', 'Northwest Passage (1940)', 'Chase, The (1994)', 'Mulan (1998)']
9 ['Rubber (2010)', 'Patlabor: The Movie (Kidô keisatsu patorebâ: The Movie) (1989)', 'Lost Highway (1997)', 'Mulholland Drive (2001)', 'Too Late for Tears (1949)']
10 ['Tangled (2010)', 'Beauty and the Beast (1991)', 'Mulan (1998)', 'Enchanted (2007)', 'Aladdin and the King of Thieves (1996)']
11 ['Rubber (2010)', 'Blood Diamond (2006)', 'Northwest Passage (1940)', 'Getaway, The (1994)', 'Aelita: The Queen of Mars (Aelita) (1924)']
12 ['Ghost (1990)', 'Click (2006)', 'Michael (1996)', 'Purple Rose of Cairo, The (1985)', 'Big (1988)']
13 ['Rubber (2010)', 'Tremors 4: The Legend Begins (2004)', 'Pulse (2006)', 'Cave, The (2005)', 'Ichi the Killer (Koroshiya 1) (2001)']
14 ['Rubber (2010)', 'Northwest Passage (1940)', 'Legends of the Fall (1994)', 'Last of the Mohicans, The (1992)', 'Alamo, The (1960)']
15 ['Mars Needs Moms (2011)', 'Robots (2005)', 'Inception (2010)', 'Megamind (2010)', 'Treasure Planet (2002)']