Skip to content

Latest commit

 

History

History
504 lines (407 loc) · 26.1 KB

05_Differentiation.md

File metadata and controls

504 lines (407 loc) · 26.1 KB

데이터분석과 미분

1. 데이터분석에서의 미분의 의미

예측모형의 성능과 미분

  • 데이터분석의 목표는 어떤 데이터의 예측을 위한 최적의 예측 모형을 찾는 것이다. 최적의 예측 모형은 모수를 잘 선택하여 모형의 성능을 높이는 , 즉 최적화하는 과정과 같다.
  • 예를들어 어떤 데이터에 대한 선형예측모형의 예측값은 가중치 w와 데이터의 변수 x의 선형조합으로 만들어진다.
  • 이 때에 가중치 w가 모수(=계수)가 되며 모수를 어떤 것을 선택하느냐에 따라서 모형의 성능이 달라지게 된다. 모형의 성능은 크기를 비교하기 위한 값이므로 스칼라가 되어야 한다.
  • 모수 선택에서 모형의 성능 측정까지의 과정은 다변수함수를 계산하는 과정과 같다. 이렇듯 예측모형의 성능을 높이기 위한 함수를 성능함수 performance function 라고 한다. 성능함수의 값은 클 수록 좋다.
  • 반대로 모형의 성능값이 아닌 모형의 예측값과 목표값을 비교하여 얼마나 차이가 있는지 오류를 따져 이 오류를 작게하는 함수로 손실함수 loss function, 비용함수 cost function, 오류함수 error functiion 이 있다.
  • 이렇듯 최적화의 대상이 되는 함수들, 성능함수, 손실함수, 비용함수, 오류함수를 목적함수라고 한다. 목적함수를 선택한 후에는 모수를 조절함으로써 목적함수를 크게 또는 작게할 수 있다.
  • 목적함수는 모수 w 를 입력받아 성능 또는 손실 값을 출력해주며, 입력변수 인 w를 조정하면 출력값도 변하게 된다. 입력변수의 변화에 따라 출력값의 변화하는 비율을 보여주는 것을 미분 diffrentiation이라고 한다.
  • 즉 데이터 분석에서의 미분의 의미는, 최적의 예측모형을 판단하는 기준으로 모형의 성능을 높이기위하여 적절한 목적함수를 가지고 입력변수로 가중치 w를 받아 조절함으로써 이와 함께 변하는 성능(손실)인 출력값과의 변화 비율을 나타내는 일종의 신호와 같다.

분석할 데이터 -> 목적함수 선택 -> 입력변수 가중치 w 조절 -> 변화하는 출력값 -> 미분 적용 -> 모수 w의 변화와 성능(손실) 출력값의 변화에 대한 변화율 확인 -> 모형의 성능 확인 -> 성능이 좋은 것 또는 오류가 작은 모형 선택 -> 최적의 예측 모형 도출

  • 이러한 과정을 최적화 optimization 이라고 한다.

PCA principle component analysis 에서의 최적화와 미분

  • 주성분 분석 즉 PCA 의 최적화 과정을 떠올려보면, 원래 행렬과 역변환 행렬을 사용하여 만든 행렬의 차를 가장 작게 하는 문제가 되었다.
  • 최적화의 대상이 된 목적함수를 최소화하기 위한 차원축소 벡터 를 찾는 문제였다. 이를 위해 목적함수를 미분하여 얻은 값이 영벡터가 되는 값 즉 역변환 행렬과 변환 행렬의 관계를 푸는 문제가 되었다.
  • 처음의 최적화 식에 위의 값을 대입하고 모든 벡터에 대해 적용하면, 최적의 변환 행렬 W 를 찾는 문제인 랭크-k 근사 문제가 되며, W 는 가장 큰 k 번쨰까지의 특잇값에 해당하는 오른쪽특이벡터임을 알 수 있었다.
  • 즉 PCA 과정에서 사용된 목적함수와 미분은, 모수의 변화에 대한 예측모형의 성능값의 변화율을 확인하여 최적의 모형을 만드는 모수 W를 찾는 역할을 했다는 것을 알 수 있다.

