<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>bonggyulim 님의 블로그</title>
    <link>https://bonggyulim.tistory.com/</link>
    <description>bonggyulim 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Fri, 15 May 2026 00:46:03 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>bonggyulim</managingEditor>
    <item>
      <title>추가로 알아두면 좋은 전처리: PCA, Vectorization, SMOTE</title>
      <link>https://bonggyulim.tistory.com/40</link>
      <description>&lt;p data-end=&quot;252&quot; data-start=&quot;137&quot; data-ke-size=&quot;size16&quot;&gt;전처리를 하다 보면 결측치 처리, 인코딩, 스케일링만으로 끝나지 않는 경우도 많다.&lt;br /&gt;데이터 형태와 문제 유형에 따라 &lt;b&gt;차원축소&lt;/b&gt;, &lt;b&gt;벡터화&lt;/b&gt;, &lt;b&gt;클래스 불균형 처리&lt;/b&gt;까지 함께 고려할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;322&quot; data-start=&quot;254&quot; data-ke-size=&quot;size16&quot;&gt;다만 이 기법들은 모든 문제에 무조건 사용하는 것이 아니라,&lt;br /&gt;데이터 특성과 모델 목적에 맞게 선택적으로 적용해야 한다.&lt;/p&gt;
&lt;h3 data-end=&quot;322&quot; data-start=&quot;254&quot; data-ke-size=&quot;size23&quot;&gt;1. PCA&lt;/h3&gt;
&lt;p data-end=&quot;499&quot; data-start=&quot;341&quot; data-ke-size=&quot;size16&quot;&gt;차원축소는 feature 수가 많을 때 정보를 최대한 유지하면서 차원을 줄이는 방법이다.&lt;br /&gt;컬럼이 너무 많으면 학습 속도가 느려지고, 불필요한 노이즈가 많아질 수 있다.&lt;br /&gt;이럴 때 대표적으로 &lt;b&gt;PCA(Principal Component Analysis)&lt;/b&gt; 를 사용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1775544679476&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.decomposition import PCA

pca = PCA(n_components=2)

X_train_pca = pca.fit_transform(X_train_standard)
X_test_pca = pca.transform(X_test_standard)

print(&quot;원본 shape:&quot;, X_train_standard.shape)
print(&quot;축소 후 shape:&quot;, X_train_pca.shape)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. TF-IDF 벡터화&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;벡터화는 &lt;b&gt;텍스트 데이터를 숫자 형태로 바꾸는 작업&lt;/b&gt;이다.&lt;br /&gt;머신러닝 모델은 문자열 자체를 직접 처리하지 못하기 때문에,&lt;br /&gt;문장을 단어 빈도나 중요도 기반의 숫자 벡터로 변환한 뒤 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1775544722068&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from sklearn.feature_extraction.text import TfidfVectorizer

tfidf_vectorizer = TfidfVectorizer()
X_train_tfidf = tfidf_vectorizer.fit_transform(X_train_text)
X_test_tfidf = tfidf_vectorizer.transform(X_test_text)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. SMOTE&lt;/h3&gt;
&lt;p data-end=&quot;2307&quot; data-start=&quot;2183&quot; data-ke-size=&quot;size16&quot;&gt;SMOTE는 &lt;b&gt;클래스 불균형이 있는 분류 문제&lt;/b&gt;에서 소수 클래스를 늘려 학습 균형을 맞추는 방법이다.&lt;br /&gt;예를 들어 정상 데이터는 많고 이상 데이터는 적다면, 모델이 다수 클래스를 중심으로만 학습할 가능성이 커진다.&lt;/p&gt;
&lt;p data-end=&quot;2343&quot; data-start=&quot;2309&quot; data-ke-size=&quot;size16&quot;&gt;이럴 때 SMOTE를 사용하면 소수 클래스를 보강할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1775544867244&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from imblearn.over_sampling import SMOTE
from sklearn.model_selection import train_test_split

X_train_cls, X_test_cls, y_train_cls, y_test_cls = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

smote = SMOTE(random_state=42)
X_train_smote, y_train_smote = smote.fit_resample(X_train_cls, y_train_cls)

print(&quot;원본 학습 데이터 분포:&quot;)
print(y_train_cls.value_counts())

print(&quot;SMOTE 적용 후 분포:&quot;)
print(y_train_smote.value_counts())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;주의할 점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;146&quot; data-start=&quot;36&quot; data-section-id=&quot;1jssz6u&quot;&gt;&lt;b&gt;차원축소(PCA), 벡터화(TF-IDF/CountVectorizer)&lt;/b&gt;&lt;br /&gt;&amp;rarr; &lt;b&gt;학습 데이터로만 fit&lt;/b&gt; 하고,&lt;br /&gt;&amp;rarr; 테스트 데이터에는 &lt;b&gt;transform만&lt;/b&gt; 한다.&lt;/li&gt;
&lt;li data-end=&quot;231&quot; data-start=&quot;148&quot; data-section-id=&quot;sf8ulj&quot;&gt;&lt;b&gt;SMOTE&lt;/b&gt;&lt;br /&gt;&amp;rarr; &lt;b&gt;학습 데이터에만 적용&lt;/b&gt;해서 resample 한다.&lt;br /&gt;&amp;rarr; 테스트 데이터에는 &lt;b&gt;적용하지 않는다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AI dev/Machine Learning</category>
      <author>bonggyulim</author>
      <guid isPermaLink="true">https://bonggyulim.tistory.com/40</guid>
      <comments>https://bonggyulim.tistory.com/40#entry40comment</comments>
      <pubDate>Tue, 7 Apr 2026 15:56:29 +0900</pubDate>
    </item>
    <item>
      <title>딥러닝 - RNN</title>
      <link>https://bonggyulim.tistory.com/39</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;RNN 이란&lt;/span&gt;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;RNN(Recurrent Neural Network)은 &lt;b&gt;순서가 있는 데이터(Sequential Data)&lt;/b&gt; 를 처리하기 위해 만든 신경망이다.&lt;br&gt;일반적인 신경망은 입력 하나하나를 서로 독립적으로 처리하지만, RNN은 &lt;b&gt;이전 입력의 정보까지 함께 반영&lt;/b&gt;할 수 있다.&lt;br&gt;그래서 RNN은 다음과 같은 문제에 자주 사용된다.&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;li&gt;센서 시계열 분석&lt;/li&gt;&lt;li&gt;행동 인식&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 RNN은 시퀀스가 길어질수록 오래된 정보를 잘 기억하지 못하는 한계가 있다.&lt;br&gt;이 한계를 보완한 구조가 &lt;b&gt;LSTM(Long Short-Term Memory)&lt;/b&gt; 이다.&lt;br&gt;LSTM은 RNN처럼 순차 데이터를 처리하면서도,&lt;br&gt;&lt;b&gt;중요한 정보는 오래 기억하고 불필요한 정보는 버릴 수 있도록&lt;/b&gt; 설계된 모델이다.&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpEvCz/dJMcaax56Cn/thKw2MU9kNaGljKvGtupX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpEvCz/dJMcaax56Cn/thKw2MU9kNaGljKvGtupX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpEvCz/dJMcaax56Cn/thKw2MU9kNaGljKvGtupX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpEvCz%2FdJMcaax56Cn%2FthKw2MU9kNaGljKvGtupX1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;824&quot; height=&quot;207&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot; style=&quot;text-align: center;&quot;&gt;&lt;b&gt; 입력 시퀀스 → 이전 정보와 현재 입력 반영 → hidden state 갱신 → 반복 → 최종 출력&amp;nbsp;&lt;/b&gt;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot;&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;RNN의 동작 과정&lt;/h3&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 입력 시퀀스&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;RNN은 데이터를 한 번에 처리하지 않고,&lt;br&gt;&lt;b&gt;시간 순서대로 하나씩 입력받는다.&lt;/b&gt;&lt;br&gt;예를 들어 시계열 데이터가 다음과 같다고 하자.&lt;br&gt;x1, x2, x3, x4&lt;br&gt;그러면 RNN은 다음과 같이 처리한다.&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;x1 처리&lt;/li&gt;&lt;li&gt;x2 처리 + 이전 정보 반영&lt;/li&gt;&lt;li&gt;x3 처리 + 이전 정보 반영&lt;/li&gt;&lt;li&gt;x4 처리 + 이전 정보 반영&lt;/li&gt;&lt;/ul&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. Hidden State&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;RNN의 핵심은 &lt;b&gt;Hidden State(은닉 상태)&lt;/b&gt; 다.&lt;br&gt;Hidden State는 쉽게 말하면 &lt;b&gt;이전까지 입력된 정보의 요약본&lt;/b&gt;이다.&lt;br&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_t&lt;/li&gt;&lt;li&gt;이전 hidden state h_(t-1)&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;를 함께 사용해서 새로운 hidden state h_t를 만든다.&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot;&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;RNN 예제&lt;/h3&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;import tensorflow as tf
from tensorflow.keras import models, layers

# 예시 데이터 shape: (batch, time_steps, features)
# 예: 시퀀스 길이 50, 특성 수 3

model = models.Sequential([
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;layers.SimpleRNN(32, input_shape=(50, 3)),
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;layers.Dense(3, activation='softmax')
])

# 모델 컴파일
model.compile(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;optimizer='adam',
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;loss='sparse_categorical_crossentropy',
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;metrics=['accuracy']
)

model.summary()&lt;/code&gt;&lt;/pre&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;RNN에서 주의할 점&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;1) RNN은 보통 &lt;b&gt;3차원의 입력&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;(batch, time_steps, features)&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;2) &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;시계열 데이터를 다룰 때는 일반적인 표 데이터처럼 순서를 무작정 섞으면 안 된다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;3) 긴 시퀀스에서는&lt;b&gt; LSTM&lt;/b&gt;이나 &lt;b&gt;GRU&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;&lt;b&gt;LSTM&lt;/b&gt;: 중요한 정보를 더 오래 기억할 수 있도록 만든 구조&lt;/li&gt;&lt;li&gt;&lt;b&gt;GRU&lt;/b&gt;: LSTM보다 구조를 단순화한 모델&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot;&gt;</description>
      <category>AI dev/Deep Learning</category>
      <author>bonggyulim</author>
      <guid isPermaLink="true">https://bonggyulim.tistory.com/39</guid>
      <comments>https://bonggyulim.tistory.com/39#entry39comment</comments>
      <pubDate>Tue, 7 Apr 2026 15:46:20 +0900</pubDate>
    </item>
    <item>
      <title>딥러닝 - CNN</title>
      <link>https://bonggyulim.tistory.com/38</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;CNN이란&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;285&quot; data-start=&quot;135&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;CNN(Convolutional Neural Network)은 이미지처럼 &lt;b&gt;가로&amp;middot;세로 형태를 가진 데이터&lt;/b&gt;를 처리하는 데 강한 딥러닝 모델이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;일반적인 신경망은 이미지를 1차원으로 펼쳐서 처리하지만, CNN은 이미지의 &lt;b&gt;공간적 특징&lt;/b&gt;을 유지한 채 학습한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;316&quot; data-start=&quot;287&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그래서 CNN은 다음과 같은 문제에서 많이 사용된다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;367&quot; data-start=&quot;318&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;329&quot; data-start=&quot;318&quot; data-section-id=&quot;17b8ghj&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;손글씨 숫자 분류&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;341&quot; data-start=&quot;330&quot; data-section-id=&quot;1pfabg0&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;얼굴 이미지 분류&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;356&quot; data-start=&quot;342&quot; data-section-id=&quot;vlozdu&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;동물/사물 이미지 분류&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;367&quot; data-start=&quot;357&quot; data-section-id=&quot;1q18q11&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;의료 영상 분석&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1121&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dpFkmT/dJMcacbAMaV/kFSfjYVQkX67eN48kq4oG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dpFkmT/dJMcacbAMaV/kFSfjYVQkX67eN48kq4oG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dpFkmT/dJMcacbAMaV/kFSfjYVQkX67eN48kq4oG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdpFkmT%2FdJMcacbAMaV%2FkFSfjYVQkX67eN48kq4oG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1121&quot; height=&quot;381&quot; data-origin-width=&quot;1121&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;720&quot; data-start=&quot;631&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 입력 이미지 &amp;rarr; Convolution &amp;rarr; ReLU &amp;rarr; Pooling &amp;rarr; 특징 추출 반복 &amp;rarr; Flatten &amp;rarr; Dense Layer &amp;rarr; 출력 &lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;512&quot; data-start=&quot;494&quot; data-section-id=&quot;373u4n&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;CNN의 동작 과정 &lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-end=&quot;512&quot; data-start=&quot;494&quot; data-section-id=&quot;373u4n&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1. Convolution&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;575&quot; data-start=&quot;513&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;필터(커널)를 이미지 위로 이동시키며 특징(선, 모서리, 곡선)을 추출한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/02YPS/dJMcacbAMMR/fUIzqkObHhuYR21vH2mVTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/02YPS/dJMcacbAMMR/fUIzqkObHhuYR21vH2mVTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/02YPS/dJMcacbAMMR/fUIzqkObHhuYR21vH2mVTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F02YPS%2FdJMcacbAMMR%2FfUIzqkObHhuYR21vH2mVTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;389&quot; height=&quot;129&quot; data-origin-width=&quot;389&quot; data-origin-height=&quot;129&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-end=&quot;588&quot; data-start=&quot;577&quot; data-section-id=&quot;oohjh0&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. ReLU&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;647&quot; data-start=&quot;589&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;음수 값을 0으로 바꾸는 활성화 함수다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;비선형성을 추가해 더 복잡한 패턴을 학습할 수 있게 만든다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8uOe1/dJMcacimOyj/zxIfDiyO9qsqLThPwdVyIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8uOe1/dJMcacimOyj/zxIfDiyO9qsqLThPwdVyIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8uOe1/dJMcacimOyj/zxIfDiyO9qsqLThPwdVyIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8uOe1%2FdJMcacimOyj%2FzxIfDiyO9qsqLThPwdVyIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;343&quot; height=&quot;257&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-end=&quot;663&quot; data-start=&quot;649&quot; data-section-id=&quot;1fex4pz&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3. Pooling&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;724&quot; data-start=&quot;664&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;특징맵의 크기를 줄여 계산량을 낮추고, 중요한 정보만 남긴다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;주로 MaxPooling을 많이 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;348&quot; data-origin-height=&quot;145&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRT7FI/dJMcagygZdF/LckEspUhVUi8VWwwBT20BK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRT7FI/dJMcagygZdF/LckEspUhVUi8VWwwBT20BK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRT7FI/dJMcagygZdF/LckEspUhVUi8VWwwBT20BK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRT7FI%2FdJMcagygZdF%2FLckEspUhVUi8VWwwBT20BK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;348&quot; height=&quot;145&quot; data-origin-width=&quot;348&quot; data-origin-height=&quot;145&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-end=&quot;740&quot; data-start=&quot;726&quot; data-section-id=&quot;14wvsyk&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;4. Flatten&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;762&quot; data-start=&quot;741&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2차원 특징맵을 1차원 벡터로 펼친다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-end=&quot;782&quot; data-start=&quot;764&quot; data-section-id=&quot;aocf1j&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;5. Dense Layer&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;809&quot; data-start=&quot;783&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;추출한 특징을 종합해서 최종 클래스를 예측한다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;809&quot; data-start=&quot;783&quot; data-ke-size=&quot;size23&quot;&gt;MNIST 예제&lt;/h3&gt;
&lt;pre id=&quot;code_1775533421118&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import tensorflow as tf
from tensorflow.keras import layers, models

# 1. MNIST 데이터 불러오기
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()

# 2. 정규화
x_train = x_train / 255.0
x_test = x_test / 255.0

# 3. CNN 입력 형태 맞추기
# (batch, height, width, channel)
x_train = x_train[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]

# 4. CNN 모델 구성
model = models.Sequential([
    layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
    layers.MaxPooling2D((2, 2)),

    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),

    layers.Flatten(),
    layers.Dense(128, activation='relu'),
    layers.Dense(10, activation='softmax')
])

# 5. 모델 컴파일
model.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

# 6. 학습
model.fit(x_train, y_train, epochs=5, batch_size=64, validation_split=0.1)

# 7. 평가
test_loss, test_acc = model.evaluate(x_test, y_test)
print(&quot;Test Accuracy:&quot;, test_acc)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CNN에서 주의할 점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) CNN은 보통 &lt;b&gt;4차원의 입력&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;(batch, height, width, channel)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) &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;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;x_train&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;x_train&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;255.0, &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;x_test&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;x_test&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;255.0&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) &lt;b&gt;출력층과 loss 함수&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;라벨이 0,1,2,3... 같은 정수면 &amp;rarr; sparse_categorical_crossentropy&lt;/li&gt;
&lt;li&gt;라벨이 [0,0,1,0,...] 같은 원-핫이면 &amp;rarr; categorical_crossentropy&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4)&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 data-end=&quot;1798&quot; data-start=&quot;1786&quot; data-section-id=&quot;1rgoskb&quot;&gt;Dropout 추가&lt;/li&gt;
&lt;li data-end=&quot;1826&quot; data-start=&quot;1799&quot; data-section-id=&quot;tcpqk9&quot;&gt;데이터 증강(Data Augmentation)&lt;/li&gt;
&lt;li data-end=&quot;1857&quot; data-start=&quot;1838&quot; data-section-id=&quot;1gj4wim&quot;&gt;Epoch 너무 크게 잡지 않기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5) Pooling을 너무 많이 하면 정보가 사라진다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;</description>
      <category>AI dev/Deep Learning</category>
      <author>bonggyulim</author>
      <guid isPermaLink="true">https://bonggyulim.tistory.com/38</guid>
      <comments>https://bonggyulim.tistory.com/38#entry38comment</comments>
      <pubDate>Tue, 7 Apr 2026 13:44:52 +0900</pubDate>
    </item>
    <item>
      <title>딥러닝의 기본 개념 정리</title>
      <link>https://bonggyulim.tistory.com/37</link>
      <description>&lt;p data-end=&quot;367&quot; data-start=&quot;189&quot; data-ke-size=&quot;size16&quot;&gt;딥러닝을 처음 공부할 때 가장 헷갈리는 부분은 &amp;ldquo;모델이 도대체 어떤 계산을 하고, 어떻게 학습되는가&amp;rdquo;이다.&lt;br /&gt;코드를 따라 치는 것은 가능해도, &lt;b&gt;입력값이 어떻게 예측값으로 바뀌고&lt;/b&gt;, &lt;b&gt;왜 가중치가 수정되는지&lt;/b&gt;, &lt;b&gt;활성화함수와 옵티마이저는 각각 언제 쓰이는지&lt;/b&gt;가 연결되지 않으면 전체 구조를 이해하기 어렵다.&lt;/p&gt;
