Проблемы с производительностью при обработке больших объемов данных в Python с использованием массивов - PullRequest
2 голосов
/ 29 октября 2019

У меня истекает срок отслеживания:

Рассмотрим трассу положения (например, отражающего золотого шарика) в поле зрения, измеренного в разные моменты времени на камере.

Теперь я хотел бы написать свой собственный код для обработки данных ... Мои данные представлены в виде массивного структурированного массива, и я беру с него все, что мне нужно.

По сути, я начинаю ссписок с записями в виде (положение, время) для каждой точки.

Я перебираю все точки и вычисляю расстояние в пространстве и времени каждой точки в наборе данных для этих точек, следующих за после это в измерении.

В зависимости от количества данных, я получаю много сотен тысяч (distance_space / distance_time) кортежей. Этим мне нужно вычислить так называемые кривые MSD (MSD: среднее квадратное расстояние), где я строю расстояние, например, золотой шарик от его происхождения в пространстве за прошедшее время.

Теперь я немера только 1 трасса, но скажем 200 ... поэтому я хочу различать и отдельные трассы, что открывает еще одно измерение.

Я могу извлечь расчетные точки данных в ОГРОМНЫЙ список

MSD_list

с, например,> 100.000.000 записей, каждая из которых является кортежем 3:

[(distance_space, distance_time, traceID),...,...]

Это уже занимает некоторое время, но все еще выполнимо ... Я создаю массив numpy и сохраняю этосписок в нем (занимает ~ 20 секунд), рабочий пример ниже со списком, содержащим 3 готовых кортежа из 2 отдельных трасс, поэтому очень маленький объем данных ...

import numpy as np

MSD_list = [(0,0,0),(0.5,1,0),(1,2,0),(0,0,1),(2,1,1),(4,2,1)]
MSD_traces = [[] for x in range(2)]

#   MSD_traces is a list that collects the data later on in a nested loop.

MSD_array = np.zeros(len(MSD_list),dtype = [('d_space', 'f8'),('d_time', 'i4'), ('traceID', 'i4')])
MSD_array[:] = MSD_list

#   Now I want to go into the array, select all the data that has a common traceID,
#   then I select a subarray with same timelag and go into a second inner loop...

for i in range(2): #2 = the amount of unique traces in my example

    for k in range(np.max(MSD_array[MSD_array['traceID']==i]['d_time'])+1): 
        #iterating from d_time 0 to the maximum d_time in that trace

        if MSD_array[(MSD_array['traceID']==i) & (MSD_array['d_time']==k)]['d_space'].size: 
            #checking for empty array where np.mean() yields error

            msd_mean = np.mean(MSD_array[(MSD_array['traceID']==i) & (MSD_array['d_time']==k)]['d_space'])
            MSD_traces[i].append((msd_mean, k))

print(MSD_traces[0])
print(MSD_traces[1])

Вывод:

[(0.0, 0), (0.5, 1), (1.0, 2)]
[(0.0, 0), (2.0, 1), (4.0, 2)]

Код работает нормально. Это займет много времени. Могу поспорить, что я использую списки и numy массивы неоптимально

В этом примере я получаю список, который содержит обе трассировки MSD_traces [0] и MSD_traces [1], каждая из которых содержит среднее расстояние и соответствующее времяотставание соответственно. В общем, длина трасс не одинакова.

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

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

Есть какие-нибудь советы?

Best, хаби

// edit: код сверху немного отличается

Я редактировал код и сохраненные массивыв цикле к переменной, чтобы «сохранить это представление» массива, я также попытался ускорить процесс, удалив переменные, которые мне больше не нужны (их перезапись - это разница?):

import numpy as np

MSD_list = [(0,0,0),(0.5,1,0),(1,2,0),(0,0,1),(2,1,1),(4,2,1)]
MSD_traces = [[] for x in range(2)]

#   MSD_traces is a list that collects the data later on in a nested loop.

MSD_array = np.zeros(len(MSD_list),dtype = [('d_space', 'f8'),('d_time', 'i4'), ('traceID', 'i4')])
MSD_array[:] = MSD_list

del MSD_list

#   Now I want to go into the array, select all the data that has a common traceID,
#   then I select a subarray with same timelag and go into a second inner loop...

for i in range(2): #2 = the amount of unique traces in my example

    MSD_array_ctID = MSD_array[MSD_array['traceID']==i]
    max_d_time = np.max(MSD_array_ctID['d_time'])

    for k in range(max_d_time+1): 
        #iterating from d_time 0 to the maximum d_time in that trace
        MSD_array_ctID_ctime = MSD_array_ctID[MSD_array_ctID['d_time']==k]
        size = MSD_array_ctID_ctime['d_space'].size

        if size: 
            #checking for empty array where np.mean() yields error

            msd_mean = np.mean(MSD_array_ctID_ctime['d_space'])
            MSD_traces[i].append((msd_mean, k))
            del msd_mean

        del size
        del MSD_array_ctID_ctime

    del max_d_time
    del MSD_array_ctID

с помощью

timeit()

Время для первого кода составляет 8,65 мс, время для второго 8,62 мс ... разница не велика :( Я сделал это без печати списков в конце.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...