나만의 SymPy 튜토리얼

SymPy 튜토리얼

구글 서치 결과를 보니, 이 문서로 유입되는 트래픽이 좀 있는 것 같아서 업데이트 함. 앞으로도 계속 업데이트 예정.

SymPy 설치

설치과정은 다음의 링크로 대체한다.

SymPy 공식 설치 안내 링크 : https://docs.sympy.org/latest/install.html#installation

R에서 python 사용을 위한 패키지 불러오기

library(reticulate)
use_virtualenv("r-reticulate")

변수 정의하기

Sympy에서 변수를 설정한다는 것은 앞으로 이것들을 변수로 보고, 적분을 한다던지, 미분을 한다던지 하겠다는 것이다.

x, yz를 변수로 선언해보도록 하자.

from sympy import *
x, y, z = symbols('x y z')

사칙 연산 그리고, 제곱과 제곱근

다음과 같이 정의된 변수에 다음과 같이 사칙 연산이 가능하다. Sympy는 문자를 계산하는 프로그램이므로 아래와 같이 사칙 연산을 입력하면, 입력한 식 자체를 하나의 식을 받아들이는 것이다. 예를 들어, 우리가 방정식

\[ x^2 = 2 \] 풀고 싶다고 하면, 제곱을 어떻게 Sympy에서 입력하는 지를 알아야 하겠다. 따라서 아래의 코드들은 앞으로 식을 입력할 때 어떤 식으로 입력할 수 있는지 알아두는 것이라고 생각하면 됨.

  • 사칙연산
x + y
## x + y
x - y
## x - y
x * y
## x*y
x / y
## x/y
  • 제곱과 제곱근
x ** y
## x**y
sqrt(x)
## sqrt(x)
  • 지수함수
exp(x)
## exp(x)
  • 삼각함수
sin(x)
## sin(x)
cos(y)
## cos(y)
tan(x)
## tan(x)

식 입력하기

위에서 배운 식 입력방법을 사용하여, expr이라는 변수에 식 자체를 입력할 수 있다. 다음은 \[ x (x + y) \] 라는 식을 변수 expr에 저장하는 방법이다.

expr = x * (x + y)
expr
## x*(x + y)

식 전개하기

위에서 입력한 식을 전개해보자. \[ x (x + y) = x^2 + xy \] 이것을 Sympy에서는 expand를 써서 할 수 있음.

expr = expand(expr)
expr
## x**2 + x*y

잘 전개되는 것을 확인할 수 있다. 위의 식을 좀 더 복잡하게 만들기 위해서 \((x + y)\)를 곱해주도록 하자.

expr = expr * (z + y)
expr = expand(expr)
expr
## x**2*y + x**2*z + x*y**2 + x*y*z

묶어내기

위에서 복잡하게 만든 식

\(x^{2} y + x^{2} z + x y^{2} + x y z\)

\(y\)로 묶어내는 방법은 다음과 같이 collect 명령어를 사용하는 것이다.

collect(expr, y)
## x**2*z + x*y**2 + y*(x**2 + x*z)

결과는 y의 0승, 1승, 2승 항들로 묶여나오는 것을 볼 수 있다.

\(x^{2} z + x y^{2} + y \left(x^{2} + x z\right)\)

인수분해

위에서 복잡하게 만든 식

\(x^{2} y + x^{2} z + x y^{2} + x y z\)

을 곱셈 꼴로 나타내기 위해서는 factor 명령어를 사용한다.

factor(expr)
## x*(x + y)*(y + z)

간단하게 만들기 simplify

주어진 식을 간단한 꼴로 나타내고 싶을 때, simplify를 먼저 시도해보자. 하지만 이게 잘 안 될 경우, factor 혹은 trigsimp (삼각함수 전용) 시도할 것.

  • 예제 1

\(x^{2} y + x^{2} z + x y^{2} + x y z\)

을 간단하게 만들기

simplify(expr)
## x*(x*y + x*z + y**2 + y*z)
  • 예제 2. 삼각함수 공식들

\(\sin^{2}{\left(x \right)} + \cos^{2}{\left(x \right)}\) 를 간단히 나타내면 우리는 1이 된다는 것을 알고 있다. 이것도 Sympy는 다 해준다.

simplify(sin(x)**2 +cos(x)**2)
## 1

심지어 다음과 같은 아이들도 된다.

\[ \frac{sin(x)}{cos(x)} = tan(x) \]

simplify(sin(x)/cos(x))
## tan(x)

\[ 2 sin(x) cos(x) = sin (2x) \]

simplify(2*sin(x)*cos(x))
## sin(2*x)

미분, 적분

미적분을 다루기 위해서 식을 한층 업그레이드 시키자.

expr = (expr * sin(x)) * x
expr
## x*(x**2*y + x**2*z + x*y**2 + x*y*z)*sin(x)

현재 expr에 들어있는 식을 수식으로 써보면 다음과 같다.

\(x \left(x^{2} y + x^{2} z + x y^{2} + x y z\right) \sin{\left(x \right)}\)

딱 봐도 너무 짜증남. 위 식을 \(x\)에 대하여 미분해보자.

diff(expr, x)
## x*(2*x*y + 2*x*z + y**2 + y*z)*sin(x) + x*(x**2*y + x**2*z + x*y**2 + x*y*z)*cos(x) + (x**2*y + x**2*z + x*y**2 + x*y*z)*sin(x)

대박. 너무 좋음. 그렇다면 적분은..?

