2015-08-07 3 views
6

Итак, я просматривал StackOverflow в течение достаточно долгого времени, но я не могу показаться, чтобы найти решение для моей проблемыNumpy: Среднее значений, соответствующих уникальных координатных позиций

Рассмотрим этот

import numpy as np 
coo = np.array([[1, 2], [2, 3], [3, 4], [3, 4], [1, 2], [5, 6], [1, 2]]) 
values = np.array([1, 2, 4, 2, 1, 6, 1]) 

Коа-массив содержит координатные положения (x, y) x = (1, 2, 3, 3, 1, 5, 1) y = (2, 3, 4, 4, 2, 6, 2)

и массивы значений - некоторые данные для этой точки сетки.

Теперь я хочу получить среднее значение всех значений для каждой уникальной точки сетки. Например, координата (1, 2) происходит в положениях (0, 4, 6), поэтому для этой точки я хочу values[[0, 4, 6]].

Как я могу получить это для всех уникальных точек сетки?

+1

Что такое dtype 'coo'? Являются ли значения всегда неотрицательными ints? Максимальное значение для координат? – unutbu

+1

dtype в моем случае будет «плавать», а координаты могут принимать произвольные значения, а также отрицательные – HansSnah

+0

@HansSnah Надеюсь, вы не пытаетесь провести проверки равенства по плаванию в реальном приложении. :) –

ответ

3

Вы можете сортировать coo с помощью np.lexsort, чтобы привести дубликаты друг к другу. Затем запустите np.diff вдоль строк, чтобы получить маску запусков уникальных XY в отсортированной версии. Используя эту маску, вы можете создать массив идентификаторов, который будет иметь одинаковый идентификатор для дубликатов. Затем массив ID можно использовать с np.bincount, чтобы получить суммирование всех значений с одним и тем же идентификатором, а также их количество и, следовательно, средние значения в качестве конечного результата. Вот реализация идти вдоль этих линий -

# Use lexsort to bring duplicate coo XY's in succession 
sortidx = np.lexsort(coo.T) 
sorted_coo = coo[sortidx] 

# Get mask of start of each unique coo XY 
unqID_mask = np.append(True,np.any(np.diff(sorted_coo,axis=0),axis=1)) 

# Tag/ID each coo XY based on their uniqueness among others 
ID = unqID_mask.cumsum()-1 

# Get unique coo XY's 
unq_coo = sorted_coo[unqID_mask] 

# Finally use bincount to get the summation of all coo within same IDs 
# and their counts and thus the average values 
average_values = np.bincount(ID,values[sortidx])/np.bincount(ID) 

Пример прогона -

In [65]: coo 
Out[65]: 
array([[1, 2], 
     [2, 3], 
     [3, 4], 
     [3, 4], 
     [1, 2], 
     [5, 6], 
     [1, 2]]) 

In [66]: values 
Out[66]: array([1, 2, 4, 2, 1, 6, 1]) 

In [67]: unq_coo 
Out[67]: 
array([[1, 2], 
     [2, 3], 
     [3, 4], 
     [5, 6]]) 

In [68]: average_values 
Out[68]: array([ 1., 2., 3., 6.]) 
+1

Очень умный! Благодарю. Я уже реализовал его в своем коде! – HansSnah

+0

Вы можете получить подсчеты из позиций индексов результата 'diff', это в основном то, что np.unique', когда вы запрашиваете 'return_counts = True', и это обычно быстрее, чем вызов' bincount'. – Jaime

+0

@Jaime Ah yeah, который можно использовать для подсчета. Не знал о показателях производительности, связанных с этими двумя подходами, хорошо знать, спасибо! – Divakar

2

Вы можете использовать where:

>>> values[np.where((coo == [1, 2]).all(1))].mean() 
1.0 
+0

Я думаю, что это сработает, если я переберу все уникальные значения, но я бы хотел этого избежать – HansSnah

1

Это очень вероятно, будет быстрее, чтобы сгладить ваши индексы , то есть:

flat_index = coo[:, 0] * np.max(coo[:, 1]) + coo[:, 1] 

затем использовать np.unique на нем:

unq, unq_idx, unq_inv, unq_cnt = np.unique(flat_index, 
              return_index=True, 
              return_inverse=True, 
              return_counts=True) 
unique_coo = coo[unq_idx] 
unique_mean = np.bincount(unq_inv, values)/unq_cnt 

чем аналогичный подход с использованием lexsort.

Но под капотом метод практически такой же.

+0

Также очень аккуратно, однако я обнаружил, что при применении к моим данным плоский индекс не уникален, а результаты несколько отличаются для некоторые комбинации по сравнению с подходом lexsort – HansSnah

+0

Это, вероятно, из-за того, что я испортил: вам нужно умножить индексы строк на самый большой индекс столбца, а не на самый большой индекс строки. Я отредактировал выше, теперь должен работать нормально. – Jaime

+0

ОП разъяснил [в комментариях] (http://stackoverflow.com/questions/31878240/numpy-average-of-values-corresponding-to-unique-coordinate-positions/31880196#comment51674739_31878240), что значения 'coo' могут быть поплавками. Если 'coo = np.array ([[0, 2], [0.5, 1]])', то 'flat_index' будет равно' array ([2., 2.]) ', Таким образом, объединение двух координат, которые не являются тоже самое. – unutbu

1

Это простой один вкладыш с использованием numpy_indexed пакета (отказ от ответственности: Я ее автор):

import numpy_indexed as npi 
unique, mean = npi.group_by(coo).mean(values) 

должен быть сопоставим с принятым в настоящее время ответа в исполнении, как это делает подобные вещи под капотом ; но все в хорошо проверенной упаковке с приятным интерфейсом.

+0

Спасибо! Я ценю комментарий, но не тестировал/не реализовал вашу программу, так как не хочу, чтобы количество зависимостей во всех моих проектах было как можно более низким. – HansSnah

+0

Это и пипс, и конда, устанавливаемый на всех платформах; но это ваш звонок. Не стесняйтесь скопировать и вырезать соответствующие биты из моего репо. –

Смежные вопросы