Numpy: оптимальный способ подсчета индексов в массиве

У меня есть массив indexs. Он очень длинный (>10k), и каждое значение int довольно маленькое (<100). например

indexs = np.array([1, 4, 3, 0, 0, 1, 2, 0]) # int index array
indexs_max = 4 # already known

Теперь я хочу подсчитать появление каждого значения индекса (например, 0 для 3 раз, 1 для 2 раз...) и получить counts как np.array([3, 2, 1, 1, 1]). Я протестировал 4 метода следующим образом:

UPDATE: _test4 — соль @Ch3steR:


indexs = np.random.randint(0, 10, (20000,))
indexs_max = 9

def _test1():
    counts = np.zeros((indexs_max + 1, ), dtype=np.int32)
    for ind in indexs:
        counts[ind] += 1
    return counts

def _test2():
    counts = np.zeros((indexs_max + 1,), dtype=np.int32)
    uniq_vals, uniq_cnts = np.unique(indexs, return_counts=True)
    counts[uniq_vals] = uniq_cnts
    # this is because some value in range may be missing
    return counts

def _test3():
    therange = np.arange(0, indexs_max + 1)
    counts = np.sum(indexs[None] == therange[:, None], axis=1)
    return counts

def _test4():
    return np.bincount(indexs, minlength=indexs_max+1)

Запустите 500 раз, их использование времени соответственно 32.499472856521606s, 0.31386804580688477s, 0.14069509506225586s, 0.017721891403198242s. Хотя _test3 является самым быстрым, он использует дополнительную большую память.

Поэтому я прошу любые лучшие методы. Спасибо :) (@Ch3steR)


UPDATE: np.bincount пока кажется оптимальным.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
0
84
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете использовать np.bincount для подсчета вхождений в массиве.

indexs = np.array([1, 4, 3, 0, 0, 1, 2, 0])
np.bincount(indexs)
# array([3, 2,  1,  1,  1])
#        0's 1's 2's 3's 4's count

Есть нюанс np.bincount(x).size == np.amax(x)+1

Пример:

indexs = np.array([5, 10])
np.bincount(indexs)
# array([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])
#                       5's            10's count

Здесь он будет подсчитывать вхождения от 0 до максимума в массиве, обходной путь может быть

c = np.bincount(indexs) # indexs is [5, 10]
c = c[c>0]
# array([1,  1])
#        5's 10's count

Если у вас нет пропущенных значений, то есть от 0 до your_max, вы можете использовать np.bincount.

Еще одно предостережение:

Из документов:

Подсчитайте количество вхождений каждого значения в массив неотрицательных целых чисел.

Большой! test4 is bincount: ` использование времени в (с): тест 1: 32,499472856521606 тест 2: 0,31386804580688477 тест 3: 0,14069509506225586 тест 4: 0,017721891403198242 `

graphitump 17.12.2020 08:44

Другие вопросы по теме