|
|
# Лабораторная работа 4. «Визуализация связей в виде графов»
|
|
|
|
|
|
[назад](README.md)
|
|
|
|
|
|
При выполнении данной лабораторной работы производится визуализация связей социальных сетей в виде графа.
|
|
|
|
|
|
## 1. Запрос перечня друзей пользователя
|
|
|
|
|
|
Для выполнения работы импортируем необходимый пакет.
|
|
|
|
|
|
```python
|
|
|
import vk_api
|
|
|
```
|
|
|
|
|
|
Как и при выполнении первой лабораторной работы создаем подключение, а далее находим друзей `user1` с помощью вызова метода `friends.get`.
|
|
|
|
|
|
```python
|
|
|
friends_user1 = tools.get_all('friends.get', 100, {'user_id': user1})
|
|
|
```
|
|
|
|
|
|
На выходе получим перечень `id` друзей пользователя. API VK позволяет дополнительно сразу запрашивать параметры пользователя такие как:
|
|
|
|
|
|
```python
|
|
|
nickname, domain, sex, bdate, city, country, timezone,
|
|
|
photo_50, photo_100, photo_200_orig, has_mobile,
|
|
|
contacts, education, online, relation, last_seen,
|
|
|
status, can_write_private_message, can_see_all_posts,
|
|
|
can_post, universities
|
|
|
```
|
|
|
|
|
|
Необходимые параметры указываются в параметре `fields`. При этом для выполнения текущей задачи имеет ценность лишь список друзей. Поэтому дополнительный параметры указывать не будем.
|
|
|
|
|
|
Итоговый код будет выглядеть следующим образом.
|
|
|
|
|
|
```python
|
|
|
import vk_api
|
|
|
import time
|
|
|
import json
|
|
|
import pickle
|
|
|
user1 = 249771326
|
|
|
|
|
|
def auth_handler():
|
|
|
""" При двухфакторной аутентификации вызывается эта
|
|
|
функция. """
|
|
|
# Код двухфакторной аутентификации
|
|
|
key = input("Enter authentication code: ")
|
|
|
# Если: True ‐ сохранить, False ‐ не сохранять.
|
|
|
remember_device = True
|
|
|
return key, remember_device
|
|
|
|
|
|
def stop_f(items):
|
|
|
print (items)
|
|
|
|
|
|
def get_groups_users(friends_list, tools):
|
|
|
friends_out = {}
|
|
|
for friend in friends_list:
|
|
|
try:
|
|
|
friends_out[friend] = tools.get_all('friends.get', 100, {'user_id': friend})
|
|
|
except Exception:
|
|
|
friends_out[friend] = []
|
|
|
time.sleep(1)
|
|
|
return friends_out
|
|
|
|
|
|
def main():
|
|
|
login, password = '<ВАШ ЛОГИН>', '<ВАШ ПАРОЛЬ>'
|
|
|
vk_session = vk_api.VkApi(
|
|
|
login,
|
|
|
password,
|
|
|
# функция для обработки двухфакторной аутентификации
|
|
|
auth_handler=auth_handler
|
|
|
)
|
|
|
try:
|
|
|
vk_session.auth()
|
|
|
except vk_api.AuthError as error_msg:
|
|
|
print(error_msg)
|
|
|
|
|
|
tools = vk_api.VkTools(vk_session)
|
|
|
friend_list=[]
|
|
|
friend_list.append(user1)
|
|
|
friends_out = get_groups_users(friend_list, tools)
|
|
|
print(friends_out)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
main()
|
|
|
```
|
|
|
|
|
|
В результате исполнения этого данного получится JSON-response со списком друзей пользователя, `id` которого, был указан в переменной `user1`.
|
|
|
|
|
|
## 2. Формирование графа друзей пользователя
|
|
|
|
|
|
Установим модуль networkX (необходима версия 1.9).
|
|
|
|
|
|
```python
|
|
|
pip install networkx==1.9
|
|
|
```
|
|
|
|
|
|
Далее реализуем функции для визуализации графа.
|
|
|
|
|
|
```python
|
|
|
import networkx as nx
|
|
|
|
|
|
def make_graph(friends_out, friends_friends):
|
|
|
graph = nx.Graph()
|
|
|
graph.add_node(user1, size = friends_out[user1]['count'])
|
|
|
for i in friends_out[user1]['items']:
|
|
|
try:
|
|
|
graph.add_node(i, size=friends_friends[i]['count'])
|
|
|
intersection = set(friends_out[user1]['items']).intersection(
|
|
|
set(friends_friends[i]['items']))
|
|
|
graph.add_edge(user1, i, weight=len(intersection))
|
|
|
except Exception:
|
|
|
print("err")
|
|
|
return graph
|
|
|
```
|
|
|
|
|
|
Данная функция создает граф, вершинами которого являются узлы, содержащие `id` друзей, а также связывает между собой пользователя и его друга. Так как необходимо связать не только пользователя и друзей, а ещё и друзей между собой, то модифицируем код следующим образом.
|
|
|
|
|
|
```python
|
|
|
def make_graph(friends_out, friends_friends):
|
|
|
graph = nx.Graph()
|
|
|
graph.add_node(user1, size = friends_out[user1]['count'])
|
|
|
|
|
|
for i in friends_out[user1]['items']:
|
|
|
try:
|
|
|
graph.add_node(i, size = friends_friends[i]['count'])
|
|
|
intersection = set(friends_out[user1]['items']).intersection(
|
|
|
set(friends_friends[i]['items']))
|
|
|
graph.add_edge(user1, i, weight=len(intersection))
|
|
|
except Exception:
|
|
|
print("err")
|
|
|
|
|
|
for i in range(len(friends_out[user1]['items'])):
|
|
|
id1 = friends_out[user1]['items'][i]
|
|
|
for k in range(i+1, len(friends_out[user1]['items'])):
|
|
|
id2 = friends_out[user1]['items'][k]
|
|
|
try:
|
|
|
intersection = set(friends_friends[id1]['items']).intersection(
|
|
|
set(friends_friends[id2]['items']))
|
|
|
if len(intersection) > 0:
|
|
|
graph.add_edge(id1, id2, weight=len(intersection))
|
|
|
except Exception:
|
|
|
print("err friend")
|
|
|
return graph
|
|
|
```
|
|
|
|
|
|
Здесь дополнительно добавляется переменная `friends_friends`, которая содержит в себе списки друзей друзей пользователя.
|
|
|
|
|
|
Данная переменная появляется в результате вызова метода `get_groups_users` куда на вход подаем список `id` друзей пользователя.
|
|
|
|
|
|
```python
|
|
|
friend_friends = get_groups_users(friends_out[user1]['items'], tools)
|
|
|
```
|
|
|
|
|
|
Количество запросов ограничено, поэтому с целью экономии предлагается использовать модуль `pickle`. Данный модуль реализует мощный алгоритм сериализации и десериализации объектов Python. "Pickling" – процесс преобразования объекта Python в поток байтов, а "unpickling" – обратная операция, в результате которой поток байтов преобразуется обратно в Python-объект. Поток байтов легко можно записать в файл, поэтому модуль `pickle` широко применяется для сохранения и загрузки сложных объектов в Python.
|
|
|
|
|
|
Пример его использования выглядит следующим образом.
|
|
|
|
|
|
```python
|
|
|
with open('friends_friends.pkl', 'wb') as output:
|
|
|
pickle.dump(friend_friends, output, pickle.HIGHEST_PROTOCOL)
|
|
|
```
|
|
|
|
|
|
Этот пример для сохранения объекта. Следующий пример – для загрузки объекта.
|
|
|
|
|
|
```python
|
|
|
with open('friends_friends.pkl', 'rb') as input:
|
|
|
friends_friends = pickle.load(input)
|
|
|
```
|
|
|
|
|
|
Вызовем функцию `make_graph` в функции `main`.
|
|
|
|
|
|
```python
|
|
|
g = make_graph(friends_out, friend_friends)
|
|
|
```
|
|
|
|
|
|
После формирования связей так же рекомендуется сохранить полученный граф при помощи Pickle.
|
|
|
|
|
|
## 3. Визуализация графа друзей пользователя
|
|
|
|
|
|
Сформированный граф необходимо визуализировать. Для этого будем использовать модуль `matplotlib` (необходимая версия – 2.2.4).
|
|
|
|
|
|
Реализуем функцию визуализации.
|
|
|
|
|
|
```python
|
|
|
def plot_graph(graph, adjust_nodesize):
|
|
|
#pos = nx.drawing.layout.circular_layout(graph)
|
|
|
pos=nx.spring_layout(graph, k=0.1)
|
|
|
# нормализуем размер вершины для визуализации.
|
|
|
# Оптимальное значение параметра
|
|
|
#vadjust_nodesize ‐ от 300 до 500
|
|
|
nodesize = [graph.node[i]['size']/adjust_nodesize for i in graph.nodes()]
|
|
|
#нормализуем толщину ребра графа. Здесь хорошо подходит
|
|
|
#нормализация по Standard Score
|
|
|
edge_mean = numpy.mean([graph.edge[i[0]][i[1]]['weight'] for i in graph.edges()])
|
|
|
edge_std_dev = numpy.std([graph.edge[i[0]][i[1]]['weight'] for i in graph.edges()])
|
|
|
edgewidth = [ ((graph.edge[i[0]][i[1]]['weight'] ‐ edge_mean)/edge_std_dev/2) for i in graph.edges()]
|
|
|
|
|
|
#создаем граф для визуализации
|
|
|
nx.draw_networkx_nodes(
|
|
|
graph,
|
|
|
pos,
|
|
|
node_size=nodesize,
|
|
|
node_color='y',
|
|
|
alpha=0.9
|
|
|
)
|
|
|
nx.draw_networkx_edges(
|
|
|
graph,
|
|
|
pos,
|
|
|
width=edgewidth,
|
|
|
edge_color='b'
|
|
|
)
|
|
|
nx.draw_networkx_labels(graph, pos, fontsize=5)
|
|
|
# сохраняем и показываем визуализированный граф
|
|
|
plt.savefig('saved')
|
|
|
plt.show()
|
|
|
```
|
|
|
|
|
|
Вызовем реализованную функцию в `main`.
|
|
|
```python
|
|
|
plot_graph(g, 500)
|
|
|
```
|
|
|
В результате работы кода будет получено изображение графа друзей пользователя.
|
|
|
|
|
|
Данный метод является довольно простым, т.к. при этом не происходит процесс кластеризации графа, для лучшего понимания его структуры. Однако этот пример удобен для понимания процесса работы с графами. |