&lt;p data-end=&quot;536&quot; data-start=&quot;369&quot; data-ke-size=&quot;size16&quot;&gt;이번 글에서는 딥러닝의 가장 기본이 되는 &lt;b&gt;퍼셉트론&lt;/b&gt;, &lt;b&gt;다층 퍼셉트론(MLP)&lt;/b&gt;, &lt;b&gt;행렬곱&lt;/b&gt;, &lt;b&gt;활성화함수&lt;/b&gt;, &lt;b&gt;순전파와 역전파&lt;/b&gt;, &lt;b&gt;옵티마이저&lt;/b&gt;까지 하나의 흐름으로 정리해보겠다.&lt;br /&gt;마지막에는 &lt;b&gt;정확도(ACC)를 높이기 위해 어떤 점을 고민해야 하는지&lt;/b&gt;도 함께 정리한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;559&quot; data-start=&quot;543&quot; data-section-id=&quot;frvegh&quot; data-ke-size=&quot;size23&quot;&gt;1. 딥러닝이란 무엇인가&lt;/h3&gt;
&lt;p data-end=&quot;665&quot; data-start=&quot;561&quot; data-ke-size=&quot;size16&quot;&gt;딥러닝은 입력 데이터 &lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&amp;nbsp;를 받아 정답 &lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 에 가깝게 예측하도록, 모델 내부의 &lt;b&gt;가중치(weight)&lt;/b&gt; 와 &lt;b&gt;편향(bias)&lt;/b&gt; 를 반복적으로 조정하는 학습 방법이다.&lt;/p&gt;
&lt;p data-end=&quot;745&quot; data-start=&quot;667&quot; data-ke-size=&quot;size16&quot;&gt;사람이 직접 규칙을 하나하나 만드는 것이 아니라, 모델이 데이터를 통해 &amp;ldquo;어떤 특징이 중요한지&amp;rdquo;를 스스로 학습하게 만드는 방식이다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;536&quot; data-start=&quot;369&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 입력 &amp;rarr; 선형 계산 &amp;rarr; 활성화함수 &amp;rarr; 예측 &amp;rarr; 손실 계산 &amp;rarr; 역전파 &amp;rarr; 옵티마이저 업데이트 &lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;891&quot; data-start=&quot;855&quot; data-ke-size=&quot;size16&quot;&gt;이 과정을 수많은 반복을 통해 수행하면서 모델의 성능을 높여간다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;891&quot; data-start=&quot;855&quot; data-ke-size=&quot;size23&quot;&gt;2. 퍼셉트론: 딥러닝의 가장 작은 계산 단위&lt;/h3&gt;
&lt;p data-end=&quot;1011&quot; data-start=&quot;928&quot; data-ke-size=&quot;size16&quot;&gt;딥러닝의 기본 단위는 &lt;b&gt;퍼셉트론(Perceptron)&lt;/b&gt; 이다.&lt;br /&gt;퍼셉트론은 여러 입력값을 받아 각각의 중요도를 반영한 뒤 하나의 값으로 합친다.&lt;/p&gt;
&lt;p data-end=&quot;1030&quot; data-start=&quot;1013&quot; data-ke-size=&quot;size16&quot;&gt;수식으로 표현하면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;315&quot; data-origin-height=&quot;49&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L3DYH/dJMcahKKfRV/4VmrK91GcSankLGlZKJhFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L3DYH/dJMcahKKfRV/4VmrK91GcSankLGlZKJhFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L3DYH/dJMcahKKfRV/4VmrK91GcSankLGlZKJhFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL3DYH%2FdJMcahKKfRV%2F4VmrK91GcSankLGlZKJhFk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;315&quot; height=&quot;49&quot; data-origin-width=&quot;315&quot; data-origin-height=&quot;49&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;1104&quot; data-start=&quot;1081&quot; data-ke-size=&quot;size16&quot;&gt;벡터 형태로 더 간단히 쓰면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;123&quot; data-origin-height=&quot;38&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEOgGj/dJMcacbAfZB/V4QA9Kq6hu2HoKdn3hkKYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEOgGj/dJMcacbAfZB/V4QA9Kq6hu2HoKdn3hkKYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEOgGj/dJMcacbAfZB/V4QA9Kq6hu2HoKdn3hkKYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEOgGj%2FdJMcacbAfZB%2FV4QA9Kq6hu2HoKdn3hkKYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;123&quot; height=&quot;38&quot; data-origin-width=&quot;123&quot; data-origin-height=&quot;38&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;1127&quot; data-start=&quot;1124&quot; data-ke-size=&quot;size16&quot;&gt;여기서&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1184&quot; data-start=&quot;1129&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1141&quot; data-start=&quot;1129&quot; data-section-id=&quot;1x5xh15&quot;&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;: 입력값&lt;/li&gt;
&lt;li data-end=&quot;1154&quot; data-start=&quot;1142&quot; data-section-id=&quot;1czx3v1&quot;&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;W&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;: 가중치&lt;/li&gt;
&lt;li data-end=&quot;1166&quot; data-start=&quot;1155&quot; data-section-id=&quot;1qtrij0&quot;&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;: 편향&lt;/li&gt;
&lt;li data-end=&quot;1184&quot; data-start=&quot;1167&quot; data-section-id=&quot;chtkax&quot;&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;z&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;: 선형 결합 결과&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;1189&quot; data-start=&quot;1186&quot; data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;1334&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size16&quot;&gt;즉, 퍼셉트론은 입력 특징마다 서로 다른 중요도를 부여해 하나의 결과를 만드는 구조라고 볼 수 있다.&lt;br /&gt;예를 들어 어떤 입력값은 예측에 매우 중요할 수 있고, 어떤 값은 거의 영향을 주지 않을 수 있다.&lt;br /&gt;이때 그 중요도를 반영하는 값이 바로 가중치다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;1334&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size23&quot;&gt;3. 왜 활성화함수가 필요한가&lt;/h3&gt;
&lt;p data-end=&quot;1483&quot; data-start=&quot;1362&quot; data-ke-size=&quot;size16&quot;&gt;퍼셉트론의 계산 결과 &lt;span&gt;&lt;span&gt;z&lt;/span&gt;&lt;/span&gt;&amp;nbsp;는 기본적으로 &lt;b&gt;선형 결합&lt;/b&gt;이다.&lt;br /&gt;그런데 선형 계산만 여러 번 반복하면, 층을 깊게 쌓더라도 결국 하나의 큰 선형식과 크게 다르지 않다.&lt;br /&gt;즉, 복잡한 패턴을 학습하기 어렵다.&lt;/p&gt;
&lt;p data-end=&quot;1530&quot; data-start=&quot;1485&quot; data-ke-size=&quot;size16&quot;&gt;그래서 등장하는 것이 &lt;b&gt;활성화함수(Activation Function)&lt;/b&gt; 다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;97&quot; data-origin-height=&quot;44&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dlkKoZ/dJMcagdZ0wd/pJ9BQK2MkB3iKzpTHmzjT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dlkKoZ/dJMcagdZ0wd/pJ9BQK2MkB3iKzpTHmzjT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dlkKoZ/dJMcagdZ0wd/pJ9BQK2MkB3iKzpTHmzjT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdlkKoZ%2FdJMcagdZ0wd%2FpJ9BQK2MkB3iKzpTHmzjT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;97&quot; height=&quot;44&quot; data-origin-width=&quot;97&quot; data-origin-height=&quot;44&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;1334&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size16&quot;&gt;활성화함수는 모델에 &lt;b&gt;비선형성&lt;/b&gt;을 추가한다.&lt;br /&gt;이 비선형성이 있어야 딥러닝 모델은 단순한 직선 문제가 아니라, 실제 데이터에 존재하는 복잡한 패턴까지 학습할 수 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;1334&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size23&quot;&gt;4. 대표적인 활성화함수&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4-1. Sigmoid&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;159&quot; data-origin-height=&quot;72&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VviFa/dJMcacbAgak/cksc81cKOnow6MwXmZyOaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VviFa/dJMcacbAgak/cksc81cKOnow6MwXmZyOaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VviFa/dJMcacbAgak/cksc81cKOnow6MwXmZyOaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVviFa%2FdJMcacbAgak%2Fcksc81cKOnow6MwXmZyOaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;159&quot; height=&quot;72&quot; data-origin-width=&quot;159&quot; data-origin-height=&quot;72&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;1873&quot; data-start=&quot;1791&quot; data-ke-size=&quot;size16&quot;&gt;Sigmoid는 입력값을 0과 1 사이로 압축하는 함수다.&lt;br /&gt;출력값을 확률처럼 해석하기 쉽기 때문에 &lt;b&gt;이진 분류의 출력층&lt;/b&gt;에서 자주 사용된다.&lt;br /&gt;입력이 커질수록 출력은 1에 가까워지고, 입력이 작아질수록 0에 가까워진다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4-2. ReLu&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;217&quot; data-origin-height=&quot;55&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rotS6/dJMb9960afc/qaGSsH8jr5kvTESfgbl4hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rotS6/dJMb9960afc/qaGSsH8jr5kvTESfgbl4hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rotS6/dJMb9960afc/qaGSsH8jr5kvTESfgbl4hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrotS6%2FdJMb9960afc%2FqaGSsH8jr5kvTESfgbl4hk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;217&quot; height=&quot;55&quot; data-origin-width=&quot;217&quot; data-origin-height=&quot;55&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ReLU는 음수는 0으로 만들고, 양수는 그대로 통과시키는 아주 단순한 함수다.&lt;br /&gt;이미지 분류에서 많이 사용한다&lt;br /&gt;계산이 빠르고 학습 효율도 좋아서 &lt;b&gt;은닉층에서 가장 많이 사용되는 활성화함수&lt;/b&gt; 중 하나다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4-3. Tanh&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;191&quot; data-origin-height=&quot;74&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JPaiZ/dJMcah42MqI/wnD2Q5dVdYQGDgMk1zMxfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JPaiZ/dJMcah42MqI/wnD2Q5dVdYQGDgMk1zMxfk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JPaiZ/dJMcah42MqI/wnD2Q5dVdYQGDgMk1zMxfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJPaiZ%2FdJMcah42MqI%2FwnD2Q5dVdYQGDgMk1zMxfk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;191&quot; height=&quot;74&quot; data-origin-width=&quot;191&quot; data-origin-height=&quot;74&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tanh는 출력을 -1에서 1 사이로 압축한다.&lt;br /&gt;시계열 데이터에서 많이 사용한다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4-4.SoftMax&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;217&quot; data-origin-height=&quot;73&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d5298f/dJMb990glWm/b1qSIti4j5jjWsyhIbjSV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d5298f/dJMb990glWm/b1qSIti4j5jjWsyhIbjSV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d5298f/dJMb990glWm/b1qSIti4j5jjWsyhIbjSV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd5298f%2FdJMb990glWm%2Fb1qSIti4j5jjWsyhIbjSV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;217&quot; height=&quot;73&quot; data-origin-width=&quot;217&quot; data-origin-height=&quot;73&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;1334&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size16&quot;&gt;Softmax는 여러 출력값을 전체 합이 1이 되도록 바꿔준다.&lt;br /&gt;다중 분류 문제에서 클래스별로 합이 1인 확률분포 형태로 변환한다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;1334&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size23&quot;&gt;5. 다층 퍼셉트론(MLP)&lt;/h3&gt;
&lt;p data-end=&quot;2531&quot; data-start=&quot;2408&quot; data-ke-size=&quot;size16&quot;&gt;퍼셉트론 하나만으로는 복잡한 문제를 충분히 해결하기 어렵다.&lt;br /&gt;그래서 여러 퍼셉트론을 층 형태로 쌓은 구조를 사용하게 되는데, 이를 &lt;b&gt;다층 퍼셉트론(MLP, Multi-Layer Perceptron)&lt;/b&gt; 이라고 한다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;1334&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;입력층&amp;rarr;은닉층&amp;rarr;출력층&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;2677&quot; data-start=&quot;2594&quot; data-ke-size=&quot;size16&quot;&gt;여기서 중요한 것은 &lt;b&gt;은닉층(Hidden Layer)&lt;/b&gt; 이다.&lt;br /&gt;은닉층은 입력 데이터의 패턴을 더 추상적인 형태로 변환해 다음 층으로 전달한다.&lt;/p&gt;
&lt;h4 data-end=&quot;3840&quot; data-start=&quot;3828&quot; data-section-id=&quot;v90hun&quot; data-ke-size=&quot;size20&quot;&gt;1) 선형 계산&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;154&quot; data-origin-height=&quot;47&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cap7Zx/dJMcaiCQRwn/c1kum2HZprmzl6k5UZouP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cap7Zx/dJMcaiCQRwn/c1kum2HZprmzl6k5UZouP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cap7Zx/dJMcaiCQRwn/c1kum2HZprmzl6k5UZouP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcap7Zx%2FdJMcaiCQRwn%2Fc1kum2HZprmzl6k5UZouP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;154&quot; height=&quot;47&quot; data-origin-width=&quot;154&quot; data-origin-height=&quot;47&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-end=&quot;3874&quot; data-start=&quot;3859&quot; data-section-id=&quot;1uzvpbw&quot; data-ke-size=&quot;size20&quot;&gt;2) 활성화함수 적용&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;101&quot; data-origin-height=&quot;41&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPEpOT/dJMcahjG9s1/J1zty2oCKKUvnrRbAddKBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPEpOT/dJMcahjG9s1/J1zty2oCKKUvnrRbAddKBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPEpOT/dJMcahjG9s1/J1zty2oCKKUvnrRbAddKBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPEpOT%2FdJMcahjG9s1%2FJ1zty2oCKKUvnrRbAddKBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;101&quot; height=&quot;41&quot; data-origin-width=&quot;101&quot; data-origin-height=&quot;41&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-end=&quot;1334&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size16&quot;&gt;한 층은 결국&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-end=&quot;1334&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;입력&lt;/span&gt;&lt;span&gt;&amp;rarr;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;행렬곱&lt;/span&gt;&lt;span&gt;&amp;rarr;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;편향더하기&lt;/span&gt;&lt;span&gt;&amp;rarr;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;활성화함수&lt;/span&gt;&lt;/span&gt; &lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1334&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size16&quot;&gt;라는 흐름으로 작동한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;1334&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size23&quot;&gt;6. 순전파(Forward Propagation)&lt;/h3&gt;
&lt;p data-end=&quot;4150&quot; data-start=&quot;4107&quot; data-ke-size=&quot;size16&quot;&gt;입력 데이터가 들어와서 최종 예측값이 계산되는 과정을 &lt;b&gt;순전파&lt;/b&gt;라고 한다.&lt;br /&gt;예를 들어 은닉층이 하나인 모델이라면 순전파는 다음과 같이 진행된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;148&quot; data-origin-height=&quot;156&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ChO5v/dJMcagrvMD1/qpb7ouyKwTW5JZ9gKOoLck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ChO5v/dJMcagrvMD1/qpb7ouyKwTW5JZ9gKOoLck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ChO5v/dJMcagrvMD1/qpb7ouyKwTW5JZ9gKOoLck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FChO5v%2FdJMcagrvMD1%2Fqpb7ouyKwTW5JZ9gKOoLck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;148&quot; height=&quot;156&quot; data-origin-width=&quot;148&quot; data-origin-height=&quot;156&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;4342&quot; data-start=&quot;4286&quot; data-ke-size=&quot;size16&quot;&gt;입력이 각 층을 통과하면서 점차 변환되고, 마지막에 예측값 ŷ&amp;nbsp;가 만들어진다.&lt;/p&gt;
&lt;p data-end=&quot;4460&quot; data-start=&quot;4344&quot; data-ke-size=&quot;size16&quot;&gt;순전파에서 중요한 점은 &lt;b&gt;활성화함수는 바로 이 단계에서 사용된다는 것&lt;/b&gt;이다.&lt;br /&gt;즉, 순전파는 단순히 행렬곱만 하는 과정이 아니라, 각 층마다 &lt;b&gt;선형 계산과 활성화함수 적용을 함께 수행하는 과정&lt;/b&gt;이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;1334&quot; data-start=&quot;1191&quot; data-ke-size=&quot;size23&quot;&gt;7. 손실함수(Loss Function)&lt;/h3&gt;
&lt;p data-end=&quot;4564&quot; data-start=&quot;4494&quot; data-ke-size=&quot;size16&quot;&gt;예측값이 나왔다면, 이제 그 값이 실제 정답과 얼마나 차이가 나는지 계산해야 한다.&lt;br /&gt;이때 사용하는 것이 &lt;b&gt;손실함수&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-end=&quot;4599&quot; data-start=&quot;4566&quot; data-ke-size=&quot;size16&quot;&gt;손실함수는 모델의 예측이 얼마나 틀렸는지를 수치로 나타낸다.&lt;/p&gt;
&lt;h4 data-end=&quot;4599&quot; data-start=&quot;4566&quot; data-ke-size=&quot;size20&quot;&gt;회귀 문제: MSE&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;187&quot; data-origin-height=&quot;69&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PugX3/dJMb99TslS1/OOYlMYo89tXxwtPehICuuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PugX3/dJMb99TslS1/OOYlMYo89tXxwtPehICuuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PugX3/dJMb99TslS1/OOYlMYo89tXxwtPehICuuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPugX3%2FdJMb99TslS1%2FOOYlMYo89tXxwtPehICuuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;187&quot; height=&quot;69&quot; data-origin-width=&quot;187&quot; data-origin-height=&quot;69&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-end=&quot;4599&quot; data-start=&quot;4566&quot; data-ke-size=&quot;size20&quot;&gt;이진 분류: Binary Cross Entropy&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;390&quot; data-origin-height=&quot;82&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RDMM6/dJMcahxc7IH/4oNq7kjQCYh9zKGLz7sVvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RDMM6/dJMcahxc7IH/4oNq7kjQCYh9zKGLz7sVvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RDMM6/dJMcahxc7IH/4oNq7kjQCYh9zKGLz7sVvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRDMM6%2FdJMcahxc7IH%2F4oNq7kjQCYh9zKGLz7sVvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;390&quot; height=&quot;82&quot; data-origin-width=&quot;390&quot; data-origin-height=&quot;82&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-end=&quot;4836&quot; data-start=&quot;4800&quot; data-section-id=&quot;142vfwu&quot; data-ke-size=&quot;size20&quot;&gt;다중 분류: Categorical Cross Entropy&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;185&quot; data-origin-height=&quot;69&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u00xZ/dJMcacimh3I/IEat1usMKF3w7hNOl4nEm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u00xZ/dJMcacimh3I/IEat1usMKF3w7hNOl4nEm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u00xZ/dJMcacimh3I/IEat1usMKF3w7hNOl4nEm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu00xZ%2FdJMcacimh3I%2FIEat1usMKF3w7hNOl4nEm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;185&quot; height=&quot;69&quot; data-origin-width=&quot;185&quot; data-origin-height=&quot;69&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;손실값이 작을수록 예측이 정답에 더 가깝다는 뜻이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;4599&quot; data-start=&quot;4566&quot; data-ke-size=&quot;size23&quot;&gt;8. 역전파(Backpropagation)&lt;/h3&gt;
&lt;p data-end=&quot;5029&quot; data-start=&quot;4949&quot; data-ke-size=&quot;size16&quot;&gt;손실함수를 계산한 뒤에는, 이 손실을 줄이기 위해 각 가중치와 편향을 어떻게 수정해야 할지 알아야 한다.&lt;br /&gt;이 과정을 &lt;b&gt;역전파&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;p data-end=&quot;5071&quot; data-start=&quot;5031&quot; data-ke-size=&quot;size16&quot;&gt;역전파의 핵심은 &lt;b&gt;손실 &lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&amp;nbsp;을 각 파라미터에 대해 미분하는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;108&quot; data-origin-height=&quot;59&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Bw0kV/dJMcajaFEyy/mq4xakqL7HMC0YSuGKHjW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Bw0kV/dJMcajaFEyy/mq4xakqL7HMC0YSuGKHjW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Bw0kV/dJMcajaFEyy/mq4xakqL7HMC0YSuGKHjW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBw0kV%2FdJMcajaFEyy%2Fmq4xakqL7HMC0YSuGKHjW0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;108&quot; height=&quot;59&quot; data-origin-width=&quot;108&quot; data-origin-height=&quot;59&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;5207&quot; data-start=&quot;5147&quot; data-ke-size=&quot;size16&quot;&gt;이 값들은 &lt;b&gt;기울기(gradient)&lt;/b&gt; 이며, 손실을 줄이려면 어느 방향으로 이동해야 하는지를 알려준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;197&quot; data-origin-height=&quot;60&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddyzv4/dJMcaadMyxt/VkITHwPcCCG6yXf9ketjS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddyzv4/dJMcaadMyxt/VkITHwPcCCG6yXf9ketjS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddyzv4/dJMcaadMyxt/VkITHwPcCCG6yXf9ketjS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fddyzv4%2FdJMcaadMyxt%2FVkITHwPcCCG6yXf9ketjS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;197&quot; height=&quot;60&quot; data-origin-width=&quot;197&quot; data-origin-height=&quot;60&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;5426&quot; data-start=&quot;5382&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;출력층의 오차를 뒤에서부터 앞층으로 전달하면서 각 층의 기울기를 계산한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;4599&quot; data-start=&quot;4566&quot; data-ke-size=&quot;size23&quot;&gt;9. 옵티마이저(Optimizer)&lt;/h3&gt;
&lt;p data-end=&quot;5594&quot; data-start=&quot;5528&quot; data-ke-size=&quot;size16&quot;&gt;역전파로 기울기를 계산했다면, 이제 실제로 파라미터를 수정해야 한다.&lt;br /&gt;이 역할을 담당하는 것이 &lt;b&gt;옵티마이저&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-end=&quot;5619&quot; data-start=&quot;5596&quot; data-ke-size=&quot;size16&quot;&gt;가장 기본적인 업데이트 식은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;154&quot; data-origin-height=&quot;107&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baC5Ha/dJMcafF9Kkb/KjsAghkGDvXpnq9K8kSU00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baC5Ha/dJMcafF9Kkb/KjsAghkGDvXpnq9K8kSU00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baC5Ha/dJMcafF9Kkb/KjsAghkGDvXpnq9K8kSU00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaC5Ha%2FdJMcafF9Kkb%2FKjsAghkGDvXpnq9K8kSU00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;154&quot; height=&quot;107&quot; data-origin-width=&quot;154&quot; data-origin-height=&quot;107&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;5759&quot; data-start=&quot;5723&quot; data-ke-size=&quot;size16&quot;&gt;여기서 &lt;span&gt;&lt;span&gt;&amp;eta;는&lt;/span&gt;&lt;/span&gt;&amp;nbsp;학습률(learning rate)이다.&lt;br /&gt;손실이 줄어드는 방향으로 가중치와 편향을 조금씩 이동시키는 것이다.&lt;/p&gt;
&lt;p data-end=&quot;5801&quot; data-start=&quot;5761&quot; 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 data-end=&quot;5830&quot; data-start=&quot;5825&quot; data-section-id=&quot;1o4r88&quot;&gt;SGD&lt;/li&gt;
&lt;li data-end=&quot;5841&quot; data-start=&quot;5831&quot; data-section-id=&quot;htjs68&quot;&gt;Momentum&lt;/li&gt;
&lt;li data-end=&quot;5851&quot; data-start=&quot;5842&quot; data-section-id=&quot;xkji6x&quot;&gt;RMSProp&lt;/li&gt;
&lt;li data-end=&quot;5858&quot; data-start=&quot;5852&quot; data-section-id=&quot;1j42x6p&quot;&gt;Adam&lt;/li&gt;
&lt;li data-end=&quot;5858&quot; data-start=&quot;5852&quot; data-section-id=&quot;1j42x6p&quot;&gt;Nadam&lt;/li&gt;
&lt;li data-end=&quot;5858&quot; data-start=&quot;5852&quot; data-section-id=&quot;1j42x6p&quot;&gt;AdamW&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무와 학습 예제에서는 Adam을 많이 사용하는 편이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;5918&quot; data-start=&quot;5898&quot; data-section-id=&quot;605ito&quot; data-ke-size=&quot;size23&quot;&gt;10. 딥러닝 학습의 전체 흐름&lt;/h3&gt;
&lt;p data-end=&quot;5918&quot; data-start=&quot;5898&quot; data-section-id=&quot;605ito&quot; data-ke-size=&quot;size16&quot;&gt;1) 입력 데이터 준비&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;50&quot; data-origin-height=&quot;33&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dX3ypk/dJMcadnZHfg/GhIGiKEYFtq8x0bCC04DV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dX3ypk/dJMcadnZHfg/GhIGiKEYFtq8x0bCC04DV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dX3ypk/dJMcadnZHfg/GhIGiKEYFtq8x0bCC04DV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdX3ypk%2FdJMcadnZHfg%2FGhIGiKEYFtq8x0bCC04DV1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;50&quot; height=&quot;33&quot; data-origin-width=&quot;50&quot; data-origin-height=&quot;33&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 순전파&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;70&quot; data-origin-height=&quot;36&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/drETwG/dJMcahKKhGi/YRhFZ4ImqR4KIcIQa7Jk51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/drETwG/dJMcahKKhGi/YRhFZ4ImqR4KIcIQa7Jk51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/drETwG/dJMcahKKhGi/YRhFZ4ImqR4KIcIQa7Jk51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdrETwG%2FdJMcahKKhGi%2FYRhFZ4ImqR4KIcIQa7Jk51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;70&quot; height=&quot;36&quot; data-origin-width=&quot;70&quot; data-origin-height=&quot;36&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 손실 계산&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;72&quot; data-origin-height=&quot;39&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvTHTd/dJMcah42NZd/1vcddQli8o2c0ZrOJCjSF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvTHTd/dJMcah42NZd/1vcddQli8o2c0ZrOJCjSF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvTHTd/dJMcah42NZd/1vcddQli8o2c0ZrOJCjSF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvTHTd%2FdJMcah42NZd%2F1vcddQli8o2c0ZrOJCjSF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;72&quot; height=&quot;39&quot; data-origin-width=&quot;72&quot; data-origin-height=&quot;39&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) 역전파&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;73&quot; data-origin-height=&quot;47&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dII5A9/dJMcahKKhG5/wwU86skaiB7XpQgkMOy2KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dII5A9/dJMcahKKhG5/wwU86skaiB7XpQgkMOy2KK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dII5A9/dJMcahKKhG5/wwU86skaiB7XpQgkMOy2KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdII5A9%2FdJMcahKKhG5%2FwwU86skaiB7XpQgkMOy2KK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;73&quot; height=&quot;47&quot; data-origin-width=&quot;73&quot; data-origin-height=&quot;47&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5) 옵티마이저 업데이트&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;150&quot; data-origin-height=&quot;57&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc3Wu2/dJMcacbAhHb/sTuqkjZPkagUR4QtyxfP41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc3Wu2/dJMcacbAhHb/sTuqkjZPkagUR4QtyxfP41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc3Wu2/dJMcacbAhHb/sTuqkjZPkagUR4QtyxfP41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc3Wu2%2FdJMcacbAhHb%2FsTuqkjZPkagUR4QtyxfP41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;150&quot; height=&quot;57&quot; data-origin-width=&quot;150&quot; data-origin-height=&quot;57&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6) 1) ~ 5)를 반복&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;6414&quot; data-start=&quot;6384&quot; data-section-id=&quot;1cgasxf&quot; data-ke-size=&quot;size23&quot;&gt;11. Epoch, Batch, Iteration&lt;/h3&gt;
&lt;p data-end=&quot;6469&quot; data-start=&quot;6416&quot; data-ke-size=&quot;size16&quot;&gt;딥러닝에서는 전체 데이터를 한 번에 학습하지 않고, 여러 묶음으로 나누어 학습하는 경우가 많다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;6566&quot; data-start=&quot;6471&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;6503&quot; data-start=&quot;6471&quot; data-section-id=&quot;109taeo&quot;&gt;&lt;b&gt;Epoch&lt;/b&gt;: 전체 데이터를 한 바퀴 학습한 횟수&lt;/li&gt;
&lt;li data-end=&quot;6535&quot; data-start=&quot;6504&quot; data-section-id=&quot;b61uer&quot;&gt;&lt;b&gt;Batch&lt;/b&gt;: 한 번에 모델에 넣는 데이터 묶음&lt;/li&gt;
&lt;li data-end=&quot;6566&quot; data-start=&quot;6536&quot; data-section-id=&quot;1lj8co6&quot;&gt;&lt;b&gt;Iteration&lt;/b&gt;: 배치 하나를 학습한 횟수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;6638&quot; data-start=&quot;6568&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 데이터가 1000개이고 batch size가 100이라면,&lt;br /&gt;1 epoch는 10 iteration으로 구성된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;6638&quot; data-start=&quot;6568&quot; data-ke-size=&quot;size23&quot;&gt;12. 모델 성능을 높이기 위해 어떤 고민을 해야 할까&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딥러닝 모델을 만들다 보면 자연스럽게 &amp;ldquo;어떻게 하면 정확도를 더 높일 수 있을까?&amp;rdquo;라는 질문을 하게 된다.&lt;br /&gt;하지만 정확도를 올리는 방법은 단순히 epoch를 늘리는 것만이 아니다.&lt;br /&gt;오히려 &lt;b&gt;데이터, 전처리, 모델 구조, 학습 방식, 평가 방법&lt;/b&gt;을 함께 고민해야 한다.&lt;/p&gt;
&lt;h4 data-end=&quot;6868&quot; data-start=&quot;6840&quot; data-section-id=&quot;1kees7t&quot; data-ke-size=&quot;size20&quot;&gt;12-1. 데이터 품질을 먼저 의심해야 한다&lt;/h4&gt;
&lt;p data-end=&quot;6909&quot; data-start=&quot;6870&quot; data-ke-size=&quot;size16&quot;&gt;성능이 낮을 때 가장 먼저 확인해야 할 것은 모델보다 &lt;b&gt;데이터&lt;/b&gt;다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;7003&quot; data-start=&quot;6911&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;6930&quot; data-start=&quot;6911&quot; data-section-id=&quot;mk4jww&quot;&gt;라벨이 잘못 붙어 있지는 않은지&lt;/li&gt;
&lt;li data-end=&quot;6946&quot; data-start=&quot;6931&quot; data-section-id=&quot;et6vp6&quot;&gt;결측치나 이상치가 많은지&lt;/li&gt;
&lt;li data-end=&quot;6973&quot; data-start=&quot;6947&quot; data-section-id=&quot;1uxf9kr&quot;&gt;클래스별 데이터 수가 너무 불균형하지 않은지&lt;/li&gt;
&lt;li data-end=&quot;7003&quot; data-start=&quot;6974&quot; data-section-id=&quot;2ctt0&quot;&gt;학습 데이터와 테스트 데이터의 분포가 너무 다른지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;7109&quot; data-start=&quot;7005&quot; data-ke-size=&quot;size16&quot;&gt;아무리 좋은 모델을 써도 데이터 자체에 문제가 있으면 정확도는 쉽게 올라가지 않는다.&lt;br /&gt;실무에서도 모델 구조보다 데이터 정제와 라벨 품질 개선이 더 큰 성능 향상을 만드는 경우가 많다.&lt;/p&gt;
&lt;h4 data-end=&quot;7146&quot; data-start=&quot;7116&quot; data-section-id=&quot;gqznre&quot; data-ke-size=&quot;size20&quot;&gt;12-2. 입력 전처리가 적절한지 확인해야 한다&lt;/h4&gt;
&lt;p data-end=&quot;7263&quot; data-start=&quot;7148&quot; data-ke-size=&quot;size16&quot;&gt;입력값의 범위가 너무 크거나, 특성마다 단위 차이가 심하면 학습이 불안정해질 수 있다.&lt;br /&gt;예를 들어 어떤 변수는 0~1 범위인데, 다른 변수는 0~10000 범위라면 가중치 학습이 한쪽에 치우칠 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;7289&quot; data-start=&quot;7265&quot; data-ke-size=&quot;size16&quot;&gt;그래서 보통 다음과 같은 전처리를 고려한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;7371&quot; data-start=&quot;7291&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;7311&quot; data-start=&quot;7291&quot; data-section-id=&quot;ud4h55&quot;&gt;정규화(Normalization)&lt;/li&gt;
&lt;li data-end=&quot;7334&quot; data-start=&quot;7312&quot; data-section-id=&quot;gs5exg&quot;&gt;표준화(Standardization)&lt;/li&gt;
&lt;li data-end=&quot;7344&quot; data-start=&quot;7335&quot; data-section-id=&quot;qe32kb&quot;&gt;원-핫 인코딩&lt;/li&gt;
&lt;li data-end=&quot;7354&quot; data-start=&quot;7345&quot; data-section-id=&quot;k1ankt&quot;&gt;텍스트 토큰화&lt;/li&gt;
&lt;li data-end=&quot;7371&quot; data-start=&quot;7355&quot; data-section-id=&quot;1o7ibl6&quot;&gt;이미지 리사이즈 및 정규화&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;7418&quot; data-start=&quot;7373&quot; data-ke-size=&quot;size16&quot;&gt;전처리는 단순한 보조 작업이 아니라, 모델 성능에 직접 영향을 주는 핵심 단계다.&lt;/p&gt;
&lt;h4 data-end=&quot;7455&quot; data-start=&quot;7425&quot; data-section-id=&quot;vfa3o5&quot; data-ke-size=&quot;size20&quot;&gt;12-3. 모델 구조가 문제에 맞는지 봐야 한다&lt;/h4&gt;
&lt;p data-end=&quot;7488&quot; data-start=&quot;7457&quot; data-ke-size=&quot;size16&quot;&gt;모든 문제를 MLP 하나로 해결할 수 있는 것은 아니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;7606&quot; data-start=&quot;7490&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;7507&quot; data-start=&quot;7490&quot; data-section-id=&quot;v03e3d&quot;&gt;이미지 데이터: CNN 계열&lt;/li&gt;
&lt;li data-end=&quot;7549&quot; data-start=&quot;7508&quot; data-section-id=&quot;ox8mhl&quot;&gt;시계열 데이터: RNN, LSTM, GRU, Transformer 계열&lt;/li&gt;
&lt;li data-end=&quot;7575&quot; data-start=&quot;7550&quot; data-section-id=&quot;1hrjdoc&quot;&gt;텍스트 데이터: Transformer 계열&lt;/li&gt;
&lt;li data-end=&quot;7606&quot; data-start=&quot;7576&quot; data-section-id=&quot;1s2m85i&quot;&gt;표형 데이터: MLP, 트리 기반 모델과 비교 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;7705&quot; data-start=&quot;7608&quot; data-ke-size=&quot;size16&quot;&gt;즉, 데이터 형태에 맞는 모델 구조를 선택해야 한다.&lt;br /&gt;문제 유형에 비해 지나치게 단순한 모델은 성능 한계가 있고, 반대로 지나치게 복잡한 모델은 과적합을 유발할 수 있다.&lt;/p&gt;
&lt;h4 data-end=&quot;7741&quot; data-start=&quot;7712&quot; data-section-id=&quot;16mgx6s&quot; data-ke-size=&quot;size20&quot;&gt;12-4. 과적합과 과소적합을 함께 봐야 한다&lt;/h4&gt;
&lt;p data-end=&quot;7782&quot; data-start=&quot;7743&quot; data-ke-size=&quot;size16&quot;&gt;정확도를 높이고 싶다고 해서 무조건 더 오래 학습시키는 것은 위험하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;7880&quot; data-start=&quot;7784&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;7827&quot; data-start=&quot;7784&quot; data-section-id=&quot;10b4bbh&quot;&gt;&lt;b&gt;과소적합(Underfitting)&lt;/b&gt;: 학습 데이터조차 제대로 못 맞춤&lt;/li&gt;
&lt;li data-end=&quot;7880&quot; data-start=&quot;7828&quot; data-section-id=&quot;vtcxh&quot;&gt;&lt;b&gt;과적합(Overfitting)&lt;/b&gt;: 학습 데이터는 잘 맞추지만 새로운 데이터는 못 맞춤&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;7964&quot; data-start=&quot;7882&quot; data-ke-size=&quot;size16&quot;&gt;따라서 학습 정확도와 검증 정확도를 함께 비교해야 한다.&lt;br /&gt;학습 정확도만 높고 검증 정확도가 낮다면, 모델이 훈련 데이터만 외운 상태일 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;8064&quot; data-start=&quot;7987&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;7996&quot; data-start=&quot;7987&quot; data-section-id=&quot;esjdb&quot;&gt;Dropout&lt;/li&gt;
&lt;li data-end=&quot;8013&quot; data-start=&quot;7997&quot; data-section-id=&quot;12qfso3&quot;&gt;Early Stopping&lt;/li&gt;
&lt;li data-end=&quot;8027&quot; data-start=&quot;8014&quot; data-section-id=&quot;zam1ej&quot;&gt;정규화(L1, L2)&lt;/li&gt;
&lt;li data-end=&quot;8055&quot; data-start=&quot;8028&quot; data-section-id=&quot;tcpqk9&quot;&gt;데이터 증강(Data Augmentation)&lt;/li&gt;
&lt;li data-end=&quot;8064&quot; data-start=&quot;8056&quot; data-section-id=&quot;16qs1k&quot;&gt;모델 단순화&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-end=&quot;8097&quot; data-start=&quot;8071&quot; data-section-id=&quot;1k925gk&quot; data-ke-size=&quot;size20&quot;&gt;12-5. 하이퍼파라미터 튜닝이 필요하다&lt;/h4&gt;
&lt;p data-end=&quot;8097&quot; data-start=&quot;8071&quot; data-section-id=&quot;1k925gk&quot; data-ke-size=&quot;size16&quot;&gt;대표적으로 조정할 값은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;8216&quot; data-start=&quot;8148&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;8163&quot; data-start=&quot;8148&quot; data-section-id=&quot;f0njy&quot;&gt;학습률&lt;/li&gt;
&lt;li data-end=&quot;8176&quot; data-start=&quot;8164&quot; data-section-id=&quot;6v4q6p&quot;&gt;batch size&lt;/li&gt;
&lt;li data-end=&quot;8186&quot; data-start=&quot;8177&quot; data-section-id=&quot;1coyou9&quot;&gt;epoch 수&lt;/li&gt;
&lt;li data-end=&quot;8194&quot; data-start=&quot;8187&quot; data-section-id=&quot;a1x70&quot;&gt;은닉층 수&lt;/li&gt;
&lt;li data-end=&quot;8201&quot; data-start=&quot;8195&quot; data-section-id=&quot;1ul7t04&quot;&gt;뉴런 수&lt;/li&gt;
&lt;li data-end=&quot;8216&quot; data-start=&quot;8202&quot; data-section-id=&quot;19nsf6m&quot;&gt;optimizer 종류&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;8306&quot; data-start=&quot;8218&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 학습률이 너무 크면 발산할 수 있고, 너무 작으면 학습이 지나치게 느려질 수 있다.&lt;br /&gt;따라서 적절한 값을 찾는 과정이 필요하다.&lt;/p&gt;
&lt;h4 data-end=&quot;8346&quot; data-start=&quot;8313&quot; data-section-id=&quot;6wybsf&quot; data-ke-size=&quot;size20&quot;&gt;12-6. Accuracy만 볼지 다시 생각해야 한다&lt;/h4&gt;
&lt;p data-end=&quot;8436&quot; data-start=&quot;8348&quot; data-ke-size=&quot;size16&quot;&gt;정확도(Accuracy)는 직관적이지만, 항상 좋은 지표는 아니다. 예를 들어 클래스 불균형이 심한 문제에서는 정확도가 높아도 실제 성능은 나쁠 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;8542&quot; data-start=&quot;8438&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 전체 데이터의 95%가 정상, 5%가 이상이라면 모든 데이터를 정상이라고 예측해도 Accuracy는 95%가 된다. 하지만 이런 모델은 이상 탐지에는 거의 쓸모가 없다.&lt;/p&gt;
&lt;p data-end=&quot;8571&quot; data-start=&quot;8544&quot; data-ke-size=&quot;size16&quot;&gt;그래서 경우에 따라 다음 지표도 함께 봐야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;8623&quot; data-start=&quot;8573&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;8584&quot; data-start=&quot;8573&quot; data-section-id=&quot;1s5h3ha&quot;&gt;Precision&lt;/li&gt;
&lt;li data-end=&quot;8593&quot; data-start=&quot;8585&quot; data-section-id=&quot;72gs3h&quot;&gt;Recall&lt;/li&gt;
&lt;li data-end=&quot;8604&quot; data-start=&quot;8594&quot; data-section-id=&quot;15ypay&quot;&gt;F1-score&lt;/li&gt;
&lt;li data-end=&quot;8614&quot; data-start=&quot;8605&quot; data-section-id=&quot;z5lca4&quot;&gt;ROC-AUC&lt;/li&gt;
&lt;li data-end=&quot;8623&quot; data-start=&quot;8615&quot; data-section-id=&quot;3hd15c&quot;&gt;PR-AUC&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;8692&quot; data-start=&quot;8625&quot; data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;ACC를 높이는 것&amp;rdquo;이 목표인지, 아니면 &amp;ldquo;정말 중요한 클래스를 잘 잡는 것&amp;rdquo;이 목표인지 먼저 정의해야 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;</description>
      <category>AI dev/Deep Learning</category>
      <author>bonggyulim</author>
      <guid isPermaLink="true">https://bonggyulim.tistory.com/37</guid>
      <comments>https://bonggyulim.tistory.com/37#entry37comment</comments>
      <pubDate>Mon, 6 Apr 2026 17:30:14 +0900</pubDate>
    </item>
    <item>
      <title>I/O 바운드와 CPU 바운드</title>
      <link>https://bonggyulim.tistory.com/36</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;병렬처리를 할 때 가장 먼저 해야 할 일은 작업이 CPU 바운드인지, I/O 바운드인지 구분하는 것이다.&lt;br /&gt;느린 원인이 계산인지 대기인지에 따라 적합한 병렬처리 방식이 달라지기 때문이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. CPU 바운드란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU 바운드는 &lt;b&gt;계산량이 많아서 CPU가 오래 일하는 작업&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;235&quot; data-start=&quot;229&quot; data-ke-size=&quot;size16&quot;&gt;예를 들면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;298&quot; data-start=&quot;237&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;245&quot; data-start=&quot;237&quot; data-section-id=&quot;17spkkw&quot;&gt;이미지 처리&lt;/li&gt;
