Какой потенциально лучший алгоритм для решения этого вложенного цикла для python, чем тот, который я использую?

#python-3.x #for-loop #nested-loops

Вопрос:

У меня есть вложенный цикл, который должен проходить через огромное количество данных.

Предполагая,что фрейм данных со случайными значениями размером 1000 000 строк каждый имеет расположение X, Y в 2D-пространстве. Существует окно длиной 10, которое поочередно просматривает все строки данных размером 1 м, пока не будут выполнены все вычисления.

Объяснение того, что должен делать код:

  • Каждая строка представляет координаты в плоскости X-Y.
  • r_test содержит диаметры различных кругов исследований в нашей двумерной плоскости (плоскость X-Y).
  • Для каждых 10 точек/строк, для каждого отдельного диаметра в r_test , мы сравниваем расстояние между каждой точкой с оставшимися 9 точками, и если значение меньше R, мы добавляем 2 H . Затем мы вычисляем H/(N**5) и сохраняем его c_10 с индексом, соответствующим диаметру исследования.
  • Для этих первых 10 точек , наконец, когда петля прошла все эти диаметры r_test , мы считываем наклон установленной линии и сохраняем его S_wind[ii] . Таким образом, первые 9 точек данных не будут иметь никакого значения, рассчитанного для них, что позволит их np.inf отличить позже.
  • Затем окно перемещается на одну точку вниз по строкам и повторяет этот процесс до S_wind тех пор, пока не будет завершено.

Какой потенциально лучший алгоритм для решения этой проблемы, чем тот, который я использую? в python 3.x?

Заранее большое спасибо!

 import numpy as np
import pandas as pd
####generating input data frame
df = pd.DataFrame(data = np.random.randint(2000, 6000, (1000000, 2)))
df.columns= ['X','Y']


####====creating upper and lower bound for the diameter of the investigation circles    
x_range =max(df['X']) - min(df['X']) 
y_range = max(df['Y']) - min(df['Y'])
R = max(x_range,y_range)/20
d = 2
N = 10 #### Number of points in each window
#r1 = 2*R*(1/N)**(1/d)  
#r2 = (R)/(1 d)
#r_test = np.arange(r1, r2, 0.05)
##===avoiding generation of empty r_test
r1 = 80
r2= 800  
r_test = np.arange(r1, r2, 5) 

S_wind = np.zeros(len(df['X']))   np.inf

for ii in range (10,len(df['X'])): #### maybe the code run slower because of using len() function instead of a number
        c_10 = np.zeros(len(r_test))  np.inf
        H = 0
        C = 0
        N = 10 ##### maybe I should also remove this
        for ind in range(len(r_test)):
            for i in range (ii-10,ii):
                for j in range(ii-10,ii):
                    dd = r_test[ind] - np.sqrt((df['X'][i] - df['X'][j])**2  (df['Y'][i] - df['Y'][j])**2)
                    if dd > 0:
                        H  = 1
            c_10[ind] = (H/(N**2))

        S_wind[ii] = np.polyfit(np.log10(r_test), np.log10(c_10), 1)[0]   
 

Комментарии:

1. Было бы очень полезно, если бы вы объяснили, что ваш код должен был делать со всеми этими точками данных. Я озадачен целым рядом вещей, и я даже не добрался до вложенного цикла, о котором вы спрашиваете. Почему вы берете пятый корень из 1/10 и используете кратное ему в качестве нижней границы диапазона? Лучшие имена переменных могут стать началом того, чтобы сделать код более понятным.

2. @Blckknight Спасибо за ваш комментарий. Мои извинения, я попытаюсь очистить код сейчас.

3. @Blckknight Я попытался объяснить, что должен делать код. Помогает ли это вам понять назначение кода? Пожалуйста, дайте мне знать, если мне нужно будет уточнить больше. Большое спасибо!

4. Поэтому я пытаюсь протестировать способ использования широковещательной передачи numpy для устранения трех внутренних циклов, но я обнаружил, что r_test это пустой массив для моих случайных данных. Это то, что должно быть возможно, или вычисления как-то неверны?

5. @Blckknight Спасибо за комментарий. Нет, на самом деле он не должен быть пустым. Я изменил код таким образом, чтобы избежать каких-либо пустых r_test . Этот код похож на мой реальный код, за исключением того, что данные здесь генерируются случайным образом, а длина окна составляет всего 10, а в моем случае-200.

Ответ №1:

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

Внутренние петли сравнивают десять 2D-точек друг с другом попарно. Это просто смерть за использование массива numpy 10x10x2:

 # replacing the `for ind` loop and its contents:
points = np.hstack((np.asarray(df['X'])[ii-10:ii, None], np.asarray(df['Y'])[ii-10:ii, None]))
differences = np.subtract(points[None, :, :],  points[:, None, :]) # broadcast to 10x10x2
squared_distances = (differences * differences).sum(axis=2)
within_range = squared_distances[None,:,:] < (r_test*r_test)[:, None, None]  # compare squares
c_10 = within_range.sum(axis=(1,2)).cumsum() * 2 / (N**2)

S_wind[ii] = np.polyfit(np.log10(r_test), np.log10(c_10), 1)[0] # this is unchanged...
 

Я не очень pandas сообразителен, поэтому, вероятно, есть лучший способ собрать значения X и Y в один 2-мерный массив numpy. Вы сгенерировали случайные данные в формате, который я нахожу наиболее полезным, а затем преобразовали во что-то менее полезное для числовых операций!

Обратите внимание, что этот код совпадает с выводом вашего кода цикла. Я не уверен, что это на самом деле делает то, что вы хотите, так как в вашем текущем коде есть несколько немного странных вещей. Например, вам может не понадобиться cumsum в моем коде, что соответствует только повторной инициализации H до нуля во внешнем цикле. Если вы не хотите, чтобы совпадения для меньших значений r_test снова подсчитывались для больших значений, вы можете пропустить эту сумму (или, что эквивалентно, переместить H = 0 строку между циклами for ind и for i циклами в исходном коде).