# 6. СЕТЕВЫЕ СООБЩЕСТВА И КЛАСТЕРНЫЙ АНАЛИЗ ДАННЫХ СОЦИАЛЬНЫХ СЕТЕЙ 

[назад](README.md)

Сетевое сообщество представляет собой группу пользователей социальной сети, объединенных по тому или иному признаку. Как правило, связи внутри группы сильнее между собой, чем с внешней средой. При представлении социальной сети в виде графа сообщества могут выделяться кластерами. 

Строго математического определения сообществ не существует. По этой причине выделение кластеров происходит исходя из задаваемых исследователями параметров. При этом существует целый ряд подходов для выделения сообществ.

На рис. 19 изображено два графа с выделенными кластерами, описывающими сообщества. На графе слева подобное выделение кластеров является очевидным даже визуально, однако это скорее идеальный случай. В реальности же отыскание сообществ в графе – задача далеко не тривиальная, как например, в случае графа расположенного слева на рис. 19. Разными цветами обозначены наиболее вероятные сообщества, полученные при проведении кластерного анализа. 

![Рис. 19. Примеры графов с выделенными сообществам](images/2021-09-05_01-00-56.png)  
Рис. 19. Примеры графов с выделенными сообществами 

Одним из возможных методов кластерного анализа является расчёт на основе *кластерного коэффициента*. 

Кластерным коэффициентом вершины $`v_i`$ называется мера плотности связей данной вершины с соседними. Пусть $`G_i = (V_i, E_i)`$ – подграф графа $`G`$, включающий вершины, связанные с $`v_i`$ (назовем их соседями вершины $`v_i`$ ). Обозначим $`|V_i| = n_i`$ – количество соседей вершины $`v_i`$ , а $`|E_i| = m_i`$ – количество ребер между соседями вершины $`v_i`$. Кластерный коэффициент вершины $`v_i`$ определяется следующим образом 

```math
C(v_i) = \frac{\text{число рёбер в $`G_i`$}}{\text{маскимальное число рёбер в $`G_i`$}} = \frac{m_i}{\binom{n_i}{2}} = \frac{2 m_i}{n_i (n_i - 1)}.
```

Таким образом, кластерный коэффициент графа $`G`$ – представляет собой среднее значение кластерного коэффициента по всем своим вершинам: 

```math
C(G) = \frac{1}{n} \sum_i C(v_i).
```

Опираясь на определение кластерного коэффициента можно ввести понятие плотности связей в графе 

```math
\rho = \frac{2 m}{n(n-1)},
```
где $`m`$ – количество рёбер в графе; $`n`$ – количество вершин. 

Тогда для определенного кластера $`С`$ (сообщества) плотность связей равна количеству рёбер в этом сообществе $`m_c`$, делённому на максимально возможное количество рёбер в сообществе 

```math
\delta_{internal} (C) = \frac{2m_c}{n_c(n_c-1)}
```

А внешняя для данного кластера $`С`$ плотность аналогично получается при вычислении 

```math
\delta_{external} (C) = \frac{2 m_{external}}{n_c(n_c-1)}
```
где $`m_{external}`$ – полное число внешних связей (рёбер). 

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

```math
\delta_{internal} < \rho < \delta_{external}.
```

Таким образом, можно находить кластеры путем анализа максимума разницы внутренних и внешних плотностей, вводя следующий параметр 

```math
max = (\delta_{internal} - \delta_{external}).
```

При этом имеется ряд сложностей. Во-первых, для максимизации такой формулы нужно вначале выделить 
необходимое сообщество, что сопряжено с большим количеством переборов. А во-вторых задача отыскания сообществ при помощи плотности внутренних связей в графе на основе кластерного коэффициента решается в определенной степени приближенно: 
- используются эвристики (нет гарантии схождения, однако 
на практике это, как правило, работает); 
- используется жадный алгоритм (нет гарантии нахождения 
глобального минимума); 
- приближенно ищется глобальный минимум (это задача 
комбинаторной оптимизации); 
- часто используется рекурсивное разбиение графа на 2 части. 

Рассмотрим иные подходы, использующиеся для выявления сетевых сообществ. 

Наиболее распространенными подходами к разбиению графов на кластеры являются следующие алгоритмы: 
- алгоритмы основанные на модулярности (жадный алгоритм, а также спектральная максимизация модулярности); 
- алгоритмы разреза графов; 
- эвристические алгоритмы (случайные блуждания и алгоритмы использующие степень посредничества). 

## Алгоритмы основанные на модулярности

Один из способов отыскания сетевых сообществ, также связанный с соотношением внутренней и внешней плотности кластера в графе, основывается на понятии *модулярности*. 

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