2. 미분

기울기 slope

  • 기울기 : 어떤 함수관계에서의 입력변수 x의 변화에 따른 출력변수 y값의 변화율 정보, 민감도 sensitivity 라고도 한다.
    • 고장난 라디오의 음량 조절나사의 각도를 x라고 할때 출력되는 음량값을 y라고 할 수 있다. 일상적으로 조절나사를 좌우로 잘 돌리다보면, 어떤 지점에서 소리가 커지는지 경험적으로 파악할 수 있다.
    • 음량이 최대가 되는 조절나사의 각도를 찾는 문제는 변수 x에 대한 최적화문제라고 할 수 있다.
  • 수치적 최적화는 가장 적은 방법을 시도하여 가장 큰 음량일 때의 최적의 x를 찾는 것을 의미한다. 가장 적은 횟수로 최적의 x를 찾으려면 다음과 같은 정보를 따라야한다.
    • x1의 위치에서 각도를 증가시켰을 때 음량 y가 커졌다면, 다음 시도인 x2는 x1보다 큰 값이어야 가장 큰 y값에 다가간다.
    • x1의 위치에서 각도를 증가시켰을 때 음량 y가 작아졌다면, 다음 시도인 x2는 x1보다 작은 값이어야 가장 큰 y값에 다가간다.
  • 즉 기울기는 음량이 가장 큰 y값을 찾기 위해 조절나사의 각도 x를 x1, x2, x3, ... 최소한의 횟수로 변화시키려고 할 때, x1의 다음값을 어떻게 설정하면 좋을지에 대한 정보를 제공해준다.

그래프에서의 기울기

  • 입력변수 x의 변화(x2-x)에 대한 출력변수의 변화(f(x2)-f(x))의 비율
  • 그래프에서의 기울기는 x의 변화량인 가 0으로 근접해 갈 때의 변화율이다.
  • 한 점에서의 접선의 기울기는 x의 변화량에 따라 달라질 수 있다. x2, x3, x4 과의 tangent 값이 달라지기 때문이다. 따라서 기울기를 통일해 주기 위해, x의 변화량을 무한대로 0에 가깝게 만드는 방식을 사용.

수치미분

  • 기울기를 정확하게 구할 수 있는 방법
  • scipy.misc 패키지의 derivative() 명령어를 사용하면 기울기를 구할 수 있다. 정확한 값은 아니다.
  • 인수로 함수 f, 좌표 x, 이동할 거리 dx 가 사용된다. dx는 작을 수록 좋지만, 너무 작으면 부동소수점 연산의 오버플로우 오류가 발생하여 역으로 오차가 증폭할 수 있으므로 주의해야한다.
    • 부동소수점 연산의 오버플로우 : 정수는 이진법으로 표현 가능하지만, 소수는 어렵다. 소수는 원래 무한대의 수이다. 파이썬은 소수를 17 자리까지만 나타내준다. 모든 수는 이러한 오차가 있다고 봐야한다.

미분 differentiation

  • 미분 : 어떤 함수로부터 그 함수의 기울기를 출력하는 새로운 함수를 만드는 작업이다. 미분은 동사이다.
    • 새로운 함수 = 기울기 출력 함수
  • 미분의 표기법

미분 가능

  • 모든 함수가 미분 가능한 것은 아니다. 어떤 경우는 미분을 할 수 없는 경우도 있다.
  • 미분을 할 수 없는 경우는 미분 불가능 이라고 하고, 미분이 가능한 경우는 미분 가능 이라고 한다.
    • ReLU 함수에서 x=0 인 경우는 미분 불가능에 해당한다.
    • x >0 이면 기울기는 0 이지만, x < 0 이면 기울기가 1 이다. x = 0 인 경우는 기울기를 구할 수 없다.

