<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>yeongdev</title>
    <link>https://seo0west0.tistory.com/</link>
    <description>개발 기록 </description>
    <language>ko</language>
    <pubDate>Wed, 3 Jun 2026 00:42:09 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>seooeyeong</managingEditor>
    <image>
      <title>yeongdev</title>
      <url>https://tistory1.daumcdn.net/tistory/5417136/attach/abbe36b7fe4d4d05af9da905b502de89</url>
      <link>https://seo0west0.tistory.com</link>
    </image>
    <item>
      <title>PCA란 무엇인가 | 공분산 행렬과 고유벡터로 이해하는 차원 축소</title>
      <link>https://seo0west0.tistory.com/99</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;PCA(Principal Component Analysis)는 데이터를 더 적은 차원으로 압축하면서도, 원래 데이터의 중요한 정보를 최대한 유지하려는 차원 축소 기법이다. 핵심은 단순히 컬럼 개수를 줄이는 것이 아니라, &lt;b&gt;데이터가 가장 많이 퍼져 있는 방향을 새로운 축으로 다시 표현하는 것&lt;/b&gt;이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;PCA를 왜 사용하는가&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;머신러닝에서는 feature 수가 많아질수록 문제가 생길 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;계산량 증가&lt;/li&gt;
&lt;li&gt;feature 간 중복 정보 증가&lt;/li&gt;
&lt;li&gt;시각화 어려움&lt;/li&gt;
&lt;li&gt;overfitting 가능성 증가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 키와 몸무게처럼 거의 비슷하게 움직이는 feature 두 개가 있다면, 두 feature를 모두 사용하는 대신 &amp;ldquo;사람의 체격&amp;rdquo; 같은 하나의 축으로 줄여서 표현할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA는 이런 식으로:&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;원래 feature 공간
&amp;rarr; 정보 손실을 최소화하면서
&amp;rarr; 더 적은 축으로 표현
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하는 과정이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;PCA는 평균 중심화부터 시작한다&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA에서 가장 먼저 하는 작업은 평균 중심화(mean centering)다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 각 feature에서 평균을 빼준다.&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;x_new = x - mean(x)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 이렇게 하냐면, PCA는 데이터의 &amp;ldquo;흩어진 방향&amp;rdquo;을 찾는 알고리즘이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 중심이 제각각이면 실제 분산 방향을 제대로 보기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 PCA 전에 각 feature를 평균 기준으로 shift해서 원점 중심으로 이동시키는 과정이 먼저 필요하다고 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;공분산 행렬이 왜 필요한가&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평균 중심화를 한 뒤에는 공분산 행렬(covariance matrix)을 계산한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공분산 행렬은 변수들이 함께 어떻게 움직이는지를 담고 있는 행렬이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;\begin{bmatrix}Var(X_1) &amp;amp; Cov(X_1, X_2) \\Cov(X_2, X_1) &amp;amp; Var(X_2)\end{bmatrix}&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대각선 &amp;rarr; 각 변수의 분산&lt;/li&gt;
&lt;li&gt;비대각선 &amp;rarr; 변수 간 공분산&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공분산이 크다는 것은 두 변수 방향이 비슷하게 움직인다는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 공분산 행렬은 변수와 변수 사이의 상관 구조를 표현하기 위한 행렬이라고 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;PCA는 &amp;ldquo;분산이 큰 방향&amp;rdquo;을 찾는다&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA의 핵심은 이것이다.&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;데이터가 가장 많이 퍼진 방향 찾기
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면 데이터가 많이 퍼져 있다는 것은 그 방향이 데이터를 설명하는 정보량이 크다는 의미이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 데이터가 대각선 방향으로 길게 퍼져 있다면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;x축, y축 기준보다&lt;/li&gt;
&lt;li&gt;대각선 방향 기준이&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 더 잘 설명할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 PCA는 기존 좌표계 대신 새로운 basis를 도입해서 데이터를 바라보는 과정으로 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;고유값과 고유벡터가 등장하는 이유&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공분산 행렬에서 분산이 가장 큰 방향을 찾기 위해 고유값 분해(eigendecomposition)를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ax = \lambda x&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;x &amp;rarr; 고유벡터&lt;/li&gt;
&lt;li&gt;\lambda &amp;rarr; 고유값&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA에서는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고유벡터 &amp;rarr; 새로운 축 방향&lt;/li&gt;
&lt;li&gt;고유값 &amp;rarr; 해당 방향의 분산 크기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;고유값이 큰 고유벡터
&amp;rarr; 데이터가 많이 퍼진 방향
&amp;rarr; 중요한 주성분
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 PCA는 공분산 행렬의 고유값과 고유벡터를 구한 뒤, 큰 고유값에 해당하는 축을 선택하는 과정으로 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;PCA를 basis 변경으로 이해하기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA를 가장 직관적으로 이해하는 방법은:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;basis를 바꾸는 과정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;으로 보는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는:&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;x축, y축 기준
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;으로 데이터를 표현했다면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA 이후에는:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;데이터가 실제로 많이 퍼진 방향 기준
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;으로 데이터를 다시 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, feature를 삭제하는 느낌보다는:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;기존 좌표계
&amp;rarr; 데이터에 더 적합한 좌표계
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로 바꾸는 과정에 가깝다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 PCA는 새로운 basis system을 도입해 데이터를 projection하는 관점으로 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;PCA 전체 흐름&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;원본 데이터
&amp;rarr; 평균 중심화
&amp;rarr; 공분산 행렬 계산
&amp;rarr; 고유값 / 고유벡터 계산
&amp;rarr; 큰 고유값의 고유벡터 선택
&amp;rarr; 새로운 축으로 데이터 변환
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;실전에서 PCA를 쓸 때 주의할 점&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 스케일 차이가 크면 결과가 왜곡될 수 있다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키(cm)와 연봉(원)을 같이 PCA하면 연봉 feature가 분산을 거의 지배할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 보통 PCA 전에는 StandardScaler 같은 정규화를 먼저 한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. PCA는 feature 의미가 흐려질 수 있다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA 이후 feature는:&lt;/p&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;PC1, PC2 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 새로운 축으로 바뀐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 기존 컬럼 의미가 직접적으로 유지되지 않을 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 분산이 크다고 항상 중요한 건 아니다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA는 &amp;ldquo;분산이 큰 방향&amp;rdquo;을 중요하다고 가정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 실제 문제에서는 작은 분산 feature가 더 중요한 경우도 존재할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA는 공분산 행렬에서 분산이 가장 큰 방향을 고유벡터로 찾아, 데이터를 더 적은 차원에서 표현하는 차원 축소 기법이다.&lt;/p&gt;</description>
      <category>AI &amp;amp; Machine Learning/ML 수학</category>
      <category>featureengineering</category>
      <category>PCA</category>
      <category>고유값</category>
      <category>고유벡터</category>
      <category>공분산행렬</category>
      <category>데이터전처리</category>
      <category>머신러닝</category>
      <category>선형대수</category>
      <category>주성분분석</category>
      <category>차원축소</category>
      <author>seooeyeong</author>
      <guid isPermaLink="true">https://seo0west0.tistory.com/99</guid>
      <comments>https://seo0west0.tistory.com/99#entry99comment</comments>
      <pubDate>Tue, 2 Jun 2026 09:24:22 +0900</pubDate>
    </item>
    <item>
      <title>Gradient, Jacobian, Hessian 정리 | 입력과 출력 차원에 따라 미분 결과가 달라지는 이유</title>
      <link>https://seo0west0.tistory.com/98</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;딥러닝 수학에서 Gradient, Jacobian, Hessian이 헷갈리는 이유는 미분 공식이 어려워서라기보다 &lt;b&gt;입력과 출력의 형태가 달라지기 때문&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력이 스칼라인지 벡터인지, 출력이 스칼라인지 벡터인지에 따라 미분 결과는 숫자, 벡터, 행렬로 달라진다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;먼저 함수 형태를 구분해야 한다&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;미분 결과를 이해하려면 함수가 어떤 형태인지 먼저 봐야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 형태 의미 미분 결과&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;f: \mathbb{R} \rightarrow \mathbb{R}&lt;/td&gt;
