Быстрый (самый лучший) метод для перебора пар индексов в Python с использованием numpyPython

Программы на Python
Ответить
Anonymous
 Быстрый (самый лучший) метод для перебора пар индексов в Python с использованием numpy

Сообщение Anonymous »

Я строю граф с ~10000 узлами, каждый узел имеет метаданные, которые определяют, с какими другими узлами он будет соединен, используя ребро.

Поскольку количество возможностей ребра (~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)
Поскольку количество пар узлов составляет ~50 миллионов, это занимает ~14 минут. Я сократил количество возможностей, отсортировав пары художников, чьи жизни не пересекались. С методами numpy, работающими под капотом C, это выполнилось менее чем за 5 секунд и собрало около 30 миллионов пар, которые нужно было только проверить:

Код: Выделить всё

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)
Удивительно, что это по-прежнему работает более ~13 минут – вместо того, чтобы улучшить время выполнения примерно на 40 %.
Удивительно, но итерация по индексам матрицы происходит намного быстрее, несмотря на все 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)
Это продолжалось менее 5 минут, несмотря на повторную итерацию 50 миллионов раз.

Это удивительно и многообещающе, и мне бы хотелось выясните, что делает эту попытку быстрее, чем предыдущая попытка, и как изменить ее, чтобы она стала еще быстрее.
Как я могу улучшить время выполнения, используя правильные методы?

Интересно, есть ли возможность дальнейшего использования numpy, например. нет необходимости использовать циклы for даже при вызове функции расчета, используя вместо этого метод, аналогичный .apply() в pandas dataframe.
(Я также заметил, что цикл через zip например, для i, j в zip(overlap_pairs[:, 0],lapover_pairs[:, 1]) не улучшило время выполнения.)

Подробнее здесь: https://stackoverflow.com/questions/793 ... sing-numpy
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»