Вводится понятие модулярности, под которой понимается скалярная величина из отрезка $`[-1, 1]`$, выражаемая следующей формулой 

```math
Q = \frac{1}{2m} \sum_{i,j} \left( A_{ij} - \frac{d_i d_j}{2m} \right) \delta(C_i, C_j),
```

где $`𝐴`$ – матрица смежности графа; $`A_{ij}`$ – $`(i, j)`$ элемент матрицы $`𝐴`$; $`d_i`$ – степень $`i`$-й вершины графа; $`C_i`$ – метка вершины (номер сообщества, к которому относится вершина); $`m`$ общее количество ребер в графе; $`\delta(C_i, C_j)`$ – дельта-функция (единица, если $`C_i = C_j`$, ноль иначе). 

В этой формуле просчитывается количество связей, находящихся внутри одного кластера, и потом они складываются. 

Стоит отметить, что в формуле присутствует член $`\frac{d_i d_j}{2m}`$. Его роль в следующем: сравнивается данное разбиение на кластеры (сообщества) со случайным графом. Если имеет место случайный граф, то в таком случае нет хороших кластеров. Таким образом, плотность в таком графе можно использовать как относительную метрику: у сообщества плотность должна быть строго больше, чем 
в случайном графе. 

Если имеется узел со степенью $`d_i`$, то к нему присоединено $`d_i`$ рёбер. Вероятность того, что произвольное ребро присоединено к узлу, равна $`\frac{d_i}{2m}`$, а вероятность связи между ребрами равна $`\frac{d_i d_j}{2m}`$. Иначе говоря, мы вычисляем разницу между реальным количеством рёбер и ожидаемым. При этом сумма не равна нулю, если мы работаем в пределах одного кластера. 

Таким образом, при хорошем разбиении на кластеры модулярность высокая, если кластер один, то модулярность равна 0.

Задача поиска выделения сообществ в графе сводится к поиску таких $`C_i`$, которые будут максимизировать значение модулярности. Примеры графов с различными значениями модулярности 
представлены на рис. 20. 

Поскольку модулярность описывает качество разделения графа на группы, к решению задачи отыскания оптимального разбиения графа можно подойти, решая задачу максимизации. Однако простым перебором решить эту задачу практически невозможно, так как число вариантов разделения $`n`$ узлов на $`k`$ групп растёт, экспоненциально с ростом $`n`$. 

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

![Рис. 20. Значение коэффициента модулярности при выделении различных кластеров](images/2021-09-05_14-02-57.png)   
Рис. 20. Значение коэффициента модулярности при выделении различных кластеров

Отметим, что модулярность можно не только использовать как критерий, но и отслеживать как показатель развития сообщества. 

Рассмотрим жадный алгоритм оптимизации функции модулярности, имеющий в своём основании пошаговое 
объединение двух групп, дающих наибольший прирост модулярности. 

Рассмотрим некое разбиение узлов из N на k групп (N – множество узлов с числом элементов n). Функция модулярности будет равна

```math
Q_1 = \frac{1}{m} \sum_{l=1,l \neq i, l\neq j}^k ? + \left( m_i + m_j + \frac{d(N_i)^2 + d(N_j)^2}{4m} \right).
```

Теперь объединим группы $`i`$ и $`j`$ в одну, которую обозначим как $`N_{i \cup j} = N_i \cup N_j`$. Функция модулярности для нового графа будет иметь следующий вид 

```math
Q_2 = \frac{1}{m} \sum_{l=1,l \neq i, l\neq j}^k \left( m_l - \frac{d(N_l)^2}{4m} \right) + \frac{1}{m} \left( m_{i \cup j} - \frac{d(N_{i \cup j})^2}{4m} \right).
```

Число дуг внутри группы $`𝑁_{i \cup j}`$ равно сумме дуг внутри групп $`N_i`$ и $`N_j`$ плюс число дуг между ними. Иными словами

```math
m_{i \cup j} = m_i + m_j + m_{i,j}.
```

Степень объединённой группы $`N_{i \cup j}`$ равна сумме степеней групп $`𝑁_i`$ и $`𝑁_j`$, то есть 

```math
d(N_{i \cup j}) = d(𝑁_i) + d(𝑁_j).
```

Следовательно

```math
d(N_{i \cup j})^2 = d(𝑁_i)^2 + d(𝑁_j)^2 + 2 d(𝑁_i) d(𝑁_j).
```

Учитывая это, получаем 

```math
\Delta Q = Q_2 - Q_1 = \frac{1}{m} \left( m_{i,j} - \frac{2 d(𝑁_i) d(𝑁_j)}{4m} \right) = \frac{1}{m} \left( m_{i,j} - \frac{d(𝑁_i) d(𝑁_j)}{2m} \right)
```

