Случаи, когда NumPy не лучший вариант

Python довольно интуитивно понятен для новичков, когда они используют собственные типы данных коллекции. По мере того, как код становится более сложным, время выполнения увеличивается. В этом фрагменте будет сравниваться скорость нативных массивов в Python с массивами NumPy.

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

Давайте подготовимся к написанию кода

Чтобы сравнить NumPy и собственные массивы, давайте напишем код.

Этот фрагмент кода создает два массива - собственный массив Python и объект NumPy. Оба они содержат целые элементы от 0 до 9. Я также импортировал модуль времени - мы вернемся к нему позже.

Как найти разницу в скорости

Это просто. Нам просто нужно использовать модуль времени и найти разницу между двумя моментами: моментом перед выполнением блока кода и моментом сразу после него. Я использую функциюperf_counter_ns() вместо time(), так как мне нужна максимально возможная точность. Обратите внимание, что одна секунда составляет 1 000 000 000 наносекунд.

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

Примечание: мой компьютер в настоящее время использует AMD Ryzen 5 в качестве процессора. В зависимости от вашего процессора ваши результаты могут отличаться.

Тест 1: функция печати

Наверное, каждый использует функцию печати либо для отладки, либо просто для отображения содержимого массива. Давайте посмотрим, как он работает с массивами разного размера. Для удобства чтения продолжительность конвертируется в секунды.

+------------+-------------------+------------------+
| Array size | Duration (Native) | Duration (NumPy) |
+------------+-------------------+------------------+
|         10 |         0.0002097 |        0.0001529 |
|      1 000 |         0.0096579 |        0.0134756 |
|  1 000 000 |          9.481898 |       10.7749533 |
+------------+-------------------+------------------+

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

Тест 2: нахождение среднего арифметического

Сделаем некоторые расчеты. Чтобы найти среднее значение в массиве Python, мы должны найти сумму всех элементов и разделить ее на количество элементов. В NumPy мы можем сделать это так же, как или, мы могли бы просто использовать функцию mean().

native_mean = sum(native_lst)/len(native_lst)
numpy_mean1 = numpy_lst.sum()/numpy_lst.size
numpy_mean2 = numpy_lst.mean()

Запишем продолжительность всех трех. Метод поиска numpy_mean1 помечен как «Dur. (NumPy 1) », а для numpy_mean2Dur. (NumPy 2) ».

Поскольку длительность довольно мала, в следующей таблице в качестве единицы времени используются наносекунды.

+------------+---------------+----------------+----------------+
| Array size | Dur. (Native) | Dur. (NumPy 1) | Dur. (NumPy 2) |
+------------+---------------+----------------+----------------+
|         10 |          2400 |          80000 |         100600 |
|      1 000 |         15000 |          61000 |          95100 |
|  1 000 000 |      49311000 |         737000 |        1233100 |
+------------+---------------+----------------+----------------+

Ух ты! Мы можем сделать как минимум три наблюдения:

  • Нативные методы работают медленнее по мере увеличения размера массива. Можно сказать, что в какой-то момент, если массив вырастет в 10 раз, потребуется в 10 раз больше времени, чтобы найти среднее значение всех элементов.
  • При работе с небольшими массивами требуется гораздо больше времени при работе с массивами NumPy. Потеря времени проявляется и во время кодирования - вероятно, вам понадобится больше секунды, чтобы импортировать NumPy и инициализировать массив NumPy.
  • Первый метод NumPy быстрее второго. Для меня это неинтуитивно: два вызова функций - это больше, чем один, и я ожидал, что функция mean() будет делать то же самое, но быстрее.

Заключение: когда нам следует использовать NumPy?

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

Чтобы оценить этот размер, я пошел методом проб и ошибок и использовал второй тест в этой статье. В этом тесте я использовал более быстрый метод NumPy (первый).

Барабанная дробь… результаты!

По моим результатам, это происходит, когда размер массива составляет около 4000–5000.

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