Во-первых, вы можете работать с data.reshape(N,-1)
, так как вас интересует сортировка последних 2-х измерений.
простой способ, чтобы получить число уникальных значений для каждой строки сбрасывать каждую строку в набор, и пусть это сделать сортировку:
[len(set(i)) for i in data.reshape(data.shape[0],-1)]
Но это итерация, через вероятно, быстрый один ,
Проблема с «векторизации» заключается в том, что набор или список уникальных значений в каждой строке будет отличаться по длине. «строки с различной длиной» - это красный флаг, когда речь идет о «векторизации». У вас больше нет «прямоугольной» компоновки данных, которая делает возможным большинство векторизации.
Вы можете сортировать каждую строку:
np.sort(data.reshape(N,-1))
array([[1, 2, 2, 3, 3, 5, 5, 5, 6, 6],
[1, 1, 1, 2, 2, 2, 3, 3, 5, 7],
[0, 0, 2, 3, 4, 4, 4, 5, 5, 9],
[2, 2, 3, 3, 4, 4, 5, 7, 8, 9],
[0, 2, 2, 2, 2, 5, 5, 5, 7, 9]])
Но как можно определить уникальные значения в каждой строке без перебора? Подсчет числа ненулевых различий может просто сделать трюк:
In [530]: data=np.random.randint(10,size=(5,10))
In [531]: [len(set(i)) for i in data.reshape(data.shape[0],-1)]
Out[531]: [7, 6, 6, 8, 6]
In [532]: sdata=np.sort(data,axis=1)
In [533]: (np.diff(sdata)>0).sum(axis=1)+1
Out[533]: array([7, 6, 6, 8, 6])
Я собирался добавить предупреждение о поплавках, но если np.unique
работает для ваших данных, мой подход должен работать так же хорошо.
[(np.bincount(i)>0).sum() for i in data]
Это итеративный решение, которое явно быстрее, чем мой len(set(i))
версии, и конкурентоспособна с diff...sort
.
В [585]: data.shape Out [585]: (10000, 400)
In [586]: timeit [(np.bincount(i)>0).sum() for i in data]
1 loops, best of 3: 248 ms per loop
In [587]: %%timeit
sdata=np.sort(data,axis=1)
(np.diff(sdata)>0).sum(axis=1)+1
.....:
1 loops, best of 3: 280 ms per loop
Я только что нашел более быстрый способ использовать bincount
, np.count_nonzero
In [715]: timeit np.array([np.count_nonzero(np.bincount(i)) for i in data])
10 loops, best of 3: 59.6 ms per loop
Я был удивленно улучшил скорость. Но затем я вспомнил, что count_nonzero
используется в других функциях (например, np.nonzero
), чтобы выделить пространство для их результатов возврата. Поэтому имеет смысл, что эта функция будет закодирована для максимальной скорости. (Это не помогает в случае diff...sort
, потому что он не принимает параметр оси).
Рассматривали ли вы запись функции Fortran для этого и обертывание ее с помощью f2py? В подпрограмме fortran вы можете легко распараллелить с помощью OpenMP. Я часто прибегаю к этому подходу, когда мне нужно ускорить цикл с интенсивным вычислением. – deepak
Другим подходом может быть использование numba http://numba.pydata.org. У этого есть декоратор векторизации, который, я считаю, может быть применим к этому случаю.Я не эксперт в numba, поэтому вы можете взглянуть на него. – deepak
Спасибо deepak. Я не знаю Fortran, я бы предпочел использовать cython, я должен использовать другой язык. Я могу изучить, как использовать numba. – martinako