&lt;li data-end=&quot;257&quot; data-start=&quot;246&quot; data-section-id=&quot;1y1j6hl&quot;&gt;영상 프레임 분석&lt;/li&gt;
&lt;li data-end=&quot;265&quot; data-start=&quot;258&quot; data-section-id=&quot;sf9zr0&quot;&gt;수치 계산&lt;/li&gt;
&lt;li data-end=&quot;276&quot; data-start=&quot;266&quot; data-section-id=&quot;1dgy3o1&quot;&gt;머신러닝 전처리&lt;/li&gt;
&lt;li data-end=&quot;286&quot; data-start=&quot;277&quot; data-section-id=&quot;15mblfg&quot;&gt;압축, 암호화&lt;/li&gt;
&lt;li data-end=&quot;298&quot; data-start=&quot;287&quot; data-section-id=&quot;16y32oh&quot;&gt;대규모 반복 연산&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. I/O 바운드란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I/O 바운드는 &lt;b&gt;외부 자원 응답을 기다리느라 느린 작업&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;444&quot; data-start=&quot;438&quot; data-ke-size=&quot;size16&quot;&gt;예를 들면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;500&quot; data-start=&quot;446&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;456&quot; data-start=&quot;446&quot; data-section-id=&quot;iezpp6&quot;&gt;파일 읽기/쓰기&lt;/li&gt;
&lt;li data-end=&quot;465&quot; data-start=&quot;457&quot; data-section-id=&quot;1vve378&quot;&gt;API 호출&lt;/li&gt;
&lt;li data-end=&quot;473&quot; data-start=&quot;466&quot; data-section-id=&quot;j6gnqw&quot;&gt;웹 크롤링&lt;/li&gt;
&lt;li data-end=&quot;481&quot; data-start=&quot;474&quot; data-section-id=&quot;16x29ma&quot;&gt;DB 조회&lt;/li&gt;
&lt;li data-end=&quot;489&quot; data-start=&quot;482&quot; data-section-id=&quot;uvkole&quot;&gt;소켓 통신&lt;/li&gt;
&lt;li data-end=&quot;500&quot; data-start=&quot;490&quot; data-section-id=&quot;1kdtvhu&quot;&gt;업로드/다운로드&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;556&quot; data-start=&quot;531&quot; data-section-id=&quot;1w5jsqo&quot; data-ke-size=&quot;size23&quot;&gt;3. CPU 바운드는 어떻게 병렬처리 방법&lt;/h3&gt;
&lt;p data-end=&quot;627&quot; data-start=&quot;558&quot; data-ke-size=&quot;size16&quot;&gt;CPU 바운드는 계산을 여러 CPU 코어나 프로세스에 나눠서 처리해야 한다.&lt;br /&gt;그래서 보통 &lt;b&gt;멀티프로세스&lt;/b&gt;를 사용한다.&lt;/p&gt;
&lt;h4 data-end=&quot;643&quot; data-start=&quot;629&quot; data-section-id=&quot;ww8b9m&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;왜 멀티프로세스인가?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-end=&quot;732&quot; data-start=&quot;644&quot; data-ke-size=&quot;size16&quot;&gt;계산이 많은 작업은 CPU를 실제로 오래 점유한다.&lt;br /&gt;이 경우에는 스레드보다 &lt;b&gt;프로세스를 여러 개 띄워서 CPU 코어를 분산 활용하는 방식&lt;/b&gt;이 더 맞다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 기준으로는 보통 이렇게 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1775459557048&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from concurrent.futures import ProcessPoolExecutor

def heavy_task(x):
    return x * x

with ProcessPoolExecutor(max_workers=4) as executor:		# 4개의 프로세스를 사용
    results = list(executor.map(heavy_task, range(10)))

print(results)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. I/O 바운드는 어떻게 병렬처리 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;I/O 바운드는 CPU가 기다리는 시간이 길기 때문에,&lt;br /&gt;그 기다리는 동안 다른 작업을 처리하게 만들면 된다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4-1. 멀티스레드&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 읽기, API 요청, DB 조회처럼 기다리는 작업이 많을 때 스레드를 여러 개 두면 효율적이다.&lt;/p&gt;
&lt;pre id=&quot;code_1775459728408&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from concurrent.futures import ThreadPoolExecutor
import time

def fetch_data(x):
    time.sleep(1)
    return f&quot;data-{x}&quot;

with ThreadPoolExecutor(max_workers=5) as executor:
    results = list(executor.map(fetch_data, range(10)))

print(results)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4-2. 비동기(async)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API 요청, 채팅 서버, 웹소켓처럼 대기 중심 작업이 많을 때는 비동기 처리를 많이 쓴다.&lt;br /&gt;비동기 처리는 병렬처리보다는 동시성 처리에 더 가깝다.&lt;/p&gt;
&lt;pre id=&quot;code_1775459620336&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import asyncio

async def fetch_data(x):		# async = 비동기 처리
    await asyncio.sleep(1)		# await = 기다리는 동안 다른 작업 처리
    return f&quot;data-{x}&quot;

async def main():
    tasks = [fetch_data(i) for i in range(10)]
    results = await asyncio.gather(*tasks)	# gather를 통해 여러 비동기 동시 실행
    print(results)

asyncio.run(main())&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-end=&quot;3081&quot; data-start=&quot;3063&quot; data-section-id=&quot;1u31b4y&quot; data-ke-size=&quot;size23&quot;&gt;5. 정리 및 주의점&lt;/h3&gt;
&lt;p data-end=&quot;3081&quot; data-start=&quot;3063&quot; data-section-id=&quot;1u31b4y&quot; data-ke-size=&quot;size16&quot;&gt;정리하면 CPU 바운드는 계산이 병목인 작업이고, I/O 바운드는 외부 응답 대기가 병목인 작업이다.&lt;br /&gt;따라서 CPU 바운드는 멀티프로세스, I/O 바운드는 멀티스레드나 비동기 방식을 주로 사용한다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;881&quot; data-start=&quot;864&quot; data-section-id=&quot;diqvb8&quot;&gt;계산이 많다 &amp;rarr; &lt;b&gt;멀티프로세스&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;908&quot; data-start=&quot;882&quot; data-section-id=&quot;1gqat7y&quot;&gt;파일/DB/API 대기가 많다 &amp;rarr; &lt;b&gt;멀티스레드&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;951&quot; data-start=&quot;909&quot; data-section-id=&quot;klzdny&quot;&gt;네트워크 요청이 매우 많고 비동기 라이브러리를 쓸 수 있다 &amp;rarr;&lt;b&gt; async&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;3783&quot; data-start=&quot;3759&quot; data-section-id=&quot;5g07ba&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CPU 바운드&lt;/b&gt;인데 &lt;b&gt;스레드&lt;/b&gt;만 늘리는 경우 - 계산 작업은 기대만큼 빨라지지 않을 수 있다.&lt;br /&gt;&lt;b&gt;I/O 바운드&lt;/b&gt;인데 &lt;b&gt;프로세스&lt;/b&gt;를 과하게 쓰는 경우 - 오버헤드만 커질 수 있다.&lt;br /&gt;작업 성격을 안 보고 무조건 병렬화하는 경우 - 오히려 더 느려질 수 있다.&lt;br /&gt;공유 자원을 많이 두는 경우 - 락 경쟁, 병목, 버그가 생기기 쉽다.&lt;br /&gt;워커 수를 무조건 많이 늘리는 경우 - 컨텍스트 스위칭, 메모리 사용량, 관리 비용이 증가해 오히려 느려질 수 있다. &lt;/p&gt;</description>
      <category>CS &amp;amp; Fundamentals</category>
      <author>bonggyulim</author>
      <guid isPermaLink="true">https://bonggyulim.tistory.com/36</guid>
      <comments>https://bonggyulim.tistory.com/36#entry36comment</comments>
      <pubDate>Mon, 6 Apr 2026 16:24:05 +0900</pubDate>
    </item>
    <item>
      <title>ML - 모델 학습 및 평가</title>
      <link>https://bonggyulim.tistory.com/35</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 전처리가 끝났다면 이제 본격적으로 머신러닝 모델을 학습시키고 성능을 평가할 수 있다. 실제 머신러닝 프로젝트에서는 모델 하나만 사용하는 것이 아니라, 여러 모델을 비교해보고 데이터에 더 잘 맞는 모델을 선택하는 과정이 중요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 이번 글에서는 대표적인 &lt;b&gt;회귀 모델&lt;/b&gt;과 &lt;b&gt;분류 모델&lt;/b&gt;의 기본 사용법을 정리한다. &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;628&quot; data-start=&quot;579&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;603&quot; data-start=&quot;579&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;회귀 예제:&lt;/b&gt; tips 데이터셋&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;628&quot; data-start=&quot;604&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;분류 예제:&lt;/b&gt; iris 데이터셋&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1. 회귀 모델 학습 파트&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;1336&quot; data-start=&quot;1251&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;회귀는 &lt;b&gt;연속적인 숫자 값&lt;/b&gt;을 예측하는 문제이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;예를 들어 집값, 매출, 온도, 점수처럼 숫자로 표현되는 값을 예측할 때 회귀 모델을 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이번 예제에서는 tips 데이터셋을 사용해서 **팁 금액(tip)**을 예측해본다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;1.0. 데이터 준비&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775305654727&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;tips = sns.load_dataset(&quot;tips&quot;).copy()

# 결측치 / 중복 제거
tips = tips.dropna().drop_duplicates()

# 먼저 설명력이 높을 가능성이 큰 컬럼만 사용
selected_features_reg = [&quot;total_bill&quot;, &quot;size&quot;, &quot;smoker&quot;, &quot;time&quot;]

X_reg = tips[selected_features_reg]
y_reg = tips[&quot;tip&quot;]

categorical_cols_reg = X_reg.select_dtypes(include=[&quot;object&quot;, &quot;category&quot;]).columns.tolist()
numeric_cols_reg = X_reg.select_dtypes(include=[&quot;int64&quot;, &quot;float64&quot;]).columns.tolist()

preprocessor_reg = ColumnTransformer(
    transformers=[
        (&quot;num&quot;, StandardScaler(), numeric_cols_reg),
        (&quot;cat&quot;, OneHotEncoder(handle_unknown=&quot;ignore&quot;), categorical_cols_reg)
    ]
)

X_train_reg, X_test_reg, y_train_reg, y_test_reg = train_test_split(
    X_reg, y_reg, test_size=0.2, random_state=42
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; tips 데이터셋에는 총 결제 금액, 성별, 흡연 여부, 요일, 시간대, 인원 수 등의 정보가 들어 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 중에서 tip을 타깃으로 두고 나머지 컬럼을 입력값으로 사용한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;letter-spacing: 0px; color: #333333;&quot;&gt;여기서는 수치형 컬럼에는 StandardScaler를 적용하고, 범주형 컬럼에는 OneHotEncoder를 적용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;1.1. LinearRegression &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; LinearRegression은 가장 기본적인 선형 회귀 모델이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;입력 변수와 타깃 사이의 선형 관계를 바탕으로 예측한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;해석이 쉽고 빠르기 때문에 회귀 문제의 첫 출발점으로 많이 사용한다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775305406336&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;lr_reg_model = Pipeline([
    (&quot;preprocessor&quot;, preprocessor_reg),
    (&quot;model&quot;, LinearRegression())
])

lr_reg_model.fit(X_train_reg, y_train_reg)
lr_reg_pred = lr_reg_model.predict(X_test_reg)

print(lr_reg_pred[:5])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 선형 관계가 어느 정도 잘 맞는 데이터에서는 좋은 기준 모델이 될 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;다만 관계가 복잡하거나 비선형 패턴이 강하면 성능이 제한될 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;1.2. Ridge &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; Ridge는 선형 회귀에 &lt;b&gt;L2 정규화&lt;/b&gt;를 추가한 모델이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;변수가 많거나 다중공선성이 있을 때 계수가 지나치게 커지는 것을 완화하는 데 도움이 된다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775305453311&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ridge_reg_model = Pipeline([
    (&quot;preprocessor&quot;, preprocessor_reg),
    (&quot;model&quot;, Ridge(alpha=1.0))
])

ridge_reg_model.fit(X_train_reg, y_train_reg)
ridge_reg_pred = ridge_reg_model.predict(X_test_reg)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 선형 회귀와 비슷하게 사용할 수 있지만, 과적합을 조금 더 안정적으로 제어할 수 있다는 장점이 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt; 1.3. Lasso &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; Lasso는 선형 회귀에 &lt;b&gt;L1 정규화&lt;/b&gt;를 추가한 모델이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;불필요한 변수의 계수를 0으로 만들 수 있어서 변수 선택 효과가 나타날 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775305491775&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;lasso_reg_model = Pipeline([
    (&quot;preprocessor&quot;, preprocessor_reg),
    (&quot;model&quot;, Lasso(alpha=0.1))
])

lasso_reg_model.fit(X_train_reg, y_train_reg)
lasso_reg_pred = lasso_reg_model.predict(X_test_reg)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 변수가 많고 어떤 변수가 중요한지 함께 보고 싶을 때 자주 사용한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;다만 alpha 값에 따라 성능 차이가 크게 날 수 있으므로 튜닝이 중요하다.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;1800&quot; data-end=&quot;1947&quot;&gt;선형 회귀 모델은 입력 변수가 많아지거나 서로 비슷한 정보를 가진 변수가 함께 들어오면, 특정 계수가 지나치게 커지면서 훈련 데이터에만 잘 맞는 방향으로 학습될 수 있다. 이런 문제를 완화하기 위해 사용하는 방법이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;정규화(Regularization)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p style=&quot;background-color: #fafafa; color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;1949&quot; data-end=&quot;2046&quot;&gt;정규화는 모델의 계수가 너무 커지지 않도록 패널티를 주는 방식이다.&lt;br /&gt;즉, 단순히 훈련 데이터에만 맞추는 것이 아니라 조금 더 일반화된 예측을 하도록 유도하는 역할을 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-start=&quot;2454&quot; data-end=&quot;2499&quot;&gt;&lt;b&gt;L1 정규화(Lasso)&lt;/b&gt;: 불필요한 변수의 계수를 0으로 만들 수 있음&lt;/li&gt;
&lt;li data-start=&quot;2500&quot; data-end=&quot;2545&quot;&gt;&lt;b&gt;L2 정규화(Ridge)&lt;/b&gt;: 계수 크기를 전반적으로 줄여 과적합을 완화함&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;1.4. DecisionTreeRegressor &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; DecisionTreeRegressor는 데이터를 규칙 기반으로 계속 나누면서 예측하는 모델이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;비선형 관계를 잘 다룰 수 있고, 구조를 이해하기도 비교적 쉽다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775305532354&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;tree_reg_model = Pipeline([
    (&quot;preprocessor&quot;, preprocessor_reg),
    (&quot;model&quot;, DecisionTreeRegressor(random_state=42))
])

tree_reg_model.fit(X_train_reg, y_train_reg)
tree_reg_pred = tree_reg_model.predict(X_test_reg)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 데이터의 복잡한 패턴을 잡아낼 수 있지만, 깊이가 너무 깊어지면 과적합되기 쉽다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt; 1.5. RandomForestRegressor &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; RandomForestRegressor는 여러 개의 결정트리를 만들어 그 결과를 평균내는 앙상블 모델이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;단일 트리보다 일반화 성능이 더 좋은 경우가 많고, 실무에서도 자주 사용한다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775305562375&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rf_reg_model = Pipeline([
    (&quot;preprocessor&quot;, preprocessor_reg),
    (&quot;model&quot;, RandomForestRegressor(random_state=42))
])

rf_reg_model.fit(X_train_reg, y_train_reg)
rf_reg_pred = rf_reg_model.predict(X_test_reg)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 기본 성능이 안정적인 편이라 회귀 문제에서 자주 비교 대상으로 올라오는 모델이다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;1.6. KNeighborsRegressor &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;4793&quot; data-start=&quot;4714&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;가까운 이웃들의 값을 참고해서 예측하는 모델이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;단순하지만 데이터 스케일에 민감하고, 데이터 양이 많아지면 예측 속도가 느려질 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1775305608327&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;knn_reg_model = Pipeline([
    (&quot;preprocessor&quot;, preprocessor_reg),
    (&quot;model&quot;, KNeighborsRegressor(n_neighbors=5))
])

knn_reg_model.fit(X_train_reg, y_train_reg)
knn_reg_pred = knn_reg_model.predict(X_test_reg)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;1.7. SVR &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 서포트 벡터 머신을 회귀에 적용한 모델이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;복잡한 관계를 잘 잡을 수 있지만, 데이터가 많아질수록 학습 비용이 커질 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775305616265&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;svr_reg_model = Pipeline([
    (&quot;preprocessor&quot;, preprocessor_reg),
    (&quot;model&quot;, SVR())
])

svr_reg_model.fit(X_train_reg, y_train_reg)
svr_reg_pred = svr_reg_model.predict(X_test_reg)&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;1388&quot; data-start=&quot;1338&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. 분류 모델 학습 파트 &lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;5490&quot; data-start=&quot;5379&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;분류는 정답이 숫자 연속값이 아니라 &lt;b&gt;범주(label)&lt;/b&gt; 인 문제이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;예를 들어 이메일이 스팸인지 아닌지, 꽃의 품종이 무엇인지, 고객이 이탈할지 말지 등을 예측할 때 분류 모델을 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;5536&quot; data-start=&quot;5492&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이번 예제에서는 iris 데이터셋을 사용해서 &lt;b&gt;꽃의 품종&lt;/b&gt;을 예측해본다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;5536&quot; data-start=&quot;5492&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt; 2.0. 데이터 준비&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775305831696&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;iris = load_iris(as_frame=True)
df_iris = iris.frame

X_clf = df_iris.drop(&quot;target&quot;, axis=1)
y_clf = df_iris[&quot;target&quot;]