미분공식

  • 몇 가지 미분공식을 조합하여 복잡한 함수의 도함수를 구할 수 있다.

    • 기본미분공식

    상수미분, 거듭제곱미분, 지수미분, 로그미분

    • 선형조합법칙, 곱셈법칙, 연쇄법칙
  • 기본미분공식

    • 상수미분 : 상수를 미분하면 0 이 된다. (기울기 0의 의미)
    • 거듭제곱미분 : n 제곱이 n-1 제곱이 되고, n 은 지수와 곱해진다.
    • 로그미분 : 로그를 미분하면 지수가 역수로 변환된다.
    • 지수미분 : 밑이 오일러인 지수를 미분해도 변하지 않는다.
  • 선형조합법칙

    • 어떤 함수에 상수를 곱한 함수를 미분하면, 도함수에 상수를 곱한 것과 같다.
    • 두 함수를 더한 함수를 미분하면, 각 도함수를 합한 것과 같다.
  • 곱셈법칙

    • 두 함수를 곱한 함수의 미분은 각 개별 함수의 도함수를 사용하여 원래 함수의 도함수를 구한다.
  • 연쇄법칙 chain rule

  • 미분하고자 하는 함수의 입력변수가 다른함수의 출력변수인 경우에 적용할 수 있다.

  • 함수가 복잡할 경우에는 f, h, g, y 등의 중간변수를 만들고 함수의 관계에 따라서 구분지은 후 연쇄법칙을 적용한다.



2차 도함수 second derivative

  • 도함수의 기울기
  • 도함수를 미분하여 만든 도함수를 말한다. 함수 f의 기울기 출력함수인 도함수를 다시 미분하여 도함수의 기울기를 출력해주는 함수이다.
  • 함수, 도함수, 2차 도함수의 관계 (오목과 볼록의 기준은 아래에서 올려다본 시점, 오목은 봉우리, 볼록은 계곡)
    • 함수가 오목 concave -> 도함수값 감소 -> 2차 도함수값 음수
    • 함수가 볼록 convex -> 도함수값 증가 -> 2차 도함수값 양수
    • 2차 도함수값을 볼록도 convexity 라고도 부른다.

편미분 partial differentiation

  • 다변수 함수의 미분
  • 다변수이기때문에 변수 각각에 대해서 따로 미분이 가능하다. 따라서 하나의 함수에서 여러개의 도함수가 나올 수 있다.
  • 어떤 하나의 독립변수에 대해 미분을 할 때는 다른 독립변수를 상수 처럼 취급하여 계산한다.

    ,

다변수함수의 연쇄법칙

  • 다변수함수가 연결 되어 있을때에도 연결법칙을 사용하여 미분할 수 있다.
  • N개의 함수 f1, f2, ..., fN 가 입력변수 x를 가질때 출력변수 y1, y2, ..., yN 라고 한다. yN 을 입력받는 함수 g와 출력 z라고 한다. 이때 변수 x값의 변환에 따른 z의 값의 변화
    • 편미분미분 + 편미분미분 + ... 의 형태이다.
  • N개의 함수 f1, f2, ..., fN이 x1, x2, ..., xM 개의 입력변수를 갖는 다변수함수라고 할 때, 변수 x1값의 변화에 따른 z의 변화
    • 편미분편미분 + 편미분편미분 + ... 의 형태이다. 변수 x2, x3, ..., xM 에 대해서도 똑같이 적용된다.

2차 편미분

  • 편미분에 대한 2차 도함수. 즉 다변수 함수의 도함수의 도함수.
  • 2차 편미분 방법은 1차 편미분을 하고, 그 결과를 가지고 다시 편미분을 한다. 이 과정에서 여러개의 변수 중 어떤 것을 선택할지는 자유롭게 정할 수 있다.
  • 순서데로 선택한 변수를 아래첨자를 써서 표기한다.
    • (순서 바뀜)
    • (순서 바뀜)
  • 슈와르츠 정리
  • 연속 함수이고, 미분 가능한 함수인 경우 미분의 순서가 바뀌어도 결과는 같다.
  • 변수가 여러개이고 동시에 함수들이 서로 연결되어 있는 경우는 1차, 2차 편미분 과정에서 연쇄법칙과 곱셈법칙이 여러번 사용될 수 있다.