&lt;td&gt;스칼라 입력 &amp;rarr; 스칼라 출력&lt;/td&gt;
&lt;td&gt;스칼라&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;f: \mathbb{R}^n \rightarrow \mathbb{R}&lt;/td&gt;
&lt;td&gt;벡터 입력 &amp;rarr; 스칼라 출력&lt;/td&gt;
&lt;td&gt;Gradient&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;f: \mathbb{R}^n \rightarrow \mathbb{R}^m&lt;/td&gt;
&lt;td&gt;벡터 입력 &amp;rarr; 벡터 출력&lt;/td&gt;
&lt;td&gt;Jacobian&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;f: \mathbb{R}^n \rightarrow \mathbb{R}의 2차 미분&lt;/td&gt;
&lt;td&gt;벡터 입력 &amp;rarr; 스칼라 출력 함수의 2차 미분&lt;/td&gt;
&lt;td&gt;Hessian&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 &lt;b&gt;입력과 출력이 몇 차원인지&lt;/b&gt;다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Gradient | 다변수 함수의 1차 미분&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gradient는 입력이 여러 개인 함수의 각 입력 방향별 변화율을 모아둔 벡터다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;f(x, y, z) = xyz
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 변수에 대해 편미분하면 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;&amp;part;f/&amp;part;x = yz
&amp;part;f/&amp;part;y = xz
&amp;part;f/&amp;part;z = xy
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 gradient는 아래처럼 쓴다.&lt;/p&gt;
&lt;pre class=&quot;fix&quot;&gt;&lt;code&gt;&amp;nabla;f = (yz, xz, xy)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, gradient는 &lt;b&gt;각 입력 변수가 출력값에 얼마나 영향을 주는지&lt;/b&gt;를 담은 벡터다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Gradient가 중요한 이유&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;머신러닝에서는 손실 함수가 보통 여러 파라미터를 입력으로 받고, 하나의 손실값을 출력한다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Loss(w1, w2, ..., wn) &amp;rarr; loss value
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 각 파라미터 방향으로 손실이 얼마나 변하는지 알아야 업데이트 방향을 정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 딥러닝 최적화에서 gradient가 기본이 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Jacobian | 벡터 함수를 미분한 행렬&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jacobian은 입력도 여러 개, 출력도 여러 개인 함수에서 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;F(x, y, z) = (f1, f2, f3)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처럼 출력이 여러 개라면, 각 출력값을 각 입력값에 대해 모두 편미분해야 한다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;          입력 x   입력 y   입력 z
출력 f1   &amp;part;f1/&amp;part;x  &amp;part;f1/&amp;part;y  &amp;part;f1/&amp;part;z
출력 f2   &amp;part;f2/&amp;part;x  &amp;part;f2/&amp;part;y  &amp;part;f2/&amp;part;z
출력 f3   &amp;part;f3/&amp;part;x  &amp;part;f3/&amp;part;y  &amp;part;f3/&amp;part;z
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 만들어지는 행렬이 Jacobian이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Jacobian을 직관적으로 보면&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jacobian은 &lt;b&gt;입력과 출력의 모든 조합에 대한 변화율 표&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력이 3개이고 출력이 3개라면 Jacobian은 3&amp;times;3 행렬이 된다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;입력 3개 &amp;times; 출력 3개 &amp;rarr; 3&amp;times;3 행렬
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력 하나만 보는 것이 아니라, 각 출력이 각 입력에 얼마나 민감하게 반응하는지를 모두 정리한 것이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Hessian | 다변수 함수의 2차 미분 행렬&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hessian은 벡터 입력을 받는 스칼라 출력 함수의 2차 미분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1차 미분인 gradient가 벡터이므로, 그 gradient를 다시 입력 변수들에 대해 미분하면 행렬이 된다.&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;f: Rⁿ &amp;rarr; R
1차 미분 &amp;rarr; Gradient vector
2차 미분 &amp;rarr; Hessian matrix
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hessian은 각 변수 조합에 대한 2차 변화율을 담는다.&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;&amp;part;&amp;sup2;f/&amp;part;x₁&amp;part;x₁   &amp;part;&amp;sup2;f/&amp;part;x₁&amp;part;x₂
&amp;part;&amp;sup2;f/&amp;part;x₂&amp;part;x₁   &amp;part;&amp;sup2;f/&amp;part;x₂&amp;part;x₂
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Hessian은 함수가 얼마나 휘어지는지, 곡률 정보를 담는 행렬이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Gradient, Jacobian, Hessian 차이&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개념 대상 함수 결과 형태 의미&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gradient&lt;/td&gt;
&lt;td&gt;벡터 입력 &amp;rarr; 스칼라 출력&lt;/td&gt;
&lt;td&gt;벡터&lt;/td&gt;
&lt;td&gt;각 입력 방향의 변화율&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jacobian&lt;/td&gt;
&lt;td&gt;벡터 입력 &amp;rarr; 벡터 출력&lt;/td&gt;
&lt;td&gt;행렬&lt;/td&gt;
&lt;td&gt;입력-출력 모든 조합의 변화율&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hessian&lt;/td&gt;
&lt;td&gt;벡터 입력 &amp;rarr; 스칼라 출력의 2차 미분&lt;/td&gt;
&lt;td&gt;행렬&lt;/td&gt;
&lt;td&gt;곡률, 2차 변화율&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;딥러닝에서 어떻게 연결되는가&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딥러닝에서는 입력, 파라미터, 출력이 대부분 벡터나 행렬 형태다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 단순한 스칼라 미분보다 gradient, Jacobian 같은 벡터 미분 개념이 더 자주 등장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적으로:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;손실 함수 최적화 &amp;rarr; Gradient&lt;/li&gt;
&lt;li&gt;여러 출력이 입력에 반응하는 구조 &amp;rarr; Jacobian&lt;/li&gt;
&lt;li&gt;곡률 기반 최적화 또는 2차 근사 &amp;rarr; Hessian&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;으로 연결된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;핵심 흐름&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;스칼라 함수 미분
&amp;rarr; 다변수 함수 미분
&amp;rarr; Gradient
&amp;rarr; 벡터 함수 미분
&amp;rarr; Jacobian
&amp;rarr; 2차 미분
&amp;rarr; Hessian
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gradient는 다변수 함수의 1차 미분 벡터, Jacobian은 벡터 함수의 1차 미분 행렬, Hessian은 다변수 함수의 2차 미분 행렬이다.&lt;/p&gt;</description>
      <category>AI &amp;amp; Machine Learning/ML 수학</category>
      <category>Gradient</category>
      <category>Hessian</category>
      <category>Jacobian</category>
      <category>다변수함수</category>
      <category>딥러닝수학</category>
      <category>머신러닝수학</category>
      <category>벡터미분</category>
      <category>선형대수</category>
      <category>최적화</category>
      <category>편미분</category>
      <author>seooeyeong</author>
      <guid isPermaLink="true">https://seo0west0.tistory.com/98</guid>
      <comments>https://seo0west0.tistory.com/98#entry98comment</comments>
      <pubDate>Tue, 2 Jun 2026 09:23:50 +0900</pubDate>
    </item>
    <item>
      <title>고유값과 고유벡터 정리 | 행렬 변환 후에도 방향이 유지되는 벡터</title>
      <link>https://seo0west0.tistory.com/97</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;고유값(Eigenvalue)과 고유벡터(Eigenvector)는 행렬이 공간을 어떻게 변형시키는지 보여주는 핵심 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 중요한 점은, 어떤 벡터들은 행렬 변환을 거쳐도 방향이 유지된다는 것이다. 이때 얼마나 늘어나거나 줄어드는지를 나타내는 값이 고유값이고, 그 방향을 유지하는 벡터가 고유벡터다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;고유벡터란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 행렬을 벡터에 곱하면 방향과 크기가 모두 바뀐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 특정 벡터는:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;방향은 유지되고
길이만 변한다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 특수한 경우가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 벡터를 고유벡터(Eigenvector)라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 &amp;ldquo;행렬을 곱해도 방향이 유지되는 벡터&amp;rdquo;를 고유벡터라고 설명한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;고유값이란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고유벡터가 얼마나 늘어나거나 줄어드는지를 나타내는 값이 고유값(Eigenvalue)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수식으로는 이렇게 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ax = \lambda x&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;A &amp;rarr; 행렬&lt;/li&gt;
&lt;li&gt;x &amp;rarr; 고유벡터&lt;/li&gt;
&lt;li&gt;\lambda &amp;rarr; 고유값&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;pre class=&quot;dns&quot;&gt;&lt;code&gt;행렬 A를 곱했더니
방향은 그대로이고
길이만 &amp;lambda;배 바뀐다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라는 의미다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 &amp;ldquo;자기 자신 방향으로 다시 나오는 벡터&amp;rdquo;라는 관점으로 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;왜 중요한가&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬은 공간을 늘리고, 줄이고, 회전시키는 변환이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 고유벡터는:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;변환 후에도 방향이 유지되는 특별한 축
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이라고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 고유값과 고유벡터는:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬이 공간을 어떤 방향으로 얼마나 변형시키는지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 보여준다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;고유값 계산 흐름&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고유값은 아래 과정으로 계산한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 기본 식에서 시작&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ax = \lambda x&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 한쪽으로 정리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(A - \lambda I)x = 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 I는 항등행렬이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. 0벡터 말고 다른 해가 존재해야 함&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고유벡터는 0벡터가 아니어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서:&lt;/p&gt;
&lt;pre class=&quot;clojure&quot;&gt;&lt;code&gt;(A - &amp;lambda;I)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 역행렬을 가지면 안 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. determinant 조건 사용&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 아래 조건을 만족해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;\det(A - \lambda I) = 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 식을 풀면 고유값이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 determinant가 0이어야 역행렬이 존재하지 않고, 그 조건으로 고유값을 계산한다고 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2&amp;times;2 행렬 예시&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬이 아래와 같다고 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A =\begin{bmatrix}2 &amp;amp; 3 \\3 &amp;amp; 2\end{bmatrix}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고유값 계산은:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;\det(A - \lambda I) = 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;을 푸는 과정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;\begin{vmatrix}2-\lambda &amp;amp; 3 \\3 &amp;amp; 2-\lambda\end{vmatrix}= 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전개하면:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2-\lambda)^2 - 9 = 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;\lambda = 5,\ -1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 값이 고유값이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;고유벡터는 어떻게 구할까&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고유값을 구한 뒤 다시:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(A - \lambda I)x = 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에 대입해서 x를 구하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 \lambda = 5를 넣으면:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;45도 방향 벡터
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;들이 고유벡터가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 \lambda = -1이면:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;반대 방향으로 뒤집히는 벡터
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;들이 고유벡터가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 특정 방향 벡터를 넣었을 때 5배로 늘어나거나, 방향이 뒤집혀 나오는 예시로 설명한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;determinant가 왜 등장하는가&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고유값 계산에서 determinant가 나오는 이유는:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;역행렬이 없어야
0벡터 외의 해가 존재하기 때문
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;\det(A - \lambda I)=0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;은 단순 공식 암기가 아니라:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;고유벡터가 존재할 조건&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;을 의미한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;PCA와 고유값 연결&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고유값과 고유벡터는 PCA와 직접 연결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PCA에서는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;분산이 큰 방향 &amp;rarr; 고유벡터&lt;/li&gt;
&lt;li&gt;그 크기 &amp;rarr; 고유값&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;으로 해석한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;데이터가 가장 많이 퍼진 방향
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;을 찾는 과정이 PCA다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;핵심 흐름&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;행렬 변환
&amp;rarr; 방향 유지 벡터 찾기
&amp;rarr; 고유벡터
&amp;rarr; 얼마나 늘어나는가
&amp;rarr; 고유값
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고유벡터는 행렬 변환 후에도 방향이 유지되는 벡터이고, 고유값은 그 벡터가 얼마나 늘어나거나 줄어드는지를 나타내는 값이다.&lt;/p&gt;</description>
      <category>AI &amp;amp; Machine Learning/ML 수학</category>
      <category>determinant</category>
      <category>eigenvalue</category>
      <category>eigenvector</category>
      <category>LinearAlgebra</category>
      <category>PCA기초</category>
      <category>고유값</category>
      <category>고유벡터</category>
      <category>딥러닝수학</category>
      <category>선형대수</category>
      <category>행렬변환</category>
      <author>seooeyeong</author>
      <guid isPermaLink="true">https://seo0west0.tistory.com/97</guid>
      <comments>https://seo0west0.tistory.com/97#entry97comment</comments>
      <pubDate>Tue, 2 Jun 2026 09:23:17 +0900</pubDate>
    </item>
    <item>
      <title>[SK플래닛] ASAC 빅데이터전문가 11기 | 32일차</title>
      <link>https://seo0west0.tistory.com/92</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;32일차는 딥러닝으로 넘어가면서, 기존 머신러닝과 무엇이 달라지는지 큰 흐름을 잡은 날이었다. 앞에서는 Y = f(X)에서 좋은 함수를 찾는다는 관점으로 머신러닝을 봤다면, 이번에는 그 함수 f를 인공신경망 구조로 만들고, 입력과 출력의 형태를 훨씬 자유롭게 설계할 수 있다는 점을 봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 전통적인 머신러닝은 대부분 데이터를 2D matrix 형태로 맞춰야 했지만, 딥러닝은 이미지, 영상, 음성, 텍스트처럼 더 복잡한 입력과 출력을 다룰 수 있다는 점이 크게 달랐다. 물론 자유도가 커진 만큼 파라미터도 많아지고, 학습 시간과 비용도 커진다는 점도 같이 봤다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. AI, Machine Learning, Deep Learning의 관계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 AI, ML, DL의 관계를 다시 정리했다. AI는 가장 큰 범주이고, 그 안에서 기계가 데이터로부터 규칙을 학습하는 방식이 Machine Learning이었다. Deep Learning은 그 머신러닝 안에서 인공신경망을 깊게 쌓아 복잡한 관계를 학습하는 방식으로 볼 수 있었다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;AI
= 문제를 인식하고 해결하는 지능을 구현하는 기술

