2D Numpy массив: очень быстрое обновление строк другим массивом на основе столбца критериев - PullRequest
0 голосов
/ 11 июля 2020

Допустим, у меня есть массив 2D Numpy A , и я хочу обновить указанные c строки с другим массивом B на основе столбца id в качестве критерия.

Дело в том, что мне нужно очень быстро получить этот ! Сначала я попытался сделать это с помощью Pandas, но производительность была недостаточной. В массиве A около 10000 строк, и мне нужно обрабатывать от 100 до 500 таких обновлений в секунду.

Можно ли добиться этого с помощью простого Numpy? Или мне нужно использовать Numba или Cython?

A = np.array([
   [1000001,'Peter',11],
   [1000002,'Bob',22],
   [1000003,'Julie',33],
   [1000004,'Larry',44],
   ...
])

B = [
   [1000002,'Bob',77],
   [1000004,'Mia',88],
]

Результат A должен выглядеть так:

[
   [1000001,'Peter',11],
   [1000002,'Bob',77],
   [1000003,'Julie',33],
   [1000004,'Mia',88],
   ...
]

Обновление:

После нескольких попыток я нашел решение Numpy, которое работает довольно хорошо:

def update_array(A, B):
    A[np.where(np.isin(A[:,0], B[:,0]))] = B
    return A

Есть ли еще более быстрый подход в Numpy? Или кто-нибудь знает, как это сделать с Нумбой? Когда я просто устанавливаю декоратор @jit, я получаю сообщение об ошибке.

Обновление 2

Исходные потоки данных из соединения Websocket и поступают фактически в списке форматов dict.

A = [ 
   {'id': 1000001, 'name': 'Peter', 'points': 11}, 
   {'id': 1000002, 'name': 'Bob', 'points': 22}, 
   {'id': 1000003, 'name': 'Julie', 'points': 33}, 
   {'id': 1000004, 'name': 'Larry', 'points': 44}, 
   ... 
]

B = [ 
   {'id': 1000002, 'name': 'Bob', 'points': 77}, 
   {'id': 1000004, 'name': 'Mia', 'points': 88},
] 

Сначала я подумал, что это быстрее для преобразования данных в Pandas DataFrame или Numpy массив для дальнейшей обработки, но теперь у меня сложилось впечатление, что преобразование каждого пакета данных занимает больше времени, чем фактическая обработка данных.

Обновление 3

Попробовав несколько подходов, я выбрал структуру «dict of dict» с идентификаторами в качестве ключей. Преобразование исходной структуры происходит довольно быстро, используя понимание списка. Это означает, что вся дальнейшая обработка данных теперь также сильно зависит от понимания списка, который, на мой взгляд, не является самым читаемым кодом. Тем более, что в моем случае обрабатываемые мною словари не всегда имеют одинаковую глубину, что приводит к еще большему пониманию списка. Боже, я действительно сходил с ума от этого сегодня ... Pandas было намного лучше с этой стороны, но я не мог добиться там производительности. Теперь с этим подходом dict я считаю, что это не самый элегантный способ ... но, по крайней мере, я могу обрабатывать около 20 000 обновлений dict в секунду, что является большим улучшением!

A = { 
   1000001: {'name': 'Peter', 'points': 11}, 
   1000002: {'name': 'Bob', 'points': 22}, 
   1000003: {'name': 'Julie', 'points': 33}, 
   1000004: {'name': 'Larry', 'points': 44}, 
   ... 
}

B = { 
   1000002, {'name': 'Bob', 'points': 77}, 
   1000004, {'name': 'Mia', 'points': 88},
} 
* 1049 что я делаю с данными. Там я могу достичь только около 100 в секунду, поэтому я решил выполнять эти вычисления не в реальном времени, а через запланированные интервалы. Я все еще хотел бы узнать, насколько далеко он может go с другими подходами, довольно впечатляет, насколько велика разница в производительности между простыми python подходами. Не говоря уже о Numba или Cython ... Если у кого-то есть идеи, я буду рад узнать больше!

Ответы [ 2 ]

0 голосов
/ 11 июля 2020

Вот как вы обновляете с помощью Numpy (Numba должна работать так же):

A[np.isin(A[:,0],B[:,0])]=B

вывод:

[['1000001' 'Peter' '11']
 ['1000002' 'Bob' '77']
 ['1000003' 'Julie' '33']
 ['1000004' 'Mia' '88']]
0 голосов
/ 11 июля 2020

Вот простой способ, используя только Python:

A = {
    1000001: ('Peter', 11),
    1000002: ('Bob', 22),
    1000003: ('Julie', 33),
    1000004: ('Larry', 44),
}

B = {
    1000002: ('Bob', 77),
    1000004: ('Mia', 88),
}

A.update(B)

Тогда A:

{
    1000001: ('Peter', 11),
    1000002: ('Bob', 77),
    1000003: ('Julie', 33),
    1000004: ('Mia', 88)
}

Мой ноутбук может делать это A.update(B) примерно 4 миллиона раз в секунду.

Вот решение Pandas, но на предоставленных небольших выборочных данных оно в 1000 раз медленнее:

dfA = pd.DataFrame(A)
dfB = pd.DataFrame(B)

dfA[0] = dfA[0].astype(int)
dfB[0] = dfB[0].astype(int)

dfA.set_index(0, inplace=True)
dfB.set_index(0, inplace=True)

dfA.update(dfB)

Теперь dfA:

             1   2
0                 
1000001  Peter  11
1000002    Bob  77
1000003  Julie  33
1000004    Mia  88
...