вычислить алгоритм начальной загрузки, используя Map / Reduce - PullRequest
18 голосов
/ 22 марта 2011

Этот вопрос изначально был домашним заданием, которое я получил, но мой ответ был неправильным, и мне любопытно, как лучше всего решить эту проблему.

Цель состоит в том, чтобы вычислить ключевые аспекты "алгоритма начальной загрузки системы Рекомендатора", используя 4 шага сокращения карты. У меня проблема с третьим шагом, поэтому я приведу только его детали.


ввод: записи вида:
1. (идентификатор населения, элемент, номер рейтинг пользователей, сумма рейтингов, сумма рейтинг в квадрате)
2. (Население идентификатор, сплиттер, любители / антипатии, пункт, количество пользователей рейтинга, сумма рейтинги, сумма рейтингов в квадрате)

2-я форма во многом похожа на 1-ую, но для каждой записи (сплиттер, любители / дислайкеры) - запись, где "лайкеры / дислайкеры" - логическое значение.

Это означает (я думаю), что есть 2 ^ | предметов | записи секунд формируются для каждой записи из 1-й формы ... (многие одноклассники ошибочно предположили (опять же, я думаю ..), что количество записей 1-й и 2-й формы одинаковое)

Описание задачи:

Этот шаг вычисляет для каждого фильма сплиттера квадрат ошибки (SE), вызванный каждым фильмом.

  • Выходные данные: записи формы (идентификатор популяции, элемент сплиттера, элемент, квадрат ошибки на элементе при разбивке на сплиттер).

Подсказка:

предположим, что существует строка, которая предшествует (в порядке сортировки системы) любой идентификатор сплиттера фильма.

Это нужно сделать за один шаг mapreduce!

дополнительный фон:
Это было изучено в контексте "Вызова Netflix"

SE определение: SE definition

РЕДАКТИРОВАТЬ: дополнительные материалы, касающиеся проблемы [некоторое описание проблемы netflix и математическая информация о проблеме] можно найти в по этой ссылке [особенно слайды 12-24]

EDIT2: обратите внимание на то, что, поскольку мы используем карту / уменьшение, мы не можем предполагать, что что-либо о записях ORDER будет обработано [как в карте, так и в уменьшении].

1 Ответ

3 голосов
/ 16 августа 2011

Я не уверен, что понимаю ваш вопрос.

То, что вы в конечном итоге хотите, это SE (U).После некоторых математических подробностей на слайдах 23 и 24 он «тривиально» вычисляется с помощью \ sum_ {i} SE (U) _i

. Вы сами поняли, что 4-е и последнее сентября - это карта, которую нужно уменьшить, чтобы получитьэта сумма.

3-й шаг - это уменьшение карты для получения (в стиле LaTeX)

SE(U)_i = \sum_{u in U_i} (r_{u,i} - r_i)^2

enter image description here

  • Функция уменьшения суммируется по u вU_i
  • Функция карты разбивает термины для суммирования

В Python это может выглядеть следующим образом:

def map(Ui):
    ''' Ui is the list of user who have rated the film i'''
    for user in Ui:
        results.append((user,(r_{u,i} - r_i)^2))

def reduce(results):
    ''' Returns a final pair (item, SE(U)_i ) '''
    return (item, sum([value for user,value in results]))

Редактировать : MyПервоначальный ответ был неполным.Позвольте мне снова объяснить.

В конечном итоге вы хотите SE (U) для каждого сплиттера.

Шаг a готовит некоторые полезные данные о предметах.Пропущенные записи определяются следующим образом:

key = (population_id, item)
value =
    number: |U_i|,
    sum_of_ratings: \sum_{u \ in U_i} r_{u,i} 
    sum_of_squared_ratings: \sum_{u \in U_i} r_{u,i} ^2
  • Функция карты анализирует статистику по элементам.
  • Функции сокращения вычисляют суммы.

Теперь для любого данного фильма сплиттера M:

U_M = U_{+M} + U_{-M} + U_{M?}

Шаг b явно вычисляет для каждого сплиттера M статистику для небольших подгрупп населения M + и M-.