Machine Learning
= 데이터를 기반으로 기계가 스스로 규칙을 학습하는 방법

Deep Learning
= 인공신경망을 이용해 복잡한 데이터 관계를 학습하는 머신러닝 기법
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 딥러닝도 머신러닝의 한 종류라는 점은 같았다. 다만 기존 머신러닝보다 모델 구조의 자유도가 높고, 입력과 출력의 형태도 다양하게 설정할 수 있다는 점이 달랐다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 딥러닝의 장점과 부담&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딥러닝의 장점은 복잡한 함수를 잘 근사한다는 점이었다. 기존 머신러닝에서는 사람이 feature를 어느 정도 잘 만들어야 했다면, 딥러닝은 데이터 안에서 필요한 특징을 모델이 직접 학습할 수 있다. 이미지나 음성처럼 사람이 규칙을 직접 만들기 어려운 데이터에서 강한 이유도 여기에 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 단점도 명확했다. 파라미터 수가 많아지기 때문에 학습 시간과 비용이 커지고, 좋은 데이터를 많이 확보해야 한다. 또 모델이 왜 그런 결과를 냈는지 해석하기 어렵다는 점도 있었다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;딥러닝의 장점
- 복잡한 비선형 관계를 잘 표현한다.
- 특징 추출을 모델이 함께 학습한다.
- 이미지, 음성, 텍스트처럼 복잡한 데이터에 강하다.

딥러닝의 부담
- 파라미터 수가 많다.
- 학습 시간과 비용이 크다.
- 해석이 어렵다.
- 좋은 데이터 확보가 중요하다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 &amp;ldquo;딥러닝이 무조건 좋다&amp;rdquo;가 아니라, 문제의 복잡도와 데이터 규모에 따라 선택해야 한다는 쪽으로 이해했다. 작은 정형 데이터라면 기존 머신러닝이 더 적합할 수도 있고, 이미지나 텍스트처럼 구조가 복잡한 데이터라면 딥러닝을 고려할 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. FNN은 가장 기본적인 신경망 구조였다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순방향 신경망, 즉 FNN은 가장 기본적인 신경망 구조였다. 입력이 들어오고, hidden layer를 거쳐, output layer로 나가는 한 방향 구조다. 피드백 구조 없이 앞에서 뒤로만 흐른다.&lt;/p&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;Input Layer
&amp;rarr; Hidden Layer
&amp;rarr; Output Layer
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Input layer는 내가 가진 데이터의 형태에 따라 정해진다. 예를 들어 10개의 feature를 가진 데이터라면 input node도 10개가 필요하다. MNIST처럼 28&amp;times;28 흑백 이미지라면, 단순 FNN에서는 이를 784개의 값으로 펼쳐 input layer에 넣을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Output layer는 문제의 목적에 따라 정해진다. 회귀 문제라면 값을 하나 내보내면 되고, 0부터 9까지 숫자를 분류하는 문제라면 10개의 output node가 필요하다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;입력층
= 데이터의 feature 개수에 맞춰 결정

출력층
= 내가 풀려는 문제의 목적에 맞춰 결정

은닉층
= 모델 설계자가 조정하는 영역
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 남은 건 input과 output은 어느 정도 문제에 의해 고정되지만, hidden layer는 설계의 영역이라는 점이었다. 몇 층을 쌓을지, 각 층에 node를 몇 개 둘지, 어떤 activation function을 쓸지는 실험과 경험이 필요하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Activation Function은 비선형성을 넣는 역할이었다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신경망에서 각 뉴런은 입력과 가중치의 선형결합을 계산한 뒤 activation function을 통과시킨다. 만약 activation function이 없으면 여러 층을 쌓아도 결국 선형결합의 반복에 가까워져 복잡한 관계를 표현하기 어렵다.&lt;/p&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;입력값
&amp;rarr; 가중치와 선형결합
&amp;rarr; Activation Function
&amp;rarr; 다음 Layer로 전달
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기에는 sigmoid 계열을 많이 사용했지만, 딥러닝에서는 ReLU 계열이 많이 쓰인다고 했다. sigmoid는 값이 양끝에서 포화되면서 gradient가 작아지는 문제가 있고, 지수함수 계산이 들어가서 연산 비용도 있다. 반면 ReLU는 0보다 작으면 0, 크면 그대로 내보내는 단순한 구조라 계산이 빠르다.&lt;/p&gt;
&lt;pre class=&quot;excel&quot;&gt;&lt;code&gt;Sigmoid
= 0~1 사이로 값을 눌러줌
= gradient saturation 문제가 생길 수 있음

ReLU
= max(0, x)
= 계산이 빠르고 딥러닝에서 많이 사용됨
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 ReLU도 음수 구간이 전부 0이 되면 학습이 멈출 수 있는 문제가 있다. 그래서 Leaky ReLU, ELU 같은 변형도 존재한다. 이 부분은 activation function도 단순 선택지가 아니라 모델 성능과 학습 안정성에 영향을 주는 요소라는 점이 남았다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 학습은 결국 Loss를 줄이는 파라미터를 찾는 과정이었다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딥러닝도 결국 학습의 관점에서는 머신러닝과 같았다. 모델이 예측한 값과 실제값의 차이를 Loss Function으로 계산하고, 그 값을 줄이는 방향으로 파라미터를 업데이트한다.&lt;/p&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;모델 예측
&amp;rarr; Loss 계산
&amp;rarr; Gradient 계산
&amp;rarr; 파라미터 업데이트
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 신경망의 파라미터가 앞쪽 layer에 숨어 있다는 점이었다. Loss Function은 최종 output에서 계산되지만, 앞쪽 hidden layer의 weight도 이 loss에 영향을 준다. 그래서 chain rule을 이용해 뒤에서 앞으로 미분값을 전달해야 한다. 이것이 backpropagation이었다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;Backpropagation
= Loss에서 시작해
= output layer &amp;rarr; hidden layer 방향으로
= 미분값을 역방향으로 전달하며
= 각 weight를 업데이트하는 과정
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에는 backpropagation을 그냥 &amp;ldquo;딥러닝 학습 알고리즘&amp;rdquo;처럼 들었는데, 이번에는 chain rule을 이용해 합성함수의 미분을 역방향으로 계산하는 구조로 이해할 수 있었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. Mini-batch는 학습 단위를 나누는 방식이었다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;신경망을 학습할 때 전체 데이터를 한 번에 넣으면 메모리와 시간이 부담될 수 있다. 반대로 한 샘플씩 학습하면 경로가 너무 흔들릴 수 있다. 그래서 보통은 데이터를 작은 묶음으로 나눈 mini-batch 방식으로 학습한다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;Batch
= 전체 데이터를 한 번에 사용

Stochastic
= 한 샘플씩 사용

Mini-batch
= 일부 샘플 묶음 단위로 사용
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mini-batch는 전체 batch보다 빠르고, 매번 조금씩 다른 데이터 묶음으로 학습하기 때문에 일반화에도 도움이 될 수 있다. 다만 batch size도 hyperparameter라서 적당한 값을 찾아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 실제로 딥러닝 코드에서 batch_size, epochs, iterations를 자주 보는 이유와 연결됐다. epoch는 전체 train data가 모델을 한 번 통과한 횟수이고, iteration은 한 epoch를 끝내기 위해 필요한 batch 업데이트 횟수였다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. CNN은 이미지의 공간 구조를 살리기 위한 구조였다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 CNN의 기본 아이디어를 봤다. FNN에 이미지를 넣으려면 28&amp;times;28 이미지를 784개의 1D 벡터로 펼쳐야 한다. 그런데 이렇게 하면 픽셀의 위아래, 좌우 관계가 약해진다. 이미지는 개별 픽셀보다 주변 픽셀과의 영역적 관계가 중요하기 때문에, CNN은 이 공간 구조를 살리기 위해 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CNN에서 핵심은 Convolution Layer와 Pooling Layer였다. Convolution은 필터를 이미지 위에 움직이며 특정 패턴을 찾는 연산이다. 예전 이미지 처리에서 세로선, 가로선, edge를 찾기 위해 필터를 쓰던 것처럼, CNN에서는 이 필터의 값을 학습 가능한 weight로 본다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;Convolution Layer
= 필터를 이용해 이미지의 특징을 추출

Feature Map
= 필터를 적용한 결과

Pooling Layer
= 특징맵의 크기를 줄이고 대표값을 뽑음

Flatten Layer
= 추출된 특징을 1차원으로 펼쳐 Dense Layer에 전달
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pooling은 feature map을 그대로 쓰지 않고, 일정 영역을 대표값으로 줄이는 과정이었다. Max Pooling은 해당 영역에서 가장 큰 값을 뽑고, Average Pooling은 평균을 사용한다. 결국 CNN은 이미지에서 특징을 뽑고, 크기를 줄이고, 마지막에는 flatten해서 기존 신경망처럼 분류나 회귀 목적에 연결하는 구조로 이해됐다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;32일차는 딥러닝의 전체 구조를 처음으로 크게 잡은 날이었다. 딥러닝도 결국 Y = f(X)에서 좋은 함수를 찾는 머신러닝의 한 종류지만, 그 함수 f를 인공신경망 구조로 만들고, 입력과 출력의 형태를 더 유연하게 다룰 수 있다는 점이 달랐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FNN에서는 input layer와 output layer가 데이터와 목적에 의해 정해지고, hidden layer는 모델 설계의 영역이라는 점이 남았다. Activation function은 비선형성을 넣는 역할을 하고, backpropagation은 loss에서 시작해 미분값을 역방향으로 전달하는 학습 과정이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CNN은 이미지 데이터를 단순히 1D로 펴는 대신, 필터와 convolution을 통해 공간적 특징을 추출하는 구조였다. 이미지에서는 픽셀 하나보다 주변 영역의 패턴이 중요하기 때문에, convolution과 pooling이 왜 필요한지 조금 더 연결해서 볼 수 있었다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;32일차는 딥러닝을 머신러닝의 확장으로 보고, FNN의 기본 구조와 CNN의 이미지 특징 추출 흐름을 처음 연결해서 이해한 날이었다.&lt;/b&gt;&lt;/p&gt;</description>
      <category>[SK플래닛] ASAC 빅데이터전문가 11기/학습기록</category>
      <category>activationfunction</category>
      <category>backpropagation</category>
      <category>cnn</category>
      <category>Convolution</category>
      <category>DeepLearning</category>
      <category>FNN</category>
      <category>MiniBatch</category>
      <category>ReLU</category>
      <category>딥러닝</category>
      <category>인공신경망</category>
      <author>seooeyeong</author>
      <guid isPermaLink="true">https://seo0west0.tistory.com/92</guid>
      <comments>https://seo0west0.tistory.com/92#entry92comment</comments>
      <pubDate>Tue, 2 Jun 2026 08:58:39 +0900</pubDate>
    </item>
    <item>
      <title>선형 변환과 행렬 정리 | 행렬을 함수처럼 이해하는 방법</title>
      <link>https://seo0west0.tistory.com/96</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;선형대수에서 행렬은 단순한 숫자 배열이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬은 벡터를 다른 벡터로 바꾸는 &lt;b&gt;변환(transform)&lt;/b&gt; 으로 볼 수 있다. 이 관점이 중요한 이유는 딥러닝, 컴퓨터 그래픽스, 추천 시스템처럼 벡터를 계속 변환하는 모델들이 결국 행렬 연산 위에서 동작하기 때문이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;선형 변환이란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선형 변환(linear transformation)은 벡터 공간에서 다른 벡터 공간으로 보내는 함수다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 모든 함수가 선형 변환은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선형 변환은 아래 두 조건을 만족해야 한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1. 덧셈 보존
2. 상수배 보존
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;T(x + y) = T(x) + T(y)
T(ax) = aT(x)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 성질이 유지되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 선형 변환은 &amp;ldquo;벡터 공간 사이의 함수 중 덧셈과 상수배가 보존되는 변환&amp;rdquo;이라고 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;왜 &amp;ldquo;선형&amp;rdquo;이라는 말을 쓰는가&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;T(x) = 3x
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;는 선형 변환이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면:&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;T(x + y) = 3(x + y)
          = 3x + 3y
          = T(x) + T(y)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 성립하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면:&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;T(x) = 3x + 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;은 선형 변환이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상수항 +1 때문에 덧셈 보존이 깨진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 ax + b 형태는 일반적으로는 선형 함수라고 부르지만, 선형대수에서 말하는 선형 변환은 아니라고 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;행렬은 선형 변환을 표현하는 도구&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선형 변환의 핵심은:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬로 표현할 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 2차원 벡터를 3배 확대하는 변환은 아래 행렬로 표현할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;[3 0]
[0 3]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 행렬을 벡터에 곱하면:&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;(x, y) &amp;rarr; (3x, 3y)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 벡터 전체가 3배 확대된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 &amp;ldquo;3배 확대 변환은 대각선이 3인 행렬과 동일한 역할을 한다&amp;rdquo;고 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;행렬 곱은 &amp;ldquo;변환 적용&amp;rdquo;이다&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬과 벡터의 곱은 단순 계산이 아니라:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;입력 벡터 &amp;rarr; 변환 &amp;rarr; 출력 벡터
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로 이해하는 편이 맞다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;A = [2 0]
    [0 2]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이면:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;A(1, 3) = (2, 6)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, (1, 3) 벡터를 2배 확대하는 변환이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;회전과 대칭도 행렬로 표현된다&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬은 확대만 하는 것이 아니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;x축 대칭&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;[1  0]
[0 -1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 행렬은 y값 부호를 뒤집는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;(a, b) &amp;rarr; (a, -b)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;회전 변환&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 회전도 행렬 하나로 표현된다.&lt;/p&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;[ cos&amp;theta;  -sin&amp;theta; ]
[ sin&amp;theta;   cos&amp;theta; ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 행렬은 단순 숫자표가 아니라:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;확대&lt;/li&gt;
&lt;li&gt;축소&lt;/li&gt;
&lt;li&gt;회전&lt;/li&gt;
&lt;li&gt;대칭&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 변환 자체를 표현하는 도구다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 고등학교에서 배운 회전&amp;middot;대칭 이동이 결국 행렬 변환 관점으로 연결된다고 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;딥러닝에서 행렬이 중요한 이유&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딥러닝에서는 입력 벡터가 여러 층(layer)을 지나면서 계속 변환된다.&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;입력 벡터
&amp;rarr; 행렬 곱
&amp;rarr; 활성화 함수
&amp;rarr; 행렬 곱
&amp;rarr; 출력
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 신경망은 결국:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벡터를 계속 다른 벡터로 변환하는 과정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이라고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 &amp;ldquo;딥러닝은 행렬 연산을 계속 때려 넣는 구조&amp;rdquo;라는 흐름으로 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;함수와 행렬을 같은 관점으로 보기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고등학교에서는 보통:&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;f(x)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형태의 함수만 배운다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 선형대수에서는:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;벡터 &amp;rarr; 벡터
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;형태의 함수까지 확장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이 변환을 가장 효율적으로 표현하는 도구가 행렬이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉:&lt;/p&gt;
&lt;pre class=&quot;fix&quot;&gt;&lt;code&gt;행렬 = 벡터 변환 함수
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라는 관점으로 이해하는 것이 핵심이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;핵심 흐름&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;벡터
&amp;rarr; 선형 변환
&amp;rarr; 행렬 표현
&amp;rarr; 행렬 곱
&amp;rarr; 새로운 벡터
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;행렬은 숫자 배열이 아니라, 벡터를 다른 벡터로 바꾸는 선형 변환을 표현하는 도구다.&lt;/p&gt;</description>
      <category>AI &amp;amp; Machine Learning/ML 수학</category>
      <category>LinearAlgebra</category>
      <category>LinearTransformation</category>
      <category>matrixtransformation</category>
      <category>딥러닝수학</category>
      <category>벡터변환</category>
      <category>선형대수</category>
      <category>선형변환</category>
      <category>행렬</category>
      <category>행렬곱</category>
      <category>행렬함수</category>
      <author>seooeyeong</author>
      <guid isPermaLink="true">https://seo0west0.tistory.com/96</guid>
      <comments>https://seo0west0.tistory.com/96#entry96comment</comments>
      <pubDate>Mon, 1 Jun 2026 11:24:35 +0900</pubDate>
    </item>
    <item>
      <title>벡터 Norm과 Inner Product 정리 | 벡터 크기와 방향 유사도를 계산하는 방법</title>
      <link>https://seo0west0.tistory.com/95</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;벡터를 다룰 때 가장 많이 사용하는 개념이 Norm과 Inner Product(내적)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Norm은 벡터의 크기를 계산하는 방법이고, Inner Product는 두 벡터가 얼마나 같은 방향을 바라보는지를 계산하는 연산이다. 머신러닝에서는 거리 계산, 유사도 계산, 추천 시스템, word embedding 같은 거의 모든 벡터 기반 모델에서 계속 등장한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Norm이란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Norm은 벡터의 크기(length)를 정의하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 익숙한 것은 유클리드 거리 기반의 L2 Norm이다.&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;||x||₂ = &amp;radic;(x₁&amp;sup2; + x₂&amp;sup2; + ... + xₙ&amp;sup2;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;x = (3, 4)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라면:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;||x||₂ = &amp;radic;(3&amp;sup2; + 4&amp;sup2;) = 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 우리가 중학교&amp;middot;고등학교에서 배운 피타고라스 거리와 같은 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 L2 norm은 우리가 흔히 아는 유클리드 거리라고 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;L1 Norm과 L2 Norm 차이&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Norm은 하나만 있는 것이 아니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;L1 Norm&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;gherkin&quot;&gt;&lt;code&gt;||x||₁ = |x₁| + |x₂| + ... + |xₙ|
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;x = (3, -4)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라면:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;||x||₁ = 3 + 4 = 7
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;L2 Norm&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;||x||₂ = &amp;radic;(x₁&amp;sup2; + x₂&amp;sup2; + ... + xₙ&amp;sup2;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 벡터라면:&lt;/p&gt;
&lt;pre class=&quot;coq&quot;&gt;&lt;code&gt;||x||₂ = 5
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;L1 vs L2 차이&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종류 특징&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;L1 Norm&lt;/td&gt;
&lt;td&gt;절댓값 합&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L2 Norm&lt;/td&gt;
&lt;td&gt;유클리드 거리&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;머신러닝에서는 이 차이가 규제(regularization)와 연결된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;L1 &amp;rarr; Lasso&lt;/li&gt;
&lt;li&gt;L2 &amp;rarr; Ridge&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 L1/L2 norm은 이후 규제 방식과 연결된다고 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Inner Product(내적)이란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내적은 두 벡터의 각 성분을 곱해서 더하는 연산이다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;a &amp;middot; b = a₁b₁ + a₂b₂ + ... + aₙbₙ
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;a = (1, 2)
b = (3, 4)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이면:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;a &amp;middot; b = 1&amp;times;3 + 2&amp;times;4 = 11
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;내적의 기하학적 의미&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내적은 단순 계산만이 아니라, 두 벡터의 방향 관계로도 해석할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;a &amp;middot; b = ||a|| ||b|| cos&amp;theta;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 것은 cos&amp;theta;다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각도 의미&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;cos&amp;theta; &amp;gt; 0&lt;/td&gt;
&lt;td&gt;비슷한 방향&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cos&amp;theta; = 0&lt;/td&gt;
&lt;td&gt;수직&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cos&amp;theta; &amp;lt; 0&lt;/td&gt;
&lt;td&gt;반대 방향&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 내적은 단순 곱셈이 아니라:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 벡터가 얼마나 같은 방향을 바라보는가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 계산하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 내적은 벡터 방향 유사도를 계산하는 데 사용되며, 추천 시스템&amp;middot;word2vec&amp;middot;transformer와 연결된다고 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;직교(Orthogonal)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 벡터의 내적이 0이면 두 벡터는 직교한다고 한다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;a &amp;middot; b = 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(1, 0) &amp;middot; (0, 1) = 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 두 벡터는 서로 수직이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자료에서도 직교는 &amp;ldquo;내적이 0인 특수한 경우&amp;rdquo;로 설명된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Projection(정사영)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Projection은 한 벡터를 다른 벡터 방향으로 투영하는 개념이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말하면:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 방향으로 얼마나 영향을 주는가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 계산하는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내적 공식은 Projection과 연결된다.&lt;/p&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;a &amp;middot; b = ||a|| ||b|| cos&amp;theta;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서:&lt;/p&gt;
&lt;pre class=&quot;coq&quot;&gt;&lt;code&gt;||a|| cos&amp;theta;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;는 a 벡터가 b 방향으로 얼마나 투영되는지를 의미한다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;왜 중요한가&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Norm과 Inner Product는 머신러닝 거의 모든 곳에서 등장한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Norm&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;거리 계산&lt;/li&gt;
&lt;li&gt;정규화&lt;/li&gt;
&lt;li&gt;규제(L1/L2)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Inner Product&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;cosine similarity&lt;/li&gt;
&lt;li&gt;추천 시스템&lt;/li&gt;
&lt;li&gt;word embedding&lt;/li&gt;
&lt;li&gt;transformer attention&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 cosine similarity는 내적 기반 유사도 계산이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;핵심 흐름&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;mathematica&quot;&gt;&lt;code&gt;Norm &amp;rarr; 벡터 크기
Inner Product &amp;rarr; 방향 유사도
Projection &amp;rarr; 특정 방향 영향력
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Norm은 벡터의 크기를 정의하고, Inner Product는 두 벡터의 방향 유사도를 계산하는 핵심 연산이다!!&lt;/p&gt;</description>
      <category>AI &amp;amp; Machine Learning/ML 수학</category>
      <category>CosineSimilarity</category>
      <category>InnerProduct</category>
      <category>L1Norm</category>
      <category>L2Norm</category>
      <category>LinearAlgebra</category>
      <category>projection</category>
      <category>VectorNorm</category>
      <category>머신러닝수학</category>
      <category>벡터내적</category>
      <category>선형대수</category>
      <author>seooeyeong</author>
      <guid isPermaLink="true">https://seo0west0.tistory.com/95</guid>
      <comments>https://seo0west0.tistory.com/95#entry95comment</comments>
      <pubDate>Mon, 1 Jun 2026 11:23:58 +0900</pubDate>
    </item>
    <item>
      <title>Span, Basis, Dimension 정리 | 벡터 공간을 표현하는 최소 기준</title>
      <link>https://seo0west0.tistory.com/94</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Basis는 벡터 공간을 표현하는 데 필요한 &lt;b&gt;최소한의 기준 벡터 집합&lt;/b&gt;이다. 어떤 벡터들이 공간 전체를 만들 수 있고, 동시에 서로 중복되지 않는다면 그 벡터들은 해당 공간의 basis가 된다. Dimension은 그 basis에 포함된 벡터의 개수로 정의된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Basis를 이해하기 전에 봐야 할 개념&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Basis는 단독으로 이해하기 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 흐름이 같이 연결된다.&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;선형 결합 &amp;rarr; Span &amp;rarr; 선형 독립 &amp;rarr; Basis &amp;rarr; Dimension
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 개념은 따로 있는 것이 아니라, &amp;ldquo;벡터 공간을 어떤 기준으로 표현할 것인가&amp;rdquo;라는 문제로 이어진다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;선형 결합이란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선형 결합은 여러 벡터에 각각 스칼라를 곱한 뒤 더하는 방식이다.&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;a₁v₁ + a₂v₂ + ... + aₙvₙ
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 (1, 0)과 (0, 1)이 있을 때:&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;2(1, 0) + 3(0, 1) = (2, 3)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 기존 벡터를 재료처럼 조합해 새로운 벡터를 만드는 방식이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Span이란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Span은 주어진 벡터들의 선형 결합으로 만들 수 있는 &lt;b&gt;모든 벡터의 집합&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 (1, 0), (0, 1)은 2차원 평면의 모든 벡터를 만들 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;a(1, 0) + b(0, 1) = (a, b)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이 두 벡터는 2차원 공간 전체를 span한다고 말할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Basis의 조건&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 벡터 집합이 basis가 되려면 두 조건을 만족해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건 의미&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Span&lt;/td&gt;
&lt;td&gt;해당 공간 전체를 만들 수 있어야 함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linear Independence&lt;/td&gt;
&lt;td&gt;중복된 벡터가 없어야 함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, basis는 &lt;b&gt;공간을 만들 수 있으면서도 불필요한 벡터가 없는 집합&lt;/b&gt;이다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Basis 예시&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 공간에서 아래 두 벡터는 basis가 된다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(1, 0), (0, 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 벡터는 2차원 전체를 만들 수 있고, 서로 독립이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 아래 세 벡터는 basis가 아니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(1, 0), (0, 1), (1, 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이유는 (1, 1)을 앞의 두 벡터로 만들 수 있기 때문이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(1, 1) = (1, 0) + (0, 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공간 전체를 만들 수는 있지만, 중복된 벡터가 포함되어 있으므로 basis라고 볼 수 없다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Dimension이란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dimension은 basis에 들어 있는 벡터의 개수다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;2차원 공간 &amp;rarr; basis 벡터 2개
3차원 공간 &amp;rarr; basis 벡터 3개
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차원은 단순히 좌표축의 개수가 아니라, &lt;b&gt;그 공간을 표현하는 데 필요한 독립적인 기준 벡터의 개수&lt;/b&gt;라고 이해하면 된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Basis는 하나만 있는 게 아니다&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 공간의 basis는 (1, 0), (0, 1)만 있는 것이 아니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(1, 0), (1, 1)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 벡터도 서로 독립이고 2차원 전체를 만들 수 있으므로 basis가 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 표준 기저는 가장 익숙한 basis일 뿐이고, basis 자체는 여러 방식으로 선택할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;왜 중요한가&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Basis를 이해하면 이후 개념이 훨씬 자연스럽게 이어진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;좌표 표현&lt;/li&gt;
&lt;li&gt;선형 변환&lt;/li&gt;
&lt;li&gt;행렬의 의미&lt;/li&gt;
&lt;li&gt;PCA&lt;/li&gt;
&lt;li&gt;차원 축소&lt;/li&gt;
&lt;li&gt;딥러닝의 벡터 표현&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 PCA는 데이터를 더 잘 설명하는 방향으로 basis를 바꾸는 관점으로 이해할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Basis는 벡터 공간 전체를 표현할 수 있으면서도 중복이 없는 최소한의 기준 벡터 집합이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AI &amp;amp; Machine Learning/ML 수학</category>
      <category>basis</category>
      <category>Dimension</category>
      <category>LinearAlgebra</category>
      <category>PCA기초</category>
      <category>span</category>
      <category>기저벡터</category>
      <category>벡터공간</category>
      <category>선형결합</category>
      <category>선형대수</category>
      <category>선형독립</category>
      <author>seooeyeong</author>
      <guid isPermaLink="true">https://seo0west0.tistory.com/94</guid>
      <comments>https://seo0west0.tistory.com/94#entry94comment</comments>
      <pubDate>Mon, 1 Jun 2026 11:23:18 +0900</pubDate>
    </item>
    <item>
      <title>[SK플래닛] ASAC 빅데이터전문가 11기 | 31일차</title>
      <link>https://seo0west0.tistory.com/91</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;31일차는 오전에는 Git 특강과 실습을 진행했고, 오후에는 AWS 기반 분석 자동화 흐름을 다룬 날이었다. Git은 단순히 팀 협업할 때만 쓰는 도구라고 생각하기 쉬운데, 이번에는 혼자 개발할 때도 변경 이력을 남기고 필요할 때 특정 시점으로 돌아가기 위해 필요하다는 점을 먼저 잡았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오후에는 S3 Tables / Iceberg 기반의 데이터, Athena SQL 실행, Bedrock 모델 호출, Markdown 보고서 생성 흐름을 봤다. 직접 분석 코드를 짜는 것에서 한 단계 더 나아가, 사용자의 질문을 받아 SQL을 실행하고 LLM으로 분석 보고서를 만드는 구조였다. 다만 이 과정에서도 LLM이 만든 SQL이나 해석 결과를 그대로 믿으면 안 되고, SQL 결과와 수치가 맞는지 확인해야 한다는 점이 중요했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Git은 GitHub가 아니라 버전 관리 도구였다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 다시 잡은 개념은 Git과 GitHub의 차이였다. Git은 프로젝트의 변경 이력을 기록하는 분산 버전 관리 도구이고, GitHub는 Git 저장소를 원격으로 올리고 협업할 수 있게 해주는 호스팅 서비스다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;Git
= 버전 관리 도구

GitHub
= Git 저장소를 올려두는 원격 호스팅 서비스
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예전에는 파일명을 최종, 진짜최종, 진짜진짜최종처럼 바꿔가며 관리했다면, Git은 파일의 변경 이력을 커밋 단위로 남긴다. 그래서 언제, 누가, 무엇을 바꿨는지 추적할 수 있고, 필요하면 이전 커밋으로 돌아갈 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분에서 Git이 협업용 도구이기도 하지만, 혼자 개발할 때도 필요하다는 말이 남았다. 프로젝트가 커지면 내가 언제 무엇을 바꿨는지도 헷갈리기 때문에, 초반부터 Git을 켜두고 작업하는 습관이 필요해 보였다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Working Directory, Staging Area, Local Repository&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Git 기초에서 가장 헷갈리기 쉬운 부분은 파일이 바로 커밋되는 것이 아니라는 점이었다. 파일을 수정하면 먼저 Working Directory에 변경사항이 생기고, git add를 하면 Staging Area에 올라간다. 그 다음 git commit을 해야 Local Repository에 이력이 저장된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Working Directory
&amp;rarr; 실제 파일을 수정하는 공간

Staging Area
&amp;rarr; 커밋할 파일을 준비하는 공간

Local Repository
&amp;rarr; 커밋이 저장되는 공간
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실습에서는 lab1 폴더를 만들고, git init으로 저장소를 초기화한 뒤 README.md, index.js를 만들었다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;cd ~/git-labs/lab1

git init

echo &quot;# My Project&quot; &amp;gt; README.md
echo &quot;console.log('hello');&quot; &amp;gt; index.js

git status
git add .
git commit -m &quot;feat: 프로젝트 초기 설정&quot;

git log --oneline
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 흐름을 직접 해보니까 git status를 자주 확인해야 하는 이유가 보였다. 지금 파일이 추적되지 않은 상태인지, 스테이징된 상태인지, 커밋할 것이 없는 상태인지 계속 확인해야 실수를 줄일 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. commit 메시지는 나중에 보는 사람을 위한 기록이었다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커밋 메시지도 단순히 아무 말이나 적는 것이 아니었다. 수정, 작업중, fix처럼 적으면 나중에 이력을 봤을 때 무엇이 바뀌었는지 알기 어렵다. 그래서 Conventional Commits처럼 타입을 붙여 메시지를 쓰는 방식이 소개됐다.&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;feat: 로그인 API 연동 완료
fix: 회원가입 이메일 중복 검사 오류 수정
docs: README 설치 가이드 업데이트
refactor: UserService 메서드 분리
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커밋은 단순 저장이 아니라 변경 이력이다. 그래서 커밋 메시지는 현재의 나보다 나중에 이 코드를 다시 볼 사람에게 더 중요할 수 있다. 이 부분은 기술 블로그 글 제목을 쓰는 것과도 비슷하게 느껴졌다. 짧지만 무엇이 바뀌었는지 드러나야 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Branch와 merge, rebase는 이력을 다루는 방식이 달랐다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브랜치는 원래 코드와 독립적으로 기능을 개발할 수 있게 해주는 흐름이었다. 실습에서는 feat/login 브랜치를 만들어 로그인 기능을 추가하고, 다시 main으로 돌아와 병합했다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;git checkout -b feat/login

echo &quot;function login() {}&quot; &amp;gt;&amp;gt; index.js
git add index.js
git commit -m &quot;feat: 로그인 함수 추가&quot;

git checkout main
git merge feat/login
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;merge와 rebase의 차이도 봤다. merge는 브랜치의 이력을 그대로 보존하면서 합치는 방식이고, rebase는 브랜치 커밋을 대상 브랜치 뒤로 재배치해 선형 이력을 만드는 방식이다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;merge
= 이력 보존
= 공유 브랜치에서 안전

rebase
= 이력 정리
= PR 전 로컬 이력 정리에 적합
= 공유 브랜치에서는 주의
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 rebase가 더 깔끔하니 항상 좋은 것처럼 보였는데, 공유된 브랜치에서 rebase를 하면 팀원들의 이력과 꼬일 수 있다는 점이 중요했다. 이력은 예쁘게 만드는 것도 중요하지만, 협업 상황에서는 안전한 방식이 먼저였다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. conflict는 Git이 판단을 멈춘 상태였다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;충돌은 같은 파일의 같은 줄을 두 브랜치에서 서로 다르게 수정했을 때 발생했다. Git이 어느 쪽을 선택해야 할지 모르기 때문에 개발자에게 직접 판단을 맡기는 상황이었다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD
version=1.5
=======
version=2.0
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; branch-a
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;충돌 마커를 보면 위쪽은 현재 브랜치 내용이고, 아래쪽은 병합하려는 브랜치 내용이다. 해결할 때는 마커를 지우고 원하는 내용만 남긴 뒤 다시 git add, git commit을 해야 했다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;git status

# 파일 직접 수정 후
git add config.txt
git commit
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분에서 Git이 자동으로 모든 걸 해결해주는 도구는 아니라는 점이 보였다. 단순한 파일 이동이나 다른 줄 수정은 자동 병합할 수 있지만, 같은 줄을 다르게 바꾼 경우에는 결국 사람이 판단해야 했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. reset, revert, stash는 되돌리는 목적이 달랐다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오전 실습에서는 작업을 되돌리는 여러 방법도 다뤘다. reset은 HEAD를 과거 커밋으로 옮기면서 이력을 지우는 방식이고, revert는 기존 커밋을 지우지 않고 그 내용을 취소하는 새 커밋을 추가하는 방식이었다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;reset
= 이력을 지운다
= push 전 로컬 정리에 적합

revert
= 이력을 추가한다
= 이미 공유된 브랜치에서 안전
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reset도 세 가지 모드가 있었다.&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;--soft
= 커밋만 취소, staging 유지

--mixed
= 커밋과 staging 취소, 파일은 유지

--hard
= 커밋, staging, 파일 변경까지 되돌림
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;-hard는 가장 위험하지만, 실수했더라도 reflog로 복구할 수 있다는 점도 같이 봤다. 그래도 공유 브랜치에서는 reset보다 revert를 쓰는 것이 안전하다는 점이 더 중요하게 남았다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stash는 커밋하지 않은 작업을 잠시 보관하는 기능이었다. 아직 커밋하기 애매한 작업 중인데 급하게 브랜치를 바꿔야 할 때 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;git stash push -m &quot;WIP: new feature 작업 중&quot;

git stash list

git stash pop
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pop은 꺼내면서 stash 목록에서 제거하고, apply는 꺼내도 목록에 남겨둔다. 이 차이는 여러 환경에 같은 변경사항을 적용해야 할 때 중요할 것 같다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. cherry-pick은 필요한 커밋만 가져오는 방식이었다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cherry-pick은 다른 브랜치의 특정 커밋만 현재 브랜치로 가져오는 기능이었다. 브랜치 전체를 merge하지 않고, 필요한 수정 하나만 가져올 수 있다는 점이 특징이었다.&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;git cherry-pick &amp;lt;commit_hash&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 feat/api 브랜치에 여러 커밋이 있는데, 그중 버그픽스 커밋 하나만 main에 반영하고 싶을 때 사용할 수 있다. 다만 cherry-pick은 커밋을 복사하는 것이기 때문에 원본 커밋과 새 커밋의 해시는 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기능은 편리하지만 남용하면 이력이 복잡해질 수 있다. 그래서 급한 핫픽스나 릴리즈 브랜치에 특정 커밋만 가져와야 할 때처럼 목적이 분명할 때 쓰는 게 좋아 보였다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 오후에는 Athena와 Bedrock을 연결한 Skill 흐름을 봤다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오후에는 Git과는 다른 방향으로, AWS 기반 분석 자동화 흐름을 봤다. 핵심은 nemotron_kr.personas_new 같은 인구통계성 데이터를 대상으로, 사용자의 질문을 받아 SQL을 만들고 Athena로 실행한 뒤, Bedrock 모델이 인사이트를 생성해 Markdown 보고서로 출력하는 구조였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흐름은 대략 이렇게 정리됐다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;사용자 질문
&amp;rarr; 분석 차원 파악
&amp;rarr; SQL 템플릿 선택
&amp;rarr; Athena 실행
&amp;rarr; Bedrock으로 인사이트 생성
&amp;rarr; Markdown 보고서 출력
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Skill 파일에서는 generate_report(user_question) 한 번으로 이 과정을 자동화하는 형태가 정리되어 있었다. 단, 중요한 제한도 있었다. Opus처럼 비싼 모델 호출은 금지되어 있었고, Sonnet이나 Haiku 모델을 사용해야 했다. 또 Athena workgroup은 student로 고정하고, LLM이 만든 SQL은 실행 전에 사람이 확인해야 한다는 조건도 있었다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;주의할 점

1. 비싼 모델 호출 금지
2. Athena workgroup은 student 사용
3. max_tokens 제한 확인
4. SQL 결과와 보고서 수치 일치 여부 검증
5. LLM이 만든 SQL은 사람이 확인
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 &amp;ldquo;AI가 보고서를 자동으로 만들어준다&amp;rdquo;보다 &amp;ldquo;AI가 중간 과정을 도와주지만, 실행 SQL과 수치 검증은 사람이 책임져야 한다&amp;rdquo;는 쪽으로 이해했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;31일차는 오전과 오후의 주제가 달랐지만, 둘 다 &amp;ldquo;도구를 제대로 쓰려면 흐름을 알아야 한다&amp;rdquo;는 공통점이 있었다. Git은 단순히 명령어를 외우는 것이 아니라 Working Directory, Staging Area, Local Repository, Remote Repository 사이에서 변경사항이 어떻게 이동하는지 이해해야 했다. 그래야 branch, merge, reset, revert, stash, cherry-pick이 어떤 상황에서 필요한지 구분할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오후의 AWS Skill 흐름도 마찬가지였다. 겉으로는 질문을 넣으면 보고서가 나오는 구조처럼 보이지만, 실제로는 SQL 템플릿 선택, Athena 실행, Bedrock 호출, Markdown 렌더링이 연결되어 있었다. 특히 LLM이 생성한 결과를 그대로 믿는 것이 아니라, SQL 결과와 보고서 수치가 맞는지 검증해야 한다는 점이 중요했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Git은 코드 이력을 안전하게 다루는 도구였고, AWS Skill은 분석 과정을 자동화하는 구조였다. 둘 다 편리하지만, 내부 흐름을 모르면 문제가 생겼을 때 어디서 틀어졌는지 찾기 어렵겠다는 생각이 들었다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;31일차는 Git으로 코드 변경 이력을 관리하는 흐름과, AWS 기반 Skill로 분석 보고서를 자동화하는 흐름을 함께 보면서 도구의 내부 단계를 이해해야 한다는 점을 확인한 날이었다.&lt;/b&gt;&lt;/p&gt;</description>
      <category>[SK플래닛] ASAC 빅데이터전문가 11기/학습기록</category>
      <category>Branch</category>
      <category>cherrypick</category>
      <category>Conflict</category>
      <category>git</category>
      <category>github</category>
      <category>Merge</category>
      <category>rebase</category>
      <category>reset</category>
      <category>revert</category>
      <category>versioncontrol</category>
      <author>seooeyeong</author>
      <guid isPermaLink="true">https://seo0west0.tistory.com/91</guid>
      <comments>https://seo0west0.tistory.com/91#entry91comment</comments>
      <pubDate>Mon, 1 Jun 2026 08:57:20 +0900</pubDate>
    </item>
    <item>
      <title>[SK플래닛] ASAC 빅데이터전문가 11기 | 29일차</title>
      <link>https://seo0west0.tistory.com/90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;29일차는 오전에는 SVM의 기본 아이디어를 보고, 이후에는 Kaggle House Prices 데이터를 이용해 회귀 모델링 전처리 흐름을 정리한 날이었다. SVM에서는 &amp;ldquo;데이터를 어떤 경계로 나눌 것인가&amp;rdquo;를 봤고, House Prices 실습에서는 &amp;ldquo;train과 test를 같은 기준으로 전처리하려면 어떻게 해야 하는가&amp;rdquo;를 봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이날 가장 크게 남은 건 모델 자체보다 &lt;b&gt;전처리 기준을 train에서만 만들어야 한다&lt;/b&gt;는 점이었다. 결측치를 채우는 기준, 인코딩 규칙, 스케일링 기준까지 전부 train에서 만들고 test에는 적용만 해야 했다. 코드가 길어지는 이유도 결국 이 기준을 지키기 위해서였다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. SVM은 margin이 넓은 경계선을 찾는다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SVM은 데이터를 구분하는 경계선을 찾는 모델이다. 2차원에서는 직선, 3차원에서는 평면, 더 높은 차원에서는 초평면으로 데이터를 나눈다. 단순히 아무 선이나 긋는 것이 아니라, 두 클래스 사이의 margin이 가장 넓어지는 경계선을 찾는다는 점이 핵심이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 선형회귀처럼 오차를 줄이는 모델과 비슷하게 느껴졌는데, SVM은 관점이 조금 달랐다. 회귀는 예측값과 실제값의 차이를 줄이는 쪽이라면, SVM은 양쪽 클래스가 경계선에서 얼마나 떨어져 있는지를 본다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;SVM의 기본 흐름

1. 데이터를 나눌 수 있는 경계선을 찾는다.
2. 양쪽 클래스에서 가장 가까운 점들을 기준으로 margin을 본다.
3. margin이 가장 넓어지는 경계선을 선택한다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 현실 데이터는 항상 깔끔하게 나뉘지 않는다. 그래서 일부 오분류를 어느 정도 허용할지 정해야 하는데, 이때 중요한 파라미터가 C였다.&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;C가 크다
&amp;rarr; 개별 데이터의 에러를 강하게 줄이려 함
&amp;rarr; train 데이터에 타이트하게 맞을 수 있음

C가 작다
&amp;rarr; 일부 에러를 허용
&amp;rarr; 경계가 더 느슨해질 수 있음
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 KNN에서 k값을 조절하던 것과 비슷하게 느껴졌다. 모델마다 조절하는 방식은 다르지만, 결국 underfitting과 overfitting 사이에서 적당한 지점을 찾는 과정이었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. House Prices는 회귀 문제지만 시계열은 아니었다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에는 Kaggle의 House Prices 데이터를 사용했다. train에는 정답인 SalePrice가 있고, test에는 이 정답 컬럼이 빠져 있었다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;train_df = pd.read_csv(train_path)
test_df = pd.read_csv(test_path)

print(train_df.shape)
print(test_df.shape)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(1460, 81)
(1459, 80)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;train과 test의 컬럼 수가 1개 차이 나는 이유는 SalePrice 때문이다. 이 데이터의 목적은 특정 조건을 가진 주택의 가격을 예측하는 것이다. 주택 가격 데이터라서 시간 흐름을 떠올릴 수도 있지만, 이번 실습은 &amp;ldquo;시간에 따라 가격이 어떻게 변할까?&amp;rdquo;가 아니라 &amp;ldquo;이런 조건의 주택은 얼마일까?&amp;rdquo;를 푸는 회귀 문제였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 차이를 먼저 잡는 게 중요했다. 같은 집값 데이터라도 시간 흐름을 예측하면 시계열이고, 특정 시점의 속성으로 가격을 예측하면 회귀 문제가 된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 회귀에서는 target 분포와 이상치를 먼저 봤다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회귀 문제에서는 target의 분포와 이상치를 먼저 확인해야 했다. GrLivArea와 SalePrice를 그려보니, 주거 면적이 4000을 넘는 일부 샘플이 튀어 보였다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;sns.lmplot(data=train_df, y=&quot;SalePrice&quot;, x=&quot;GrLivArea&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;prolog&quot;&gt;&lt;code&gt;train_df[train_df[&quot;GrLivArea&quot;] &amp;gt; 4000]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 샘플은 4개였고, 이번 실습에서는 전체 회귀 관계를 크게 왜곡할 수 있다고 보고 제거했다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;train_df.drop(
    train_df[train_df[&quot;GrLivArea&quot;] &amp;gt; 4000].index,
    inplace=True
)

train_df.shape
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(1456, 81)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 이상치는 무조건 지우는 것이 아니라는 점도 같이 남았다. 고가 주택 시장까지 잘 맞춰야 하는 목적이라면 오히려 중요한 샘플일 수 있다. 이번에는 전체적인 회귀 모델의 안정성을 위해 제거한 것이고, 실제 프로젝트에서는 목적에 따라 판단해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그다음에는 SalePrice 분포를 봤다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;sns.histplot(train_df[&quot;SalePrice&quot;])
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가격 데이터는 오른쪽으로 긴 꼬리를 가진 형태였다. 고가 주택이 적지만 값이 매우 크기 때문에 분포가 한쪽으로 쏠려 있었다. 그래서 로그 변환을 적용했다.&lt;/p&gt;
&lt;pre class=&quot;prolog&quot;&gt;&lt;code&gt;train_df[&quot;SalePrice&quot;] = np.log1p(train_df[&quot;SalePrice&quot;])

sns.histplot(train_df[&quot;SalePrice&quot;])
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델은 로그 변환된 값을 예측하게 된다. 따라서 나중에 제출할 때는 np.expm1()으로 다시 원래 가격 단위로 되돌려야 했다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 결측치는 컬럼 의미에 따라 다르게 채웠다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전처리에서는 먼저 Id를 따로 보관하고 제거했다. Id는 학습에는 필요 없지만 Kaggle 제출에는 필요하기 때문이다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;train_id = train_df.loc[:, &quot;Id&quot;]
test_id = test_df.loc[:, &quot;Id&quot;]

train_df.drop(&quot;Id&quot;, axis=1, inplace=True)
test_df.drop(&quot;Id&quot;, axis=1, inplace=True)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 train에서 정답지인 SalePrice를 분리했다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;y_df = train_df.loc[:, &quot;SalePrice&quot;]
train_df.drop(&quot;SalePrice&quot;, axis=1, inplace=True)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 train과 test는 같은 feature 컬럼을 가져야 한다. 결측치를 확인해보니 PoolQC, MiscFeature, Alley, Fence처럼 대부분 비어 있는 컬럼도 있었고, LotFrontage처럼 일부만 비어 있는 컬럼도 있었다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;train_ms = pd.DataFrame(
    train_df.isnull().sum(),
    columns=[&quot;MissCount&quot;]
)

train_ms = train_ms.loc[train_ms[&quot;MissCount&quot;] &amp;gt; 0, :]
train_ms[&quot;MissPrecent&quot;] = (train_ms[&quot;MissCount&quot;] / len(train_df)) * 100

train_ms.sort_values(by=&quot;MissPrecent&quot;, ascending=False)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결측치 처리는 하나의 방식으로 밀어붙이지 않았다. 값이 없다는 것 자체가 의미인 범주형 컬럼은 &quot;None&quot;으로 채웠고, 시설이 없어서 면적이나 연도가 없는 경우에 가까운 수치형 컬럼은 0으로 채웠다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;for col in nones:
    train_df.fillna({col: &quot;None&quot;}, inplace=True)
    test_df.fillna({col: &quot;None&quot;}, inplace=True)

for col in zeros:
    train_df.fillna({col: 0}, inplace=True)
    test_df.fillna({col: 0}, inplace=True)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 Utilities처럼 대부분 같은 값으로 들어 있는 컬럼은 feature로 쓰기 어렵다고 보고 제거했다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;train_df.drop(&quot;Utilities&quot;, axis=1, inplace=True)
test_df.drop(&quot;Utilities&quot;, axis=1, inplace=True)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서 계속 신경 써야 했던 것은 &lt;b&gt;train에서 판단한 기준을 test에도 그대로 적용한다&lt;/b&gt;는 점이었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. LotFrontage는 Neighborhood별 중앙값으로 채웠다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 기억에 남는 전처리는 LotFrontage였다. 이 컬럼은 도로와 연결된 선형 피트 정보인데, 단순히 전체 평균으로 채우면 지역별 차이가 사라질 수 있다. 그래서 Neighborhood별 중앙값을 기준으로 채웠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;train에서는 groupby().transform()을 사용했다.&lt;/p&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;train_df[&quot;LotFrontage&quot;] = train_df.groupby(
    by=&quot;Neighborhood&quot;
)[&quot;LotFrontage&quot;].transform(
    lambda x: x.fillna(x.median())
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;test에는 train에서 만든 기준을 적용해야 하므로, 먼저 train 기준의 reference table을 만들었다.&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;ref_table = train_df.groupby(
    by=&quot;Neighborhood&quot;
)[&quot;LotFrontage&quot;].agg(&quot;median&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그다음 test에 merge해서 결측치에만 train 기준 중앙값을 넣었다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;test_df = pd.merge(
    test_df,
    ref_table,
    how=&quot;left&quot;,
    left_on=&quot;Neighborhood&quot;,
    right_on=&quot;Neighborhood&quot;
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;merge 이후에는 LotFrontage_x, LotFrontage_y처럼 컬럼명이 나뉘어서, 기존 test 값이 비어 있는 경우에만 LotFrontage_y를 넣고 다시 컬럼명을 정리했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 단순 결측치 처리보다 훨씬 실전적인 느낌이었다. 전체 평균으로 한 번에 채우는 것보다, 유사한 그룹을 기준으로 값을 채우는 방식이 더 자연스러울 수 있었다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 인코딩과 스케일링도 train 기준으로 맞췄다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자형 컬럼은 모델이 바로 사용할 수 없기 때문에 인코딩이 필요했다. 순서나 등급성이 있다고 본 컬럼은 Label Encoding을 적용했다. 여기서도 fit()은 train에만 사용했다.&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;for col in ordinals:
    le = LabelEncoder()
    le.fit(train_df[col])

    train_df[col] = le.transform(train_df[col])

    prev_classes = list(le.classes_)

    for label in np.unique(test_df[col]):
        if label not in prev_classes:
            prev_classes.append(label)

    le.classes_ = np.array(prev_classes)
    test_df[col] = le.transform(test_df[col])
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;test에서 처음 보는 값이 나올 수 있어서 unseen label도 처리했다. 코드가 길어지는 이유는 결국 train 기준을 유지하면서도 test에서 에러가 나지 않도록 하기 위해서였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;One-Hot Encoding에서는 train과 test의 컬럼 수가 달라졌다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;train_df = pd.get_dummies(train_df, columns=nominals, prefix_sep=&quot;_&quot;)
test_df = pd.get_dummies(test_df, columns=nominals, prefix_sep=&quot;_&quot;)

print(train_df.shape)
print(test_df.shape)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(1456, 248)
(1459, 236)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;train에만 있는 더미 컬럼은 test에 0으로 추가하고, test에만 생긴 더미 컬럼은 제거했다. 컬럼 수가 같아진 뒤에도 컬럼 순서를 train 기준으로 다시 맞췄다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;test_df = pd.DataFrame(test_df, columns=train_df.columns)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스케일링도 마찬가지였다. StandardScaler는 train에만 fit()하고, test에는 transform()만 적용했다.&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;scaler = StandardScaler()

scaler.fit(train_df)

X_train = scaler.transform(train_df)
X_train = pd.DataFrame(X_train, columns=train_df.columns)

X_test = scaler.transform(test_df)
X_test = pd.DataFrame(X_test, columns=train_df.columns)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막에 컬럼 수와 순서가 맞는지 확인했다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;print(X_train.shape)
print(X_test.shape)
print((X_train.columns != X_test.columns).sum())
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;(1456, 248)
(1459, 248)
0
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 상태가 되어야 모델에 넣을 준비가 된 것이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. Lasso와 Ridge로 회귀 모델을 돌렸다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델링에서는 K-Fold를 사용했다. 이번에는 validation을 따로 빼기보다, train 내부에서 K-Fold로 성능을 확인하는 흐름이었다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;kfold = KFold(
    n_splits=6,
    shuffle=True,
    random_state=1234
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평가 지표는 MSE 계열을 사용했다. scikit-learn에서는 작을수록 좋은 지표를 scoring에 사용할 때 neg_가 붙는 구조라서, 다시 음수를 붙여 양수 MSE로 바꿔 사용했다.&lt;/p&gt;
&lt;pre class=&quot;autohotkey&quot;&gt;&lt;code&gt;def mse_baseline(model):
    mse = -cross_val_score(
        model,
        X_train,
        y_df,
        cv=kfold,
        scoring=&quot;neg_mean_squared_error&quot;
    )
    return mse
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Lasso를 돌리고, 이후 RandomizedSearchCV로 alpha, max_iter, tol을 튜닝했다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;lasso_model = Lasso(random_state=1234)

parameters = {
    &quot;alpha&quot;: [1, 0.001, 0.1, 2],
    &quot;max_iter&quot;: [1000, 3000],
    &quot;tol&quot;: [0.0001, 0.00001, 0.1]
}

lasso_rgs = RandomizedSearchCV(
    lasso_model,
    param_distributions=parameters,
    n_iter=10,
    cv=kfold,
    random_state=1234,
    n_jobs=-1,
    scoring=&quot;neg_mean_squared_error&quot;
)

lasso_rgs.fit(X_train, y_df)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예측값은 로그 스케일이므로 다시 원래 가격 단위로 바꿨다.&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;lasso_rgs_ypred = lasso_rgs.best_estimator_.predict(X_test)

y_pred1 = np.expm1(lasso_rgs_ypred)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ridge도 비슷한 흐름으로 진행했다. Lasso는 L1 규제, Ridge는 L2 규제를 사용한다. 둘 다 선형회귀 기반이지만, feature가 많고 one-hot 컬럼이 많이 생긴 상황에서 규제를 통해 과적합을 줄이는 역할을 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;29일차는 SVM의 margin 개념과 House Prices 회귀 전처리 흐름을 함께 본 날이었다. SVM에서는 단순히 경계선을 긋는 것이 아니라, 두 클래스 사이의 margin을 최대화하고 C값으로 에러 허용 정도를 조절한다는 점이 남았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;House Prices 실습에서는 회귀 모델링 전의 준비가 훨씬 크게 다가왔다. 이상치를 확인하고, target을 로그 변환하고, 결측치를 컬럼 의미에 맞게 채우고, 인코딩과 스케일링까지 train 기준으로 맞춰야 했다. 특히 LotFrontage를 Neighborhood별 중앙값으로 채우는 과정은 단순 평균 대체보다 더 현실적인 전처리 방식처럼 느껴졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 이 날의 핵심은 모델을 돌리기 전에 train과 test를 같은 구조로 만드는 것이었다. 컬럼 수뿐 아니라 컬럼 순서, 인코딩 기준, 스케일링 기준까지 맞춰야 모델이 test를 제대로 해석할 수 있다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;29일차는 SVM의 경계면 개념을 잡고, House Prices 데이터로 train 기준 전처리와 회귀 모델링의 기본 흐름을 정리한 날이었다.&lt;/b&gt;&lt;/p&gt;</description>
      <category>[SK플래닛] ASAC 빅데이터전문가 11기/학습기록</category>
      <category>HousePrices</category>
      <category>LabelEncoding</category>
      <category>Lasso</category>
      <category>ONEHOTENCODING</category>
      <category>Ridge</category>
      <category>StandardScaler</category>
      <category>text SVM</category>
      <category>결측치처리</category>
      <category>데이터전처리</category>
      <category>회귀분석</category>
      <author>seooeyeong</author>
      <guid isPermaLink="true">https://seo0west0.tistory.com/90</guid>
      <comments>https://seo0west0.tistory.com/90#entry90comment</comments>
      <pubDate>Fri, 29 May 2026 10:55:41 +0900</pubDate>
    </item>
    <item>
      <title>Seaborn boxplot과 violinplot 차이 | 데이터 분포 시각화하기</title>
      <link>https://seo0west0.tistory.com/89</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;평균만 보면 데이터가 어떻게 퍼져 있는지 알 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분포를 보려면 최소한 &lt;b&gt;중앙값, 사분위수, 이상치, 쏠림 정도&lt;/b&gt;를 같이 봐야 하고, 이때 가장 많이 쓰는 그래프가 boxplot과 violinplot이다. 둘 다 분포를 보는 그래프지만, boxplot은 &lt;b&gt;요약 통계&lt;/b&gt;에 강하고, violinplot은 &lt;b&gt;분포 모양 자체&lt;/b&gt;를 보여주는 데 강하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 빠르게 정리하면 이렇다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;boxplot&lt;/b&gt;: 중앙값, 사분위수, 이상치 확인용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;violinplot&lt;/b&gt;: 값이 어디에 몰려 있는지, 분포가 어떻게 생겼는지 확인용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 차이를 이해하고 나면, 어떤 그래프를 먼저 봐야 할지 훨씬 쉬워진다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;평균만 보면 왜 부족할까&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;평균이 같아도 분포는 전혀 다를 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 어떤 데이터는 값이 고르게 퍼져 있을 수 있고, 다른 데이터는 특정 구간에 몰려 있을 수 있다. 또 이상치가 몇 개 섞여 있으면 평균은 쉽게 흔들린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 분포를 볼 때는 보통 아래를 함께 확인한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중심이 어디에 있는지&lt;/li&gt;
&lt;li&gt;값이 얼마나 퍼져 있는지&lt;/li&gt;
&lt;li&gt;이상치가 있는지&lt;/li&gt;
&lt;li&gt;한쪽으로 치우쳐 있는지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸 시각적으로 빠르게 보는 데 boxplot과 violinplot이 유용하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;boxplot이 보여주는 것&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;boxplot은 데이터 분포를 &lt;b&gt;요약된 통계 형태&lt;/b&gt;로 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프 하나로 아래 정보를 바로 읽을 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중앙값&lt;/li&gt;
&lt;li&gt;25% 지점(Q1)&lt;/li&gt;
&lt;li&gt;75% 지점(Q3)&lt;/li&gt;
&lt;li&gt;사분위 범위(IQR)&lt;/li&gt;
&lt;li&gt;이상치&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 boxplot은 &amp;ldquo;데이터가 대충 어디에 모여 있고, 이상치가 있는지&amp;rdquo;를 빠르게 확인할 때 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 이런 상황에서 유용하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 그룹을 한 번에 비교할 때&lt;/li&gt;
&lt;li&gt;이상치 유무를 먼저 볼 때&lt;/li&gt;
&lt;li&gt;분포를 간단하게 요약해서 보고 싶을 때&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한마디로 boxplot은 &lt;b&gt;요약형 분포 그래프&lt;/b&gt;다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;violinplot이 보여주는 것&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;violinplot은 boxplot처럼 요약 통계만 보여주는 게 아니라, &lt;b&gt;분포의 밀도와 모양&lt;/b&gt;까지 함께 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프가 넓어지는 부분은 값이 많이 몰려 있다는 뜻이고, 좁아지는 부분은 상대적으로 적다는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 violinplot을 보면 이런 걸 더 잘 볼 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;값이 어느 구간에 많이 몰려 있는지&lt;/li&gt;
&lt;li&gt;분포가 한쪽으로 치우쳐 있는지&lt;/li&gt;
&lt;li&gt;중간이 비고 양쪽에 몰린 형태인지&lt;/li&gt;
&lt;li&gt;여러 봉우리가 있는지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 violinplot은 단순히 &amp;ldquo;범위가 넓다&amp;rdquo;보다 &lt;b&gt;분포 모양 자체&lt;/b&gt;를 읽는 데 더 강하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한마디로 violinplot은 &lt;b&gt;형태형 분포 그래프&lt;/b&gt;다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;boxplot과 violinplot 차이&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 차이는 이렇게 보면 제일 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분 boxplot violinplot&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;강점&lt;/td&gt;
&lt;td&gt;중앙값, 사분위수, 이상치 확인&lt;/td&gt;
&lt;td&gt;분포 밀도와 모양 확인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;해석 방식&lt;/td&gt;
&lt;td&gt;통계 요약 중심&lt;/td&gt;
&lt;td&gt;형태 해석 중심&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;장점&lt;/td&gt;
&lt;td&gt;단순하고 비교가 쉬움&lt;/td&gt;
&lt;td&gt;데이터 쏠림과 밀집 구간이 잘 보임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;단점&lt;/td&gt;
&lt;td&gt;분포 모양은 잘 안 보임&lt;/td&gt;
&lt;td&gt;처음 보면 해석이 조금 낯설 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 데이터 분포를 볼 때 보통은 이렇게 생각하면 된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;이상치와 범위를 먼저 보고 싶다&lt;/b&gt; &amp;rarr; boxplot&lt;/li&gt;
&lt;li&gt;&lt;b&gt;분포 모양까지 보고 싶다&lt;/b&gt; &amp;rarr; violinplot&lt;/li&gt;
&lt;li&gt;&lt;b&gt;둘 다 보고 싶다&lt;/b&gt; &amp;rarr; 같이 그리기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에선 둘 중 하나만 고르기보다, 오히려 &lt;b&gt;나란히 같이 보는 경우&lt;/b&gt;가 많다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;같이 그리면 왜 좋은가&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;boxplot과 violinplot은 서로 대체 관계라기보다 &lt;b&gt;보완 관계&lt;/b&gt;에 가깝다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;boxplot은 요약이 빠르다&lt;/li&gt;
&lt;li&gt;violinplot은 분포 모양이 잘 보인다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 두 그래프를 나란히 두면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;중앙값은 비슷한데 분포 모양은 다르네&amp;rdquo;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 포인트를 더 쉽게 찾을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 데이터가 치우쳐 있거나, 특정 구간에 값이 몰려 있는 경우엔 boxplot만 봐서는 놓치는 정보가 violinplot에서 바로 보이기도 한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Seaborn에서 같이 그리는 방법&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Seaborn은 data, x, y, hue, ax 중심으로 그래프를 그린다. boxplot과 violinplot을 나란히 그리고 싶다면 matplotlib.pyplot.subplots()로 판을 만들고, 각 축(ax)에 그래프를 넣으면 된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;import matplotlib.pyplot as plt
import seaborn as sns

fig, axes = plt.subplots(nrows=1, ncols=2, sharey=True)

sns.boxplot(
    data=data,
    y=&quot;Total intl calls&quot;,
    ax=axes[0]
)

sns.violinplot(
    data=data,
    y=&quot;Total intl calls&quot;,
    ax=axes[1]
)

axes[0].set_title(&quot;Boxplot&quot;)
axes[1].set_title(&quot;Violinplot&quot;)

plt.tight_layout()
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드에서 중요한 건 세 가지다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. subplots()&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프를 여러 개 놓을 판을 만든다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. ax&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 그래프를 어느 위치에 그릴지 지정한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. sharey=True&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 그래프가 같은 y축 범위를 쓰게 해서 비교가 쉬워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 이 구조는 단순히 예쁘게 그리기 위한 게 아니라,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;같은 축 기준으로 분포를 비교하기 위해&lt;/b&gt; 쓰는 방식이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;이상치는 무조건 제거 대상이 아니다&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;boxplot을 보면 이상치가 눈에 잘 띈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 여기서 자주 하는 실수가 &amp;ldquo;이상치는 무조건 제거해야 한다&amp;rdquo;고 생각하는 거다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로는 분석 목적에 따라 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쇼핑몰 매출 데이터라면 이상치는 오류가 아니라 &lt;b&gt;고액 구매 고객&lt;/b&gt;일 수 있고&lt;/li&gt;
&lt;li&gt;통신 사용량 데이터라면 이상치는 &lt;b&gt;헤비 유저&lt;/b&gt;일 수 있다&lt;/li&gt;
&lt;li&gt;센서 데이터라면 진짜 오류일 가능성이 더 높을 수도 있다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 이상치는 제거 여부를 먼저 정하는 게 아니라,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜 이상치처럼 보이는지 해석하는 것&lt;/b&gt;이 먼저다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;어떤 그래프를 먼저 볼까&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 보통 이렇게 간다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;빠르게 확인할 때&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 boxplot으로 범위, 중앙값, 이상치를 본다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;분포가 찝찝할 때&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그다음 violinplot으로 실제 값이 어디에 몰렸는지 확인한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;보고서나 비교 분석&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘을 나란히 그려서 요약과 모양을 같이 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉 둘 중 하나만 정답인 게 아니라,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;확인하고 싶은 정보가 다르기 때문에 선택 기준이 달라진다&lt;/b&gt;고 보는 게 맞다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;boxplot과 violinplot은 둘 다 분포를 보는 그래프지만, 보는 방식이 다르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;boxplot은 중앙값, 사분위수, 이상치를 빠르게 확인하는 데 좋고, violinplot은 값이 어디에 몰려 있는지와 분포 모양을 읽는 데 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 분포를 볼 때는 평균만 보지 말고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소한 &lt;b&gt;요약 통계와 분포 형태&lt;/b&gt;를 함께 확인하는 습관이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 둘을 같이 보면 데이터가 훨씬 덜 평면적으로 보인다!&lt;/p&gt;</description>
      <category>Data Analytics/시각화</category>
      <category>boxplot</category>
      <category>matplotlib</category>
      <category>Python시각화</category>
      <category>Seaborn</category>
      <category>subplots</category>
      <category>ViolinPlot</category>
      <category>데이터분석</category>
      <category>데이터분포</category>
      <category>사분위수</category>
      <category>이상치</category>
      <author>seooeyeong</author>
      <guid isPermaLink="true">https://seo0west0.tistory.com/89</guid>
      <comments>https://seo0west0.tistory.com/89#entry89comment</comments>
      <pubDate>Thu, 28 May 2026 09:53:00 +0900</pubDate>
    </item>
  </channel>
</rss>