Перейти к содержимому

Numexpr python что это

  • автор:

Python numexpr примеры использования

Python numexpr — 9 примеров найдено. Это лучшие примеры Python кода для numexpr.numexpr, полученные из open source проектов. Вы можете ставить оценку каждому примеру, чтобы помочь нам улучшить качество примеров.

Related in langs

def check_rational_expr(self): func = numexpr((E.a + 2.0 * E.b) / (1 + E.a + 4 * E.b * E.b)) a = arange(1e5) b = arange(1e5) * 0.1 x = (a + 2 * b) / (1 + a + 4 * b * b) y = func(a, b) assert_array_equal(x, y)
def check_broadcasting(self): a = arange(100).reshape(10, 10)[::2] c = arange(10) d = arange(5).reshape(5, 1) assert_array_equal(evaluate("a+c"), a + c) assert_array_equal(evaluate("a+d"), a + d) expr = numexpr("2.0*a+3.0*c", [("a", float), ("c", float)]) assert_array_equal(expr(a, c), 2.0 * a + 3.0 * c)
def check_reductions(self): # Check that they compile OK. assert_equal( disassemble(numexpr("sum(x**2+2, axis=None)", [("x", float)])), [("mul_fff", "t3", "r1[x]", "r1[x]"), ("add_fff", "t3", "t3", "c2[2.0]"), ("sum_ffn", "r0", "t3", None)], ) assert_equal( disassemble(numexpr("sum(x**2+2, axis=1)", [("x", float)])), [("mul_fff", "t3", "r1[x]", "r1[x]"), ("add_fff", "t3", "t3", "c2[2.0]"), ("sum_ffn", "r0", "t3", 1)], ) assert_equal( disassemble(numexpr("prod(x**2+2, axis=2)", [("x", float)])), [("mul_fff", "t3", "r1[x]", "r1[x]"), ("add_fff", "t3", "t3", "c2[2.0]"), ("prod_ffn", "r0", "t3", 2)], ) # Check that full reductions work. x = arange(10.0) assert_equal(evaluate("sum(x**2+2,axis=0)"), sum(x ** 2 + 2, axis=0)) assert_equal(evaluate("prod(x**2+2,axis=0)"), prod(x ** 2 + 2, axis=0)) # Check that reductions along an axis work y = arange(9.0).reshape(3, 3) assert_equal(evaluate("sum(y**2, axis=1)"), sum(y ** 2, axis=1)) assert_equal(evaluate("sum(y**2, axis=0)"), sum(y ** 2, axis=0)) assert_equal(evaluate("sum(y**2, axis=None)"), sum(y ** 2, axis=None)) assert_equal(evaluate("prod(y**2, axis=1)"), prod(y ** 2, axis=1)) assert_equal(evaluate("prod(y**2, axis=0)"), prod(y ** 2, axis=0)) assert_equal(evaluate("prod(y**2, axis=None)"), prod(y ** 2, axis=None)) # Check integers x = x.astype(int) assert_equal(evaluate("sum(x**2+2,axis=0)"), sum(x ** 2 + 2, axis=0)) assert_equal(evaluate("prod(x**2+2,axis=0)"), prod(x ** 2 + 2, axis=0)) # Check complex x = x + 5j assert_equal(evaluate("sum(x**2+2,axis=0)"), sum(x ** 2 + 2, axis=0)) assert_equal(evaluate("prod(x**2+2,axis=0)"), prod(x ** 2 + 2, axis=0)) # Check boolean (should cast to integer) x = (arange(10) % 2).astype(bool) assert_equal(evaluate("prod(x,axis=0)"), prod(x, axis=0)) assert_equal(evaluate("sum(x,axis=0)"), sum(x, axis=0))
def check_r0_reuse(self): assert_equal( disassemble(numexpr("x**2+2", [("x", float)])), [("mul_fff", "r0", "r1[x]", "r1[x]"), ("add_fff", "r0", "r0", "c2[2.0]")], )

Что делать если numexpr не работет с большой степенью?

Когда я пишу большое число и возвожу тоже в большую стерпеть мне ничего не выводится а когда я закрываю скрипт с помою ctrl+c то мне выдаёт ошибку KeyboardInterrupt . except ловит исключение но оно срабатывает только после ctrl+c , при повторном нажатии всё закрывается

