Chapter3 Mathematical Functions: Notebook4 Powers
저번 notebook에서는 $e^{x}$와 같이 exponent를 배웠다면 이번 notebook에서는 $x^{e}$와 같은 power에 대해서 배워본다. 사실 이 np.power()만 알아도 다양한 연산을 소화할 수 있게 된다.
공식 document를 찾아보면 numpy.power(x1, x2)를 사용할 때, x1, x2가 array_like인 것을 알 수 있다.
그리고 x1에는 base, x2에는 exponent가 들어가게 된다.
(https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.power.html)
이 array_like의 의미를 생각해보면 np.power()를 사랑할 수 밖에 없게 될 것이다. 그럼 하나씩 살펴보도록 하자.
import numpy as np
import matplotlib.pyplot as plt
np.power() Usage.1¶
그럼 이 np.power()를 이용한 연산 중에 가장 간단한 예시를 보자.
x_np = np.array([1, 2, 3, 4, 5])
power2_np = np.power(x_np, 2)
power3_np = np.power(x_np, 3)
print("power2_np:", power2_np)
print("power3_np:", power3_np)
위의 결과에서 알 수 있듯이, x1 위치에는 base가 들어가고 1, 2, 3, 4, 5의 ndarray를 넣어주고 exponent에는 2, 3의 scalar를 각각 넣으면 $x^{2}, x^{3}$를 return 해주는 것을 알 수 있다.
따라서 다음과 같이 임의의 exponent에 대한 power function을 구할 수 있다.
x_range = np.linspace(-3, 3, 500)
power2_np = np.power(x_range, 2)
power3_np = np.power(x_range, 3)
power4_np = np.power(x_range, 4)
power5_np = np.power(x_range, 5)
fig, ax = plt.subplots(figsize = (8,4))
ax.plot(x_range, power2_np, label = r'$x^{2}$')
ax.plot(x_range, power3_np, label = r'$x^{3}$')
ax.plot(x_range, power4_np, label = r'$x^{4}$')
ax.plot(x_range, power5_np, label = r'$x^{5}$')
ax.grid()
fig.legend(facecolor = (0.8, 0.8, 0.8), loc = 'upper left')
위의 Usage를 이용하면 다음과 같은 다항식도 만들어낼 수 있게 된다.
$y = 3x^{3} + 5x^{2} + x + 3$
x_range = np.linspace(-3, 3, 500)
poly_np = 3*np.power(x_range, 3) + 5*np.power(x_range, 2) + x_range + 3
fig, ax = plt.subplots(figsize = (8,4))
ax.plot(x_range, poly_np, label = r'$y = 3x^{3} + 2x^{2} + x + 3$')
fig.legend()
ax.grid()
np.power() Usage.2¶
위의 Usage.1에서 x2에 1보다 작고 0보다 큰 값을 넣으면 다음과 같은 결과가 나오게 된다.
$x^{1/2} = \sqrt{x}$
$x^{1/3} = \sqrt[3]{x}$
x_range = np.linspace(0.5, 5, 500)
sqrt2_np = np.power(x_range, 0.5)
sqrt3_np = np.power(x_range, 1/3)
fig, ax = plt.subplots(figsize = (8,4))
ax.plot(x_range, sqrt2_np, label = r'$ y = \sqrt{x} $')
ax.plot(x_range, sqrt3_np, label = r'$ y = \sqrt[3]{x} $')
ax.grid()
fig.legend(facecolor = (0.8, 0.8, 0.8), loc = 'upper right')
np.power() Usage.3¶
이번엔 x1에는 scalar를 넣고 x2에 ndarray를 넣어보자.
exponent_np = np.array([1, 2, 3, 4, 5])
exp_np1 = np.power(2, exponent_np)
exp_np2 = np.power(3, exponent_np)
print("exp_np1:", exp_np1)
print("exp_np2:", exp_np2)
이번엔 $2^{x}, 3^{x}$의 결과를 얻은 것을 알 수 있다.
즉, np.power()를 잘 이용하면 power function 뿐만 아니라 exponent function 까지도 접목시킬 수 있는 것이다.
E = np.e
radian_range = np.linspace(-3, 3, 300)
sinh_np1 = (np.exp(radian_range) - np.exp(-1*radian_range))/2
sinh_np2 = (np.power(E, radian_range) - np.power(E, -1*radian_range))/2 + 0.5
fig, ax = plt.subplots(figsize = (8,4))
ax.plot(radian_range, sinh_np1, label = 'sinh_np1')
ax.plot(radian_range, sinh_np2, label = 'sinh_np2')
ax.grid()
fig.legend(facecolor = (0.8, 0.8, 0.8), loc = 'upper left')
위의 결과에서 알 수 있듯이, 저번 notebook에서 다뤘던 expoenential function까지 np.power()로 만들 수 있는 것이다.
np.power() Usage.4¶
NumPy가 다량의 data를 한 번에 다루는 특징과 위의 배운 내용들을 조합하면 다음과 같이 사용할 수도 있다.
만약 우리가 0부터 9까지의 수들을 차례대로 2, 3, 4, 5, 6제곱을 하고싶다고 가정하자.
그러면 먼저 다음과 같이 x값들을 만들어내고 exponent들의 ndarray를 만들어낼 수 있다.
x_range = np.tile(np.arange(10), (5,1))
exp_np = np.arange(2,7).reshape(-1,1)
print(x_range)
print(exp_np)
위에서 주목할 점은 바로 shape이다. 각각의 shape은 다음과 같다.
print(x_range.shape, exp_np.shape)
눈치 빠른 독자들은 알겠지만, 우리의 똑똑한 NumPy에게 broadcasting을 시킬 예정이다.
exp_mat = np.power(x_range, exp_np)
print("exp_mat:\n", exp_mat)
위와 같이 각각 2,3,4,5,6 제곱들을 한 번에 연산할 수 있기 때문에 "불필요한 for loop"을 제거할 수 있게 된다.
다음 Chapter에서 다루겠지만 이 for loop을 제거하는 것이 곧 컴퓨터 성능을 좌우하기 때문에 vectorization의 관점에서도 위의 예시는 핵심적인 기능을 한다.