Advertisement
Guest User

Untitled

a guest
Jan 15th, 2022
183
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.57 KB | None | 0 0
  1. Построение рекомендательной системы
  2. В этом нотбуке мы выполним наш финальный проект — построим рекомендательную систему, основанную на методах, которые мы обсудили.
  3.  
  4. Для этого мы будем использовать данные от Амазон. Граф размещен в отдельном файле, он загружается в первом блоке.
  5.  
  6. Нам нужно будет реализовать три метода, обсуждавшиеся на этой неделе, и протестировать их. Но общий подход во всех трех методах один и тот же:
  7.  
  8. мы фиксируем вершину (в коде ниже это переменная query);
  9. удаляем некоторые смежные с ней ребра (в коде ниже это список samp);
  10. вычисляем специально определенное расстояние между нашей вершиной и всеми остальными (методы различаются как раз выбором расстояния);
  11. выбираем вершины с наименьшим расстоянием до выбранной, это те вершины, в которые метод предлагает провести ребра;
  12. сравниваем предложенные методом ребра с удаленными, чем больше совпадений, тем лучше сработал метод.
  13. Вспомогательные шаги уже реализованы ниже. Шаг 2 реализован в функции generate_graph. Шаги 4-5 реализованы в функции check_answer. Вам нужно реализовать только шаги 3 для всех методов.
  14.  
  15. В первом методе, который нужно реализовать, расстоянием является просто число общих соседей. Во втором методе нужно будет посчитать усеченные моменты достижения из выбранной вершины. Их мы подсчитываем приближенно, запуская случайное блуждание несколько раз. Сначала нужно реализовать функцию для одного случайного блуждания, затем функцию для приближенного вычисления усеченных моментов достижения. Длину блуждания мы фиксируем равной 10. В третьем методе нужно посчитать усеченные моменты достижения в вершину. Для них у нас есть рекуррентная формула.
  16.  
  17. Мы подробно обсуждали все три метода на этой неделе. Ниже вы также можете найти поясняющие комментарии.
  18.  
  19. Внимание: в функциях пользуйтесь только теми графами (graph или adjlist), которые переданы в аргументах. Все остальные вхождения могут измениться во время тестирования.
  20.  
  21.  
  22.  
  23.  
  24.  
  25. # В этом блоке мы загружаем граф из файла и приводим его в вид, удобный для работы
  26.  
  27. import networkx as nx
  28.  
  29. amazon = nx.read_edgelist("Amazon0302.txt", create_using=nx.Graph(), nodetype=int, data=False)
  30. amazon = nx.convert_node_labels_to_integers(amazon, ordering='decreasing degree')
  31. nodes = amazon.number_of_nodes()
  32.  
  33.  
  34. # В этом блоке собраны вспомогательные функции, которые потребуются вам для выполнения задания
  35.  
  36. # Эта функция получив на вход словарь упорядочивает его по значению меток
  37. def index_sorted(a, reverse=False):
  38.     return sorted(range(len(a)), key=lambda k: a[k], reverse=reverse)
  39.  
  40. # Эта функция позволяет выбрать ответ из посчитанных расстояний и сравнить его с целевым значением.
  41. # Она выбирает нужное количество вершин с минимальным расстоянием и находит число совпадений с удаленными ребрами.
  42. def check_answer(stat, samp, reverse=False):
  43.     index_dist = index_sorted(stat, reverse)
  44.     guess = index_dist[:len(samp)]
  45.     return len(set(samp) & set(guess))
  46.  
  47. # Эта функция генерирует тестовый пример, удаляя данные ей ребра из графа.
  48. def generate_graph(query, samp):
  49.     graph = amazon.copy()
  50.     for i in samp:
  51.         graph.remove_edge(query, i)
  52.     return graph
  53.  
  54.  
  55. # В этом блоке требуется реализовать метод числа общих соседей.
  56. # Функция в ячейке массива i должна сохранить число общих соседей query и i.
  57. # Но есть одна тонкость: ячейку с номером query и ее соседей правильно обнулить,
  58. # а то нам будут рекомендовать соединить query с query или ее соседями
  59.  
  60. def common_neighbours(graph, query):
  61.     common_neigh = [0] * nodes
  62.     # your code here
  63.     for i in graph:
  64.         for neigh in graph[i]:
  65.             if neigh in list(graph[query]):
  66.                 common_neigh[i] += 1
  67.     common_neigh[query] = 0
  68.     for v in graph[query]:
  69.         common_neigh[v] = 0
  70.  
  71.     return common_neigh
  72.  
  73.  
  74.  
  75. # На примерах в этом блоке вы можете протестировать Ваше решение. Важно: прохождение этих тестов необходимо
  76. # для получения хорошей оценки, но недостаточно: Ваше решение будет проверено на дополнительном наборе тестов
  77.  
  78. query = 422
  79. samp = [35561, 98891, 157171, 3060, 198304, 28054, 226896, 20673, 110999, 125875, 125877, 20342, 208996, 205186, 829, 189415, 212872, 164896, 104718, 78418]
  80. graph = generate_graph(query, samp)
  81.  
  82. ans = common_neighbours(graph, query)
  83. assert index_sorted(ans, reverse=True)[:len(samp)] == [829, 3060, 20673, 13141, 21150, 35561, 36377, 103988, 110999, 172699, 4863, 8961, 10572, 16003, 20342, 28054, 53201, 70084, 70323, 104718]
  84. assert check_answer(ans, samp, reverse=True) == 8
  85.  
  86. # В этом блоке требуется реализовать метод случайных блужданий.
  87. # Допишите обработку новой вершины в блуждании и учет непосещенных вершин.
  88. # Обратите внимание на массив used: вместо того, чтобы перед каждым блужданием его очищать,
  89. # мы поддерживаем номер последней посещенной итерации и сравниваем его с текущим.
  90.  
  91. import random
  92.  
  93. def hit_time(adjlist, hit_dist, hit_times, used, source, time_bound, it):
  94.     current_node = source
  95.     for step in range(time_bound):
  96.         current_node = random.choice(adjlist[current_node])
  97.         if used[current_node] != it:
  98.             # your code here
  99.             hit_dist[current_node] += step + 1 #расстояние до вершины
  100.             used[current_node] +=1 #счетчик
  101.            
  102.            
  103. def hit_distance(adjlist, query, time=10):
  104.     # инициализация статистик
  105.     hit_dist = [0] * nodes  # искомые расстояния
  106.     hit_times = [0] * nodes  # кол-во раз, когда вершина была достигнута в блуждании
  107.     used = [0] * nodes  # последняя итерация, на которой вершина была достигнута в блуждании
  108.     samples = nodes // time  # кол-во блужданий
  109.    
  110.     # запуск блужданий
  111.     for i in range(1, samples + 1):
  112.         hit_time(adjlist, hit_dist, hit_times, used, query, time, i)
  113.     # your code here
  114.     for i in hit_dist:
  115.         i = (i + time * (samples - i)) / samples   #расчет расстояний
  116.         hit_dist[query] = time
  117.  
  118. # Проверьте Ваше решение
  119.  
  120. adjlist = nx.convert.to_dict_of_lists(graph)
  121. hd = hit_distance(adjlist, query)
  122. assert check_answer(hd, samp) >= 8
  123.  
  124.  
  125.  
  126.  
  127. # В этом блоке необходимо реализовать подсчет усеченных моментов достижения в вершину.
  128. # Допишите рекуррентную функцию и постобработку (какие вершины точно не должны попасть в ответ?)
  129. # В нашем тестовом графе нет петель, но если вы захотите потестировать свое решение на других графах,
  130. # обратите внимание, что петля (ребро, идущее из вершины в саму себя) повышает степень вершины на 2
  131.  
  132. def truncated_hitting_time(graph, query, time=10):
  133.     tht = [[0 for _ in range(nodes)] for _ in range(time + 1)]
  134.     for t in range(1, time + 1):
  135.         for vert in range(nodes):
  136.             if vert == query:
  137.                 continue
  138.            
  139.             if graph.degree[vert] != 0:
  140.                 # your code here
  141.                
  142.             tht[t][vert] += 1
  143.  
  144.     # your code here
  145.    
  146.     return tht[time]
  147.  
  148.  
  149.  
  150.  
  151. # Проверьте Ваше решение
  152.  
  153. tht = truncated_hitting_time(graph, query)
  154. assert index_sorted(tht)[:len(samp)] == [164896, 254021, 110999, 212872, 20673, 172699, 3060, 104718, 205186, 194186, 35561, 36377, 829, 103988, 157171, 198304, 113283, 21150, 244935, 186662]
  155. assert check_answer(tht, samp) == 11
  156.  
  157.  
  158. # В этом блоке требуется реализовать функцию, которая принимает две разные статистики и выдает новую,
  159. # являющуюся суммой переданных
  160.  
  161. def sum_of_stats(first, second):
  162.     # your code here
  163.    
  164.  
  165.  
  166.  
  167. # Проверьте Ваше решение
  168.  
  169. assert check_answer(sum_of_stats(hd, tht), samp) >= 9
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement