Python/Numpy
3. Computation on Numpy Arrays : Universal Functions
njh1008
2025. 6. 17. 09:13
Introducing Ufuncs
- Python's default implementation does some operations very slowly.
- For many types of operations, Numpy provides a convenient interface into just this kind of statically typed, compiled routine. This is known as a vertorized operation
- This vectorized approach is designed to push the loop into the compiled layer that underlies Numpy, leading to much faster execution
- Vectorized operation in Numpy are implemented via ufuncs, whose main purpose is to quickly execute repeated operations on values in Numpy arrays. Ufuncs are extremely flexible.
Exploring Ufuncs
- Ufuncs exist in two flavors: unary ufuncs, which operate on a single input, and binary ufuncs, which operate on two inputs.
Array Arithmetic
# In[1]
x=np.arange(4)
print("x =",x)
print("x + 5 =",x+5)
print("x - 5 =",x-5)
print("x * 2 =",x*2)
print("x / 2 =",x/2)
print("x // 2 =",x//2)
# Out[1]
x = [0 1 2 3]
x + 5 = [5 6 7 8]
x - 5 = [-5 -4 -3 -2]
x * 2 = [0 2 4 6]
x / 2 = [0. 0.5 1. 1.5]
x // 2 = [0 0 1 1]
# In[2]
print("-x =",-x)
print("x ** 2 =",x**2)
print("x % 2 =",x%2)
# Out[2]
-x = [ 0 -1 -2 -3]
x ** 2 = [0 1 4 9]
x % 2 = [0 1 0 1]
# In[3]
-(0.5*x + 1) ** 2
# Out[3]
array([-1. , -2.25, -4. , -6.25])
Arithmetic operators implemented in Numpy
Operator | Equivalent ufunc | Description |
---|---|---|
+ | np.add |
Addition |
- | np.subtract |
Subtraction |
- | np.negative |
Unary negation |
* | np.multiply |
Multiplication |
/ | np.divide |
Division |
// | np.floor_divide |
Floor division |
** | np.power |
Exponentiation |
% | np.mod |
Modulus/remainder |
Absolute Value
- Using
np.absolute
ornp.abs
# In[4] x=np.array([-2,-1,0,1,2]) print(abs(x)) print(np.absolute(x)) print(abs(x))
# Out[4] [2 1 0 1 2] [2 1 0 1 2] [2 1 0 1 2]
# In[5]
x=np.array([3-4j,4-3j,2+0j,0+1j])
np.abs(x)
# Out[5]
array([5., 5., 2., 1.])
Trigonometric Functions
# In[6]
theta=np.linspace(0,np.pi,3)
print("theta =",theta)
print("sin(theta) =",np.sin(theta))
print("cos(theta) =",np.cos(theta))
print("tan(theta) =",np.tan(theta))
# Out[6]
theta = [0. 1.57079633 3.14159265]
sin(theta) = [0.0000000e+00 1.0000000e+00 1.2246468e-16]
cos(theta) = [ 1.000000e+00 6.123234e-17 -1.000000e+00]
tan(theta) = [ 0.00000000e+00 1.63312394e+16 -1.22464680e-16]
# In[7]
x=[-1,0,1]
print("x =",x)
print("arcsin(x) =",np.arcsin(x))
print("arccos(x) =",np.arccos(x))
print("arctan(x) =",np.arctan(x))
# Out[7]
x = [-1, 0, 1]
arcsin(x) = [-1.57079633 0. 1.57079633]
arccos(x) = [3.14159265 1.57079633 0. ]
arctan(x) = [-0.78539816 0. 0.78539816]
Exponents and logarithms
# In[8]
x=[1,2,3]
print("x =",x)
print("e^x =",np.exp(x))
print("2^x =",np.exp2(x))
print("3^x =",np.power(3,x))
# Out[8]
x = [1, 2, 3]
e^x = [ 2.71828183 7.3890561 20.08553692]
2^x = [2. 4. 8.]
3^x = [ 3 9 27]
# In[9]
x=[1,2,4,10]
print("x =",x)
print("ln(x) =",np.log(x))
print("log2(x) =",np.log2(x))
print("log10(x)=",np.log10(x))
# Out[9]
x = [1, 2, 4, 10]
ln(x) = [0. 0.69314718 1.38629436 2.30258509]
log2(x) = [0. 1. 2. 3.32192809]
log10(x)= [0. 0.30103 0.60205999 1. ]
# In[10]
x=[0,0.001,0.01,0.1]
print("exp(x) - 1 =",np.expm1(x))
print("log(1 + x) =",np.log1p(x))
# Out[10]
exp(x) - 1 = [0. 0.0010005 0.01005017 0.10517092]
log(1 + x) = [0. 0.0009995 0.00995033 0.09531018]
Specialized Ufuncs
- Another excellent source for more specialized ufuncs is the submodule
scipy.special
. If you want to compute some obscure mathematical function on your data, chances are it is implemented inscipy.special
.# In[11] from scipy import special
# In[12]
# Gamma function (generalized factorials) and related functions
x=[1,5,10]
print("gamma(x) =",special.gamma(x))
print("ln|gamma(x)| =",special.gammaln(x))
print("beta(x,2) =",special.beta(x,2))
# Out[12]
gamma(x) = [1.0000e+00 2.4000e+01 3.6288e+05]
ln|gamma(x)| = [ 0. 3.17805383 12.80182748]
beta(x,2) = [0.5 0.03333333 0.00909091]
# In[13]
# Error function (integral of Gaussian)
x=np.array([0,0.3,0.7,1.0])
print("erf(x) =",special.erf(x))
print("erfc(x) =",special.erfc(x))
print("erfinv(X) =",special.erfinv(x))
# Out[13]
erf(x) = [0. 0.32862676 0.67780119 0.84270079]
erfc(x) = [1. 0.67137324 0.32219881 0.15729921]
erfinv(X) = [0. 0.27246271 0.73286908 inf]
Advanced Ufuncs Features
Specifying Output
- In large calculations, it is useful to be able to specify the array where the result of the calculation will be stored.
- Rather than creating a temporary array, you can use this to write computation results directly to the memory location where you'd like them to be.
- For all ufuncs, you can do this
out
argument of the function.# In[14] x=np.arange(5) y=np.empty(5) np.multiply(x,10,out=y) print(x) print(y)
# Out[14] [0 1 2 3 4] [ 0. 10. 20. 30. 40.]
# In[15]
y=np.zeros(10)
np.power(2,x,out=y[::2])
print(y)
# Out[15]
[ 1. 0. 2. 0. 4. 0. 8. 0. 16. 0.]
Aggregations
reduce
method : if we'd like to reduce an array with a particular operation.# In[16] x=np.arange(1,6) print(np.add.reduce(x))
# Out[16] 15
# In[17]
np.multiply.reduce(x)
# Out[17]
120
accumulate
method : if we'd like to store all the intermediate results of the computation.# In[18] np.add.accumulate(x)
# Out[18] array([ 1, 3, 6, 10, 15])
# In[19]
np.multiply.accumulate(x)
# Out[19]
array([ 1, 2, 6, 24, 120])
Outer Products
outer
method : any ufunc can compute the output of all pairs of two different inputs using this method.# In[20] x=np.arange(1,6) np.multiply.outer(x,x)
# Out[20] array([[ 1, 2, 3, 4, 5], [ 2, 4, 6, 8, 10], [ 3, 6, 9, 12, 15], [ 4, 8, 12, 16, 20], [ 5, 10, 15, 20, 25]])