import numexpr math = input("> ") count_math = numexpr.evaluate(math) print(count_math) 

Отслеживать
25.4k 4 4 золотых знака 20 20 серебряных знаков 36 36 бронзовых знаков
задан 17 авг 2022 в 18:05
179 1 1 серебряный знак 14 14 бронзовых знаков
Что вы вводите?
17 авг 2022 в 18:37
999999**999999, это минимум
17 авг 2022 в 18:40

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

17 авг 2022 в 18:50

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

Времена вычисления и печати выражения 999999**999999 в Питоне. Меньше пяти секунд чтобы вычислить степень:

$ time python -c 'print((999999**999999).bit_length())' 19931548 real 0m4.435s user 0m4.420s sys 0m0.012s 

Около восьми минут чтобы вычислить и напечатать:

$ time python -c 'print(len(str(999999**999999)))' 5999994 real 7m56.762s user 7m56.664s sys 0m0.048s 

В Питоне неэффективная печать больших целых чисел к сожалению. Исправить можно поставив gmpy :

import gmpy n = gmpy.mpz(999999) m = n ** n print(len(str(m))) 

Пара секунд на вычисления и печать:

$ time python gmpy_sample.py 5999994 real 0m1.232s user 0m1.216s sys 0m0.020s 

Распараллеливание операции с вектором Numpy

Numpy — мощная библиотека Python, предназначенная для хранения и управления большими многомерными массивами. Хотя он быстрее и эффективнее, чем другие подобные коллекции, такие как списки, мы можем еще больше повысить его производительность, используя механизм распараллеливания. Распараллеливание означает разделение задач на несколько процессов для достижения одной цели. Python предоставляет несколько способов распараллеливания векторной операции numpy, включая многопроцессорную обработку и модуль numexpr.

Программы Python для распараллеливания векторной операции NumPy

Давайте обсудим способы распараллеливания вектора numpy:

Использование многопроцессорности

Каждая программа Python рассматривается как один процесс, и иногда может потребоваться одновременное выполнение нескольких процессов. Для этого в Python предусмотрен модуль multiprocessing со встроенным методом ‘Pool()’, который позволяет создавать и выполнять несколько задач одновременно.

Пример

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

Подход

Первым шагом является импорт библиотеки numpy со ссылочным именем «np» и многопроцессорностью с помощью «mp».

Затем создайте пользовательский метод вместе с параметром.

  • Внутри этого метода определите количество доступных процессов ЦП с помощью cpu_count(). Это значение в дальнейшем будет использоваться для создания пула рабочих процессов для параллельных вычислений.
  • Затем создайте пул процессов, используя Pool, который принимает «num_processes» в качестве аргумента, указывающего количество доступных процессов ЦП.
  • Теперь используйте метод карты, чтобы применить метод Square() к каждому элементу входного вектора. Этот метод разделит входной вектор на фрагменты и назначит каждый фрагмент рабочему процессу для вычислений. Функция карты автоматически распределяет рабочую нагрузку между доступными процессами и возвращает результаты в том же порядке, что и входной вектор.
  • После завершения сопоставления мы закроем пул с помощью метода close() и дождемся завершения всех рабочих процессов с помощью метода join().
  • В конце верните результат, который представляет собой список квадратов значений, полученных в результате параллельных вычислений.

Теперь создайте пустой вектор, передайте его в качестве аргумента методу и отобразите результат.

# importing required packages import numpy as np import multiprocessing as mp # user-defined method to print square of vector def square_vector_parallel(vector): num_processes = mp.cpu_count() pool = mp.Pool(processes = num_processes) result = pool.map(np.square, vector) pool.close() pool.join() return result # creating a numpy vector vec_tr = np.array([1, 2, 3, 4, 5]) # calling the method result = square_vector_parallel(vec_tr) # printing the result print(result) 

Выход

[1, 4, 9, 16, 25] 

Использование numexpr

Этот пакет Python имеет возможность распараллеливать вычисления и использовать несколько ядер или инструкции SIMD, что приводит к быстрой и эффективной работе вектора NumPy.

Пример 1

В следующем примере мы возьмем два вектора numpy и выполним над ними параллельную операцию сложения, используя библиотеку numexpr.

# importing required packages import numpy as np import numexpr as nex # creating two numpy vectors a1 = np.array([5, 2, 7, 4, 5]) a2 = np.array([4, 8, 3, 9, 5]) # printing the result print(nex.evaluate('a1 + a2')) 

Выход

[ 9 10 10 13 10] 

Пример 2

Это еще один пример, демонстрирующий использование numexpr. Мы создадим пользовательский метод, который принимает вектор в качестве параметра. Внутри этого метода определите выражение expr как «vector**2», которое возводит в квадрат каждый элемент входного вектора и передает его методу «evaluate()» numexpr для вычисления выражения в распараллеленном виде.

import numpy as np import numexpr as nex # user-defined method to print square of vector def square_vector_parallel(vector): expr = 'vector**2' result = nex.evaluate(expr) return result # creating a numpy vector vec_tr = np.array([4, 8, 6, 9, 5]) # calling the method result = square_vector_parallel(vec_tr) # printing the result print(result) 

Выход

[16 64 36 81 25] 

Пример 3

В том же коде предыдущего примера мы явно установили количество потоков, равное 4, с помощью метода set_num_threads(). Это позволяет нам реализовать параллелизм на уровне потоков при вычислении выражения.

import numpy as np import numexpr as nex # user-defined method to print square of vector def square_vector_parallel(vector): # Set the number of threads to utilize nex.set_num_threads(4) expr = 'vector**2' result = nex.evaluate(expr) return result # creating a numpy vector vec_tr = np.array([4, 8, 6, 9, 5]) # calling the method result = square_vector_parallel(vec_tr) # printing the result print(result) 

Выход

[16 64 36 81 25] 

Заключение

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

Все права защищены. © Linux-Console.net • 2019-2023

Как улучшить навыки работы с Python в 2023 году

Python — самый распространенный язык программирования в области науки о данных, и его популярность продолжает расти. За последние годы сфера влияния науки о данных существенно возросла.

Дата-сайентист часто работает с большими объемами данных. По этой причине ему нужно писать эффективный код с точки зрения времени выполнения и памяти. Код Python также должен быть хорошо структурирован и легко читаем. Эти семь советов помогут писать эффективный и читабельный код Python.

Ускорьте NumPy пакетом NumExpr

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

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

Сначала установите пакеты NumPy и NumExpr:

$ pip install numpy numexpr

Посмотрите этот пример и попробуйте его выполнить.

import numpy as np
import numexpr as ne
import timeit

var1 = np.random.random(2**27)
var2 = np.random.random(2**27)

%timeit np.sin(var1) / np.cos(var2)
# 2.73 с

%timeit ne.evaluate("sin(var1) / cos(var2)")
# 566 мс

Оператор выполняется примерно в 5 раз быстрее с помощью NumExpr. Если хотите ускорить выполнение операторов NumPy, NumExpr предоставит такую возможность.

NumExpr эффективнее всего работает с большими массивами, а максимальную производительность развивает на мощном компьютере с большим количеством ядер. Рекомендуем использовать NumExpr при наличии этих двух условий. Для операций с небольшими массивами можно применять NumPy, так как разница в производительности будет минимальной. Дело в том, что NumExpr разбивает операнды массива на небольшие фрагменты. Эти фрагменты легко помещаются в кэш процессора и распределяются между доступными ядрами процессора, что позволяет выполнять их параллельно.

Чтобы узнать больше о NumExpr, ознакомьтесь с его репозиторием на GitHub.

Освойте быструю альтернативу метода pandas apply()

Метод pandas apply() может выполнять функции вдоль оси датафрейма. Многие программисты используют метод apply() в сочетании с лямбда-функциями. Но как увеличить производительность этого метода?

Используйте пакет swifter. Он очень быстро применяет функции к датафреймам и сериям. Если pandas apply() работает на одном ядре, то swifter обеспечивает поддержку нескольких ядер.

Для начала установите пакет swifter:

$ pip install swifter

После установки пакета можете опробовать его.

import pandas as pd
import numpy as np
import swifter
import timeit