심파이 SymPy

  • 심파이는 심볼릭연산 symbolic operation 을 지원하는 파이썬의 패키지이다. 심볼릭 연산은 사람이 손으로 미분을 계산하는 것과 같은 방식으로 연산하는 기능을 말한다.
  • 일반적으로 파이썬에서 연산을 하려면 변수 x 에 값을 저장하여 변수선언을 해주어야 한다. 그러나 심볼릭 연산은 변수선언 없이도 x 를 심볼화하여 숫자계산 뿐만 복잡한 미분과 적분의 연산도 처리해준다.
  • 딥러닝 deep learning 등에서 사용되는 텐서플로 패키지나 파이토치 패키지에서도 심볼릭 연산을 지원한다.
  • 데이터 분석에서는 심파이를 사용하여 미분, 적분을 한다. 손으로 계산하는 경우는 특별히 어떤 공식을 유도할 때만 한다.

접선의 방정식

  • 단변수 함수 f(x)위의 한 점을 지나는 접선의 방정식

Python

1) 그래프로 나타낸 함수의 기울기

def f(x) :
    return x ** 3 - 3 * x ** 2 + x

x = np.linspace(-1, 3, 400)
y = f(x)

plt.plot(x, y)
plt.plot(0, 0, 'ro')
plt.plot(x, x, 'r:')
plt.plot(1, -1, 'go')
plt.plot(x, (3*1**2-6*1+1)*(x-1)-1, 'g--')

plt.xlim(-3.5, 5.5)
plt.ylim(-4, 2)
plt.xticks(np.arange(-3, 6))
plt.yticks(np.arange(-4, 2))

# 주석 설정 : xy 는 주석의, xytext 는 주석의 끝점, arrowprops 는 화살표의 속성
plt.annotate('', xy=(1, 0), xytext=(0, 0), arrowprops=dict(facecolor='gray'))
plt.annotate('', xy=(1, 1), xytext=(1, 0), arrowprops=dict(facecolor='gray'))

plt.annotate('', xy=(2, -1), xytext=(1, -1), arrowprops=dict(facecolor='gray'))
plt.annotate('', xy=(2, -3), xytext=(2, -1), arrowprops=dict(facecolor='gray'))

plt.xlabel('x')
plt.ylabel('f(x)')
plt.title('함수의 기울기')
plt.show()

slope.png

2) 수치미분

  • 함수의 기울기를 구해준다.
from scipy.misc import derivative

def f(x) :
    return x ** 3 - 3 * x ** 2 + x

x = [-.5, 0, 0.5, 1, 1.5, 2, 2.5]
f_derivative = []

for i in range(7) :
    print("x={} 의 기울기 slope={}".format(x[i], derivative(f, x[i], dx=1e-5)))
    f_derivative.append(derivative(f, x[i], dx=1e-5))

plt.plot(x, f_derivative)
plt.axhline(0, c='k', ls='--', linewidth=0.7)
plt.axvline(0, c='k', ls='--', linewidth=0.7)

for j in range(7) :
    plt.plot(x[j], f_derivative[j], 'ro', ms=3, label='x={} → {:.0f}'.format(x[j], f_derivative[j]))

plt.title('함수 $x^3 - 3x^2 + x$의 도함수 그래프', y=1.04)
plt.legend(fontsize=8)
plt.show()

=====print=====

x=-0.5 의 기울기 slope=4.750000000097732
x=0 의 기울기 slope=1.0000000000999998
x=0.5 의 기울기 slope=-1.2499999998943911
x=1 의 기울기 slope=-1.9999999998965288
x=1.5 의 기울기 slope=-1.24999999986386
x=2 의 기울기 slope=1.000000000139778
x=2.5 의 기울기 slope=4.7500000000422204

derivative.png

3) 미분가능

  • 미분 할 수 없는 경우는 미분 불가능
  • 미불 할 수 있는 경우는 미분 가능
def relu(x) :
    return np.where(x > 0, x, 0)

xx = np.linspace(-2, 2, 100)

