Поскольку количество возможностей ребра (~50M ) намного больше, чем фактическое количество добавляемых ребер (~ 300 тыс.), неоптимально просто перебирать пары узлов с помощью циклов for, чтобы проверить, следует ли добавлять ребро между ними. Используя некоторую логику для фильтрации большого количества пар, чтобы не приходилось проверять, с помощью быстрых методов numpy я быстро сократил возможности до массива всего из ~30 миллионов пар.
Однако , при переборе их вместо этого производительность не сильно улучшилась - на самом деле итерация по большей двумерной логической матрице происходит в два раза быстрее (по сравнению с моим методом, который ранее собирал значения True из матрицы и выполнял итерацию только по эти ~30 млн экземпляров). Должен быть способ получить желаемый выигрыш в производительности, но я зашел в тупик, пытаясь понять, почему некоторые методы работают быстрее и как улучшить время выполнения.
Контекст. В частности, каждый узел — это художник с метаданными, такими как местоположение, год рождения и смерти.
Я связываю двух художников на основе метода, который вычисляет меру того, насколько они близки. жили друг с другом примерно в одно время (например, два художника, живущие в одном место в то же время, в течение достаточно длительного времени, получит высокую ценность). Это типичный способ добиться именно этого (перебор индексов предпочтительнее имен):
Код: Выделить всё
for i, j in itertools.combinations(range(len(artist_names)), 2): #~50M iterations
artist1 = artist_names[i]
artist2 = artist_names[j]
#...
artist1_data = artist_data[artist1]
artist2_data = artist_data[artist2]
val = process.get_loc_similarity(artist1_data, artist2_data)
if val > 0:
G.add_edge(artist1, artist2, weight=val)
Код: Выделить всё
birth_condition_matrix = (birth_years < death_years.reshape(-1, 1))
death_condition_matrix = (death_years > birth_years.reshape(-1, 1))
overlap_matrix = birth_condition_matrix & death_condition_matrix
overlapping_pairs_indices = np.array(np.where(overlap_matrix)).T
overlapping_pairs_indices = np.column_stack((overlapping_pairs_indices[:, 0], overlapping_pairs_indices[:, 1]))
Код: Выделить всё
for i, j in overlapping_pairs_indices: #~30M iterations
if i != j:
artist1 = artist_names[i]
artist2 = artist_names[j]
artist1_data = artist_data[artist1]
artist2_data = artist_data[artist2]
val = process.get_loc_similarity(artist1_data, artist2_data)
if val > 0:
G.add_edge(artist1, artist2, weight=val)
Удивительно, но итерация по индексам матрицы происходит намного быстрее, несмотря на все 50M комбинаций:
Код: Выделить всё
for i in range(len(artist_names)):
for j in range(i + 1, len(artist_names)): #~50M iterations
if overlap_matrix[i, j]:
artist1 = artist_names[i]
artist2 = artist_names[j]
artist1_data = artist_data[artist1]
artist2_data = artist_data[artist2]
val = process.get_loc_similarity(artist1_data, artist2_data)
if val > 0:
G.add_edge(artist1, artist2, weight=val)
Это удивительно и многообещающе, и мне бы хотелось выясните, что делает эту попытку быстрее, чем предыдущая попытка, и как изменить ее, чтобы она стала еще быстрее.
Как я могу улучшить время выполнения, используя правильные методы?
Интересно, есть ли возможность дальнейшего использования numpy, например. нет необходимости использовать циклы for даже при вызове функции расчета, используя вместо этого метод, аналогичный .apply() в pandas dataframe.
(Я также заметил, что цикл через zip например, для i, j в zip(overlap_pairs[:, 0],lapover_pairs[:, 1]) не улучшило время выполнения.)
Подробнее здесь: https://stackoverflow.com/questions/793 ... sing-numpy
Мобильная версия