Матрица взаимодействий пользователь-товар
Урок вводит центральную структуру данных рекомендаций — матрицу взаимодействий — и объясняет, почему её разреженность определяет всю сложность задачи.
Матрица взаимодействий — таблица, где строки это пользователи, столбцы это товары, а в ячейке стоит сигнал (оценка, факт покупки или пусто, если взаимодействия не было).
Как выглядит задача
Почти любую рекомендательную задачу можно записать как заполнение пропусков в большой таблице. По строкам — пользователи, по столбцам — объекты, в ячейках — известные взаимодействия. Подавляющее большинство ячеек пусты, и наша цель — предсказать, что бы оказалось в пустых клетках, и порекомендовать объекты с самым высоким предсказанным интересом.
Матрица Титаник Аватар Шрек Аня 5 2 4 1 Борис 4 1 5 ? Вера 1 5 ? 4 Глеб 5 ? 4 1
Знаки ? — это то, что мы хотим предсказать. Если мы оценим, что Борис поставил бы «Шрек» низкую оценку, мы не порекомендуем ему «Шрек».
Разреженность — главная проблема
В реальности у платформы миллионы пользователей и миллионы товаров, а каждый человек взаимодействовал в лучшем случае с сотнями объектов. Значит, заполнено в матрице порядка 0,01–0,1% ячеек, а 99,9% — пусты. Это и есть разреженность, и она усложняет всё: похожих пользователей мало кто пересекает по товарам, статистики по каждой паре почти нет, а наивный перебор по полной матрице невозможен из-за размера.
R = [
[5, 2, 4, 0],
[4, 1, 5, 0],
[1, 5, 0, 4],
[5, 0, 4, 1],
]
total = len(R) * len(R[0])
filled = sum(1 for row in R for v in row if v != 0)
sparsity = 1 - filled / total
print(f"Всего ячеек: {total}")
print(f"Заполнено: {filled}")
print(f"Разреженность: {sparsity:.0%}")Вывод:
Всего ячеек: 16 Заполнено: 12 Разреженность: 25%
Как работает под капотом
На практике матрицу никогда не хранят как плотный двумерный массив — это сожрало бы терабайты пустоты. Хранят только ненулевые элементы: список троек (пользователь, товар, сигнал) или словари. Все алгоритмы курса работают именно с разреженным представлением, обходя лишь известные взаимодействия.
# разреженное хранение: только известные ячейки
interactions = {
("Аня", "Матрица"): 5,
("Аня", "Титаник"): 2,
("Борис", "Матрица"): 4,
("Борис", "Аватар"): 5,
}
for (u, i), r in interactions.items():
print(f"{u} оценил(а) '{i}' на {r}")Вывод:
Аня оценил(а) 'Матрица' на 5 Аня оценил(а) 'Титаник' на 2 Борис оценил(а) 'Матрица' на 4 Борис оценил(а) 'Аватар' на 5
Частые ошибки
- Хранить матрицу плотно. При миллионах строк и столбцов это невозможно; используйте разреженные структуры.
- Считать 0 «плохой оценкой». В матрице 0 (или пусто) почти всегда означает «нет данных», а не «не понравилось».
- Недооценивать разреженность. Многие интуитивно «очевидные» методы рассыпаются, когда пересечений между пользователями почти нет.
Итоги
- Задача рекомендаций — заполнение пропусков в матрице пользователь-товар.
- Реальные матрицы заполнены на доли процента: это и есть разреженность.
- Хранят только известные взаимодействия, а не плотный массив.
- Пустая ячейка — это «нет данных», а не «низкая оценка».