df = pd.DataFrame()

# pandas apply()
%timeit df.apply(lambda x: x**7)
# 54 мс

# swifter.apply()
%timeit df.swifter.apply(lambda x: x**7)
# 37.5 мс

Этот простой пример показывает, что метод swifter.apply() отличается более коротким временем выполнения. Разница особенно заметна на мощных компьютерах с несколькими ядрами. Если вам нужно повысить производительность проекта, обратите внимание на пакет swifter.

Используйте встроенные функции Python

Бывает так, что вы реализуете функцию, не зная, что она уже встроена в Python. Особенно часто это случается с теми, кто пришел из других языков программирования, таких как C и C++.

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

import numpy as np
from time import perf_counter

result_list = []
company_list = ["Tesla", "Block", "Palantir", "Apple"]
company_list_sample = np.repeat(company_list, 10**7)

start = perf_counter()
for company in company_list_sample:
result_list.append(company.lower())
print(perf_counter()-start)
# 17.13 с

start = perf_counter()
result_list = map(str.lower, company_list_sample)
print(perf_counter()-start)
# 0.97 с

В приведенном выше коде мы воспроизводим список из четырех записей 10 миллионов раз, поэтому получаем список из 40 миллионов записей. Затем мы преобразуем строки в списке в нижний регистр. Как видите, встроенная функция работает примерно в 17 раз быстрее. Так что используйте встроенные функции! Это увеличивает производительность, особенно при работе с большими объемами данных.

Существует и множество других встроенных функций, таких как min() , max() , all() и т. д.

Используйте списки вместо циклов

Программисты часто используют списки в сочетании с циклами для хранения результатов вычислений. Однако такой подход неэффективен с точки зрения времени выполнения. По этой причине эффективнее использовать списковое выражение. Следующий пример демонстрирует разницу в производительности.

import numpy as np
from time import perf_counter

result_list_loop = []
result_list_com = []

number_round = 10000000

start = perf_counter()
for i in range(number_round):
result_list_loop.append(i*i)
print(perf_counter()-start)
# 1.47 с

start = perf_counter()
result_list_com = [i*i for i in range(number_round)]
print(perf_counter()-start)
# 0.69 с

print(result_list_com[10])
# 100

Какой вывод можно сделать из этого примера? Необходимо использовать списковое выражение, когда это возможно. Списковое выражение является несколько спорным моментом в программировании. Некоторые считают его синтаксис сложным для чтения, поскольку одна строка кода выражает все операторы. Это дело вкуса, но производительность выше при использовании спискового выражения.

Списковое выражение начинается с открывающей скобки [ . Затем идет вычисление из цикла for . После — заголовок цикла, состоящий из трех элементов (ключевое слово for , переменная run , длина цикла). Список заканчивается закрывающей скобкой ] . Освоив этот синтаксис, вы сможете писать for -циклы гораздо компактнее.

Но как насчет использования памяти? Как уменьшить объем расходуемой памяти? Это особенно целесообразно при работе с большими списками, с которыми придется выполнять дальнейшие операции. В нашем примере в списке сохраняется 10 миллионов значений. Но нужно ли хранить непосредственно все записи или они будут нужны только по мере необходимости?

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

import sys 
from time import perf_counter

print(sys.getsizeof(result_list_com), 'bytes')
# 89095160 байт

start = perf_counter()
result_gen = (i*i for i in range(number_round))
print(perf_counter()-start)
# 0.22 мс

print(sys.getsizeof(result_gen), 'bytes')
# 112 байт

print(list(result_gen)[10])
# 100

Мы можем выполнить все операции, как в предыдущем примере. Единственное отличие заключается в том, что вместо [] используется () . Вместо списка — храним генератор. Такой подход более эффективен для памяти. Подумайте, можно ли использовать в ваших проектах списковое выражение или генераторы. Они могут повысить производительность и уменьшить объем расходуемой памяти.

Объединяйте словари с помощью синтаксиса двойной звездочки **

Как объединить словари? Это можно сделать с помощью одной строки, используя синтаксис двойной звездочки ** . Следующий пример покажет, как это работает.

dict_1 = 
dict_2 =