Отсюда получаем, что наибольший рост модулярности происходит при объединении таких групп $`N_i`$ и $`N_j`$, для которых максимальна величина

```math
\Delta(N_i, N_j) = m_{i,j} - \frac{d(N_i) d(N_j)}{2m}.
```

Также видно, что объединение групп, между которыми нет дуг ($`𝑚_{i,j} = 0`$), не может дать увеличения модулярности.

К достоинствам алгоритма модулярности можно отнести следующее: 
1. Модулярность достаточно просто интерпретируется и её значение равно разности между долей рёбер внутри сообществ, и ожидаемой долей связей, если бы рёбра были размещены случайно. 
2. Модулярность возможно эффективно пересчитывать при небольших изменениях в кластерах. 

В то же время, явными недостатками данного алгоритма являются: 
1. Функционал не является непрерывным, и задача его оптимизации – дискретная. Для поиска глобального оптимума используют приближённые схемы. Некоторые из них действительно оптимизируют значение функционала, другие же по значению модулярности выбирают наилучшее решение из найденных, то есть без гарантий локальной оптимальности решения. 
2. Существует проблема разрешающей способности (грубо говоря, функционал не видит маленькие сообщества). Эта проблема решается путем использования модифицированного функционала, 
который сохраняет все достоинства и добавляет параметр масштаба.

## Эвристические алгоритмы

Рассмотрим еще один алгоритм выделения сообществ из разряда эвристических алгоритмов. Он основывается на понятии степени посредничества (в англоязычной литературе, как правило,
обозначается – edge betweenness) – количество кратчайших путей, проходящих через ребро: 

```math
C(v) = \sum_{S \neq l \neq v} \frac{\sigma_{st}(v)}{\sigma_{st}},
```
где $`\sigma_{st}`$ – общее число кратчайших путей из вершины $`s`$ в вершину $`t`$, $`\sigma_{st}(v)`$ – число этих кратчайших путей, проходящих через вершину $`v`$. 

Идея алгоритма заключается в том, что рёбра, через которые проходит наибольшее количество кратчайших путей, являются «мостами» между кластерами в графе. Поэтому для этих рёбер описанная метрика будет высокой. Можно найти эти рёбра, удалить их, и тогда граф распадется на сообщества. 

![Рис. 21. Разделение графа на кластеры с помощью алгоритма, использующего метрику степени посредничества](images/2021-09-05_14-29-27.png)  
Рис. 21. Разделение графа на кластеры с помощью алгоритма, использующего метрику степени посредничества

В ходе выполнения алгоритма вычисляем степень посредничества и удаляем ребро с максимальным значением этой метрики. Каждый раз метрика должна быть пересчитана, так как при удалении ребер она может меняться. Делаем это до тех пор, пока в графе остаются ребра. Если хотим поделить граф на 2 части, то останавливаем процесс в тот момент, когда у нас есть 2 компоненты. Несмотря на то, что алгоритм жадный, он очень интуитивен и даёт неплохие результаты.

Пример представлен на рис. 21. При первом разбиении отделятся красный и оранжевый кластеры, потом отделятся все зеленые и т.д. 

Алгоритм имеет и недостатки: для не очень больших графов он может работать не очень хорошо, а также отличается сложностью вычислений.

## Алгоритм SCAN (Structural Clustering Algorithm for Networks) 

https://academic.microsoft.com/paper/2134008243

Ещё одним алгоритмом, с помощью которого можно осуществлять кластеризацию графа является SCAN (Structural Clustering Algorithm for Networks) алгоритм. Данный алгоритм представляет большой интерес в первую очередь тем, что помимо кластеризации графа, он также осуществляет классификацию вершин этого графа. 

Прежде чем описывать процесс классификации вершин графа по SCAN, необходимо ввести ряд следующих связанных использующихся понятий

*Структура вершин* – величина 

```math
\Gamma(x) = \{y \in X | (x,y) \in U \} \cup \{x\},
```

где $`X`$ – множество вершин графа, $`U`$ – множество рёбер графа. 

*Структурное сходство* – величина 

```math
\sigma = \frac{|\Gamma(x) \cap \Gamma(y)|}{\sqrt{|\Gamma(x)| |\Gamma(y)|}}.
``` 

Когда член кластера имеет похожую структуру с одним из его соседей, их расчетное структурное сходство будет большим. Мы используем пороговое значение 𝜀, применяя его к вычисленному структурному подобию, когда определяем принадлежность к тому или иному кластеру. 

$`\epsilon`$ – *окрестность* ядра $`N_\epsilon(x)`$ – множество вершин (больше параметра $`\mu`$), чья структурная схожесть больше параметра $`\epsilon`$. 