NB likers / dislikers - это не логическое значение само по себе , это идентификатор подпопуляции '+' или '-'

Для каждого есть 2 новые записиэлемент сплиттера:

key = (population_id, item, M, '+') 
value = 
    number: |U_i(+)|
    sum_of_ratings: \sum_{u \ in U_i(+)} r_{u,i}
    sum_of_squared_ratings: \sum_{u \in U_i(+)} r_{u,i} ^2

Same thing for '-'

Или, если вам больше нравится, отметка «dis / likers»

key = (population_id, item, M, dis/likers) 
value = 
    number: |U_i(dis/likers)|
    sum_of_ratings: \sum_{u \ in U_i(dis/likers)} r_{u,i}
    sum_of_squared_ratings: \sum_{u \in U_i(dis/likers)} r_{u,i} ^2

cf Середина слайда 24

Примечание: если вы считаете, что каждый фильм может бытьв сплиттере есть 2x | item | ^ 2 элемента второй формы;это потому, что item -> (логическое, item, splitter) - намного меньше, чем ваш 2 ^ | item |оценка, которую вы не объяснили.

Шаг c вычисляет для каждого сплиттера M расчетную SE для каждого фильма, т.е. SE (U_M) _i

Посколькусумма может быть разделена между ее различными членами:

U_M = U_{+M} + U_{-M} + U_{M?}

SE(U_M)_i = SE(U_M?)_i + SE(U_+M) + SE(U_-M)

с SE(U_{+M}), явно вычисленным с помощью этой функции карты:

def map(key, value):
    '''     
    key = (population_id, item, M, dis/likers) 
    '''
    value = 
        count: 1
        dist: (r_u,i - r_i)^2

    emit key, value

def reduce(key, values):
    ''' 
    This function explicitly computes the SE for dis/likers
    key = (population_id, item, M, dis/likers)
    value= count, dist
    '''
    emit key, sum(count, sum(dist))

Теперь все, что нам нужно SE(U_{M?})_i, что является "тривиальным""вычисления приведены на слайде 24:

SE(?)_i = \sum_{u \in U_i(?)}{r_{u,i}^2} - (\sum r)^2 / |U_i(?)|

Конечно, мы не собираемся делать такие большие суммы, но используем замечание чуть выше в лекции, а данные уже вычислены на шаге а (этоВывод, который я сделал из слайда 24 из последних 3 уравнений)

SE(?)_i = \sum_{u \in U_i}{r_{u,i}^2} - \sum_{u \in U_i('+'/'-')}{r_{u,i}^2} - (...)/ (|U_i| - |U_i('+'/'-'))

Так что это даже не карта / уменьшение, а просто шаг завершения:

def finalize(key, values):
    for [k in keys if k match key]:
        ''' From all entries get
        # from step a
        key = (population_id, item) value=(nb_ratings, sum_ratings, sum_ratings_squared)
        # from step b
        key = (population_id, item, M, '+') value=(nb_ratings_likers, sum_ratings_likers, sum_ratings_squared_likers)
        key = (population_id, item, M, '-') value=(nb_ratings_dislikers, sum_ratings_dislikers, sum_ratings_squared_dislikers)
        # from step c
        key = (population_id, item, M, '+') value=(se_likers)
        key = (population_id, item, M, '-') value=(se_dislikers)
        '''
        se_other = sum_rating_squared - sum_ratings_squared_likers  - sum_ratins_squared_dislikers - sum_ratings_likers / (nb_ratings -  (nb_ratings_likers)) - sum_ratins_squared_dislikers  - sum_ratings_likers / (nb_ratings -  (nb_ratings_likers))
        emit
            key: (population_id, splitter, item)
            value : se_likers + se_dislikers + se_other

Шаг d Наконец, последние шаги вычисляют SE для U_M.Это просто сумма предыдущих записей и тривиальное Map / Reduce:

Для сплиттера M:

SE(U_M) = \sum_i SE(U_M)_i = \sum_i SE(U_M?)_i + \sum_i SE(U_+M) + \sum_i SE(U_-M)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...