GRA Графы Алгоритм

PageRank

Также: PageRank · пейджранк · случайный блуждатель · random surfer · степенной метод · power iteration · персонализированный PageRank

Важность страницы по ссылкам: страница важна, если на неё ссылаются важные. Определение ходит по кругу, но у него есть смысл — доля времени, которую случайный читатель проводит на странице, — и простой способ счёта: раздавать важность по ссылкам, пока она не перестанет меняться. Всё решает одно число, вероятность не заскучать.

Средний 20 минут ранжирование итерации граф матрица поисковики рекомендации социальные графы классика

На этом сайте три учебника: базовый курс программирования, «Царица наук» и каталог алгоритмов, который вы читаете. Вместе это 202 страницы и 1624 ссылки между ними. Какая страница самая важная, если судить только по ссылкам? Ниже каждая страница — кружок, его размер — важность по PageRank, а сам PageRank считается у вас на глазах: шаг за шагом важность перетекает по ссылкам, пока не перестанет меняться. Двигайте ползунок d и смотрите, куда она утекает.

При обычном d = 0,85 первые места занимают главы «Царицы наук»: «Последовательности и индукция», «Простые числа», «Корень из двух и действительные числа». У математики 46,6 % всей важности при 30 % страниц, у курса — 31,7 %, а у каталога — 21,7 %, хотя статей в нём больше всего. Уменьшите d до 0,5 — и вперёд выходят статьи каталога: «Двоичный поиск», «Двоичная куча», «Алгоритм Дейкстры», а доли почти выравниваются. Подвиньте d к единице — и вся важность стекает в «Царицу наук». При d = 0,99 у неё 90 %, при d = 1 — всё.

Причина видна в самих ссылках. Каталог ссылается и на курс, и на «Царицу наук», курс — на «Царицу наук», а она — ни на кого из них. Важность течёт по ссылкам вниз по течению и обратно не возвращается. В терминах графов «Царица наук» — компонента сильной связности, из которой нет выхода, и при d = 1 она забирает всё.

Идея

Представьте читателя, который бесконечно бродит по сайту. На каждой странице он с вероятностью d щёлкает по одной из её ссылок — выбирая случайно, — а с вероятностью 1 − d ему надоедает, и он открывает случайную страницу из всех. Если бродить долго, доля времени, проведённого на каждой странице, перестаёт меняться. Эта доля и есть PageRank страницы. Число d называют коэффициентом затухания, и у него простой смысл: между двумя прыжками читатель проходит в среднем d/(1 − d) ссылок подряд — при d = 0,85 это 5,7 ссылки, при d = 0,5 — одна, при d = 0,99 — 99. Чем больше d, тем дальше видит рейтинг.

Важность страницы — сумма важностей тех, кто на неё ссылается, где каждый делит свою важность поровну между всеми своими ссылками; плюс небольшая доля, которую получает каждая страница просто так. Чтобы найти такие числа, начните с равных и повторяйте раздачу, пока числа не перестанут меняться.

Формулой: если на страницу p ссылаются страницы q с числом ссылок out(q), а всего страниц N, то

$$PR(p) = \frac{1 - d}{N} + d \sum_{q \to p} \frac{PR(q)}{\mathrm{out}(q)}.$$

Это система из N линейных уравнений, и решать её можно хоть методом Гаусса. Но для графа из миллиардов страниц Гаусс немыслим, а повторение раздачи — степенной метод — стоит один проход по ссылкам за шаг. На языке линейной алгебры PageRank — собственный вектор матрицы переходов случайного читателя с собственным числом 1, а степенной метод — умножение вектора на эту матрицу снова и снова.

Переключите сцену на «Случайного читателя». Там тот же PageRank считается буквально: читатель ходит по ссылкам, сплошная линия — переход по ссылке, пунктир — прыжок, а размер кружка — доля визитов. Доли сходятся к тем же числам, но медленно: чтобы уменьшить ошибку вдвое, шагов нужно вчетверо больше. Степенной метод за каждый шаг уменьшает ошибку хотя бы в 1/d раз.

Тупики и ловушки

Зачем вообще прыжки? Без них определение ломается в двух местах. Вот шесть страниц: F — тупик, ссылок из неё нет; D и E ссылаются только друг на друга — ловушка, куда можно войти и откуда нельзя выйти.

При d = 1 важность тупика F пропадает на каждом шаге, и через 60 шагов от единицы остаётся 0,633 — всё в ловушке D — E. Если тупик раздаёт свою важность всем поровну, сумма сохраняется, но ловушка всё равно забирает всё, и числа не сходятся: D и E на каждом шаге меняются местами, 0,489 и 0,511. Прыжки с вероятностью 1 − d чинят всё сразу: из любой страницы можно попасть куда угодно, ни тупик, ни ловушка не удерживают важность, и при d = 0,85 числа сходятся к одному ответу, где у ловушки 0,709, а у тупика — 0,061. Тупики в настоящих данных есть всегда: в нашем графе пять статей каталога пока ни на одну написанную статью не ссылаются. Их важность раздают всем поровну, как прыжок.

Почему сходится и к одному ответу

При 0 ≤ d < 1 у системы ровно одно решение — распределение вероятностей на страницах, — и степенной метод сходится к нему из любого начального распределения: после k шагов расстояние до ответа в сумме модулей не больше dk, умноженного на начальное.

Шаг — отображение x ↦ G x: доля 1 − d раздаётся всем поровну, доля d идёт по ссылкам (тупики раздают свою всем). Возьмём два распределения x и y. Часть, которая раздаётся поровну, у них одинакова и в разности сокращается. Остаётся d, умноженное на раздачу разности x − y по ссылкам, а раздача по ссылкам только перекладывает числа со страницы на страницы и не увеличивает сумму модулей. Поэтому ‖G x − G y‖ ≤ d ‖x − y‖ — сжатие. Последовательность шагов из любого начала сходится, её предел неподвижен, а неподвижная точка у сжатия одна: две разные сжимались бы друг к другу.

При d = 1 сжатия нет, и всё зависит от устройства графа: ответ может быть не единственным, как с ловушкой, или не сходиться вовсе, как D и E. Точнее оценку dk сделали Тахер Хавелвала и Сепандар Камвар в 2003 году: второе по модулю собственное число матрицы Google не больше d, а если в графе есть хотя бы две замкнутые части, из которых нельзя выйти, — равно d.

Код

Важности — массив, ссылки — списки соседей. Один шаг: всем по (1 − d)/N, потом каждая страница со ссылками раздаёт d своей важности по ссылкам, а важность тупиков копится и раздаётся всем поровну. Остановка — когда суммарное изменение за шаг меньше 10⁻¹². Суммы — простым циклом, без sum(): так вывод Python и Go совпадает до последнего знака.

При d = 0,5 доли трёх учебников — 34,0, 33,4 и 32,6 %, почти поровну, и лидируют статьи каталога: на «Двоичный поиск», «Двоичную кучу» и «Дейкстру» ссылаются многие соседи, а при частых прыжках важно именно это — у кого больше входящих ссылок поблизости. Чем больше d, тем дальше уходит читатель по цепочкам ссылок и тем важнее, куда эти цепочки в конце концов приводят. При d = 0,95 у «Царицы наук» уже 67 %, при 0,99 — 90 %.

Сколько это стоит

Один шаг — O(V + E): каждая ссылка просматривается один раз. Шагов до точности ε — не больше log(1/ε) / log(1/d). Для ε = 10⁻¹² при d = 0,85 оценка обещает 170 шагов, а нашему графу хватило 106; при d = 0,99 — 2749 шагов по оценке и 268 на деле. Оценка рассчитана на худший граф, наш сходится быстрее, но рост числа шагов при d → 1 виден и здесь: 34, 106, 189, 268. Так что d = 0,85 — компромисс: меньше d — рейтинг почти не учитывает дальние ссылки, больше — дольше считать, а важность всё сильнее стекает в ловушки.

Памяти — сам граф и два массива важностей. Граф веба в 1998 году уже не помещался в память, и в отчёте Пейджа, Брина, Мотвани и Винограда о PageRank, как его пересказывают университетские курсы, на базе из 322 миллионов ссылок хватило примерно 52 шагов. Шаги степенного метода легко делить между машинами: каждая раздаёт важность своей части страниц, — поэтому PageRank — классический пример для систем распределённой обработки графов.

Где работает

  • Поиск. С PageRank начинался Google: в 1998 году Брин и Пейдж описали поисковую машину, которая сочетала совпадение слов запроса с важностью страницы по ссылкам. Сегодня это лишь один из многих сигналов ранжирования. Как устроен поиск целиком, с индексом и ранжированием текста, — в главе курса о поисковике.
  • Рекомендации. Если прыгать не на любую страницу, а только на «свои», получается персонализированный PageRank: важность глазами одного читателя. Twitter в 2013 году описал сервис «кого читать», где «круг доверия» пользователя строился случайными блужданиями от него самого. Это задача статьи.
  • Тексты. TextRank (2004) строит граф из слов или предложений текста, где рёбра — соседство или похожесть, и выбирает ключевые слова и главные предложения по PageRank.
  • Наука. Важность журналов по цитированиям, когда ссылка из влиятельного журнала весит больше, считает Eigenfactor — тем же способом.

История

Идея «важен тот, на кого ссылаются важные» старше веба. В 1953 году социолог Лео Кац предложил индекс статуса в социальных сетях, где учитываются все цепочки знакомств, а длинные весят меньше, — это и есть коэффициент затухания, только для цепочек. В 1965 году Чарльз Хаббелл ранжировал людей по важности тех, кто их поддерживает, а в 1976 году Габриэль Пински и Фрэнсис Нарин назвали журнал влиятельным, если его цитируют влиятельные журналы. В 1998 году Сергей Брин и Ларри Пейдж описали PageRank для веба, а Джон Клейнберг в те же годы — алгоритм HITS с двумя оценками у каждой страницы: насколько она авторитетна и насколько хорошо собирает ссылки на авторитетные. Подробнее о самом Google и о фермах ссылок, которыми пытались обмануть PageRank, — в главе курса «Ферма ссылок».

Задача

Читатель отметил любимые страницы — посоветуйте, что читать дальше. Нужен персонализированный PageRank, и один из тестов — граф этого сайта.

Что читать дальше

Данные: Граф ссылок учебников legost.in: базовый курс, «Царица наук», каталог алгоритмов