X_train_clf, X_test_clf, y_train_clf, y_test_clf = train_test_split(
    X_clf,
    y_clf,
    test_size=0.2,
    random_state=42,
    stratify=y_clf
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; iris 데이터셋은 이미 수치형 변수로 정리되어 있기 때문에 비교적 간단하게 사용할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;분류 문제에서는 stratify=y를 넣어서 클래스 비율이 학습용과 테스트용에 비슷하게 유지되도록 하는 경우가 많다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;2.1. LogisticRegression&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; LogisticRegression은 이름에 회귀가 들어가지만 대표적인 분류 모델이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기본이 되는 선형 분류 모델로, 빠르고 해석도 비교적 쉬운 편이다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775305928848&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;log_clf_model = Pipeline([
    (&quot;scaler&quot;, StandardScaler()),
    (&quot;model&quot;, LogisticRegression(max_iter=1000))
])

log_clf_model.fit(X_train_clf, y_train_clf)
log_clf_pred = log_clf_model.predict(X_test_clf)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 선형적으로 구분이 어느 정도 가능한 문제에서 좋은 출발점이 된다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;2.2. KNeighborsClassifier&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; KNeighborsClassifier는 가까운 샘플들의 다수결로 클래스를 예측하는 모델이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;직관적이고 이해하기 쉽지만, 거리 기반이라 스케일링이 중요하다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775305950440&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;knn_clf_model = Pipeline([
    (&quot;scaler&quot;, StandardScaler()),
    (&quot;model&quot;, KNeighborsClassifier(n_neighbors=5))
])

knn_clf_model.fit(X_train_clf, y_train_clf)
knn_clf_pred = knn_clf_model.predict(X_test_clf)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 데이터 구조가 비교적 단순할 때 좋은 성능을 내는 경우가 많다. &lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;2.3. DecisionTreeClassifier&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;6931&quot; data-start=&quot;6831&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;DecisionTreeClassifier는 질문을 반복하면서 데이터를 나누는 방식으로 클래스를 분류한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;비선형 패턴을 반영할 수 있고, 규칙 기반이라 해석도 쉬운 편이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775305978231&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;tree_clf_model = Pipeline([
    (&quot;model&quot;, DecisionTreeClassifier(random_state=42))
])

tree_clf_model.fit(X_train_clf, y_train_clf)
tree_clf_pred = tree_clf_model.predict(X_test_clf)&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 깊이가 깊어지면 훈련 데이터에 과적합될 수 있으므로 주의가 필요하다. &lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;2.4. RandomForestClassifier&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; RandomForestClassifier는 여러 개의 결정트리를 조합한 앙상블 분류 모델이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기본 성능이 안정적이고 실무에서도 자주 사용된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775305998687&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rf_clf_model = Pipeline([
    (&quot;model&quot;, DecisionTreeClassifier(random_state=42))
])

rf_clf_model.fit(X_train_clf, y_train_clf)
rf_clf_model = tree_clf_model.predict(X_test_clf)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 단일 트리보다 과적합이 덜하고, 중요한 변수를 함께 확인할 수 있다는 장점이 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;2.5. SVC&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 서포트 벡터 머신 기반 분류 모델이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;결정 경계를 잘 찾는 편이고 성능이 좋은 경우가 많지만, 데이터가 커질수록 계산량이 증가할 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306018577&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;svc_clf_model = Pipeline([
    (&quot;scaler&quot;, StandardScaler()),
    (&quot;model&quot;, SVC())
])

svc_clf_model.fit(X_train_clf, y_train_clf)
svc_clf_pred = svc_clf_model.predict(X_test_clf)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;2.6. GradientBoostingClassifier &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 이전 모델의 오차를 보완해가며 순차적으로 학습하는 부스팅 계열 모델이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;성능이 잘 나오는 경우가 많지만, 하이퍼파라미터에 민감할 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306032544&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;gb_clf_model = Pipeline([
    (&quot;model&quot;, GradientBoostingClassifier(random_state=42))
])

gb_clf_model.fit(X_train_clf, y_train_clf)
gb_clf_pred = gb_clf_model.predict(X_test_clf)&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;3. 교차검증&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;8396&quot; data-start=&quot;8284&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;학습 데이터를 한 번만 나눠서 성능을 평가하면, 우연히 잘 나왔거나 우연히 낮게 나올 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;즉, train/test split 한 번만으로는 모델의 성능을 안정적으로 판단하기 어려울 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;8498&quot; data-start=&quot;8398&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이럴 때 사용하는 것이 &lt;b&gt;교차검증(Cross Validation)&lt;/b&gt; 이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;교차검증은 데이터를 여러 번 나눠서 반복적으로 학습하고 평가한 뒤 평균 성능을 확인하는 방식이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;3.1. cross_val_scor&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306100648&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 회귀 모델 교차검증
lr_cv_pipe = Pipeline([
    (&quot;preprocessor&quot;, preprocessor_reg),
    (&quot;model&quot;, LinearRegression())
])

cv_scores_reg = cross_val_score(
    lr_cv_pipe,
    X_reg,
    y_reg,
    cv=5,
    scoring=&quot;r2&quot;
)

print(&quot;회귀 교차검증 R2:&quot;, cv_scores_reg)
print(&quot;회귀 평균 R2:&quot;, cv_scores_reg.mean())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt; 3.2. KFold와 StratifiedKFold &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;9026&quot; data-start=&quot;8998&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;KFold는 데이터를 단순히 K개로 나눈다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1775310947425&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 회귀 모델 교차검증
lr_cv_pipe = Pipeline([
    (&quot;preprocessor&quot;, preprocessor_reg),
    (&quot;model&quot;, LinearRegression())
])

cv_scores_reg = cross_val_score(
    lr_cv_pipe,
    X_reg,
    y_reg,
    cv=5,
    scoring=&quot;r2&quot;
)

print(&quot;회귀 교차검증 R2:&quot;, cv_scores_reg)
print(&quot;회귀 평균 R2:&quot;, cv_scores_reg.mean())&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 data-end=&quot;9066&quot; data-start=&quot;9027&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;StratifiedKFold는 클래스 비율을 유지하면서 나눈다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 분류 문제에서는 클래스 비율이 중요하기 때문에 StratifiedKFold가 자주 사용된다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306176871&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 분류 모델 교차검증
skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)

rf_cv_clf_pipe = Pipeline([
    (&quot;model&quot;, RandomForestClassifier(random_state=42))
])

cv_scores_clf = cross_val_score(
    rf_cv_clf_pipe,
    X_clf,
    y_clf,
    cv=skf,
    scoring=&quot;accuracy&quot;
)

print(&quot;분류 교차검증 Accuracy:&quot;, cv_scores_clf)
print(&quot;분류 평균 Accuracy:&quot;, cv_scores_clf.mean())&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;4. 하이퍼파라미터 튜닝 &lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 모델에는 사람이 직접 설정해야 하는 값들이 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;예를 들어 트리의 최대 깊이, 랜덤포레스트의 트리 개수, KNN의 이웃 수 같은 값이 여기에 해당한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이런 값을 &lt;b&gt;하이퍼파라미터&lt;/b&gt;라고 한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 반면, 모델이 학습 과정에서 스스로 찾는 값은 학습 파라미터라고 볼 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;예를 들어 선형 회귀의 계수 값은 학습 파라미터이다. &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;8500&quot; data-end=&quot;8529&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;4.1 GridSearchCV &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;8500&quot; data-end=&quot;8529&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; GridSearchCV는 미리 정한 하이퍼파라미터 조합을 &lt;b&gt;전부 탐색&lt;/b&gt;하는 방식이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;후보 수가 많지 않을 때는 체계적으로 확인할 수 있다는 장점이 있다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306307944&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 회귀 - GridSearchCV
param_grid_reg = {
    &quot;model__n_estimators&quot;: [100, 200],
    &quot;model__max_depth&quot;: [None, 3, 5, 10]
}

rf_reg_search = GridSearchCV(
    estimator=Pipeline([
        (&quot;preprocessor&quot;, preprocessor_reg),
        (&quot;model&quot;, RandomForestRegressor(random_state=42))
    ]),
    param_grid=param_grid_reg,
    cv=5,
    scoring=&quot;r2&quot;,
    n_jobs=-1
)

rf_reg_search.fit(X_train_reg, y_train_reg)

print(&quot;회귀 최적 파라미터:&quot;, rf_reg_search.best_params_)
print(&quot;회귀 최고 교차검증 점수:&quot;, rf_reg_search.best_score_)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;8500&quot; data-end=&quot;8529&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;4.2 RandomizedSearchCV &lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot; data-start=&quot;8500&quot; data-end=&quot;8529&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; RandomizedSearchCV는 가능한 조합 전체를 다 보지 않고, 일부 조합을 &lt;b&gt;무작위로 샘플링&lt;/b&gt;해서 탐색한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;탐색 범위가 넓고 조합 수가 많을 때 더 효율적일 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306325560&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 분류 - RandomizedSearchCV
param_dist_clf = {
    &quot;model__n_estimators&quot;: [50, 100, 200, 300],
    &quot;model__max_depth&quot;: [None, 3, 5, 10, 20],
    &quot;model__min_samples_split&quot;: [2, 5, 10]
}

rf_clf_search = RandomizedSearchCV(
    estimator=Pipeline([
        (&quot;model&quot;, RandomForestClassifier(random_state=42))
    ]),
    param_distributions=param_dist_clf,
    n_iter=10,
    cv=5,
    scoring=&quot;accuracy&quot;,
    random_state=42,
    n_jobs=-1
)

rf_clf_search.fit(X_train_clf, y_train_clf)

print(&quot;분류 최적 파라미터:&quot;, rf_clf_search.best_params_)
print(&quot;분류 최고 교차검증 점수:&quot;, rf_clf_search.best_score_)&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 5. 평가 지표 정리&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt; 5.1. 회귀 평가 지표 정리 &lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 회귀 문제는 예측값과 실제값이 얼마나 차이 나는지를 기준으로 성능을 평가한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;MAE(Mean Absolute Error)&lt;/b&gt; 는 예측값과 실제값 차이의 절댓값 평균이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306556096&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mae = mean_absolute_error(y_test_reg, lr_reg_pred)&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 data-end=&quot;13182&quot; data-start=&quot;13162&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;오차를 직관적으로 이해하기 쉽다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;13204&quot; data-start=&quot;13183&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이상치의 영향이 MSE보다 덜하다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;13219&quot; data-start=&quot;13205&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;작을수록 좋다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;MSE(Mean Squared Error)&lt;/b&gt; 는 오차를 제곱해서 평균낸 값이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306570848&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mae = mean_absolute_error(y_test_reg, lr_reg_pred)&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 data-end=&quot;13434&quot; data-start=&quot;13414&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;큰 오차에 더 큰 패널티를 준다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;13447&quot; data-start=&quot;13435&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이상치에 민감하다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;13462&quot; data-start=&quot;13448&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;작을수록 좋다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;RMSE(Root Mean Squared Error)&lt;/b&gt; 는 MSE에 제곱근을 취한 값이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306592144&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rmse = np.sqrt(mse)&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 data-end=&quot;13690&quot; data-start=&quot;13662&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;다시 원래 단위로 해석할 수 있어서 직관적이다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;13711&quot; data-start=&quot;13691&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;큰 오차를 더 민감하게 반영한다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;13726&quot; data-start=&quot;13712&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;작을수록 좋다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;13892&quot; data-start=&quot;13845&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;R&amp;sup2; Score&lt;/b&gt; 는 모델이 데이터를 얼마나 잘 설명하는지를 보여주는 지표이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306606727&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;r2 = r2_score(y_test_reg, lr_reg_pred)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;13994&quot; data-start=&quot;13894&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;13908&quot; data-start=&quot;13894&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1에 가까울수록 좋다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;13939&quot; data-start=&quot;13909&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;0이면 평균 수준의 예측과 비슷하다고 볼 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;13980&quot; data-start=&quot;13940&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;음수가 나올 수도 있는데, 그 경우 평균보다도 못한 예측일 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;13994&quot; data-start=&quot;13981&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;클수록 좋다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;5.2. 분류 평가 지표 정리&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;Accuracy&lt;/b&gt; 는 전체 예측 중 정답을 맞힌 비율이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306641704&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;acc = accuracy_score(y_test_clf, rf_clf_pred)&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 data-end=&quot;14257&quot; data-start=&quot;14242&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;가장 직관적인 지표이다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;14282&quot; data-start=&quot;14258&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;데이터가 균형 잡혀 있을 때는 유용하다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;14315&quot; data-start=&quot;14283&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;클래스 불균형이 심하면 misleading할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;14329&quot; data-start=&quot;14316&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;클수록 좋다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; &lt;b&gt;F1-score&lt;/b&gt; 는 Precision과 Recall의 균형을 함께 보는 지표이다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306670776&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;f1 = f1_score(y_test_clf, rf_clf_pred, average=&quot;macro&quot;)&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 data-end=&quot;15193&quot; data-start=&quot;15157&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;둘 중 하나만 높고 하나가 낮은 상황을 보완해서 볼 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;15220&quot; data-start=&quot;15194&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;클래스 불균형 문제에서 자주 함께 확인한다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;15234&quot; data-start=&quot;15221&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;클수록 좋다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;15446&quot; data-start=&quot;15392&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Confusion Matrix&lt;/b&gt; 는 실제 클래스와 예측 클래스의 조합을 표 형태로 보여준다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306712856&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cm = confusion_matrix(y_test_clf, rf_clf_pred)
print(&quot;Confusion Matrix:\n&quot;, cm)

print(classification_report(y_test_clf, rf_clf_pred))&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;15507&quot; data-start=&quot;15448&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;15488&quot; data-start=&quot;15448&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;어떤 클래스를 잘 맞추고, 어떤 클래스를 헷갈리는지 확인할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;15507&quot; data-start=&quot;15489&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;다중분류에서도 매우 유용하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 분류 문제에서는 Accuracy만 보는 것보다 Precision, Recall, F1-score, Confusion Matrix까지 함께 보는 것이 훨씬 안전하다. &lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;6. Feature Importance / Permutation Importance &lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 모델을 학습한 뒤에는 단순히 성능만 보는 것이 아니라, &lt;b&gt;어떤 feature가 예측에 많이 기여했는지&lt;/b&gt; 확인하고 싶을 때가 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이때 자주 사용하는 것이 Feature Importance와 Permutation Importance이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;11620&quot; data-start=&quot;11594&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;6.1. Feature Importance&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;11712&quot; data-start=&quot;11622&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Feature Importance는 주로 &lt;b&gt;트리 계열 모델&lt;/b&gt;에서 많이 사용한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;각 feature가 분할에 얼마나 기여했는지를 기준으로 중요도를 계산한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306434176&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rf_importance_model = RandomForestClassifier(random_state=42)
rf_importance_model.fit(X_train_clf, y_train_clf)

feature_importance_df = pd.DataFrame({
    &quot;feature&quot;: X_train_clf.columns,
    &quot;importance&quot;: rf_importance_model.feature_importances_
}).sort_values(&quot;importance&quot;, ascending=False)

print(feature_importance_df)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;12148&quot; data-start=&quot;12066&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 값이 높을수록 모델이 해당 변수를 더 많이 참고했다는 뜻으로 해석할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;다만 트리 기반 모델에 의존적이라는 점을 기억할 필요가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;12185&quot; data-start=&quot;12155&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;6.2. Permutation Importance&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;12298&quot; data-start=&quot;12187&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Permutation Importance는 특정 feature 값을 섞었을 때 모델 성능이 얼마나 떨어지는지를 보는 방식이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;중요한 feature라면 값을 섞었을 때 성능 하락이 크게 나타난다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775306444064&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;perm_result = permutation_importance(
    rf_importance_model,
    X_test_clf,
    y_test_clf,
    n_repeats=10,
    random_state=42,
    scoring=&quot;accuracy&quot;
)

perm_importance_df = pd.DataFrame({
    &quot;feature&quot;: X_test_clf.columns,
    &quot;importance_mean&quot;: perm_result.importances_mean
}).sort_values(&quot;importance_mean&quot;, ascending=False)

print(perm_importance_df)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;12334&quot; data-start=&quot;12300&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 방법은 특정 모델에 덜 종속적이어서 활용 범위가 더 넓다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;7. 모델 평가 시각화&lt;/span&gt;&lt;/h3&gt;
&lt;h4 data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;7.1 회귀 시각화&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 회귀 문제에서는 숫자 지표만 보는 것보다 예측 결과를 시각적으로 확인하는 것이 훨씬 이해하기 쉽다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 같은 데이터셋이라도 모델마다 예측 방식이 다르기 때문에, 성능 비교표와 함께 그래프를 보면 어떤 모델이 더 안정적으로 예측하는지 빠르게 파악할 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;h4 data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 모델별 R&amp;sup2; 비교 막대그래프&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 먼저 모델별 R&amp;sup2; 비교 그래프를 그리면 전체적인 설명력을 한눈에 볼 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;R&amp;sup2;가 높을수록 실제 데이터의 흐름을 더 잘 설명한다고 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775307431424&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plt.figure(figsize=(10, 5))
sns.barplot(data=reg_results_df, x=&quot;Model&quot;, y=&quot;R2&quot;)
plt.xticks(rotation=45)
plt.title(&quot;Regression Model R2 Comparison&quot;)
plt.tight_layout()
plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;984&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bR2BfX/dJMcahYe3aV/YjhnPDzS8UpDznhoncYnF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bR2BfX/dJMcahYe3aV/YjhnPDzS8UpDznhoncYnF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bR2BfX/dJMcahYe3aV/YjhnPDzS8UpDznhoncYnF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbR2BfX%2FdJMcahYe3aV%2FYjhnPDzS8UpDznhoncYnF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;573&quot; height=&quot;285&quot; data-origin-width=&quot;984&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 실제값 vs 예측값 산점도 &lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 실제값과 예측값 산점도도 자주 사용한다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이 그래프에서 점들이 대각선 근처에 모일수록 예측이 잘된 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;점들이 넓게 퍼져 있으면 실제값과 예측값 차이가 크다는 뜻이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775309213828&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;plt.figure(figsize=(6, 6))
plt.scatter(y_test_reg, best_reg_pred, alpha=0.7)
plt.plot(
    [y_test_reg.min(), y_test_reg.max()],
    [y_test_reg.min(), y_test_reg.max()],
    linestyle=&quot;--&quot;
)
plt.xlabel(&quot;Actual Tip&quot;)
plt.ylabel(&quot;Predicted Tip&quot;)
plt.title(f&quot;Actual vs Predicted ({best_reg_name})&quot;)
plt.tight_layout()
plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;590&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZDwAU/dJMcaa5TMDl/dQJXk3OU3lbwkXdF5lP4S1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZDwAU/dJMcaa5TMDl/dQJXk3OU3lbwkXdF5lP4S1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZDwAU/dJMcaa5TMDl/dQJXk3OU3lbwkXdF5lP4S1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZDwAU%2FdJMcaa5TMDl%2FdQJXk3OU3lbwkXdF5lP4S1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;347&quot; height=&quot;347&quot; data-origin-width=&quot;590&quot; data-origin-height=&quot;590&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 잔차 시각화&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 잔차는 실제값에서 예측값을 뺀 값이며, 모델이 어디에서 얼마나 틀렸는지 보여준다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;잔차 분포가 0 근처에 고르게 모이면 비교적 안정적인 예측이라고 볼 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;반대로 특정 방향으로 치우치거나 이상하게 퍼져 있다면, 모델이 어떤 구간에서 지속적으로 과대예측 또는 과소예측하고 있을 가능성이 있다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775309173611&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;plt.figure(figsize=(8, 5))
plt.scatter(best_reg_pred, residuals, alpha=0.7)
plt.axhline(0, linestyle=&quot;--&quot;)
plt.xlabel(&quot;Predicted Value&quot;)
plt.ylabel(&quot;Residual&quot;)
plt.title(f&quot;Residual Plot ({best_reg_name})&quot;)
plt.tight_layout()
plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdoXgd/dJMcabwWAMh/2sMWbHnkeEp4q3iKNqKtOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdoXgd/dJMcabwWAMh/2sMWbHnkeEp4q3iKNqKtOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdoXgd/dJMcabwWAMh/2sMWbHnkeEp4q3iKNqKtOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdoXgd%2FdJMcabwWAMh%2F2sMWbHnkeEp4q3iKNqKtOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;463&quot; height=&quot;287&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 7.2 분류 시각화 &lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 분류 문제에서는 단순히 Accuracy만 보는 것보다, 모델이 어떤 클래스를 잘 맞추고 어떤 클래스를 헷갈리는지를 함께 보는 것이 중요하다. &lt;/span&gt;&lt;/p&gt;
&lt;h4 data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; Accuracy 비교 막대그래프 &lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1775308999161&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plt.figure(figsize=(10, 5))
sns.barplot(data=clf_results_df, x=&quot;Model&quot;, y=&quot;Accuracy&quot;)
plt.xticks(rotation=45)
plt.title(&quot;Classification Model Accuracy Comparison&quot;)
plt.tight_layout()
plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;989&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUa2E6/dJMcaiW62Ry/UeW31kAuS6iYiKhfi3wKgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUa2E6/dJMcaiW62Ry/UeW31kAuS6iYiKhfi3wKgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUa2E6/dJMcaiW62Ry/UeW31kAuS6iYiKhfi3wKgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUa2E6%2FdJMcaiW62Ry%2FUeW31kAuS6iYiKhfi3wKgk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;989&quot; height=&quot;490&quot; data-origin-width=&quot;989&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Confusion Matrix heatmap&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;8529&quot; data-start=&quot;8500&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; Confusion Matrix는 분류 문제에서 가장 대표적인 시각화이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;실제 클래스와 예측 클래스의 조합을 표 형태로 보여주기 때문에, 어떤 클래스를 정확히 맞추고 어떤 클래스를 혼동하는지 바로 확인할 수 있다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;다중분류 문제인 iris 데이터셋에서도 각 품종이 얼마나 잘 분류되는지 직관적으로 볼 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775309051353&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cm = confusion_matrix(y_test_clf, best_clf_pred)

plt.figure(figsize=(6, 5))
sns.heatmap(cm, annot=True, fmt=&quot;d&quot;, cmap=&quot;Blues&quot;)
plt.title(f&quot;Confusion Matrix ({best_clf_name})&quot;)
plt.xlabel(&quot;Predicted Label&quot;)
plt.ylabel(&quot;True Label&quot;)
plt.tight_layout()
plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;558&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EwFc1/dJMcacJqF3Y/A0TJncf2y4O1IKJevreC31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EwFc1/dJMcacJqF3Y/A0TJncf2y4O1IKJevreC31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EwFc1/dJMcacJqF3Y/A0TJncf2y4O1IKJevreC31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEwFc1%2FdJMcacJqF3Y%2FA0TJncf2y4O1IKJevreC31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;558&quot; height=&quot;490&quot; data-origin-width=&quot;558&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;15183&quot; data-start=&quot;15086&quot; data-ke-size=&quot;size16&quot;&gt;이번 글에서는 회귀와 분류 문제를 나누어 대표적인 머신러닝 모델의 기본 사용법을 살펴보고, 교차검증과 하이퍼파라미터 튜닝, 평가 지표, 그리고 시각화 방법까지 함께 정리했다.&lt;/p&gt;
&lt;p data-end=&quot;15183&quot; data-start=&quot;15086&quot; data-ke-size=&quot;size16&quot;&gt;모델을 선택할때 해석이 쉬운 LinearRegression, LogisticRegression 같은 기본 모델로 시작하고, 이후 비선형 패턴이 의심되면 DecisionTree, RandomForest, GradientBoosting, SVC 등을 비교하는 방식이 일반적이다. 데이터 스케일에 민감한 KNN, SVC 계열은 스케일링 여부를 특히 신경 써야 한다.&lt;/p&gt;
&lt;p data-end=&quot;15330&quot; data-start=&quot;15185&quot; data-ke-size=&quot;size16&quot;&gt;머신러닝에서는 모델 하나만 학습해보는 것보다 여러 모델을 같은 기준으로 비교해보는 과정이 중요하다.&lt;br /&gt;또한 성능 수치만 보는 데서 끝나지 않고, 실제 예측 결과와 오차, 클래스별 분류 결과, 변수 중요도까지 함께 확인해야 모델을 더 정확하게 이해할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;</description>
      <category>AI dev/Machine Learning</category>
      <author>bonggyulim</author>
      <guid isPermaLink="true">https://bonggyulim.tistory.com/35</guid>
      <comments>https://bonggyulim.tistory.com/35#entry35comment</comments>
      <pubDate>Sat, 4 Apr 2026 22:50:59 +0900</pubDate>
    </item>
    <item>
      <title>ML - 데이터 전처리</title>
      <link>https://bonggyulim.tistory.com/34</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;머신러닝에서 모델을 바꾸는 것만큼 중요한 것이 데이터 전처리다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;실제로 데이터를 다뤄보면 모델을 바로 학습하는 시간보다, 먼저 데이터를 확인하고 정리하고 가공하는 시간이 더 길다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;복잡한 수식 설명보다 &lt;b&gt;실제로 어떻게 전처리를 하는지&lt;/b&gt;에 집중해서 정리했다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;예시는 seaborn의 tips 데이터셋을 사용했다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-end=&quot;385&quot; data-start=&quot;277&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 1. 실습 준비&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1775289855707&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder, StandardScaler, MinMaxScaler&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-start=&quot;277&quot; data-end=&quot;385&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. 데이터 불러오기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 먼저 기본 데이터셋을 불러온다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P7MhB/dJMcaakv8Or/MjeKKGXymEAypqt8R5PZ31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P7MhB/dJMcaakv8Or/MjeKKGXymEAypqt8R5PZ31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P7MhB/dJMcaakv8Or/MjeKKGXymEAypqt8R5PZ31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FP7MhB%2FdJMcaakv8Or%2FMjeKKGXymEAypqt8R5PZ31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;404&quot; height=&quot;166&quot; data-origin-width=&quot;404&quot; data-origin-height=&quot;166&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1775289968554&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;tips = sns.load_dataset(&quot;tips&quot;)
df = tips.copy()
df.head() # 데이터 앞부분 확인&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 3. 데이터 확인&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 전처리의 시작은 데이터를 확인하는 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;컬럼 구성, 데이터 타입, 결측치 여부, 수치형 분포를 먼저 봐야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatRight&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sL9ER/dJMcahRsXnv/odOAUIGg4t1ypSwkrckoW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sL9ER/dJMcahRsXnv/odOAUIGg4t1ypSwkrckoW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sL9ER/dJMcahRsXnv/odOAUIGg4t1ypSwkrckoW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsL9ER%2FdJMcahRsXnv%2FodOAUIGg4t1ypSwkrckoW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;352&quot; height=&quot;310&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1775295862316&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;print(&quot;===== 데이터 정보 =====&quot;)
df.info()

# 수치형 컬럼의 기초 통계량 확인
print(&quot;===== 기초 통계량 =====&quot;)
df.describe()

# 컬럼명 확인
print(&quot;===== 컬럼 목록 =====&quot;)
df.columns

# 특정 컬럼 확인
df[[&quot;total_bill&quot;, &quot;tip&quot;]].head()&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;4. 결측치 확인과 처리&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 실무 데이터에서는 결측치가 자주 나온다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기본 tips 데이터셋은 결측치가 거의 없기 때문에, 실습용으로 일부 값을 비워서 처리 과정을 확인해보겠다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775296204988&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df.loc[0, &quot;total_bill&quot;] = np.nan
df.loc[3, &quot;sex&quot;] = np.nan
df.loc[5, &quot;smoker&quot;] = np.nan&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt; 4-1. 결측치 확인&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;isnull()은 결측치 여부를 확인하고, sum()을 붙이면 컬럼별 결측치 개수를 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1775296715604&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df.isnull().sum()   # 각 열의 결측치 개수 확인&lt;/code&gt;&lt;/pre&gt;
&lt;table style=&quot;border-collapse: collapse; width: 42.2089%; height: 223px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 223px;&quot;&gt;
&lt;td style=&quot;width: 2.71003%; text-align: center; height: 223px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;129&quot; data-origin-height=&quot;161&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Bn83q/dJMcab4M6Cp/GlQB2yICFTJIK4dRIKGP6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Bn83q/dJMcab4M6Cp/GlQB2yICFTJIK4dRIKGP6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Bn83q/dJMcab4M6Cp/GlQB2yICFTJIK4dRIKGP6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBn83q%2FdJMcab4M6Cp%2FGlQB2yICFTJIK4dRIKGP6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;129&quot; height=&quot;161&quot; data-origin-width=&quot;129&quot; data-origin-height=&quot;161&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;span&gt;&lt;br /&gt;&lt;/span&gt;결측지 제거전&lt;/td&gt;
&lt;td style=&quot;width: 2.71003%; text-align: center; height: 223px;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;127&quot; data-origin-height=&quot;157&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsFjAb/dJMcadheIAY/9nl4NXyhH5mJcuxILqcyp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsFjAb/dJMcadheIAY/9nl4NXyhH5mJcuxILqcyp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsFjAb/dJMcadheIAY/9nl4NXyhH5mJcuxILqcyp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsFjAb%2FdJMcadheIAY%2F9nl4NXyhH5mJcuxILqcyp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;131&quot; height=&quot;162&quot; data-origin-width=&quot;127&quot; data-origin-height=&quot;157&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;span&gt;&lt;br /&gt;&lt;/span&gt;결측치 제거 후&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;4-2. 수치형 결측치 처리&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fillna()는 비어 있는 값을 다른 값으로 채울 때 사용하는 메서드다.&lt;/p&gt;
&lt;pre id=&quot;code_1775296400876&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 수치형 컬럼은 평균이나 중앙값으로 채우는 경우가 많다
df[&quot;total_bill&quot;] = df[&quot;total_bill&quot;].fillna(df[&quot;total_bill&quot;].mean())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt; 4-3. 범주형 결측치 처리&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775296411967&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 문자형 컬럼은 최빈값으로 채우는 경우가 많다
df[&quot;sex&quot;] = df[&quot;sex&quot;].fillna(df[&quot;sex&quot;].mode()[0])
df[&quot;smoker&quot;] = df[&quot;smoker&quot;].fillna(df[&quot;smoker&quot;].mode()[0])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt; 4-4. 결측치 제거&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;fillna&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;대신&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;경우에&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;따라서는&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;dropna&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;span&gt;로&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;결측치가&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;포함된&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;행을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;제거할&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;수도&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;있다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;다만 &lt;/span&gt;&lt;span&gt;데이터&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;손실이&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;발생할&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;수&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;있으므로&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;신중히&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;사용해야&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;한다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775296491884&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df_dropna = df.dropna()&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 중복 데이터 확인과 제거&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 데이터가 여러 번 들어 있으면 학습에 왜곡이 생길 수 있다.&lt;br /&gt;그래서 중복 여부도 확인해보는 편이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5-1. 중복 확인&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1775297254572&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df.duplicated().sum()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5-2. 중복 제거&lt;/p&gt;
&lt;pre id=&quot;code_1775297288507&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;df = df.drop_duplicates()&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 이상치 확인과 제거&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상치는 다른 값들에 비해 너무 크거나 작은 값이다.&lt;br /&gt;이상치를 그대로 두면 평균, 분산, 회귀 계수 등에 영향을 줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 예제에서는 IQR 기준으로 total_bill의 이상치를 확인한 뒤, &lt;b&gt;전처리 과정 예시를 보여주기 위해 일부 이상치를 제거해보았다&lt;/b&gt;. 이상치라고 보이는 값이 모두 잘못된 데이터는 아니기 때문에, 단순히 수치 기준만으로 바로 삭제하기보다 &lt;b&gt;도메인 의미와 모델 목적을 함께 고려해서 판단해야 한다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-end=&quot;3346&quot; data-start=&quot;3322&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 6-1. 박스플롯으로 이상치 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775302173710&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 박스플롯으로 total_bill의 이상치를 먼저 확인한다.
plt.figure(figsize=(8, 4))
sns.boxplot(x=df[&quot;total_bill&quot;])
plt.title(&quot;total_bill Boxplot&quot;)
plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JVaLq/dJMb996Y4t2/2Iku4vsoOU6CDNFH4k9EaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JVaLq/dJMb996Y4t2/2Iku4vsoOU6CDNFH4k9EaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JVaLq/dJMb996Y4t2/2Iku4vsoOU6CDNFH4k9EaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJVaLq%2FdJMb996Y4t2%2F2Iku4vsoOU6CDNFH4k9EaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;644&quot; height=&quot;393&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&lt;b&gt;6-2. IQR 방식으로 이상치 찾기&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;quantile()은 분위수를 계산하는 메서드다.&lt;br /&gt;IQR 방식은 이상치를 빠르게 확인할 때 많이 사용한다.&lt;/p&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1775297557149&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# total_bill 컬럼을 기준으로 IQR 방식으로 이상치를 찾는다.
Q1 = df[&quot;total_bill&quot;].quantile(0.25)
Q3 = df[&quot;total_bill&quot;].quantile(0.75)
IQR = Q3 - Q1

# 이상치 판단 경계값 설정
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

# 이상치만 따로 확인
outliers = df[(df[&quot;total_bill&quot;] &amp;lt; lower_bound) | (df[&quot;total_bill&quot;] &amp;gt; upper_bound)]
outliers.head() &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 6-3. 이상치 제거&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이상치를 무조건 삭제하는 것이 정답은 아니다.&lt;br /&gt;실제 중요한 이벤트일 수도 있으므로, 먼저 데이터 의미를 확인하는 것이 좋다.&lt;/p&gt;
&lt;pre id=&quot;code_1775297783597&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;df = df[(df[&quot;total_bill&quot;] &amp;gt;= lower_bound) &amp;amp; (df[&quot;total_bill&quot;] &amp;lt;= upper_bound)]
print(&quot;shape:&quot;, df.shape)

# 제거 후 다시 박스플롯 확인
plt.figure(figsize=(8, 4))
sns.boxplot(x=df[&quot;total_bill&quot;])
plt.title(&quot;total_bill Boxplot After Outlier Removal&quot;)
plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제거 전 shape: (244, 7) -&amp;gt; 제거 후 shape: (235, 7)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDKcZn/dJMcajaEwYY/TnAHpHkRsHZ3cEuDjaStpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDKcZn/dJMcajaEwYY/TnAHpHkRsHZ3cEuDjaStpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDKcZn/dJMcajaEwYY/TnAHpHkRsHZ3cEuDjaStpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDKcZn%2FdJMcajaEwYY%2FTnAHpHkRsHZ3cEuDjaStpK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;644&quot; height=&quot;393&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. 필요 없는 컬럼 제거&lt;/h3&gt;
&lt;p data-end=&quot;4091&quot; data-start=&quot;4011&quot; data-ke-size=&quot;size16&quot;&gt;모든 컬럼이 항상 모델에 도움이 되는 것은 아니다.&lt;br /&gt;식별자, 누수 가능성이 있는 값, 모델과 직접 관련 없는 값은 제거 대상이 될 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;4190&quot; data-start=&quot;4157&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어 불필요한 컬럼이 있다면 아래처럼 제거할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1775300854310&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 예시
# df = df.drop(columns=[&quot;id&quot;, &quot;timestamp&quot;])&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;8. 범주형 데이터 인코딩&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;b&gt; 8-1. 라벨 인코딩&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라벨 인코딩은 범주형 값을 정수형으로 바꾸는 방식이다.&lt;br /&gt;라벨 인코딩은 순서형 범주형 데이터에 더 적합하며, 분류 문제의 타깃값 y를 숫자로 바꿀 때도 자주 사용된다.&lt;br /&gt;다만 입력값 X의 명목형 범주형 데이터에는 원-핫 인코딩이 더 적절한 경우가 많다.&lt;/p&gt;
&lt;pre id=&quot;code_1775298671805&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 라벨 인코딩은 범주형 값을 숫자로 바꾸는 방식이다.
# 원-핫 인코딩을 사용할 예정이므로, 여기서는 예시 확인용으로만 별도 복사본을 만들어 진행
df_label = df.copy()

le = LabelEncoder()
df_label[&quot;sex&quot;] = le.fit_transform(df_label[&quot;sex&quot;])
df_label[&quot;smoker&quot;] = le.fit_transform(df_label[&quot;smoker&quot;])
df_label[&quot;day&quot;] = le.fit_transform(df_label[&quot;day&quot;])
df_label[&quot;time&quot;] = le.fit_transform(df_label[&quot;time&quot;])

df_label.head() &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;373&quot; data-origin-height=&quot;162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzp23m/dJMcab4M7fU/K6FSQrK5kWkE01JxU12KRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzp23m/dJMcab4M7fU/K6FSQrK5kWkE01JxU12KRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzp23m/dJMcab4M7fU/K6FSQrK5kWkE01JxU12KRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbzp23m%2FdJMcab4M7fU%2FK6FSQrK5kWkE01JxU12KRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;373&quot; height=&quot;162&quot; data-origin-width=&quot;373&quot; data-origin-height=&quot;162&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-end=&quot;4892&quot; data-start=&quot;4876&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8-2. 원-핫 인코딩&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;4892&quot; data-start=&quot;4876&quot; data-ke-size=&quot;size16&quot;&gt;원-핫 인코딩은 주로 &lt;b&gt;입력값 X의 범주형 변수&lt;/b&gt;를 변환할 때 사용한다.&lt;br /&gt;회귀 모델, SVM, KNN처럼 문자열을 직접 처리하지 못하는 모델에서 자주 사용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1775298858054&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# 범주형 컬럼을 0/1 컬럼으로 바꾼다.
df = pd.get_dummies(
    df,
    columns=[&quot;sex&quot;, &quot;smoker&quot;, &quot;day&quot;, &quot;time&quot;],
    drop_first=True
)&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;get_dummies()는 범주형 컬럼을 여러 개의 0/1 컬럼으로 바꿔준다.&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpOxsi/dJMcadVNRBs/7trpgG76DJp2KKZDdPjWr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpOxsi/dJMcadVNRBs/7trpgG76DJp2KKZDdPjWr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpOxsi/dJMcadVNRBs/7trpgG76DJp2KKZDdPjWr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpOxsi%2FdJMcadVNRBs%2F7trpgG76DJp2KKZDdPjWr0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;659&quot; height=&quot;163&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;9. 입력값(X) / 타깃값(y) 분리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 예측 대상과 입력 데이터를 나눈다.&lt;br /&gt;이번 예시에서는 tip을 예측 대상으로 두고, 나머지 컬럼을 입력값으로 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1775300896870&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;X = df.drop(columns=[&quot;tip&quot;])
y = df[&quot;tip&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;10. 다중공선성 확인 및 제거&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전처리 단계에서는 feature들끼리 너무 비슷한 정보를 담고 있는지도 확인할 수 있다.&lt;br /&gt;이런 경우를 다중공선성이라고 하고, 특히 선형 모델 계열에서 영향을 줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 10-1. 상관관계 히트맵 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775997123815&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 수치형 컬럼끼리의 상관관계를 확인한다.
corr_matrix = X.corr()

plt.figure(figsize=(10, 8))
sns.heatmap(
    corr_matrix,
    annot=True,
    fmt=&quot;.2f&quot;,
    cmap=&quot;coolwarm&quot;,
    linewidths=0.5
)
plt.title(&quot;Feature Correlation Heatmap&quot;)
plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcp6vT/dJMcajhpRl1/jdrugP2hSsnnlfrAgZhuQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcp6vT/dJMcajhpRl1/jdrugP2hSsnnlfrAgZhuQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcp6vT/dJMcajhpRl1/jdrugP2hSsnnlfrAgZhuQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbcp6vT%2FdJMcajhpRl1%2FjdrugP2hSsnnlfrAgZhuQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;423&quot; height=&quot;357&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;10-2. 상관관계 높은 컬럼 찾기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775997305631&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;10-2. 상관관계 높은 컬럼 찾기

# 상관관계 행렬의 상삼각 영역만 사용한다.
upper_triangle = corr_matrix.where(
    np.triu(np.ones(corr_matrix.shape), k=1).astype(bool)
)

# 절댓값 기준 0.8보다 큰 컬럼을 찾는다.
high_corr_cols = [
    column for column in upper_triangle.columns
    if any(upper_triangle[column].abs() &amp;gt; 0.8)
]

print(&quot;상관관계가 높은 컬럼:&quot;, high_corr_cols)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;10-3. 상관관계 높은 컬럼 제거&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775301146046&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;X_reduced = X.drop(columns=high_corr_cols)
X_reduced.head()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상관관계가 높은 컬럼은 무조건 제거하는 것이 아니라,&lt;br /&gt;모델 특성과 데이터 의미를 같이 보고 판단하는 것이 좋다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;11. 학습 데이터 / 테스트 데이터 분리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전처리 후에는 학습용 데이터와 테스트용 데이터를 나눈다.&lt;br /&gt;모델은 학습용 데이터로 학습하고, 테스트 데이터로 성능을 확인한다.&lt;/p&gt;
&lt;pre id=&quot;code_1775301173766&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;X_train, X_test, y_train, y_test = train_test_split(
    X_reduced,
    y,
    test_size=0.2,
    random_state=42
)&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;12. 수치형 컬럼만 스케일링&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스케일링은 컬럼마다 값의 범위가 크게 다를 때 이를 맞춰주는 작업이다.&lt;br /&gt;예를 들어 어떤 컬럼은 값이 1~5 사이인데, 다른 컬럼은 1000~10000 사이일 수 있다.&lt;br /&gt;이런 상태로 모델을 학습하면 큰 값을 가지는 컬럼이 더 큰 영향을 주는 경우가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 &lt;b&gt;거리 기반 모델&lt;/b&gt;이나 &lt;b&gt;선형 모델&lt;/b&gt;, 그리고 &lt;b&gt;경사하강법&lt;/b&gt; 기반 학습에서는 스케일 차이가 성능과 학습 안정성에 영향을 줄 수 있다.&lt;br /&gt;반면 &lt;b&gt;트리 계열 모델&lt;/b&gt;은 보통 스케일링 영향을 크게 받지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의할점은 &lt;b&gt;fit_transform()은 학습 데이터에만 적용&lt;/b&gt;하고, &lt;b&gt;테스트 데이터에는 transform()만 적용&lt;/b&gt;해야 한다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 12-1. 수치형 컬럼 지정&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1775301254335&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;numeric_cols = [&quot;total_bill&quot;, &quot;size&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 12-2. StandardScaler 적용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;StandardScaler는 각 수치형 컬럼을 &lt;b&gt;평균 0, 표준편차 1&lt;/b&gt; 기준으로 변환하는 방식이다.&lt;br /&gt;이미지 픽셀값처럼 원래 범위가 분명한 데이터나, 입력값을 일정 구간으로 맞추고 싶은 경우에 자주 사용 &lt;/p&gt;
&lt;pre id=&quot;code_1775301264942&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;X_train_standard = X_train.copy()
X_test_standard = X_test.copy()

standard_scaler = StandardScaler()

X_train_standard[numeric_cols] = standard_scaler.fit_transform(X_train_standard[numeric_cols])
X_test_standard[numeric_cols] = standard_scaler.transform(X_test_standard[numeric_cols])

X_train_standard.head()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 12-3. MinMaxScaler 적용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MinMaxScaler는 각 수치형 컬럼의 값을 &lt;b&gt;0과 1 사이 범위&lt;/b&gt;로 변환하는 방식이다.&lt;br /&gt;로지스틱 회귀, 선형 회귀, SVM, KNN, PCA처럼 스케일에 민감한 모델에서 자주 사용 &lt;/p&gt;
&lt;pre id=&quot;code_1775301275958&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;X_train_minmax = X_train.copy()
X_test_minmax = X_test.copy()

minmax_scaler = MinMaxScaler()

X_train_minmax[numeric_cols] = minmax_scaler.fit_transform(X_train_minmax[numeric_cols])
X_test_minmax[numeric_cols] = minmax_scaler.transform(X_test_minmax[numeric_cols])

X_train_minmax.head()&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;730&quot; data-start=&quot;639&quot; data-ke-size=&quot;size23&quot;&gt;13. 데이터 확인 시 자주 사용하는 시각화 방법&lt;/h3&gt;
&lt;p data-end=&quot;287&quot; data-start=&quot;180&quot; data-ke-size=&quot;size16&quot;&gt;전처리를 시작하기 전에는 단순히 head(), info(), describe()만 보는 것보다,&lt;br /&gt;&lt;b&gt;시각화를 통해 데이터 분포와 관계를 함께 확인하는 것&lt;/b&gt;이 훨씬 도움이 된다.&lt;/p&gt;
&lt;p data-end=&quot;314&quot; data-start=&quot;289&quot; data-ke-size=&quot;size16&quot;&gt;특히 시각화는 다음과 같은 상황에서 유용하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;379&quot; data-start=&quot;316&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;331&quot; data-start=&quot;316&quot;&gt;수치형 컬럼의 분포 확인&lt;/li&gt;
&lt;li data-end=&quot;347&quot; data-start=&quot;332&quot;&gt;범주형 컬럼의 빈도 확인&lt;/li&gt;
&lt;li data-end=&quot;356&quot; data-start=&quot;348&quot;&gt;이상치 확인&lt;/li&gt;
&lt;li data-end=&quot;369&quot; data-start=&quot;357&quot;&gt;변수 간 관계 확인&lt;/li&gt;
&lt;li data-end=&quot;379&quot; data-start=&quot;370&quot;&gt;상관관계 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;429&quot; data-start=&quot;381&quot; data-ke-size=&quot;size16&quot;&gt;이번에는 tips 데이터셋 기준으로 자주 사용하는 기본 시각화 방법을 정리해보겠다.&lt;/p&gt;
&lt;p data-end=&quot;730&quot; data-start=&quot;639&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 13-1. 히스토그램(Histogram) &lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;552&quot; data-start=&quot;464&quot; data-ke-size=&quot;size16&quot;&gt;히스토그램은 수치형 데이터가 어떤 구간에 많이 몰려 있는지 확인할 때 사용한다.&lt;br /&gt;데이터가 한쪽으로 치우쳐 있는지, 대략적인 분포가 어떤지 파악할 수 있다.&lt;/p&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1775303652023&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plt.figure(figsize=(8, 4))
sns.histplot(df[&quot;total_bill&quot;], kde=True)
plt.title(&quot;total_bill Distribution&quot;)
plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wRSQc/dJMcagE32pE/0MyACCfPkmPZzUyyMMolX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wRSQc/dJMcagE32pE/0MyACCfPkmPZzUyyMMolX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wRSQc/dJMcagE32pE/0MyACCfPkmPZzUyyMMolX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwRSQc%2FdJMcagE32pE%2F0MyACCfPkmPZzUyyMMolX1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;686&quot; height=&quot;393&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 13-2. 카운트플롯(Countplot) &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카운트플롯은 범주형 데이터의 개수를 시각적으로 확인할 때 사용한다.&lt;br /&gt;각 범주가 얼마나 자주 등장하는지 한눈에 볼 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1775303711240&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;plt.figure(figsize=(8, 4))
sns.countplot(x=df[&quot;day&quot;])
plt.title(&quot;Count of day&quot;)
plt.show()&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mISUA/dJMcaakwbiC/wf7yDI6xBHVKKAxrDxO851/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mISUA/dJMcaakwbiC/wf7yDI6xBHVKKAxrDxO851/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mISUA/dJMcaakwbiC/wf7yDI6xBHVKKAxrDxO851/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmISUA%2FdJMcaakwbiC%2Fwf7yDI6xBHVKKAxrDxO851%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;686&quot; height=&quot;393&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 13-3. 박스플롯(Boxplot) &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;박스플롯은 수치형 데이터의 분포와 이상치를 함께 확인할 때 자주 사용한다.&lt;br /&gt;사분위수 범위와 중앙값, 그리고 이상치로 의심되는 값을 한 번에 볼 수 있다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R6PFE/dJMcacvTpNy/RHOeKkha4YvNHhCmUufOp0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R6PFE/dJMcacvTpNy/RHOeKkha4YvNHhCmUufOp0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R6PFE/dJMcacvTpNy/RHOeKkha4YvNHhCmUufOp0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR6PFE%2FdJMcacvTpNy%2FRHOeKkha4YvNHhCmUufOp0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;644&quot; height=&quot;393&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 13-4. 산점도(Scatterplot) &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;산점도는 두 수치형 변수 사이의 관계를 확인할 때 사용한다.&lt;br /&gt;특정 변수끼리 함께 증가하는지, 감소하는지, 또는 뚜렷한 패턴이 있는지 확인할 수 있다.&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;393&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RZJWE/dJMb99Trg4Z/w5XoQrF3WZN9ZwXtA6Mic0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RZJWE/dJMb99Trg4Z/w5XoQrF3WZN9ZwXtA6Mic0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RZJWE/dJMb99Trg4Z/w5XoQrF3WZN9ZwXtA6Mic0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRZJWE%2FdJMb99Trg4Z%2Fw5XoQrF3WZN9ZwXtA6Mic0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;686&quot; height=&quot;393&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;393&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-end=&quot;730&quot; data-start=&quot;639&quot; data-ke-size=&quot;size16&quot;&gt;전처리는 단순히 데이터를 정리하는 과정이 아니라,&lt;br /&gt;&lt;b&gt;모델이 학습하기 좋은 형태로 데이터를 바꾸고 불필요한 노이즈를 줄이는 과정&lt;/b&gt;이라는 점에서 매우 중요하다.&lt;/p&gt;
&lt;p data-end=&quot;860&quot; data-start=&quot;732&quot; data-ke-size=&quot;size16&quot;&gt;이번 글에서는 전처리 자체에 초점을 맞춰 흐름을 정리했고,&lt;br /&gt;다음 글에서는 이렇게 준비한 데이터를 바탕으로 &lt;b&gt;모델 학습 결과를 어떻게 평가하는지&lt;/b&gt;, 그리고 &lt;b&gt;회귀 성능 지표를 어떻게 해석해야 하는지&lt;/b&gt;를 정리해볼 예정이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;</description>
      <category>AI dev/Machine Learning</category>
      <author>bonggyulim</author>
      <guid isPermaLink="true">https://bonggyulim.tistory.com/34</guid>
      <comments>https://bonggyulim.tistory.com/34#entry34comment</comments>
      <pubDate>Sat, 4 Apr 2026 20:49:31 +0900</pubDate>
    </item>
    <item>
      <title>디자인패턴이란</title>
      <link>https://bonggyulim.tistory.com/33</link>
      <description>&lt;p data-end=&quot;261&quot; data-start=&quot;159&quot; data-ke-size=&quot;size16&quot;&gt;프로그램을 만들다 보면 비슷한 구조의 문제를 반복해서 만나게 된다.&lt;br /&gt;객체를 어떻게 생성할지, 기능을 어떻게 유연하게 바꿀지, 객체들 사이의 의존성을 어떻게 줄일지 같은 문제들이다.&lt;/p&gt;
&lt;p data-end=&quot;392&quot; data-start=&quot;263&quot; data-ke-size=&quot;size16&quot;&gt;이런 반복되는 설계 문제에 대해 많이 사용되는 해법을 정리한 것이 &lt;b&gt;디자인패턴(Design Pattern)&lt;/b&gt; 이다.&lt;br /&gt;디자인패턴은 정답 코드가 아니라, &lt;b&gt;유지보수하기 좋은 구조를 만들기 위한 설계 방법&lt;/b&gt;이라고 볼 수 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;590&quot; data-start=&quot;569&quot; data-section-id=&quot;11wamim&quot; data-ke-size=&quot;size23&quot;&gt;디자인패턴에는 어떤 것들이 있을까?&lt;/h3&gt;
&lt;p data-end=&quot;617&quot; data-start=&quot;592&quot; data-ke-size=&quot;size16&quot;&gt;디자인패턴은 생성패턴, 구조패턴, 행위패턴 3가지 종류로 나눠서 본다.&amp;nbsp;&lt;br /&gt;이번 글에서는 Python 예시로 아래 중요 패턴 5가지를 정리해보겠다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1085&quot; data-start=&quot;1025&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1085&quot; data-start=&quot;1076&quot; data-section-id=&quot;1i9qggv&quot;&gt;&lt;span&gt;&amp;nbsp;Singleton: 객체를 하나만 생성해서 공유 &lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1085&quot; data-start=&quot;1076&quot; data-section-id=&quot;1i9qggv&quot;&gt;&lt;span&gt;&amp;nbsp;Factory Method: 객체 생성 책임을 분리&lt;/span&gt;&lt;/li&gt;
&lt;li data-end=&quot;1085&quot; data-start=&quot;1076&quot; data-section-id=&quot;1i9qggv&quot;&gt;&amp;nbsp;Strategy: 알고리즘/정책을 교체 가능하게 설계&lt;/li&gt;
&lt;li data-end=&quot;1085&quot; data-start=&quot;1076&quot; data-section-id=&quot;1i9qggv&quot;&gt;&amp;nbsp;Observer: 상태 변화를 여러 객체에 알림&lt;/li&gt;
&lt;li data-end=&quot;1085&quot; data-start=&quot;1076&quot; data-section-id=&quot;1i9qggv&quot;&gt;&amp;nbsp;Adapter: 인터페이스가 다른 객체를 연결&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;437&quot; data-start=&quot;394&quot; data-ke-size=&quot;size23&quot;&gt;1. Singleton 패턴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Singleton 패턴은 &lt;b&gt;인스턴스를 하나만 생성하도록 제한하는 패턴&lt;/b&gt;이다.&lt;br /&gt;즉, 어떤 객체가 프로그램 전체에서 하나만 존재해야 할 때 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1774752244426&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# =========================
# 1. Singleton Pattern
# =========================
# 목적:
# - 인스턴스를 하나만 만들고 계속 재사용
# - 설정값, 로그 관리자 같은 전역 공용 객체에 사용

class Config:
    _instance = None  # 클래스 변수: 만들어진 인스턴스를 저장

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)	# 아직 객체가 없으면 한 번만 생성
            cls._instance.settings = {}        		# 이미 객체가 있으면 기존 객체를 그대로 반환
        return cls._instance


config1 = Config()
config2 = Config()

config1.settings[&quot;theme&quot;] = &quot;dark&quot;

print(config1.settings)     # {'theme': 'dark'}
print(config2.settings)     # {'theme': 'dark'}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;3215&quot; data-start=&quot;3193&quot; data-section-id=&quot;o3na7h&quot; data-ke-size=&quot;size23&quot;&gt;2. Factory Method 패턴&lt;/h3&gt;
&lt;p data-end=&quot;3280&quot; data-start=&quot;3224&quot; data-ke-size=&quot;size16&quot;&gt;Factory Method 패턴은 &lt;b&gt;객체 생성 책임을 별도의 메서드나 클래스에 맡기는 패턴&lt;/b&gt;이다.&lt;br /&gt;객체를 직접 생성하지 않고 &amp;ldquo;필요한 객체를 대신 만들어주는 공장&amp;rdquo;을 두는 방식이다.&lt;/p&gt;
&lt;pre id=&quot;code_1774752761994&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# =========================
# 2. Factory Method Pattern
# =========================
# 목적:
# - 객체 생성 책임을 따로 분리
# - 어떤 객체를 만들지 결정하는 로직을 한 곳에 모음

class EmailSender:
    def send(self, message):
        print(f&quot;이메일 전송: {message}&quot;)


class SmsSender:
    def send(self, message):
        print(f&quot;SMS 전송: {message}&quot;)


class NotificationFactory:
    @staticmethod
    def create(channel):
        # 생성 로직을 여기서 관리
        if channel == &quot;email&quot;:
            return EmailSender()
        elif channel == &quot;sms&quot;:
            return SmsSender()
        else:
            raise ValueError(&quot;지원하지 않는 채널&quot;)


sender = NotificationFactory.create(&quot;email&quot;)
sender.send(&quot;안녕하세요&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;4019&quot; data-start=&quot;3991&quot; data-ke-size=&quot;size16&quot;&gt;Factory를 사용하면 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;객체를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;어떻게 생성할지&lt;/b&gt;를 숨길 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;4066&quot; data-start=&quot;4021&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;4043&quot; data-start=&quot;4021&quot; data-section-id=&quot;17nxhgv&quot;&gt;클라이언트는 무엇이 필요한지만 말한다&lt;/li&gt;
&lt;li data-end=&quot;4066&quot; data-start=&quot;4044&quot; data-section-id=&quot;1rzpt19&quot;&gt;실제 생성은 Factory가 담당한다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;4097&quot; data-start=&quot;4068&quot; data-ke-size=&quot;size23&quot;&gt;3. Strategy 패턴&lt;/h3&gt;
&lt;p data-end=&quot;4198&quot; data-start=&quot;4129&quot; data-ke-size=&quot;size16&quot;&gt;Strategy 패턴은 &lt;b&gt;같은 목적을 수행하는 여러 알고리즘을 각각 분리하고, 필요에 따라 교체해서 사용하는 패턴&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;4230&quot; data-start=&quot;4200&quot; data-ke-size=&quot;size16&quot;&gt;기능은 같지만 방식이 여러 개일 때 유용하다.&lt;/p&gt;
&lt;pre id=&quot;code_1774752992334&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# =========================
# 3. Strategy Pattern
# =========================
# 목적:
# - 같은 기능을 여러 방식으로 처리
# - 상황에 따라 알고리즘/정책을 갈아끼움

class NormalDiscount:
    def apply(self, price):
        return price


class MemberDiscount:
    def apply(self, price):
        return price * 0.9


class VipDiscount:
    def apply(self, price):
        return price * 0.8


class PaymentService:
    def __init__(self, discount_strategy):
        # 어떤 할인 정책을 쓸지 외부에서 주입받음
        self.discount_strategy = discount_strategy

    def calculate_price(self, price):
        return self.discount_strategy.apply(price)


service1 = PaymentService(NormalDiscount())
service2 = PaymentService(MemberDiscount())
service3 = PaymentService(VipDiscount())

print(service1.calculate_price(10000))  # 10000
print(service2.calculate_price(10000))  # 9000.0
print(service3.calculate_price(10000))  # 8000.0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;5061&quot; data-start=&quot;4989&quot; data-ke-size=&quot;size16&quot;&gt;할인 정책이 일반, 회원, VIP로 나뉜다고 했을때 if-elif로 계속 처리하면 코드가 길어지고 수정도 어려워진다. &lt;br /&gt;Strategy 패턴은 할인 정책별로 클래스를 따로 만들고, 필요한 정책을 주입받아 사용하게 만든다.&lt;/p&gt;
&lt;h3 data-end=&quot;157&quot; data-start=&quot;138&quot; data-section-id=&quot;16alwq&quot; data-ke-size=&quot;size23&quot;&gt;PPE Guard에서의 예시&lt;/h3&gt;
&lt;p data-end=&quot;203&quot; data-start=&quot;158&quot; data-ke-size=&quot;size16&quot;&gt;PPE를 분석한다는 목적은 같지만, &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 data-end=&quot;203&quot; data-start=&quot;158&quot;&gt;비디오는 세그먼트 단위 처리&lt;/li&gt;
&lt;li data-end=&quot;203&quot; data-start=&quot;158&quot;&gt;웹캠은 실시간 이벤트 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 다 &amp;ldquo;PPE 탐지 + OCR + 결과 저장&amp;rdquo;이라는 큰 목적은 같지만, 내부 동작은 다르다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;5149&quot; data-start=&quot;5123&quot; data-ke-size=&quot;size23&quot;&gt;4. Observer 패턴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Observer 패턴은 &lt;/span&gt;&lt;b&gt;어떤 객체의 상태가 바뀌었을 때, 그 변화를 여러 객체에게 자동으로 알려주는 패턴&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1774753126643&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# =========================
# 4. Observer Pattern
# =========================
# 목적:
# - 한 객체의 변화가 생기면 여러 객체에게 자동 알림
# - 구독 / 알림 구조

class EmailObserver:
    def update(self, message):
        print(f&quot;[이메일 알림] {message}&quot;)


class SmsObserver:
    def update(self, message):
        print(f&quot;[SMS 알림] {message}&quot;)


class NewsPublisher:
    def __init__(self):
        self.observers = []  # 구독자 목록

    def subscribe(self, observer):
        self.observers.append(observer)

    def notify(self, message):
        # 상태 변화가 생기면 모든 구독자에게 알림
        for observer in self.observers:
            observer.update(message)


publisher = NewsPublisher()			# 인스턴스 생성
publisher.subscribe(EmailObserver())		# 구독자 추가
publisher.subscribe(SmsObserver())

publisher.notify(&quot;새 뉴스가 등록되었습니다.&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;5944&quot; data-start=&quot;5882&quot; data-ke-size=&quot;size16&quot;&gt;NewsPublisher는 구독자 목록을 가지고 있고, 새 소식이 생기면 모든 구독자에게 알림을 보낸다.&lt;br /&gt;이 구조의 장점은 발행자(Publisher)가 구독자의 구체적인 내부 동작을 몰라도 된다는 점이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;5944&quot; data-start=&quot;5882&quot; data-ke-size=&quot;size23&quot;&gt;5. Adapter 패턴&lt;/h3&gt;
&lt;p data-end=&quot;6107&quot; data-start=&quot;6059&quot; data-ke-size=&quot;size16&quot;&gt;Adapter 패턴은 &lt;b&gt;서로 다른 인터페이스를 가진 객체들을 연결해주는 패턴&lt;/b&gt;이다.&lt;br /&gt;기존 코드가 기대하는 방식과 실제 외부 라이브러리의 방식이 다를 때 중간에서 맞춰준다.&lt;/p&gt;
&lt;pre id=&quot;code_1774753383052&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# =========================
# 5. Adapter Pattern
# =========================
# 목적:
# - 인터페이스가 다른 기존 클래스를 현재 코드에 맞게 연결
# - 기존 코드 수정 없이 재사용 가능

class OldPrinter:
    def print_text(self, text):
        print(f&quot;기존 프린터 출력: {text}&quot;)


class PrinterAdapter:
    def __init__(self, old_printer):
        self.old_printer = old_printer

    def print(self, message):
        # 현재 코드가 기대하는 print()를
        # 기존 클래스의 print_text()로 연결
        self.old_printer.print_text(message)


def client_code(printer):
    # 여기서는 print() 메서드가 있다고 가정
    printer.print(&quot;Hello Adapter&quot;)


old_printer = OldPrinter()
adapter = PrinterAdapter(old_printer)

client_code(adapter)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;6699&quot; data-start=&quot;6624&quot; data-ke-size=&quot;size16&quot;&gt;client_code()는 print() 메서드를 기대한다. 그런데 기존 프린터는 print_text()만 가지고 있다.&lt;br /&gt;이때 Adapter가 중간에서 메서드 이름과 사용 방식을 맞춰준다. 그래서 기존 클래스를 수정하지 않고도 재사용할 수 있다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-section-id=&quot;16alwq&quot; data-start=&quot;138&quot; data-end=&quot;157&quot; data-ke-size=&quot;size23&quot;&gt;PPE Guard에서의 예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;YOLO나 EasyOCR는 원래 자기들 방식의 API가 있지만 서비스 계층에서는 그런 외부 API를 직접 알 필요가 없다.&lt;/p&gt;
&lt;p data-end=&quot;997&quot; data-start=&quot;933&quot; data-ke-size=&quot;size16&quot;&gt;나중에 OCR 엔진을 바꾸더라도&lt;br /&gt;서비스 로직 전체를 뜯어고치지 않고 &lt;b&gt;Adapter 구현체만 바꾸면 된다.&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-end=&quot;997&quot; data-start=&quot;933&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 디자인패턴은 단순히 개념을 외우기 위한 것이 아니라, 실제 프로젝트에서 &lt;b&gt;기능을 분리하고 변경에 유연하게 대응하기 위한 설계 방식&amp;nbsp;&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 기능 단위로 개발해야 하는 프로젝트에서는 하나의 큰 로직에 모든 기능을 넣기보다,&lt;br /&gt;&lt;b&gt;역할을 나누고, 교체 가능한 구조로 만들고, 외부 의존성을 분리하는 방식&lt;/b&gt;이 더 효과적이다.&lt;br /&gt;이런 구조는 기능 추가와 수정이 쉬울 뿐 아니라, 팀원들이 기능별로 나누어 개발한 뒤 다시 통합하는 과정에서도 유지보수성과 협업 효율을 높여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 좋은 설계는 패턴 이름을 많이 아는 것이 아니라,&lt;br /&gt;&lt;b&gt;현재 프로젝트에 맞는 구조를 선택해 기능 단위 개발이 가능하고 확장 가능한 코드로 만드는 것&lt;/b&gt;이라고 생각한다.&lt;/p&gt;</description>
      <category>CS &amp;amp; Fundamentals</category>
      <author>bonggyulim</author>
      <guid isPermaLink="true">https://bonggyulim.tistory.com/33</guid>
      <comments>https://bonggyulim.tistory.com/33#entry33comment</comments>
      <pubDate>Sun, 29 Mar 2026 12:28:29 +0900</pubDate>
    </item>
    <item>
      <title>RareBridge 프로젝트 회고</title>
      <link>https://bonggyulim.tistory.com/32</link>
      <description>&lt;p data-end=&quot;447&quot; data-start=&quot;292&quot; data-ke-size=&quot;size16&quot;&gt;이번 프로젝트는 &lt;b&gt;RareBridge&lt;/b&gt;라는 이름으로 진행한 프로젝트로 사용자가 입력한 증상을 바탕으로 질환 정보를 탐색하는 서비스였다. 사용자는 증상을 텍스트나 이미지 형태로 입력할 수 있고, 시스템은 이를 HPO(Human Phenotype Ontology) 코드로 변환한 뒤 희귀질환 데이터를 검색한다. 이후 질환별 매칭 점수를 계산해 상위 5개 질환 후보와 질환명, ORPHA 코드, 설명, 일치도 등의 정보를 제공하는 것이 핵심 흐름이었다.&lt;/p&gt;
&lt;h4 data-end=&quot;447&quot; data-start=&quot;292&quot; data-ke-size=&quot;size20&quot;&gt;RareBridge 핵심 기능&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;254&quot; data-start=&quot;224&quot; data-section-id=&quot;8kb4id&quot;&gt;사용자가 &lt;b&gt;증상을 텍스트나 이미지 형태로 입력&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;305&quot; data-start=&quot;255&quot; data-section-id=&quot;vol5u2&quot;&gt;입력된 증상을 &lt;b&gt;HPO(Human Phenotype Ontology) 코드로 변환&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;338&quot; data-start=&quot;306&quot; data-section-id=&quot;1sp4piq&quot;&gt;변환된 HPO를 기반으로 &lt;b&gt;희귀질환 데이터를 검색&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;365&quot; data-start=&quot;339&quot; data-section-id=&quot;t4vtzl&quot;&gt;질환별 &lt;b&gt;매칭 점수(스코어링)&lt;/b&gt; 를 계산&lt;/li&gt;
&lt;li data-end=&quot;413&quot; data-start=&quot;366&quot; data-section-id=&quot;1lz98j0&quot;&gt;&lt;b&gt;상위 5개 질환 후보&lt;/b&gt;와 질환명, ORPHA 코드, 설명, 일치도 등을 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;내가 맡은 역할&lt;/h4&gt;
&lt;p data-end=&quot;630&quot; data-start=&quot;449&quot; data-ke-size=&quot;size16&quot;&gt;프로젝트에서 PM 역할을 맡았고, 단순히 일정 조율만 하는 것이 아니라 프로젝트의 전체 구조를 정리하고 팀이 개발을 진행할 수 있는 기반을 만드는 역할을 담당했다. 구체적으로는 &lt;b&gt;아키텍처 설계, API 및 데이터 스키마 정의, 데이터베이스 설계, Orphanet 데이터셋 추가, 코드 리뷰, 프론트 배포&lt;/b&gt;를 맡아 진행했다.&lt;/p&gt;
&lt;h4 data-end=&quot;630&quot; data-start=&quot;449&quot; data-ke-size=&quot;size20&quot;&gt;프로젝트를 통해 얻은 점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트를 진행하면서 가장 크게 느낀 점은, 초기 아키텍처의 방향뿐 아니라 구현 기준까지 더 구체적으로 정해두었더라면 팀원들이 기능을 추가하거나 수정할 때 훨씬 수월했을 것이라는 점이다. 구조를 나누고 흐름을 정리하려고 하긴 했지만, 실제 개발이 진행되면서 어떤 로직을 어느 위치에서 관리해야 하는지, 새로운 기능이 들어왔을 때 어떤 구조로 확장해야 하는지를 자주 고민해야 했다. 또한 AI를 활용하는 프로젝트였기 때문에, 프롬프트와 응답 형식을 초기에 미리 정의해두었다면 코드 구조와 기능 흐름이 더 일관되고 깔끔하게 정리될 수 있었을 것이라고 느꼈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 생각하는 PM의 역할은 단순히 일정을 조율하는 것이 아니라, 팀원들이 자신의 역량을 최대한 발휘할 수 있도록 돕는 것이다. 프로젝트가 끝났을 때 결과물만 남는 것이 아니라, 팀원 모두가 한 단계 성장했다고 느낄 수 있게 만드는 것 또한 중요하다고 생각한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/RareBridge/RareBridge&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/RareBridge/RareBridge&lt;/a&gt;&lt;/p&gt;</description>
      <category>Projects</category>
      <author>bonggyulim</author>
      <guid isPermaLink="true">https://bonggyulim.tistory.com/32</guid>
      <comments>https://bonggyulim.tistory.com/32#entry32comment</comments>
      <pubDate>Thu, 19 Mar 2026 20:06:30 +0900</pubDate>
    </item>
    <item>
      <title>파이썬 기본 문법</title>
      <link>https://bonggyulim.tistory.com/31</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 출력과 변수&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;변수 선언&lt;/h3&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;a = 10
name = &quot;Python&quot;
is_ok = True
&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;/h3&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;print(a)
print(name)
print(a, name)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;f-string&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 안에 변수를 넣을 때 자주 쓴다.&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;name = &quot;봉규&quot;
age = 27
print(f&quot;이름은 {name}이고, 나이는 {age}살입니다.&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 기본 자료형&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2-1. 숫자형&lt;/h2&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;a = 10      # int
b = 3.14    # float
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사칙연산:&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;print(10 + 3)   # 13
print(10 - 3)   # 7
print(10 * 3)   # 30
print(10 / 3)   # 3.333...
print(10 // 3)  # 3   -&amp;gt; 몫
print(10 % 3)   # 1   -&amp;gt; 나머지
print(10 ** 3)  # 1000 -&amp;gt; 거듭제곱
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2-2. 문자열&lt;/h2&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;s = &quot;hello&quot;
#   인덱스
#   0 1 2 3 4
#   h e l l o&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인덱싱&lt;/h3&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;print(s[0])   # h
print(s[-1])  # o  맨 끝&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;슬라이싱&lt;/h3&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;# s[start:end:step]
print(s[0:2])  # he		2번 인덱스 전까지
print(s[:3])   # hel	
print(s[2:])   # llo	2번 인덱스부터 끝까지
print(s[::-1]) # olleh&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문자열 자주 쓰는 함수&lt;/h3&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;s = &quot; hello python &quot;

print(s.strip())       # 양쪽 공백 제거
print(s.upper())       # 대문자
print(s.lower())       # 소문자
print(s.replace(&quot;python&quot;, &quot;java&quot;))
print(s.split())       # 공백 기준 분리
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 합치기:&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;arr = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]
print(&quot;&quot;.join(arr))    # abc
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코테에서 join()은 매우 자주 나온다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2-3. 불리언&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;flag = True
print(flag)  # True
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교 연산:&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;print(3 &amp;gt; 1)   # True
print(3 == 1)  # False
print(3 != 1)  # True
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리 연산:&lt;/p&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;print(True and False)
print(True or False)
print(not True)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 리스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 많이 쓰는 자료형이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;arr = [1, 2, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;접근&lt;/h3&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;print(arr[0])
print(arr[-1]) # 뒤에서 부터 셈 -1, -2, -3 ...&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추가 / 삭제&lt;/h3&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;arr.append(6)      # 맨 뒤 추가
arr.insert(1, 10)  # 특정 위치에 삽입
arr.pop()          # 마지막 원소 제거
arr.remove(3)      # 값으로 제거
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정렬&lt;/h3&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;arr.sort()                  # 오름차순
arr.sort(reverse=True)      # 내림차순
&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;arr = [3, 1, 2]
new_arr = sorted(arr)
print(new_arr)   # [1, 2, 3]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;뒤집기&lt;/h3&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;arr.reverse()
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개수 세기&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;arr = [1, 2, 2, 3]
print(arr.count(2))  # 2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리스트 컴프리헨션&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코테에서 매우 자주 사용된다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;arr = [i for i in range(5)]
print(arr)  # [0, 1, 2, 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;arr = [i for i in range(10) if i % 2 == 0]
print(arr)  # [0, 2, 4, 6, 8]
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 배열 생성:&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;graph = [[0] * 3 for _ in range(4)]

# [
# 	[0, 0, 0],
# 	[0, 0, 0],
# 	[0, 0, 0],
# 	[0, 0, 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;graph = [[0] * 3] * 4
&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;4. 튜플&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경할 수 없는 자료형이다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;t = (1, 2, 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 = (3, 4)
print(x, y)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 딕셔너리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키-값 형태로 저장한다.&lt;/p&gt;
&lt;pre class=&quot;makefile&quot;&gt;&lt;code&gt;d = {&quot;a&quot;: 1, &quot;b&quot;: 2}
print(d[&quot;a&quot;])  # 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추가 / 수정&lt;/h3&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;d[&quot;c&quot;] = 3
d[&quot;a&quot;] = 10
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;삭제&lt;/h3&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;del d[&quot;b&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자주 쓰는 함수&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;print(d.keys())
print(d.values())
print(d.items())
print(d.get(&quot;a&quot;))      # 키가 없으면 None
print(d.get(&quot;x&quot;, 0))   # 기본값 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;빈도수 세기 패턴&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;arr = [1, 2, 2, 3, 3, 3]
count = {}

for x in arr:
    count[x] = count.get(x, 0) + 1

print(count)  # {1: 1, 2: 2, 3: 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;6. 집합(set)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복 제거와 빠른 탐색에 사용한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;s = {1, 2, 3}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;추가 / 삭제&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;s.add(4)
s.remove(2)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;포함 여부 확인&lt;/h3&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;print(3 in s)   # True
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;중복 제거&lt;/h3&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;arr = [1, 2, 2, 3, 3]
arr = list(set(arr))
print(arr)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 조건문&lt;/h2&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;x = 10

if x &amp;gt; 0:
    print(&quot;양수&quot;)
elif x == 0:
    print(&quot;0&quot;)
else:
    print(&quot;음수&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삼항 연산식:&lt;/p&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;a = 10
result = &quot;짝수&quot; if a % 2 == 0 else &quot;홀수&quot;
print(result)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 반복문&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8-1. for문&lt;/h2&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;for i in range(5):
    print(i)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;range&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;range(5)        # 0 ~ 4
range(1, 5)     # 1 ~ 4
range(1, 10, 2) # 1, 3, 5, 7, 9
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8-2. while문&lt;/h2&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;i = 0
while i &amp;lt; 5:
    print(i)
    i += 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8-3. enumerate&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인덱스와 값을 같이 사용할 때 편하다.&lt;/p&gt;
&lt;pre class=&quot;python&quot; data-ke-language=&quot;python&quot;&gt;&lt;code&gt;arr = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]

for idx, value in enumerate(arr):
    print(idx, value)&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 함수&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;def add(a, b):
    return a + b

print(add(3, 4))
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본값:&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;def greet(name=&quot;guest&quot;):
    print(f&quot;hello, {name}&quot;)
&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;def calc(a, b):
    return a + b, a - b

x, y = calc(10, 3)
print(x, y)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 예외 처리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코테에서는 많이 쓰이지 않지만 기본은 알아두면 좋다.&lt;/p&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;try:
    x = int(input())
except:
    print(&quot;숫자를 입력하세요&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;11. 코딩테스트 입력 처리&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력이 많을 때는 input()보다 sys.stdin.readline()이 빠르다.&lt;/p&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;import sys
input = sys.stdin.readline

n = int(input())
arr = list(map(int, input().split()))
&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;s = input().strip()
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;12. 코딩테스트에서 자주 쓰는 내장 함수&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12-1. map&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력을 정수로 한 번에 변환할 때 자주 사용한다.&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;arr = list(map(int, input().split()))
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12-2. sum&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;arr = [1, 2, 3, 4]
print(sum(arr))  # 10
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12-3. min, max&lt;/h2&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;arr = [5, 2, 8, 1]
print(min(arr))
print(max(arr))
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12-4. sorted&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;arr = [3, 1, 2]
print(sorted(arr))
print(sorted(arr, reverse=True))
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;key 사용:&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;words = [&quot;apple&quot;, &quot;kiwi&quot;, &quot;banana&quot;]
print(sorted(words, key=len))
&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;arr = [(2, 3), (1, 5), (2, 1)]
print(sorted(arr))                 # 첫 번째 값 기준, 같으면 두 번째 값 기준
print(sorted(arr, key=lambda x: x[1]))
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12-5. abs&lt;/h2&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;print(abs(-5))  # 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;12-6. all / any&lt;/h2&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;arr = [True, True, False]
print(all(arr))  # False
print(any(arr))  # True
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12-7. zip&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 리스트를 묶을 때 사용한다.&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;a = [1, 2, 3]
b = [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]

for x, y in zip(a, b):
    print(x, y)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;12-8. eval&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열을 코드처럼 실행해서 위험할 수 있으므로 코테에서는 거의 권장하지 않는다.&lt;br /&gt;알아만 두고 남용하지 않는 것이 좋다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;13. 코딩테스트 필수 라이브러리&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13-1. collections&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬 코테에서 가장 중요하다고 봐도 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;deque&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;양쪽에서 빠르게 삽입/삭제 가능하다.&lt;br /&gt;BFS에서 거의 필수다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;from collections import deque

q = deque([1, 2, 3])
q.append(4)       # 오른쪽 추가
q.appendleft(0)   # 왼쪽 추가
q.pop()           # 오른쪽 제거
q.popleft()       # 왼쪽 제거
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS 예시:&lt;/p&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;from collections import deque

q = deque()
q.append(1)

while q:
    x = q.popleft()
    print(x)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Counter&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원소 개수를 자동으로 세어준다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;from collections import Counter

arr = [&quot;a&quot;, &quot;b&quot;, &quot;a&quot;, &quot;c&quot;, &quot;a&quot;]
counter = Counter(arr)

print(counter)           # Counter({'a': 3, 'b': 1, 'c': 1})
print(counter[&quot;a&quot;])      # 3
print(counter.most_common(1))  # [('a', 3)]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;defaultdict&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키가 없어도 기본값으로 자동 생성된다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;from collections import defaultdict

d = defaultdict(int)
d[&quot;a&quot;] += 1
print(d[&quot;a&quot;])  # 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트 기본값:&lt;/p&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;d = defaultdict(list)
d[&quot;x&quot;].append(10)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13-2. itertools&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순열, 조합 문제에서 자주 사용한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;from itertools import permutations, combinations, product
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;permutations&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순열&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;arr = [1, 2, 3]
print(list(permutations(arr, 2)))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;combinations&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조합&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;arr = [1, 2, 3]
print(list(combinations(arr, 2)))
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;product&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중복 순열&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;arr = [1, 2, 3]
print(list(product(arr, repeat=2)))
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13-3. heapq&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위 큐를 구현할 때 사용한다.&lt;br /&gt;다익스트라, 최소 힙 문제에서 필수다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;import heapq

heap = []
heapq.heappush(heap, 3)
heapq.heappush(heap, 1)
heapq.heappush(heap, 2)

print(heapq.heappop(heap))  # 1
print(heapq.heappop(heap))  # 2
&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;import heapq

heap = []
heapq.heappush(heap, -3)
heapq.heappush(heap, -1)
heapq.heappush(heap, -2)

print(-heapq.heappop(heap))  # 3
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13-4. math&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수학 관련 문제에서 유용하다.&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;import math

print(math.sqrt(16))      # 제곱근
print(math.gcd(12, 18))   # 최대공약수
print(math.lcm(12, 18))   # 최소공배수
print(math.factorial(5))  # 팩토리얼
print(math.ceil(3.1))     # 올림
print(math.floor(3.9))    # 내림
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;13-5. bisect&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진 탐색을 쉽게 구현할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;from bisect import bisect_left, bisect_right

arr = [1, 2, 4, 4, 4, 5, 6]

print(bisect_left(arr, 4))   # 2
print(bisect_right(arr, 4))  # 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개수 구하기:&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;count = bisect_right(arr, 4) - bisect_left(arr, 4)
print(count)  # 3
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h1&gt;14. 자주 나오는 문법 패턴&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14-1. 리스트 초기화&lt;/h2&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;visited = [False] * 10
dist = [0] * 10
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14-2. 2차원 방향 탐색&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFS/BFS에서 자주 사용한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]

for i in range(4):
    nx = x + dx[i]
    ny = y + dy[i]
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14-3. swap&lt;/h2&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;a, b = b, a
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14-4. 입력값 여러 개 받기&lt;/h2&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;a, b = map(int, input().split())
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14-5. 문자열을 리스트처럼 사용&lt;/h2&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;s = &quot;abcde&quot;
for ch in s:
    print(ch)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;14-6. 아스키 코드 변환&lt;/h2&gt;
&lt;pre class=&quot;perl&quot;&gt;&lt;code&gt;print(ord('A'))   # 65
print(chr(65))    # A
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자 변환 문제에서 자주 나온다.&lt;/p&gt;</description>
      <category>Language &amp;amp; Framework/Python</category>
      <author>bonggyulim</author>
      <guid isPermaLink="true">https://bonggyulim.tistory.com/31</guid>
      <comments>https://bonggyulim.tistory.com/31#entry31comment</comments>
      <pubDate>Thu, 19 Mar 2026 19:01:39 +0900</pubDate>
    </item>
  </channel>
</rss>