*Core (ядро)* – это вершина, содержащая в $`\epsilon`$ окрестности, по крайней мере $`\mu`$ вершин. 

*Прямая структурная достижимость* – две вершины напрямую структурно-достижимы, тогда и только тогда, когда одна из вершин является ядром, а другая вершина находится в $`\epsilon`$ окрестности данного ядра. Иными словами 

```math
DirReach_{\epsilon,\mu}(x,y) \leftrightarrow Core_{\epsilon,\mu}(x) \wedge y \in N_{\epsilon} (x).
```

*Структурно-достижимые вершины* $`(x, y)`$ – две вершины структурно-достижимы, если существует последовательность 
вершин $`x_1 \ldots x_n`$ таких, что $`x_1 = x`$ и $`x_n = y`$ и $`\forall i \in \{1 \ldots (n-1)\}x_i`$ и $`x_{i+1}`$ являются напрямую структурно достижимыми:

```math
Reach_{\epsilon, \mu}(x, y) \leftrightarrow \exist x_1 \ldots x_n \in X: x_1 = x \wedge x_n = y \wedge \forall i \in \{1 \ldots (n-1)\} : DirReach_{\epsilon,\mu}(x_i, x_{i+1}).
```

*Структурно-связанные вершины* – две вершины являются структурно-связанными тогда и только тогда, когда существует третья вершина, с которой указанные вершины являются попарно структурно-достижимыми: 

```math
Connect_{\epsilon, \mu}(x,y) \leftrightarrow \exist u \in X : Reach_{\epsilon,\mu}(u,x) \wedge Reach_{\epsilon,\mu}(u,y).
```

*Hub («хаб»)* – это отдельная вершина, соседи которой принадлежат двум или более различным кластерам. 

*Outlier (посторонний, «аутлаер»)* – это отдельная вершина, все  соседи которой принадлежат одному и тому же кластеру, или не  принадлежат никакому кластеру. 

Пример графа с вершинами типа: ядро, «хаб», «аутлаер» – 
представлены на рис. 22. 

![Рис. 22. Пример графа с различными типами вершин](images/2021-09-05_14-50-40.png)  
Рис. 22. Пример графа с различными типами вершин

Процесс работы SCAN-алгоритма поэтапно описан ниже. 
1. Поиск начинается с начального посещения каждой вершины один раз, с целью нахождения структурно-связных кластеров, а затем посещения изолированных вершин, чтобы идентифицировать их (hub или outlier). 
2. SCAN выполняет один проход сети и находит все структурносвязанные кластеры для заданного параметра. В начале все  вершины помечены как неклассифицированные. Алгоритм SCAN классифицирует каждую вершину либо как являющуюся членом кластера, либо как не являющуюся. Для каждой вершины, которая еще не классифицирована, SCAN проверяет, является ли эта вершина ядром. Если вершина является ядром, новый кластер расширяется из этой вершины. В противном случае вершина помечается как не являющаяся членом кластера. 
3. Чтобы найти новый кластер, SCAN начинается с произвольной ядра $`V`$ и ищет все вершины, которые структурнодостижимы из $`V`$. Этого вполне достаточно, чтобы найти полный кластер, содержащий вершину $`V`$. Генерируется новый ID кластера, который будет назначен всем найденным вершинам. 
4. SCAN начинается, постановкой всех вершин в 𝜀 – окрестности вершины $`V`$ в очередь. Для каждой вершины в очереди вычисляются все непосредственно достижимые вершины, и в очередь вставляются те вершины, которые до сих пор не классифицированы. Это повторяется до тех пор, пока очередь не опустеет. 
5. Вершины, не являющиеся членами кластеров, могут быть дополнительно классифицированы как «хабы» или посторонние. Если отдельная вершина имеет рёбра на два или более кластеров, она может быть классифицирована как «хаб». В противном случае это «аутлаер».

SCAN-алгоритм лишен недостатков алгоритмов, использующих модулярность. Отличительной особенностью SCAN-алгоритма является наличие параметров $`\mu`$ и $`\epsilon`$, которые могут задаваться пользователем или экспертом, что позволяет избежать проблемы определения маленьких сообществ. Иными словами, пользователь или эксперт может сам определять размеры сообществ, которые необходимо определять и члены которых необходимо классифицировать. При этом нахождение оптимального значения 
данных параметров можно провести при помощи машинного обучения системы, используя определённые сегменты сети. 

Также в пользу SCAN-алгоритма выступают результаты исследования времени работы, которое значительно меньше, чем в алгоритмах, базирующихся на понятии модулярности. 

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

[назад](README.md)