dict_merged = <**dict_1, **dict_2>
print(dict_merged)
#

Прежде всего, определим два словаря с одинаковыми и разными парами “ключ-значение”. Компания Tesla была основана в 2003 году, поэтому второй словарь ( dict_2 ) является более актуальным. Если оба словаря содержат одинаковые ключи и разные значения, то используется значение последнего словаря. После слияния новый словарь содержит все три пары “ключ-значение”. Синтаксис лаконичен и компактен, поэтому объединять словари очень просто. А самое приятное в том, что можно объединить три и более словарей. Этот прием может сэкономить много времени.

Другим подходом является метод update . Этот метод обновляет первый словарь и не создает его копию. Взгляните на следующий пример.

dict_1 = 
dict_2 =

dict_1.update(dict_2)
print(dict_1)
#

Недостатком метода update является то, что можно использовать только один словарь для обновления. Если в будущем захотите объединить словари, помните об этом.

Не импортируйте ненужные модули

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

import math
from time import perf_counter

start = perf_counter()
variable = math.exp(7)
print(perf_counter()-start)
# 8.47-05 с

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

from math import exp
from time import perf_counter

start = perf_counter()
variable = exp(7)
print(perf_counter()-start)
# 4.51-05 с

В данном примере импортируем функцию exp() без точечной нотации. Используя этот трюк, можно вдвое сократить время выполнения кода.

Используйте компилятор just-in-time

Numba — это компилятор just-in-time (jit), который хорошо работает с циклами, массивами и функциями NumPy. Декораторы используются для указания Numba компилировать определенные функции. Numba компилирует декорированные функции в машинный код точно в срок, так что весь код или его часть выполняется со скоростью нативного машинного кода.

Сначала установите Numba с помощью pip.

pip install numba

После успешной установки можно использовать Numba. Взгляните на следующий пример:

import numpy as np
from numba import jit
import timeit

var = np.random.random(10**7)
num_loop = 10000

def foo(var):
result = 0
for i in range(num_loop):
result += 1
result = np.sin(var) + np.cos(var)
return result
%timeit foo(var)
# 154 мс

@jit(nopython=True)
def foo_numba(var):
result = 0
for i in range(num_loop):
result += 1
result = np.sin(var) + np.cos(var)
return result

%timeit foo_numba(var)
# 76.3 мс

Как видите, вышеупомянутый декоратор функции foo ускоряет код. Декоратор nopython=True указывает, что компиляция будет выполняться без участия интерпретатора Python. Numba ускоряет выполнение цикла и тригонометрических функций NumPy. Однако она не может использоваться со всеми функциями Python.

Ниже перечислены преимущества и недостатки Numba.

Минусы:

  • Numba не поддерживает pandas.
  • Неподдерживаемый код выполняется посредством интерпретатора и влечет дополнительные накладные расходы Numba.
  • Только неофициальная поддержка на M1/Arm64.
  • Отличная поддержка массивов и функций NumPy, а также циклов.
  • Обладает поддержкой Nvidia CUDA и может применяться для разработки нейронных сетей на основе NumPy.

Минусы и плюсы показывают, что Numba следует использовать в первую очередь для операций с NumPy. Однако в начале всегда следует проверить, подходит ли Numba для соответствующей реализации.

Заключение

Вы узнали о том, как повысить эффективность кода с точки зрения времени выполнения и сохранения памяти. Выделим главные моменты.

  • NumPy не поддерживает параллельную обработку. Для этого можно использовать NumExpr.
  • Функция Pandas apply() может быть ускорена с помощью swifter.
  • Проверьте, есть ли встроенные функции.
  • Используйте списковое выражение вместо циклов. Посмотрите, подходят ли генераторы списков для вашего проекта.
  • Объединяйте массивы с помощью синтаксиса двойной звездочки ** .
  • Не импортируйте ненужные модули.
  • Если возникают проблемы со временем выполнения, можно использовать компиляторы just-in-time. Компиляторы just-in-time ускоряют работу кода.
  • 5 модулей Python для исследования Вселенной
  • Наивный байесовский алгоритм
  • 5 способов выйти из вложенного цикла в Python

Читайте нас в Telegram, VK и Дзен

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *