Время прочтения: 6 мин.

В своей работе Data Analytic постоянно оперирует большими объемами данных. Для анализа, статистики и понимания с какими данными он работает, приходится прибегать к множествам библиотек. У каждого существуют свои наборы, под различные задачи. Так и в мой арсенал попала необычная библиотека Pyvis для создания сетевых графов. Чем же она отличается от остальных? А тем, что она интерактивная, и с ней можно работать прямо в Jupyter notebook. В своей работе библиотека использует JavaScript VisJS.

Импортируем библиотеку.

from pyvis.network import Network

Создаем сеть. В параметрах сети прописываем размеры окна отображения. Размеры указывать не обязательно, в таком случае размеры будут установлены по умолчанию 500х500 px. Используя параметр «notebook=True», окно отобразится в той же вкладке браузера.

network = Network('600px', '600px', notebook=True)

Добавляем ноды*. Первый параметр указывает на номер нода, номером могут быть как числа, так и слова. Параметр «label»- название нода. Если не указать название, оно автоматически подставится из номера нода; «title»- описание нода, которое появляется при наведении на нод.

network.add_node(1, label='Россия', title='Начальная нода')
network.add_node(2, label='обл Свердловская')
network.add_node(3, label='Подразделение - обл Свердловская')
network.add_node(4, label='Подразделение 1 - обл Свердловская')
network.add_node(5, label='Подразделение 2 - обл Свердловская')
network.add_node(6, label='Категория - обл Свердловская')
network.add_node(7, label='Кат. - A - обл Свердловская')
network.add_node(8, label='Кат. - B - обл Свердловская')
network.add_node(9, label='Кат. - C - обл Свердловская')
network.add_node(10, label='Кат. - D - обл Свердловская')

Network.show запускает отображения графа, в параметрах указываем название файла, с этим названием будет создан html файл.

network.show('cities.html')

При работе с пулом данных используют метод «add_nodes», в который передается список данных. Результат отображения будет тем же. Дополнительно добавим цвет для нода.

network = Network(notebook=True)
nodes = [1, 2, 3, 4, 5, 6, 7, 8 ,9 ,10]
labels = ['Россия', 'обл Свердловская', 'Подразделение - обл Свердловская',
          'Подразделение 1 - обл Свердловская', 'Подразделение 2 - обл Свердловская',
          'Категория - обл Свердловская', 'Кат. - A - обл Свердловская',
          'Кат. - B - обл Свердловская', 'Кат. - C - обл Свердловская',
          'Кат. - D - обл Свердловская']
titles = ['Россия'] + ['']*9
colors = ['#FF0000', '#00FF00'] + ['#B0E0E6']*8

network.add_nodes(nodes=nodes, label=labels, title = titles, color=colors)
network.show('color_cities.html')

Но сами ноды без взаимосвязей между ними нам ничего не говорят, поэтому добавим ребра, показывающие взаимосвязи.

Как и с методом «add_nodes», метод «add_edges» добавляет ребра списком. В скобках первые два параметра указывают на ноды, между которыми нужно отобразить связь. Третий параметр указывать не обязательно, он нужен для отображения силы связи. Чем больше число, тем толще ребро, по умолчанию толщина равна 1. Ребра окрашиваются в цвет нода, от которого идет связь, что очень удобно при отображении большого количества нод.

network.add_edges([(1, 2, 5), (2, 3, 5), (3, 4, 5), (3, 5, 2), (2, 6, 2), (6, 7, 2),
                   (6, 8, 2), (6, 9, 2), (6, 10, 2)])
network.show('cities_with_edges.html')

Метод «repulsion» позволяет редактировать отношение нод между собой. Параметр «node_distance» отвечает за расстояние между нодами, «spring_length»- изменяет длину ребра, чем больше, тем дальше ноды будут друг от друга.

network.repulsion(node_distance=100, spring_length=150)
network.show('cities_with_edges.html')

Для управления свойствами отображения и поведения графа добавим всего одну строку.

У параметра «filter_» есть три переменные «nodes», «edges», «physics», при указании которых появляются соответствующие панели управления. При указании filter_True отобразятся все три панели разом. Во вкладке тетради пользоваться панелями не удобно, для решения этой проблемы необходимо запустить созданный html файл, находящийся в той же директории. Настройки позволяют менять очень много свойств отображения графа, от размера шрифта до физического поведения графа.

network.show_buttons(filter_=True)
network.show('cities_with_edges_buttons.html')

Теперь испытаем датасет побольше. Загрузим датафрейм, возьмем срез первых 500 записей и посмотрим, что он содержит.

import pandas as pd

df = pd.read_excel('pyvis_data.xlsx')
df = df[:500]
df.head()

Проходим по всем столбцам датафрейма и создаем список нод, в конце добавляем нод «Россия» — это будет начальная нода.

nodes = []

for column in df.columns:
    nodes += list(df[column].drop_duplicates())
nodes.append('Россия')

Создаем ребра, добавляем размер ребра.

edges = []

for i in df.index:
    weight_name = int(df['Название'][df['Название'] == df,loc[i]['Название']].value_counts()[0])
    
    edges.append(('Россия', df.loc[i]['Название'], weight_name))
    edges.append((df.loc[i]['Название'], df.loc[i]['Подразделение объекта'], 3))
    edges.append((df.loc[i]['Подразделение объекта'], df.loc[i]['Номер подразделения'], 2))
    edges.append((df.loc[i]['Название'], df.loc[i]['Категория объекта'], 3))
    edges.append((df.loc[i]['Категория объекта'], df.loc[i]['Категория'], 2))

Взглянем на первые ребра созданного списка. Ребра начинаются от нода Россия и заканчиваются категорией D.

edges[:5]
[('Россия', 'обл Свердловская', 11),
 ('обл Свердловская', 'Подразделение - обл Свердловская', 3),
 ('Подразделение - обл Свердловская', 'Подразделение 1 - обл Свердловская', 2),
 ('обл Свердловская', 'Категория - обл Свердловская', 3),
 ('Категория - обл Свердловская', 'Категория - D - обл Свердловская', 2)]

Создадим сеть, пропишем все параметры и запустим.

net = Network(notebook=True)
net.add_nodes(nodes)
net.add_edges(edges)
net.repulsion(node_distance=150, spring_length=100)
net.show_buttons(filter_=True)
net.show(demonstration.html')

Pyvis нарисовал сетевой граф, показывая все связи между нодами.

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

В этой статье для демонстрации работы графа описывался лишь небольшой срез датафрейма по нескольким полям.

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

Надеюсь, эта статья вам поможет по-новому анализировать большие объемы данных, и вы возьмете Pyvis на вооружение.