plt.plot(xx, relu(xx))
plt.plot(0, 0, 'go', ms=10)
plt.text(0.2, 0.1, '렐루 함수는 x=0 에서 미분 불가능', fontsize=8)
plt.title('ReLU')
plt.xlabel('x')
plt.ylabel('y')
plt.show()

relu_non_diff.png

4) 함수와 도함수

  • 도함수는 함수의 기울기를 출력해주는 함수이다.
  • 미분이라는 작업, 행위를 통해서 만들어진다.
def f(x) :
    return x ** 3 - 3 * x ** 2 + x

def fprime(x) :
    return 3 * x ** 2 - 6 * x + 1

# 2차 방정식의 근 : 도함수의 근
# np.roots([n, n-1, n-2, ..., 0]) : 명령어의 인수는 제곱수의 순서대로 상수항의 값을 입력한다. 없는 제곱수는 0으로 입력해야한다.
x1, x2 = np.roots([3, -6, 1])
x_1, x_2, x_3 = np.roots([1, -3, 1, 0])

x = np.linspace(-1, 3, 400)

plt.figure(figsize=(10, 7))
plt.subplot(211)
plt.plot(x, f(x))
# 3차 함수의 근의 표시
plt.plot(x_1, 0, 'ro', ms=4)
plt.plot(x_2, 0, 'ro', ms=4)
plt.plot(x_3, 0, 'ro', ms=4)
plt.xlim(-2, 4)
plt.xticks(np.arange(-1, 4))
plt.yticks(np.arange(-5, 4))
plt.xlabel('x')
plt.title('함수 f(x)', y=1.06)
# 3차 함수의 최고점과 최저점은 도함수의 근과 같다.
plt.axvline(x1, c='b', ls='--')
plt.axvline(x2, c='b', ls='--')

plt.subplot(212)
plt.plot(x, fprime(x))
plt.xlim(-2, 4)
# 2차 함수의 근의 표시
plt.plot(x1, 0, 'go', ms=4)
plt.plot(x2, 0, 'go', ms=4)
plt.xticks(np.arange(-1, 4))
plt.yticks(np.arange(-3, 11))
plt.xlabel('x')
plt.ylabel('도함수 $f^{\prime}(x)$')
plt.axhline(0, c='r', ls='--')
plt.axvline(x1, c='b', ls='--')
plt.axvline(x2, c='b', ls='--')

plt.tight_layout()
plt.show()

derivative_second_derivative.png

제곱근 명령어

  • 상수항을 순서대로 인수로 입력 : np.roots([a, b, c, d, e])
  • 0이어도 입력해줘야 함수가 몇 차인지 인식한다.
x1, x2 = np.roots([2, 4, 1])
x1, x2

=====print=====

(-1.7071067811865475, -0.2928932188134525)
x_1, x_2, x_3 = np.roots([1, -3, 1, 0])
x_1, x_2, x_3

=====print======

(2.618033988749895, 0.38196601125010515, 0.0)

5) 함수와 도함수, 2차 도함수

def f(x) :
    return x ** 3 - 3 * x ** 2 + x

def fprime(x) :
    return 3 * x ** 2 - 6 * x + 1

def fprime2(x) :
    return 6 * x - 6

# fprime(x) 의 근
x1, x2 = np.roots([3, -6, 1])

x = np.linspace(-1, 3, 400)

plt.figure(figsize=(10, 10))

plt.subplot(311)
plt.plot(x, f(x))
plt.plot()
plt.xlim(-2, 4)
plt.xticks(np.arange(-1, 4))
plt.yticks(np.arange(-5, 4))
plt.title('함수 f(x)')
plt.xlabel('x')
plt.axvline(x1, c='b', ls='--')
plt.axvline(x2, c='b', ls='--')
plt.axvline(1, c='g', ls=':')

plt.subplot(312)
plt.plot(x, fprime(x))
plt.xlim(-2, 4)
plt.xticks(np.arange(-1, 4))
plt.yticks(np.arange(-3, 11))
plt.title('함수 $f^{\prime}(x)$')
plt.xlabel('x')
plt.axhline(0, c='r', ls='--')
plt.axvline(x1, c='r', ls='--')
plt.axvline(x2, c='r', ls='--')
plt.axvline(1, c='g', ls=':')


