구간별 함수 표현방법 (numpy.piecewise) #1

 

정의역의 구간에 따라 서로 각기 다른 함수를 정의해야할 경우

c에서는 function pointer를 사용할 경우 구현할 수 있으나 numpy의 piecewise 함수를 사용해볼 수도 있다.

여기에서는 다음 예제를 통해서

\begin{cases}
2-x & if\enspace x < -1\\x & if\enspace -1 \leq x <1\\(x-1)^2 & if \enspace x\geq1
\end{cases}

일때를 piecewise 함수를 이용해서 구해보고 결과값에 대해서 그래프까지 그려보았다.

 
 
In [1]:
import numpy as np
from matplotlib import pyplot as plt
 

범위는 3개의 구간의 상한과 하한이 -1, 1 이므로 -2.5 부터 2.5까지 1000개의 구간을 나누었다.numpy의 레퍼런스의 예제에서는 lambda함수를 이용하여 각각의 함수를 정의하는 방법이 1 나와 있기 때문에 이를 이용해서 표현해보았다.

In [2]:
x = np.linspace(-2.5, 2.5, 1000)
y=np.piecewise(x, [x < -1, (x >=-1) & (x<1) , x>=1], [ lambda x : (2-x), lambda x : x, lambda x : (x-1)**2])
 

piecewise 를 사용할 경우 일일히 람다로 정의한 함수를 기입할 수도 있으나 함수 리스트를 선언하는 방법도 있다. 이럴 경우 함수들을 좀더 간단하게 표현할 수 있다.2
정의한 결과값은 다음과 같이 그래프로 표현할 수 있다.

In [3]:
f1 = lambda x : (2-x)
f2 = lambda x : x
f3 = lambda x : (x-1)**2
function_list = [f1,f2,f3]
y=np.piecewise(x, [x < -1, (x >-1) & (x<1) , x>=1], function_list)
plt.plot (x, y)
Out[3]:
[<matplotlib.lines.Line2D at 0x47805b0>]
 
 

piecewise는 구간에 대응하는 여러 함수에 대해서 하나의 명령어로 간단하게 표현할 수 있지만 구간과 구간의 경계값이 불연속일 경우 제대로 표현되지 않는 문제점이 있다. 일단 경계 지점에서의 불연속점을 표현해보자면 plot의 argument에 marker를 정의해서 불연속점을 별도로 나타낼 수있다.

plot의 marker의 경우 ‘o’ 를 선택하면 채워진 원이 그려지지만 비어있는 점을 그리려면 facecolor를 ‘none’으로 설정한다.
위의 예에서 불연속 점은 -1, 1이므로 이를 표시해준다면.

In [4]:
plt.plot (x,y)
plt.plot (-1,f1(-1),'k', marker='o', markerfacecolor='none')
plt.plot ( -1,f2(-1),'k', marker='o')
plt.plot (1,f2(1),'k', marker='o', markerfacecolor='none')
plt.plot ( 1,f3(1),'k', marker='o')
Out[4]:
[<matplotlib.lines.Line2D at 0xa095bd0>]
 
 

위에서의 그래프로 표현할 경우 불연속 점 사이의 값에 대해서 임의로 선을 그려주는 문제점이 여전히 발생한다.
그리고 정의역은 linspace로 생성한 임의의 샘플들로 이루어져 있기 때문에 함수 y의 값에는 경계값에 대한 y가 포함될수도 있고 안될수도 있다.따라서 그래프에서 불연속값을 표현하려면 각 구간별 그래프를 별도로 그려줄 수밖에 없다.
다음과 같이 x에 대해서 범위에 따라서 각각의 x,y에 대한 sub set을 생성하고 그래프를 그려보았다.

In [5]:
range1 = ( x < -1 )
sub_x1 = x[ range1 ]
sub_y1 = y [ np.where (range1)]
range2 = (x >-1) & (x<1)
sub_x2 = x[ range2 ]
sub_y2 = y [ np.where (range2)]
range3 = ( x>=1 )
sub_x3 = x[ range3 ]
sub_y3 = y [ np.where (range3)]
In [6]:
plt.plot (sub_x1,sub_y1)
plt.plot (sub_x2,sub_y2)
plt.plot (sub_x3,sub_y3)
plt.plot (-1,f1(-1),'k', marker='o', markerfacecolor='none')
plt.plot ( -1,f2(-1),'k', marker='o')
plt.plot (1,f2(1),'k', marker='o', markerfacecolor='none')
plt.plot ( 1,f3(1),'k', marker='o')
plt.grid (True)
 
 

그래프는 깔끔하게 그려졌지만 각각 나누어서 별도로 처리한 것이므로 piecewise함수를 굳이 사용할 필요가 없는 상황이 되었다?!

sub_y1 = y [ np.where (range1)]

구문을

sub_y1 = f1 (range1)

으로만 해준 다음에 각각의 sub_y를 concatenate 구문으로 붙이면 되는 일이긴하다. 결국 piecewise함수는 각 구간에 대해서 분석/가공이 필요하다면 곧바로 적용하기에는 별로 영양가가 없어보인다.

 
 
 

Reference

  1. https://numpy.org/doc/stable/reference/generated/numpy.piecewise.html

  2. https://stackoverflow.com/questions/18972433/how-to-specify-a-range-in-numpy-piecewise-2-conditions-per-range

 
 
In [ ]:
 

WordPress conversion from piecewise_20210102.ipynb by nb2wp v0.3.1

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