Мне поручено найти общую стоимость всех элементов на переменном расстоянии от центрального элемента.Элементы расположены в 3 измерениях (столбцы в моих данных).Каждый элемент имеет уникальное местоположение, учитывая 3 измерения (и имеет уникальный идентификатор).
У меня есть рабочая версия, которая делает то, что я хочу, однако она очень медленная.Я использую itertuples, нахожу значение для каждого кортежа с использованием подмножества фрейма данных, apply (np.isclose), и я устанавливаю значение с помощью .at (см. Код ниже).
Проблема не столько в функции моего кода, сколько в масштабируемости.Поскольку я хочу установить переменное расстояние для измерения и рассчитать это значение для каждой строки, в конечном итоге выполняется итерация nrows x ndistances, и в настоящее время каждая итерация занимает 1,7 секунды (мои данные содержат> 25 000 строк, по моим оценкам, ~ 12 часовна каждое расстояние, которое я пробую).
import pandas as pd
import numpy as np
Пример структуры данных:
df = pd.DataFrame({'id':[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19],
'x':[-2,-2,-2,-1,-1,-1,-1,0,0,0,0,0,1,1,1,1,2,2,2],
'y':[2,1,0,2,1,0,-1,2,1,0,-1,-2,1,0,-1,-2,0,-1,-2],
'z':[0,1,2,-1,0,1,2,-2,-1,0,1,2,-2,-1,0,1,-2,-1,0],
'val':[0,0,0,1,0,0,6,3,7,11,0,0,14,18,10,4,20,15,2]})
df.set_index('id', inplace=True)
# The 'val' column can have any non-negative whole number, I've just picked some randomly.
«Рабочий» код до сих пор:
n = 0 #Initial distance
while n < 3: #This part allows me to set my distance range
df['n{0}'.format(n)] = np.nan #create a column for the new values
for row in df.itertuples():
valsum = df[(df['x'].apply(np.isclose, b=row.x, atol=n)) &
(df['y'].apply(np.isclose, b=row.y, atol=n)) &
(df['z'].apply(np.isclose, b=row.z, atol=n))].val.sum()
df.at[row.Index, 'n{0}'.format(n)] = valsum
n += 1
Текущий / требуемый выход:
x y z val n0 n1 n2
id
1 -2 2 0 0 0 1 22
2 -2 1 1 0 0 0 25
3 -2 0 2 0 0 6 17
4 -1 2 -1 1 1 11 54
5 -1 1 0 0 0 19 70
6 -1 0 1 0 0 17 57
7 -1 -1 2 6 6 6 31
8 0 2 -2 3 3 25 74
9 0 1 -1 7 7 54 99
10 0 0 0 11 11 46 111
11 0 -1 1 0 0 31 73
12 0 -2 2 0 0 10 33
13 1 1 -2 14 14 62 99
14 1 0 -1 18 18 95 105
15 1 -1 0 10 10 60 107
16 1 -2 1 4 4 16 66
17 2 0 -2 20 20 67 100
18 2 -1 -1 15 15 65 101
19 2 -2 0 2 2 31 80
Я знаю, что столбец 'n0' равен столбцу 'val', потому что расстояние поиска равно 0, но я хотел показать, что я ищу.Сумма всех элементов в столбце val равна 111, что совпадает, когда (x, y, z) = (0,0,0).Это потому, что (0,0,0) является центром моих данных в этом примере, и поэтому наличие расстояния 2 охватывает все элементы.Я хотел бы сделать это для полосы пропускания расстояний, скажем, 5-10.
Мой последний вопрос: как я могу сделать это, но быстрее / эффективнее?