создать пересечение из двух или более двухмерных массивов на основе общего значения в одном столбце - PullRequest
4 голосов
/ 23 января 2012

У меня есть 3 numy recarrays со следующей структурой. Первый столбец - это некоторая позиция (целое число), а второй столбец - оценка (число с плавающей запятой).

Введите:

a = [[1, 5.41],
     [2, 5.42],
     [3, 12.32],
     dtype=[('position', '<i4'), ('score', '<f4')])
     ]

b = [[3, 8.41],
     [6, 7.42],
     [4, 6.32],
     dtype=[('position', '<i4'), ('score', '<f4')])
     ]

c = [[3, 7.41],
     [7, 6.42],
     [1, 5.32],
     dtype=[('position', '<i4'), ('score', '<f4')])
     ]

Все 3 массива содержат одинаковое количество элементов.
Я ищу эффективный способ объединить эти три двумерных массива в один массив на основе столбца позиции.

Выходные данные для приведенного выше примера должны выглядеть следующим образом:

Выход:

output = [[3, 12.32, 8.41, 7.41],
          dtype=[('position', '<i4'), ('score1', '<f4'),('score2', '<f4'),('score3', '<f4')])]

Только строка с позицией 3 находится в выходном массиве, потому что эта позиция появляется во всех 3 входных массивах.

Обновление : Мой наивный подход состоит в следующем:

  1. создать вектор первых столбцов моих 3 входных массивов.
  2. используйте intersect1D, чтобы получить пересечение этих 3 векторов.
  3. каким-то образом получить индексы для вектора для всех 3 входных массивов.
  4. создать новый массив с отфильтрованными строками из 3 входных массивов.

Update2 : Каждое значение позиции может быть в одном, двух или всех трех входных массивах. В моем выходном массиве я хочу включить только строки для значений положения, которые появляются во всех 3 входных массивах.

1 Ответ

3 голосов
/ 24 января 2012

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

def count_positions(positions):
    positions = np.sort(positions)
    diff = np.ones(len(positions), 'bool')
    diff[:-1] = positions[1:] != positions[:-1]
    count = diff.nonzero()[0]
    count[1:] = count[1:] - count[:-1]
    count[0] += 1
    uniqPositions = positions[diff]
    return uniqPositions, count

Теперь используя форму функции выше, вы хотите занять только те позиции, которые встречаются 3 раза:

positions = np.concatenate((a['position'], b['position'], c['position']))
uinqPos, count = count_positions(positions)
uinqPos = uinqPos[count == 3]

Мы будем использовать сортировку поиска, поэтому мысортировка ab и c:

a.sort(order='position')
b.sort(order='position')
c.sort(order='position')

Теперь мы можем отсортировать пользователя, чтобы найти, где в каждом массиве найти каждый из наших uniqPos:

new_array = np.empty((len(uinqPos), 4))
new_array[:, 0] = uinqPos
index = a['position'].searchsorted(uinqPos)
new_array[:, 1] = a['score'][index]
index = b['position'].searchsorted(uinqPos)
new_array[:, 2] = b['score'][index]
index = c['position'].searchsorted(uinqPos)
new_array[:, 3] = c['score'][index]

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

...