integrate(expr, x)
## -x**3*y*cos(x) - x**3*z*cos(x) - x**2*y**2*cos(x) - x**2*y*z*cos(x) + 3*x**2*y*sin(x) + 3*x**2*z*sin(x) + 2*x*y**2*sin(x) + 2*x*y*z*sin(x) + 6*x*y*cos(x) + 6*x*z*cos(x) + 2*y**2*cos(x) + 2*y*z*cos(x) - 6*y*sin(x) - 6*z*sin(x)

아마 손으로는 못 풀었을듯. 풀다가 포기함. 인내심 한계 올 듯 ㄷㄷ. 손으로 풀었다고 생각해보자.. 상상만 해도 너무 신난다..

극한

우리의 갓파이는 극한도 계산이 된다.

\[ \underset{x\rightarrow 0}{lim} \frac{sin(x)}{x} = 1 \]

limit(sin(x) / x, x, 0)
## 1

방정식 풀기

위의 식을 풀기 위해서는 식을 정리해서 오른쪽을 0으로 만들어야한다. 예를들어,

\[ x^2 = 2 \] 를 풀기 위해서는

\[ x^2 - 2 = 0 \] 꼴로 만든 후 다음과 같이 입력하자.

solve(x**2 - 2, x)
## [-sqrt(2), sqrt(2)]

행렬

행렬의 연산을 알아보자.

  • 단위 행렬
eye(3)
## Matrix([
## [1, 0, 0],
## [0, 1, 0],
## [0, 0, 1]])
  • 사용자 정의 행렬

행렬을 정의할 때, 행을 기준으로 []를 사용해서 묶어주고, 행렬 전체를 []로 다시 묶어준다고 생각하면 쉬움.

A = Matrix([[ 1, -2, 3],
            [-2,  2, 1],
            [ 3,  1, 4]])
A
## Matrix([
## [ 1, -2, 3],
## [-2,  2, 1],
## [ 3,  1, 4]])
  • 벡터 정의 3 by 1

3 행 1 열의 행렬 정의는 다음과 같다.

B = Matrix([[x],
            [y],
            [z]])
B
## Matrix([
## [x],
## [y],
## [z]])
  • 벡터 정의 1 by 3

반대로 1행 3열의 행렬 정의는 다음과 같다.

B = Matrix([[ x, y, z]])
B
## Matrix([[x, y, z]])
  • 전치행렬

전치행렬을 사용해서 행렬을 만들어보자.

B = B.T * B
B
## Matrix([
## [x**2,  x*y,  x*z],
## [ x*y, y**2,  y*z],
## [ x*z,  y*z, z**2]])
  • 행렬 덧셈
A + B
## Matrix([
## [x**2 + 1,  x*y - 2,  x*z + 3],
## [ x*y - 2, y**2 + 2,  y*z + 1],
## [ x*z + 3,  y*z + 1, z**2 + 4]])
  • 행렬 곱
A * B
## Matrix([
## [ x**2 - 2*x*y + 3*x*z,  x*y - 2*y**2 + 3*y*z,  x*z - 2*y*z + 3*z**2],
## [-2*x**2 + 2*x*y + x*z, -2*x*y + 2*y**2 + y*z, -2*x*z + 2*y*z + z**2],
## [ 3*x**2 + x*y + 4*x*z,  3*x*y + y**2 + 4*y*z,  3*x*z + y*z + 4*z**2]])

다음과 같이 행렬을 하나 정의하자.

D = Matrix([[1, 2],
            [3, 2]])
D  
## Matrix([
## [1, 2],
## [3, 2]])
  • 행렬식 (Determinant)
D.det()
## -4
  • 행렬의 고유값과 고유벡터 Eigenvalues & Eigenvector
D.eigenvals()
## {4: 1, -1: 1}

즉, 고유값은 4와 -1이고, 뒤에 붙은 1은 algebraic multiplicity를 의미한다.

eigenvects 명령어를 쓰면 고유값에 고유벡터까지 딸려서 나옴.

D.eigenvects()
## [(-1, 1, [Matrix([
## [-1],
## [ 1]])]), (4, 1, [Matrix([
## [2/3],
## [  1]])])]

결과값은 다음과 같이 예쁘게 쓸 수 있다.

\(\left[ \left( -1, \ 1, \ \left[ \left[\begin{matrix}-1\\1\end{matrix}\right]\right]\right), \ \left( 4, \ 1, \ \left[ \left[\begin{matrix}\frac{2}{3}\\1\end{matrix}\right]\right]\right)\right]\)

  • 사다리꼴 행렬 (Reduced Row Echelon Form matrix)

대학시절 선대 들으면서 중간고사때 7 by 7 행렬의 사다리꼴 행렬을 울면서 계산했던 기억이 있다…

D.rref()
## (Matrix([
## [1, 0],
## [0, 1]]), (0, 1))

첫번째가 사다리꼴 행렬 변환 결과값이고, 두번째 결과값은 피봇열을 의미한다.

\(\left( \left[\begin{matrix}1 & 0\\0 & 1\end{matrix}\right], \ \left( 0, \ 1\right)\right)\)

결과 Latex으로 표시

latex(Integral(sin(x) + cos(y), x))
## '\\int \\left(\\sin{\\left(x \\right)} + \\cos{\\left(y \\right)}\\right)\\, dx'

Latex 결과 R markdown으로 보내기

chunk option을 다음과 같이 설정함.

 echo=TRUE, results='asis', fig.align ='center'
print('$' + latex(Integral(sin(x) + cos(y), x)) + '$')

\(\int \left(\sin{\left(x \right)} + \cos{\left(y \right)}\right)\, dx\)

Avatar
이삭
PhD candidate

I believe anyone can learn anything with a proper education process.

comments powered by Disqus
Next
Previous