Рейтинги хранятся в единой матрице ratings
, где строки соответствуют пользователям (индекс u
), а столбцы соответствуют элементам (индекс i
). Поскольку вы хотите вычислить sim(u, u')
, то есть сходство между пользователями, давайте предположим, что ниже kind = 'user'
.
Теперь давайте сначала посмотрим на r_{ui}r_{u'i}
без коэффициентов масштабирования с квадратным корнем. Это выражение суммируется по i
, что можно интерпретировать как умножение матрицы на r
с транспонированием r
, т.е.:
\sum_i r_{ui}r_{u'i} = \sum_i r_{ui}(r^T)_{iu'} =: s_{uu'}
Как уже было сделано выше, обозначим полученную матрицу как s
(переменная sim
в коде). Эта матрица по определению является симметричной, а ее строки / столбцы помечены индексами «пользователя» u/u'
.
Теперь масштабный «коэффициент» f_{u} := \sqrt\sum_i r^2_{ui}
на самом деле представляет собой вектор, индексированный с помощью u
(каждый элемент которого является евклидовой нормой соответствующей строки матрицы r
). Однако, построив s_{uu'}
, мы можем видеть, что f_{u}
- это не что иное, как \sqrt s_{uu}
.
Наконец, интересующий фактор сходства равен s_{uu'}/f{u}/f{u'}
. Размещенный код вычисляет это для всех индексов u/u'
и возвращает результат в виде матрицы. Для этого оно:
- вычисляет
sim
(матрица s
выше) как ratings.dot(ratings.T)
- получает квадратный корень из его диагонали (вектор
f
выше) как np.sqrt(np.diagonal(sim))
- для эффективного масштабирования строки / столбца
s
, это затем выражается в виде двумерного массива norms = np.array([np.sqrt(np.diagonal(sim))])
(обратите внимание на отсутствующий []
в вашем посте)
- наконец, матрица
s_{uu'}/f{u}/f{u'}
рассчитывается как sim / norms / norms.T
. Здесь, поскольку norms
имеет форму (1, num_of_users)
, первое деление выполняет масштабирование столбца, а деление с norms.T
масштабирует строки.