plt.subplot(313)
plt.plot(x, fprime2(x))
plt.xlim(-2, 4)
plt.xticks(np.arange(-1, 4))
plt.title('2차 도함수 $f^{\prime\prime}(x)$')
plt.axhline(0, c='r', ls='--')
plt.axvline(1, c='g', ls=':')

plt.tight_layout()
plt.show()

derivative_second_derivative_2.png

6) SymPy 와 미분

  • SymPy 는 심볼릭 연산 symbolic operation 을 지원하는 파이썬 패키지이다.
  • 심볼릭 연산이란 연필로 계산을 하는 것과 같은 방식의 미분/적분을 말한다.
  • 딥러닝 등에 많이 사용되는 파이썬의 텐서플로 패키지나 파이토치 패키지도 심볼릭 연산 기능을 갖추고 있다.
import sympy

# 쥬피터 노트북에서 수학식의 LaTeX 의 표션을 위해 필요한 설정
sympy.init_printing(use_latex='mathjax')

# x 를 심볼로 정의
x = sympy.symbols('x')
x

=====print=====

# 심볼 x 로 함수를 정의
f = x * sympy.exp(x)
f

=====print=====

# diff() 명령어로 미분
sympy.diff(f)

=====print=====

# simplify() 명령어는 함수를 소인수 분해하여 정리해준다.
sympy.simplify(sympy.diff(f))

=====print=====

7) 편미분

  • diff() 명령어의 인수로 미분할 변수를 넣어준다.
# 심볼 설정
x, y = sympy.symbols('x y')

# 함수 설정
f = x ** 2 + 4 * x * y + 4 * y ** 2

# 변수 x 로 편미분
f_partial_diff_x = sympy.diff(f, x)
f_partial_diff_x 

=====print=====

# 변수 y 로 편미분
f_partial_diff_y = sympy.diff(f, y)
f_partial_diff_y

=====print=====

상수 역할을 하는 심볼을 포함하는 함수의 미분

  • 심파이가 상수 심볼과 변수 심볼을 구분하지 못하기 때문에 편미분의 방식처럼 diff() 명령어의 인수로 미분할 변수를 지정해 주어야 한다.
# 심볼 설정
x, mu, sigma = sympy.symbols('x, mu, sigma')

# 함수 설정
f = sympy.exp((x-mu) ** 2/ sigma ** 2)

# x 변수로 미분
sympy.diff(f, x)

=====print=====

8) SymPy 로 미분 문제 풀어보기

x = sympy.symbols('x')
f = x ** 3 - 1
f_diff = sympy.diff(f, x)
f_diff_diff = sympy.diff(f, x, x)

f, f_diff, f_diff_diff

=====print=====

problem_1.PNG

x, k = sympy.symbols('x k')
f = sympy.log(x ** 2 - 3 * k)

f_diff = sympy.diff(f, x)
f_diff_diff = sympy.diff(f, x, x)

f, f_diff, f_diff_diff

=====print=====

problem_2.PNG

x, a, b = sympy.symbols('x, a, b')
f = sympy.exp(a * (x ** b))

f_diff = sympy.simplify(sympy.diff(f, x))
f_diff_diff = sympy.simplify(sympy.diff(f, x, x))

f, f_diff, f_diff_diff

=====print=====

problem_3.PNG

x, y = sympy.symbols('x, y')
f = sympy.exp(x ** 2 + 2 * y ** 2)

f_diff_x = sympy.diff(f, x)
f_diff_y = sympy.diff(x, y)
f_diff_x_x = sympy.diff(f, x, x)
f_diff_x_y = sympy.diff(f, x, y)
f_diff_y_y = sympy.diff(f, y, y)
f_diff_y_x = sympy.diff(f, y, x)

f_diff_x, f_diff_y, f_diff_x_x, f_diff_x_y, f_diff_y_y, f_diff_y_x

=====print=====

problem_4.PNG