<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>c.haha.e 블로그</title>
        <link>https://velog.io/</link>
        <description>기록용 블로그</description>
        <lastBuildDate>Wed, 08 Oct 2025 11:33:17 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. c.haha.e 블로그. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/c_haha_e" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[실전 협업]]></title>
            <link>https://velog.io/@c_haha_e/%EC%8B%A4%EC%A0%84-%ED%98%91%EC%97%85</link>
            <guid>https://velog.io/@c_haha_e/%EC%8B%A4%EC%A0%84-%ED%98%91%EC%97%85</guid>
            <pubDate>Wed, 08 Oct 2025 11:33:17 GMT</pubDate>
            <description><![CDATA[<p>그동안 협업이라고 하면 학원에서 해본 팀 프로젝트가 전부였는데 다들 친하기도했고, 유독 서로 배려를 많이 해줘서 그렇게 어렵다고 느껴본적이 없었다.</p>
<p>이런게 실전 협업인가...</p>
<p>협업 시 어떻게 대화를 해야할지 의견을 구할 지인이 내 주변엔 없다^^;</p>
<p>일 재미있게 하고싶은데
효율적으로 일하고싶은데
어렵다</p>
<p>대화스킬이 필요하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git-협업툴] Fork  사용방법]]></title>
            <link>https://velog.io/@c_haha_e/Git-%ED%98%91%EC%97%85%ED%88%B4-Fork-%EC%82%AC%EC%9A%A9%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@c_haha_e/Git-%ED%98%91%EC%97%85%ED%88%B4-Fork-%EC%82%AC%EC%9A%A9%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Tue, 23 Sep 2025 11:19:12 GMT</pubDate>
            <description><![CDATA[<p>회사에서는 현재 협업을 위해 git을 사용하고 있고, 
툴로는 fork를 사용하고 있었다.</p>
<p>그동안 배울때 Git Bash로만 진행을 해왔기 때문에 툴이라는 생각을 못하고</p>
<pre><code>원본 저장소(repository)를 통째로 복사해서 내 계정에 새로운 저장소를 만드는 것</code></pre><p>이라고 알고 있었다.</p>
<hr>
<h1 id="-fork-설치-방법">* fork 설치 방법</h1>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/47a27fd2-0b09-43db-960c-fbffa66c0bb0/image.png" alt=""></p>
<p><a href="https://git-fork.com/">https://git-fork.com/</a> 로 접속 후 환경에 맞게 다운로드 
<br></p>
<hr>
<h1 id="-fork-실행">* fork 실행</h1>
<ul>
<li>clone
<img src="https://velog.velcdn.com/images/c_haha_e/post/5dc523b8-b63e-4d82-b6e0-1b69a2975485/image.png" alt=""><pre><code>File - Clone - Repository Url 설정 - Parent Folder 설정 - Name 설정 - Clone 아이콘 클릭</code></pre><br>
<br>

</li>
</ul>
<h2 id="-git-flow">* Git Flow</h2>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/148c1f7e-500c-4ca0-9756-a47a7d0ace70/image.png" alt=""></p>
<pre><code>Repository - Git Flow - Initialize Git Flow... </code></pre><br>

<p><img src="https://velog.velcdn.com/images/c_haha_e/post/414b799d-7a94-410b-ae4b-6e582c133b6d/image.png" alt=""></p>
<pre><code>Branch명 설정 - Feature Prefix : feature/기능구현이름 설정 - Initialize Git Flow</code></pre><br>

<p><img src="https://velog.velcdn.com/images/c_haha_e/post/fafe8188-6a7e-4ac2-8397-f2d65221e7ab/image.png" alt=""></p>
<pre><code>Local Changes - 로컬에서 변경된 사항
All Commits -  현재까지 모든 commit사항
Open in - IDE 사용 가능</code></pre><br>

<h2 id="-commit-방법">* commit 방법</h2>
<p>작업 후 로컬에서 변동사항이 생기면 
<img src="https://velog.velcdn.com/images/c_haha_e/post/50ac4072-5361-4415-897d-1df1150ec9a5/image.png" alt=""></p>
<pre><code>Local Changes(숫자)로 변함 -&gt; Unstaged 에서 파일 눌러서 변동사항 확인 후 그대로 진행하려면 Stage 클릭 </code></pre><p><img src="https://velog.velcdn.com/images/c_haha_e/post/f9775eb7-c126-4c5c-acda-840ac7a3fda9/image.png" alt=""></p>
<pre><code>Unstaged -&gt; Staged로 넘어감  // 잘 못 넘겼을 시 Unstage누르면 다시 되돌아감.</code></pre><p><img src="https://velog.velcdn.com/images/c_haha_e/post/52c5ab98-e2ef-4f8f-b42b-94bda08f36d1/image.png" alt=""></p>
<pre><code>coommit 내용을 입력 한 후  Commit Files 버튼 클릭.</code></pre><br>

<h2 id="-push-방법">* push 방법</h2>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/34442dc8-11b9-4383-ba85-34916e191b41/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/0567e1c1-58b8-471d-b71a-319944eb9de3/image.png" alt=""></p>
<pre><code>Push 클릭 - Branch 설정 - Remote 설정(우선 협업시에는 로컬에서  원격origin을 우선적으로 / upstream은 원본 저장소) - push</code></pre><hr>
<h1 id="-pr보내기pull-request">* PR보내기(pull request)</h1>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/0850f749-749e-4c2b-9737-22415d6c8fb1/image.png" alt="">
<img src="https://velog.velcdn.com/images/c_haha_e/post/c944045c-e34b-44af-affc-30386c78dec2/image.png" alt=""></p>
<pre><code>내 원격 저장소에서 pull request 클릭 -  협업시 base를 내 브랜치로 설정 - compare는 작업한 브랜치 설정 - Create pull request 클릭 - 다시 확인 후 진짜 괜찮으면 Create pull request 클릭</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Putty 사용법]]></title>
            <link>https://velog.io/@c_haha_e/Putty-%EC%82%AC%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@c_haha_e/Putty-%EC%82%AC%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Tue, 23 Sep 2025 01:52:20 GMT</pubDate>
            <description><![CDATA[<h1 id="putty-준비">PuTTY 준비</h1>
<h4 id="회사나-사용하려는-서버에-id와-pw-그리고-공개키가-등록이-되어있어야-가능함">회사나 사용하려는 서버에 ID와 PW 그리고 공개키가 등록이 되어있어야 가능함!</h4>
<ol>
<li><p>공식 사이트에서 PuTTY 설치
설치하면 같이 깔리는 PuTTYgen 도 필요(키 변환용)</p>
</li>
<li><p>키 변환 (필수)</p>
</li>
</ol>
<p>PuTTY는 OpenSSH 키(id_ed25519)를 바로 못씀.
PuTTY 전용 PPK 파일로 변환</p>
<pre><code>- PuTTYgen 실행
- 메뉴에서 Conversions → Import key 선택
- C:\Users\user\.ssh\id_ed25519 선택 (개인키 파일)
- &quot;Save private key&quot; 버튼 → 예를 누르고 저장 (예: id_ed25519.ppk)</code></pre><ol start="3">
<li>PuTTY 설정<pre><code>Session 탭
Host Name: IP주소
Port: 포트번호
Connection type: SSH
</code></pre></li>
</ol>
<p>Connection → Data
Auto-login username: 본인 ID</p>
<p>Connection → SSH → Tunnels
Source port: 11434
Destination: 127.0.0.1:11434
선택: Local , Auto
Add 클릭 → L11434 127.0.0.1:11434가 목록에 생겨야 함</p>
<p>Connection → SSH → Auth → Credentials
&quot;Private key file for authentication&quot; → 아까 만든 id_ed25519.ppk 선택</p>
<p>다시 Session 탭에서
&quot;Saved Sessions&quot;에 이름 입력 (예: my_server)
&quot;Save&quot; 클릭</p>
<pre><code>
4. 접속하기</code></pre><p>Saved Sessions에서 my_server 선택 → &quot;Open&quot; → 바로 로그인
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SSH 공개키 없을때]]></title>
            <link>https://velog.io/@c_haha_e/SSH-%EA%B3%B5%EA%B0%9C%ED%82%A4-%EC%97%86%EC%9D%84%EB%95%8C</link>
            <guid>https://velog.io/@c_haha_e/SSH-%EA%B3%B5%EA%B0%9C%ED%82%A4-%EC%97%86%EC%9D%84%EB%95%8C</guid>
            <pubDate>Tue, 23 Sep 2025 01:46:06 GMT</pubDate>
            <description><![CDATA[<h1 id="기본-저장-위치-확인">기본 저장 위치 확인</h1>
<pre><code>~/.ssh/</code></pre><p>이 폴더 안에 id_rsa.pub, id_ecdsa.pub, id_ed25519.pub 같은 파일이 있으면 그게 공개키</p>
</BR>

<h1 id="키가-없을-때">키가 없을 때</h1>
<h2 id="-ed25519-방식">* Ed25519 방식</h2>
<ul>
<li>알고리즘: 타원곡선 기반(Elliptic Curve), 최신 암호화 방식.</li>
<li>키 길이: 별도 지정 불필요 (항상 256비트, RSA 3072~4096비트와 비슷하거나 더 안전).</li>
<li>장점:
생성 속도와 인증 속도가 빠름.
키 길이가 짧아서 관리하기 편리.
현대적인 보안 표준에 맞음.</li>
<li>단점: 극히 오래된 서버/시스템에서는 지원 안 될 수 있음 (하지만 요즘은 거의 다 지원).</li>
</ul>
<pre><code>ssh-keygen -t ed25519 -C &quot;이메일주소&quot;</code></pre><p>→ id_ed25519(개인키), id_ed25519.pub(공개키)가 생김</p>
<h2 id="-rsa-방식">* RSA 방식</h2>
<ul>
<li>알고리즘: RSA (전통적인 공개키 암호 방식).</li>
<li>키 길이 지정 가능: -b 4096 → 키 길이를 4096비트로 생성 (보안 강도 ↑).</li>
<li>장점: 아주 오래된 서버/시스템까지 대부분 지원.</li>
<li>단점: 키 길이가 길어질수록 연산 속도가 느려지고, 저장 공간도 더 차지함.<pre><code>ssh-keygen -t rsa -b 4096 -C &quot;이메일주소&quot;</code></pre>→ id_rsa(개인키), id_rsa.pub(공개키)가 생성.</li>
</ul>
<h1 id="정리">정리</h1>
<p>RSA 4096: 호환성 최고, 보안도 충분히 강함. (구형 서버까지 다 대응하고 싶으면 선택)</p>
<p>Ed25519: 최신 권장 방식, 빠르고 짧고 안전함. (특별히 구형 시스템 쓸 게 아니라면 이걸 추천)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[회고] 면접 ]]></title>
            <link>https://velog.io/@c_haha_e/%ED%9A%8C%EA%B3%A0-%EB%A9%B4%EC%A0%91</link>
            <guid>https://velog.io/@c_haha_e/%ED%9A%8C%EA%B3%A0-%EB%A9%B4%EC%A0%91</guid>
            <pubDate>Sat, 20 Sep 2025 01:37:20 GMT</pubDate>
            <description><![CDATA[<p>8월 22일 sk네트웍스 AI 부트캠프를 수료하고
정신이 없는 한달을 보냈다.</p>
<p>6개월간 진행한 포트폴리오를 정리하고,이력서를 작성하고, 자기소개서고 작성했다. 그 후 수정에 수정에 수정을 거치고, 여기저기서 첨삭과 컨설팅도 받고, 또또또 수정에 수정.</p>
<p>틈틈히 평일과 주말마다 사이즈 프로젝트와 개인학습까지 하다보니
어느새 3주가 흘렀다. 
어쩌다 보니 첫 면접을 보았고 느낀 것이 많아
이제부터는 종종 중요한 일들을 회고로 남겨보기로 마음먹었다.</p>
<hr>
<p>2월달의 나의 목표는 수료 후 한달안에 취업하는 것이였는데,
하나같이 비전공자에 전문학사, 무경력, 어학점수X
이런 스펙으로는 이력서를 기본 400~500개는 넣어야 그나마 취업을 할 수 있다고한다. 또한, 신입부터 연봉협상을 잘하고 들어가야한다는 이야기까지..</p>
<p>전문직에 있어서인지 개인적인 생각으론 내가 열심히하면 내 능력만큼 자연스럽게 오르는게 연봉이다.라고  생각하는 입장이라 초봉은 그렇게 중요하다고 생각을 해본적이없다. 그런데 이쪽 직종은 그게 아닌가? 이런저런 이야기를 들으니 더 더욱 취업 준비가 어려웠다. 하지만, 20대때 내가 그랬듯이 난 여전히 초봉은 크게 관여치않기로했다.</p>
<p>드디어 모든 서류의 수정을 마쳤다.
나에게로 이력서를 넣는 날이 오는구나!
이력서를 넣으면서 알게된 사실은 좀 충격적이였다
누가 IT는 학력을 안본다고 했나
안그런 회사도 있겠지만, 전문학사는 이력서를 넣어도 서류확인 안한다는 소식을 들었다. 
그 소식은 날 더 자극하였고 그날에만 약 20개의 회사에 이력서를 넣었다.
지원하는데 돈드는 것도 아니고 보던말던 난 넣을거야!! 심보였던 것 같다.</p>
<p>그렇게 약 30개 정도의 회사에 이력서를 넣고
정말 오랜만에 전 직장 동료들을 만나 점심을 먹고있는데 나에게도 면접제의가 왔다.
아니, 200~300개는 넣어야 면접 볼까말까라며...?
난 서류만 끝냈고 면접은 준비가 안됐는데 걱정이 되면서도 기분좋은 떨림이 돌았다.</p>
<p>스타트업, 소규모회사, 복지 이것저것 따지지않고 상관없이 나의 경력을 터줄 곳을 찾은게 신의 한수였나보다.</p>
<p>내 인생에 이런 스타일의 면접을 보게되는 날이 오다니!
전공이 피부미용인지라 인생 첫 취업은 교수님 직장으로 면접같은거 없이 조기취업으로 들어갔었고, 그 뒤로는 경력이 있으니 이력서를 내면 짧게 인사형식 3<del>5분 그 후 바로 실전 데모를 10</del>20분정도 하는게 내 삶의 면접방식이였는데
드라마에서만 보던 여러면접관들앞에 앉아서 구두로 보는 면접을 내가 하게되었다. </p>
<p>부트캠프를 진행하면서도 면접에대한 많은 이야기를 들었던터라 걱정을 많이했다.
질문에 한마디도 대답을 못하면 어떻게하지?</p>
<p>실은 근 10년간 1:1으로 고객과 단둘이 근육,피부에 대한 얘기만하다보니 여러사람과 이야기하는 것, 많은 사람들앞에서 내 의견을 말하는것, 목소리를 크게 내는 것, 피부 쪽이 아닌 다른 주제로 내 생각을 잘 전달하거나 표현하는 법이 엄청나게 퇴화 된 걸 스스로도 느꼈기에 더 걱정을 했다.</p>
<p>그래 자기소개조차 버벅거리면 얼마나 멍청해보일까 그거라도 안떨고 말할 수 있게 연습하자! 생각했고, 거짓말 안하고 100번 이상 연습했다.</p>
<ul>
<li>다른말은 잘 못해도 자기소개는 하고 나올 수 있겠지.</li>
<li>그래 30개 넣는게 면접들어온게 어디야 경험이다 생각하고 여유롭게 마음 먹자</li>
<li>처음하는 경험이지만 프로젝트와 포트폴리오작성도 그랬듯이 하다보면 결과는 나오겠지 </li>
</ul>
<p>계속 마인드 컨트롤을하면서 첫 면접을 갔다.</p>
<hr>
<h1 id="첫-면접-회고---취업">첫 면접 회고  (+ 취업)</h1>
<hr>
<blockquote>
<p>2025년 9월 18일 성수동 스타트업 회사 11시</p>
</blockquote>
<ul>
<li>간단한 자기소개 없이 시작</li>
<li>40분 기술문제풀이세션</li>
<li>문제풀이방식 설명</li>
<li>기술면접 + 인성면접</li>
</ul>
<br>

<p>이렇게 진행되었다. 결과는 처참.....
그래도 배운건 정말 많았다.</p>
<br>

<ul>
<li><p>기술문제 풀이 설명시 타인에게 전달방식 미숙 </p>
</li>
<li><p>-&gt; 방향성은 맞는데 설명이 많이 부실하다는 평을 받음.</p>
</li>
<li><p>기본적인 에러펑션에 대한 무지 </p>
</li>
<li><p>-&gt; 기본적인 지식조차 숙지가 안된 느낌.</p>
</li>
<li><p>AI부트캠프를 듣게된 과정 전달미스 </p>
</li>
<li><p>-&gt; 흥미를 쉽게 느끼고 쉽게 식는다는 느낌을 줌. 끝맺음을 안하는 사람이 되어버림.  </p>
</li>
<li><p>전문용어 무지 </p>
</li>
<li><p>-&gt; 질문의도 잘못파악 + 엉뚱한대답</p>
</li>
<li><p>학점은행제를 선택한 이유와 진행방식의 부조화 </p>
</li>
<li><p>-&gt; 더 공부하려고 시작했는데 왜 자격증취득으로 학점대체를 했는지 부가설명 부족 바로 면접관이 의문을 품고 역 질문하게 됨.</p>
</li>
<li><p>&#39;아!네! 아닙니다!&#39; 의 남발 </p>
</li>
<li><p>-&gt; 면접과 질문에 네라고 대답을 한건지 아니라고 대답을 한건지 불분명.</p>
</li>
<li><p>너무 떨어서 말의 끝맺음이나 확실한 의사표현을 못함 </p>
</li>
<li><p>-&gt; 어리숙한 모습으로 보여짐.</p>
</li>
<li><p>성격 묻는 질문에 업무역량이랑 관련없는 말을 함 </p>
</li>
<li><p>-&gt; 낮을 많이 가리는 편이지만 친해지면 정이많다.  </p>
</li>
<li><p>추가 공부</p>
</li>
<li><p>-&gt; Node.js / LangGraph / Typescript </p>
</li>
</ul>
<p><del>-&gt; 성격 답변은 다시 생각해도 수치풀...🤦‍♀️</del></p>
<hr>
<p>더 많은 부분에서 이 부분이 문제구나!
집에가서 회고써야겠다! 했는데..
기억이 저것뿐이다.. 더 많았던것같았는데 </p>
<p>인생 첫 면접다운 면접이였는데
내가 너무 이상하게 면접을 본건지 중간에 면접관 중 한분이 
&#39;그 전 면접보셨을거잖아요?&#39; 라고 하셨고,
나는 염소 목소리로 &#39;아? 아니요 첫 면접입니다!&#39; 라고했다...하하하하
그래서일까?</p>
<pre><code>뉴비네 뉴비야 허허허, 
열심히도 삐약삐약 하는구나 허허허,
질문 의도를 좀 더 자세히 설명을 해줘야겠다. </code></pre><p>이런 느낌을 받았다. 감사합니다! 덕분에 면접이 조금 덜 무서워습니다!!!</p>
<p>우선 오늘 회고한 부분은 내일있는 면접때 설명을 보완해야겠다. 300~400개 넣으면 30곳은 볼수있을까? 30곳을 보게되면 면접이 쉬워지기는할까?? 아무튼 다음면접부터는 사진도 찍어와야징</p>
<h1 id="-추가-의문">+ 추가 의문</h1>
<ul>
<li><p>집에와서 자고일어나니 의문이 들었다 기술문제풀이에 llm을 쓰라고 했기에 그 안에서만 생각을 했고 어쩌피 llm쓰는거 수량과 가격도 받오면 되겠다 생각했는데 다시 생각해보니 쓸 필요가 없을 것 같다.</p>
</li>
<li><p>PDF에서 이미지 텍스트를 추출한 후,</p>
</li>
<li><p>이미지의 픽셀을 이용해서 색을 추출하고,</p>
</li>
<li><p>사람이 읽을수 있는 색 이름으로 변환하고,</p>
</li>
<li><p>텍스트에서 수량과 가격을 추출하고
그렇게되면 llm을 굳이? 구현만 해놓으면 비용을 아끼는 방법이 되지않을까?</p>
</li>
</ul>
<hr>
<hr>
<hr>
<hr>
<h1 id="두번째-면접-회고">두번째 면접 회고</h1>
<blockquote>
<p>2025년 9월 19일 안암동 소규모 회사 10시</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/35529e48-7583-4e2e-848a-82903c5beead/image.jpg" alt=""></p>
<ul>
<li>간단한 자기소개 시작</li>
<li>1시간 기술면접 + 인성면접</li>
</ul>
<p>드디어 예상하고 준비한 간단한 자기소개로 시작하는 면접을 봤다.
어제처럼 염소되지않으려고 최대한 천천히 말을 하려고 노력했고, 문장의 끝맺음을 확실히하려고 했다. 어제보다는 조금은 수월하게 대답했고, 30분 ~ 1시간정도 본다했던 면접은 1시간을 조금 넘겨 끝이났다!!! (그마저도 면접관 중 한 분께서 1 시간을 꽉 채웠네요. 하면서 정리를 하셨다. <del>일정이 후에 또 있으신가?</del>)</p>
<ul>
<li><p>재귀함수의 단점</p>
</li>
<li><p>-&gt; 서버과부화가 아닌 메모리부족 </p>
</li>
<li></li>
<li><p>-&gt; 기초중에 기초인데 공부 더 해야겠다.</p>
</li>
<li><p>정확하고 디테일한 정보 부족</p>
</li>
<li><p>-&gt; 어제와 마찬가지로 트랜스포머가 뭔가요? 하는 식의 질문에 디테일하고 명확한 설명이 부족했다. </p>
</li>
<li><p>개발자 F12모드가 막힌 이유에대해 생각해봤는지</p>
</li>
<li><p>-&gt; 사이드 프로젝트를 진행중인데 신한은행 대출상품 크롤링 시 개발자 모드가 안켜져서 다른 크롤링방식을 찾고있다 말했는데, 그 이유가 뭔지 질문하셨다. 금융쪽이라 보안때문인가했는데 원하는 답이 아닌 것 같았다. 전혀 생각해본적없는 뱡향이라 당황했고 목표는 크롤링이라 크롤링을 할 수 있는 방향성에 대해서만 생각을 해봤지 왜 막혔는지 생각해본적은 없다고 답했다. (신한은행 api 이용)</p>
</li>
<li><p>어학점수의 부재</p>
</li>
<li><p>-&gt; 이 부분은 스스로도 많이 느끼고 있는 부분이라 취업하고 회사에 적응이되면 공부해서 취득해 보려고한다.</p>
</li>
<li><p>fhir 추가 공부</p>
</li>
<li><p>-&gt; 의료 시스템 간 데이터 상호운용성을 보장하기 위해 만들어진 국제 표준</p>
</li>
</ul>
<hr>
<p>어제와 다른 면접분위기에
또 면접 경력이 쌓였구나!!! 가볍게 생각하면서도 한편으론 기대를 하며 회사를 나왔다.
나와서 생각해보니 급여도 안물어본거면, 가망이없는거였나?</p>
<p>아ㅜㅜ
내가 하고싶던 헬스케어 분야였고,
코드리뷰도 매번 다 봐주신다고했고,
<strong>여직원도 둘</strong>이나 있고!!!!! -&gt; <del>제일 좋았다 점심 천천히 먹을 수 있겠지...?</del>
두분 다 인상도 좋으셨고 편안한 마음이 들었다.
건물이 노후되서 겨울에 추울것 같은 것과 엘레베이터가 없는 것 화장실이 외부 건물 공용이라는거 빼면 다 좋았다!</p>
<hr>
<hr>
<h1 id="합격-전화">합격 전화</h1>
<p>근처에 사는 친구와 오랜만에 밥을 먹으려고 약속을 잡아둔터라 면접이 끝났고 고대에서 출발하니까 10분정도면 도착한다고 전화를 한 후 핸드폰을 보니 10시 15분쯤 부재중이 와있었다.</p>
<p>어제 면접 본곳..? 문자도 없었다.</p>
<p>너무 처참하게 망했던터라 그저 &#39;오늘 면접 볼 사람이 늦어서 전화한다는걸 착오로 나한테 한건가?&#39;라는 생각이 제일 먼저 들었다.
문자로 부재중전화를 확인했다고 남겼고 바로 전화가왔다. 핸드폰 넘어로 내가 합격했다고 말하는 소리가 들렸다....</p>
<p>엥?
왜지?
나를??</p>
<p>생각이 들었지만 그저 좋았다.
6개월을 또 취업준비해야하나 싶었는데..
감사한 마음으로 가야지! 나도 이제 직장인이다!!!!!
경력을 야무지게 쌓아야지!!!
어디가서 나도 이제 개발자라는 말을 할 수 있게되다니 감격이다!!!</p>
<p>너무 심장이 콰쾅거려서 손이 덜덜덜 팟타이를 코로 먹은건지 입으로 먹은건지. 암튼좋다!
추가로 월급이 백이상 줄었으니...씀씀이를 줄여야겠다ㅠㅠ
맛있는 음식들 안녕.....</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[FastAPI_1]]></title>
            <link>https://velog.io/@c_haha_e/FastAPI</link>
            <guid>https://velog.io/@c_haha_e/FastAPI</guid>
            <pubDate>Thu, 04 Sep 2025 23:14:46 GMT</pubDate>
            <description><![CDATA[<p>지난번 UV게시물에 작성한 fastapi설치 방법으로 진행
--&gt; <a href="https://velog.io/@c_haha_e/UV">지난번 UV환경 만들고, fastapi 설치 방법 보기</a></p>
<h1 id="1-fastapi-기본-실행-작성코드">1. FastAPI 기본 실행 작성코드</h1>
<pre><code class="language-py"># main.py
from fastapi import FastAPI

app = FastAPI()

@app.get(&quot;/&quot;)
def read_root():
    return{&quot;Hello&quot;:&quot;world&quot;}</code></pre>
<blockquote>
<p><strong>get</strong>은 조회 용도</p>
</blockquote>
<h1 id="2-엔드포인트api-기능-코드-작성">2. 엔드포인트(API) 기능 코드 작성</h1>
<pre><code class="language-py"># main.py 
from fastapi import FastAPI

app = FastAPI()

@app.get(&quot;/&quot;)
def read_root():
    return{&quot;Hello&quot;:&quot;World&quot;}

@app.get(&quot;/item/{item_id}&quot;)
def read_item(item_id:int, q:str = None):
    return {&quot;item_id&quot;:item_id, &quot;q&quot;:q}</code></pre>
<h1 id="3-엔드포인트api-기능-코드-분리">3. 엔드포인트(API) 기능 코드 분리</h1>
<blockquote>
<p><strong>router</strong>폴더를 만들고 그 안에 <strong>_<em>init_</em>.py</strong> 폴더와 <strong>엔드포인트.py</strong> 파일 생성 후 <strong>엔드포인트.py</strong>에 코드 분리시키기
main.py에 작성해둔 items 기능 코드를 items.py로 이동시킴 </p>
</blockquote>
<pre><code class="language-py"># router/items.py

from fastapi import APIRouter

router = APIRouter()

@router.get(&quot;/items/{item_id}&quot;)
def read_item(item_id: int, q: str = None):
    return {&quot;item_id&quot;: item_id, &quot;q&quot;: q}</code></pre>
<blockquote>
<p>그 후 main.py에 router/items.py 로 옮겨준 코드를 연결시킴
이때, prefix와 tags 그리고 description 지정할 수 있음</p>
</blockquote>
<pre><code class="language-py"># main.py

from fastapi import FastAPI
from routers import items

app = FastAPI()

@app.get(&quot;/&#39;&quot;)
def read_root():
    return {&quot;Hello&quot;:&quot;World&quot;}

app.include_router(items.router, prefix=&quot;/items&quot; tags = [&quot;items&quot;])</code></pre>
<blockquote>
<p>연결시켜줄 때 prefix를 지정하면 router/items.py에서 </p>
</blockquote>
<pre><code>@router.get(&quot;/items/{item_id}&quot;)를 
@router(&quot;/{item_id}&quot;)로 바꿔줘야함.</code></pre><h3 id="-prefixitems-란">* prefix=&quot;/items&quot; 란?</h3>
<blockquote>
<p>이 라우터(items.router) 안에 있는 모든 경로(path) 앞에 자동으로 /items를 붙여줌</p>
</blockquote>
<h3 id="-tags--items-란">* tags = [&quot;items&quot;] 란?</h3>
<blockquote>
<p>Swagger UI(/docs)에서 이 라우터에 속한 API들을 &quot;items&quot;라는 그룹으로 묶어줌.
<img src="https://velog.velcdn.com/images/c_haha_e/post/1e3bb0f2-796c-433f-803e-97272ecb440d/image.png" alt=""></p>
</blockquote>
<h3 id="-description-이란">* description 이란?</h3>
<blockquote>
<p><strong>Swagger UI(자동 문서)</strong>에서 API 설명을 보여주고 싶을 때 쓰는 옵션</p>
</blockquote>
<pre><code class="language-py"># 엔드포인트(라우트) 전체 설명 

# router/items.py
from fastapi import APIRouter

router = APIRouter()

@router.get(
    &quot;/{item_id}&quot;,
    description=&quot;아이템 ID로 특정 아이템을 조회합니다. &quot;
                &quot;q 파라미터를 넣으면 검색 조건이 추가됩니다.&quot;
)
def read_item(item_id: int, q: str = None):
    return {&quot;item_id&quot;: item_id, &quot;q&quot;: q}</code></pre>
<ul>
<li>엔드포인트(라우트) 전체 설명 
<img src="https://velog.velcdn.com/images/c_haha_e/post/dd4e1bed-4fe1-4444-9572-ccdb3b173a24/image.png" alt=""></li>
</ul>
<pre><code class="language-py"># 개별 파라미터 설명

# router/items.py

from fastapi import APIRouter, Path, Query

router = APIRouter()

@router.get(&quot;/items/{item_id}&quot;)
def read_item(
    item_id: int = Path(..., description=&quot;조회할 아이템의 고유 ID&quot;),
    q: str | None = Query(None, description=&quot;검색 필터에 사용할 문자열&quot;)
):
    return {&quot;item_id&quot;: item_id, &quot;q&quot;: q}</code></pre>
<ul>
<li>개별 파라미터 설명
<img src="https://velog.velcdn.com/images/c_haha_e/post/7af4964b-8df1-45c7-879f-815bee5aa539/image.png" alt=""></li>
</ul>
<hr>
<h3 id="--fastapi-주요-파라미터-타입-정리">- FastAPI 주요 파라미터 타입 정리</h3>
<table>
<thead>
<tr>
<th>타입 (Type)</th>
<th>사용 위치</th>
<th>데이터 출처</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Field</strong></td>
<td><strong>Pydantic 모델 내부</strong></td>
<td>Request Body(JSON)</td>
<td><code>{&quot;name&quot;: &quot;김철수&quot;}</code></td>
</tr>
<tr>
<td><strong>Query</strong></td>
<td>함수 파라미터</td>
<td>URL 쿼리 스트링(Query String)</td>
<td><code>/items?q=search</code></td>
</tr>
<tr>
<td><strong>Path</strong></td>
<td>함수 파라미터</td>
<td>URL 경로(Path Parameter)</td>
<td><code>/items/123</code></td>
</tr>
<tr>
<td><strong>Body</strong></td>
<td>함수 파라미터</td>
<td>Request Body(JSON 데이터)</td>
<td><code>{&quot;title&quot;: &quot;책 제목&quot;}</code></td>
</tr>
<tr>
<td><strong>Header</strong></td>
<td>함수 파라미터</td>
<td>HTTP 요청 헤더</td>
<td><code>Authorization: Bearer &lt;token&gt;</code></td>
</tr>
</tbody></table>
<br>

<ul>
<li>Field와 Body의 차이</li>
</ul>
<table>
<thead>
<tr>
<th>구분</th>
<th><strong>Field</strong></th>
<th><strong>Body</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>사용 위치</strong></td>
<td><strong>Pydantic 모델 클래스 내부</strong></td>
<td><strong>엔드포인트 함수 파라미터</strong></td>
</tr>
<tr>
<td><strong>용도</strong></td>
<td>모델의 각 필드 정의 (검증/메타데이터 추가)</td>
<td>Body 데이터를 직접 받기</td>
</tr>
<tr>
<td><strong>언제 사용</strong></td>
<td>구조화된 데이터 모델 정의 시</td>
<td>단순 값이나 특별한 경우</td>
</tr>
<tr>
<td><strong>권장도</strong></td>
<td>대부분의 경우 권장</td>
<td>특수한 경우에만 사용</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[UV]]></title>
            <link>https://velog.io/@c_haha_e/UV</link>
            <guid>https://velog.io/@c_haha_e/UV</guid>
            <pubDate>Thu, 04 Sep 2025 04:34:55 GMT</pubDate>
            <description><![CDATA[<h1 id="uv-">UV ?</h1>
<p>Rust로 개발한 초고속 파이썬 패키지 &amp; 프로젝트 매니저</p>
<h1 id="uv의-역할">UV의 역할</h1>
<p>UV는 파이썬 개발에 필요한 여러 도구를 하나로 합친 것</p>
<ul>
<li>pip 대체 : uv pip install fastapi → pip보다 10~100배 빠른 설치</li>
<li>pip-tools 대체 : uv pip compile → requirements 락파일 생성</li>
<li>virtualenv/venv 대체 : 프로젝트마다 자동 가상환경 관리 (uv run, uv add)</li>
<li>pipx 대체 : uvx ruff check . → 설치 없이 툴 실행</li>
<li>pyenv 대체 일부 : uv python install 3.12 → 파이썬 버전 설치/관리</li>
</ul>
<p>즉, <strong>파이썬 환경 세팅 + 패키지 관리 + 툴 실행 + 파이썬 버전 설치</strong>를 올인원으로 해결하는 툴</p>
<h1 id="uv의-특징">UV의 특징</h1>
<blockquote>
<h4 id="속도">속도</h4>
<p>Rust로 구현돼서 pip 대비 훨씬 빠름
캐싱/병렬 설치 최적화 → 수십~수백 배 성능 향상 가능</p>
</blockquote>
<blockquote>
<h4 id="호환성">호환성</h4>
<p>uv pip … 인터페이스는 pip와 거의 동일해서 기존 습관 그대로 사용 가능.
requirements.txt 워크플로도 지원.</p>
</blockquote>
<blockquote>
<h4 id="통합성">통합성</h4>
<p>한 도구로 가상환경, 패키지, 툴, 파이썬 버전까지 관리 가능.
별도 pip, pipx, pyenv, poetry를 오가며 쓸 필요가 줄어듦.</p>
</blockquote>
<blockquote>
<h4 id="자동-관리">자동 관리</h4>
<p>uv run … 실행 시 자동으로 프로젝트 전용 venv 생성/사용.
사용자는 activate/deactivate 같은 걸 직접 안 해도 됨.</p>
</blockquote>
<h4 id="-uv-와-uvicorn">+ uv 와 uvicorn</h4>
<p>uv = 패키지/환경/런타임 관리 도구
uvicorn = ASGI 서버 (FastAPI 실행할 때 쓰는 서버, 이름만 비슷)</p>
<hr>
<h1 id="설치">설치</h1>
<blockquote>
<ul>
<li>macOS / Linux</li>
</ul>
</blockquote>
<pre><code>curl -LsSf https://astral.sh/uv/install.sh | sh</code></pre><blockquote>
<ul>
<li>PowerShell(Windows)</li>
</ul>
</blockquote>
<pre><code>powershell -ExecutionPolicy ByPass -c &quot;irm https://astral.sh/uv/install.ps1 | iex&quot;</code></pre><blockquote>
<ul>
<li>CMD(Windows)_스탠드얼론 설치</li>
</ul>
</blockquote>
<pre><code>powershell -ExecutionPolicy Bypass -Command &quot;iwr https://astral.sh/uv/install.ps1 -UseBasicParsing | iex&quot;</code></pre><ul>
<li>추후 업그레이드 시<pre><code>uv self update</code></pre></li>
</ul>
<p>또는</p>
<blockquote>
<ul>
<li>CMD(Windows)_pipx 설치</li>
</ul>
</blockquote>
<pre><code>python -m pip install --user pipx
python -m pipx ensurepath
pipx install uv</code></pre><ul>
<li>추후 업그레이드 시<pre><code>pipx upgrade uv</code></pre></li>
</ul>
<blockquote>
<h2 id="설치-확인">설치 확인</h2>
</blockquote>
<pre><code>uv --version</code></pre><br>

<h3 id="중요-pip-install-uv-로-설치하게-되면-설치되는-위치가-현재-실행-중인-파이썬-환경에-따라-달라짐">중요) pip install uv 로 설치하게 되면 설치되는 위치가 현재 실행 중인 파이썬 환경에 따라 달라짐</h3>
<p>이 경우:</p>
<blockquote>
<p>-다른 프로젝트에서 패키지 버전이 충돌할 수 있고,
-PATH 설정이 꼬이면 uv 명령이 안 잡히거나, 특정 가상환경 안에서 인식이 안 될 수도 있음</p>
</blockquote>
<p>그래서 공식 문서도 pip install uv보다는 
<strong>curl로 스탠드얼론 설치</strong>하거나 <strong>pipx install uv로 격리 설치를 추천</strong>
이렇게 하면 시스템 파이썬에 섞이지 않고, 항상 깨끗한 uv 실행 파일을 전역에서 쓸 수 있음.</p>
<hr>
<h2 id="프로젝트-초기화">프로젝트 초기화</h2>
<pre><code>uv init --app</code></pre><p>현재 디렉토리에 <strong>pyproject.toml</strong>이 생김</p>
<hr>
<h2 id="fastapi-설치">fastapi 설치</h2>
<pre><code>uv add fastapi[standard]</code></pre><h2 id="-uv-add-fastapi-와-uv-pip-install-fastapi-의-차이">+ <strong>uv add fastapi</strong> 와 <strong>uv pip install fastapi</strong> 의 차이</h2>
<p>둘 다 패키지를 설치하지만, 쓰임새와 관리 방식이 다름.
<br></p>
<h3 id="-uv-pip--pip-대체-모드">* uv pip … (pip 대체 모드)</h3>
<blockquote>
<p>기존 pip를 빠르게 대체하는 모드
 requirements.txt나 수동 패키지 설치에 익숙한 경우 그대로 사용 가능
 <strong>가상환경</strong> : 원하면 직접 python -m venv .venv 같은 걸 만들어야 함
 =&gt; 기존 pip 워크플로우와 100% 유사하게 쓰고 싶을 때</p>
</blockquote>
<pre><code> uv pip install fastapi
uv pip list
uv pip uninstall fastapi</code></pre><h3 id="-uv-add--프로젝트-모드">* uv add … (프로젝트 모드)</h3>
<blockquote>
<p>pyproject.toml + uv.lock 기반의 프로젝트 단위 패키지 관리
pyproject.toml 파일을 수정하고, uv.lock을 자동 생성
프로젝트 의존성을 기록하고 재현성 보장
<strong>가상환경</strong> : 프로젝트마다 자동으로 venv를 생성하고 관리함
=&gt; 팀 단위 협업, CI/CD, 재현 가능한 환경을 원할 때</p>
</blockquote>
<pre><code>uv init --app             # 프로젝트 초기화 (pyproject.toml 생성)
uv add fastapi[standard]  # fastapi 추가 → toml/lock 자동 업데이트
uv run fastapi dev        # 프로젝트 실행 (자동 가상환경)</code></pre><hr>
<h2 id="-fastapi와-fastapistandard-차이점">+ <strong>fastapi</strong>와 <strong>fastapi[standard]</strong> 차이점</h2>
<blockquote>
<p>-<strong>uv add fastapi</strong> 만 하면 필수 의존성만 설치 (uvicorn은 빠져있음)
-<strong>uv add fastapi[standard]</strong> 를 하면 uvicorn, python-dotenv 등 개발용에 필요한 라이브러리까지 같이 설치</p>
</blockquote>
<hr>
<h2 id="mainpy-실행">main.py 실행</h2>
<pre><code>uv run fastapi dev main.py          # 배포 시 부적합</code></pre><p>또는</p>
<pre><code>uv run uvicorn main:app --reload    # 배포 시 사용 가능</code></pre><h2 id="-uv-run-fastapi-dev-mainpy-과-uv-run-uvicorn-mainapp---reload-차이">+ <strong>uv run fastapi dev main.py</strong> 과 <strong>uv run uvicorn main:app --reload</strong> 차이</h2>
<blockquote>
<table>
<thead>
<tr>
<th>명령어</th>
<th>내부 동작</th>
<th>편의 기능</th>
<th>적합한 상황</th>
</tr>
</thead>
<tbody><tr>
<td><code>uv run fastapi dev main.py</code></td>
<td>Uvicorn 실행 (자동 감지)</td>
<td><code>.env</code> 로드, 파일 자동 검색, 개발용 기본 설정</td>
<td><strong>개발 환경</strong> (학습/실험)</td>
</tr>
<tr>
<td><code>uv run uvicorn main:app --reload</code></td>
<td>직접 Uvicorn 실행</td>
<td>없음 (옵션 직접 지정 필요)</td>
<td><strong>개발/운영 모두</strong> (더 명시적)</td>
</tr>
</tbody></table>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[딥러닝]순차 데이터와 순환 신경망]]></title>
            <link>https://velog.io/@c_haha_e/%EB%94%A5%EB%9F%AC%EB%8B%9D%EC%88%9C%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%99%80-%EC%88%9C%ED%99%98-%EC%8B%A0%EA%B2%BD%EB%A7%9D</link>
            <guid>https://velog.io/@c_haha_e/%EB%94%A5%EB%9F%AC%EB%8B%9D%EC%88%9C%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%99%80-%EC%88%9C%ED%99%98-%EC%8B%A0%EA%B2%BD%EB%A7%9D</guid>
            <pubDate>Mon, 25 Aug 2025 10:03:45 GMT</pubDate>
            <description><![CDATA[<h1 id="피드-포워드">피드 포워드</h1>
<pre><code>입력 데이터의 흐름이 앞으로만 전달되는 신경망
이전 장에서 배웠던 완전 연결 신경망과 합성곱 신경망이 모두 피드포워드 신경망에 속함</code></pre><p><img src="https://velog.velcdn.com/images/c_haha_e/post/89094a92-5abd-4089-9968-d5457b994b9e/image.png" alt=""></p>
<h1 id="순환-신경망rnn">순환 신경망(RNN)</h1>
<pre><code>RNN은 일반적인 완전 연결 신경망과 거의 비슷
뉴런의 출력이 다시 자기 자신으로 전달
어떤 샘플을 처리할 때 바로 이전에 사용했던 데이터를 재사용(이전 샘플의 정보를 가지고있음)

- 타임스텝 : 샘플을 처리하는 한 단계를 의미(한 샘플의 시퀀스의 길이)
- 셀 : 순환신경망에서의 층을 의미
- 은닉상태 : 셀의 출력을 의미</code></pre><h1 id="tanh-함수">tanh 함수</h1>
<pre><code>은닉층의 활성화 함수로 하이퍼볼릭 탄젠트 함수사용
tanh 함수는 s자 모양을 띄어 시그모이드 함수라고도 불리지만, 시그모이드 함수와 달리 -1 ~ 1 사이의 범위를 가짐
순환신경망의 활성화함수로 많이 사용</code></pre><h1 id="순환-신경망의-가중치-크기모델-파라미터-수">순환 신경망의 가중치 크기(모델 파라미터 수)</h1>
<pre><code>완전연결망가중치(은닉층X뉴런) + 순환망가중치(뉴런^2) + 각 뉴런 절편</code></pre><h1 id="순환층의-입력과-출력">순환층의 입력과 출력</h1>
<pre><code>샘플마다 2개의 차원을 가짐.
보통 하나의 샘플을 하나의 시퀀스라고 말함.
시퀀스 안에는 여러 개의 아이템들이 있고 이 길이를 타임스텝이라고 함.
</code></pre><h4 id="by-정민님">by. 정민님</h4>
<h2 id="순환-신경망rnn-recurrent-neural-network">순환 신경망(RNN, Recurrent Neural Network)</h2>
<h2 id="순차-데이터">순차 데이터</h2>
<p>텍스트나 시계열 데이터(일정한 시간 간격으로 기록된 데이터)와 같이 순서에 의미가 있는 데이터를 뜻한다</p>
<p>ex) “I am a boy” 는 이해되지만 “boy am a I”는 말이 되지 않는다</p>
<h3 id="순환-신경망에서는-마지막-셀의-출력이-1차원이기-때문에-flatten-클래스로-펼칠-필요가-없다-셀의-출력을-그대로-밀집층에-사용할-수-있다"> 순환 신경망에서는 마지막 셀의 출력이 1차원이기 때문에 Flatten 클래스로 펼칠 필요가 없다. 셀의 출력을 그대로 밀집층에 사용할 수 있다.</h3>
<h2 id="simplernn">SimpleRNN</h2>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/423c951f-07a4-43cb-9311-cc278e8b6dde/image.png" alt=""></p>
<p>RNN은 이전 시점의 출력을 다음 시점의 입력으로 넘겨서, 시간 순서대로 한 스텝씩 <strong>도장 찍듯이</strong> 처리하는 신경망이다. </p>
<p>즉, <code>파란 네모(정답)</code>을 예측하기 위해 <code>노란 네모(같은 행의 값)</code>를 주는 것이 아니라, <code>빨간 네모(4개행의 각 데이터/하나의 윈도우)</code>를 제공하는 방식이다.</p>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/d59c71da-8a09-4531-9ff5-3702ab009ddc/image.png" alt=""></p>
<p>뉴런의 출력이 다시 자기 자신으로 전달된다</p>
<p>= 어떤 샘플을 처리할 때, 바로 이전에 사용했던 데이터를 재사용한다</p>
<p>즉, 이전 타임스텝의 샘플을 기억하지만 오래될수록 순환되는 정보는 희미해진다.</p>
<blockquote>
<p>OA는 A를 처리 후 출력된 결과이다. 
OA는 다시 뉴런으로 들어가, B를 처리할 때 같이 사용된다. 
= OB는 A에 대한 정보가 어느정도 포함되어 있다.
OC에는 OB를 사용하므로, A와 B에 대한 정보가 어느정도 들어있다. 이때, 상대적으로 B에 대한 정보가 더 많이 들어있을 것이다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/534a6ace-3462-4129-97fd-113dd4403f2a/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/7969574a-ac87-42da-99b5-6f2cd76ba70f/image.png" alt=""></p>
<p><code>셀(cell)</code> : 순환 신경망에서 층을 부르는 말</p>
<p><code>은닉상태(hidden state)</code> : 셀의 출력</p>
<h3 id="rnn-코드">RNN 코드</h3>
<ol>
<li><p>데이터셋 생성</p>
<p> 30일치 과거 데이터를 기반으로 다음날을 예측하기 위한 구조</p>
<pre><code class="language-python"> from torch.utils.data import Dataset, DataLoader
 import pandas as pd
 import numpy as np
 class NetflixDataset(Dataset):
   def __init__(self,csv_path):
     df = pd.read_csv(csv_path)
     self.data = df.iloc[:,1:4].to_numpy()
     # 0과 1 사이로 정규화
     self.data = self.data / np.max(self.data)
     # 정답(종가)
     self.label = df.iloc[:,-1].to_numpy()
     self.label = self.label / np.max(self.label)
   def __len__(self):
     return len(self.data) - 30 #시작일로부터 30일치 데이터이므로 (시계열 데이터이기때문에 가능)
   def __getitem__(self,idx):
     data = self.data[idx: idx+30]
     label = self.label[idx+30]
     return data, label</code></pre>
 <aside>

<h3 id="왜-30-30을-하는가"> 왜 +30/-30을 하는가?</h3>
<ol>
<li> <code>idx=0</code>일 때:</li>
</ol>
<ul>
<li><code>data</code>: <code>self.data[0:30]</code> → 0~29일까지 총 30일치 입력 데이터</li>
<li><code>label</code>: <code>self.label[30]</code> → 30번째 날(즉, 31번째 날)의 종가 = 우리가 예측해야 할 값</li>
</ul>
<ol>
<li> <code>len(self.data) = 1000</code>이면, 가능한 샘플 개수는 <code>1000 - 30 = 970</code>개</li>
</ol>
<ul>
<li><code>idx=0 → 예측은 30번째 날</code></li>
<li><code>idx=969 → 예측은 999번째 날</code></li>
<li><code>idx=970 → self.label[1000]</code> ← 이건 <strong>존재하지 않음 (오버 인덱스!)</strong></aside>
</li>
</ul>
</li>
<li><p>데이터 분류</p>
<p>  시계열 데이터는 shuffle 금지!!!</p>
<pre><code class="language-python"> netflix_dataset = NetflixDataset(&#39;/content/train.csv&#39;)
 data, label = next(iter(netflix_dataset))
 netflix_dataloader = DataLoader(netflix_dataset, batch_size=32)
 data, label = next(iter(netflix_dataloader))
 data.shape, label.shape</code></pre>
</li>
<li><p>모델 정의</p>
<pre><code class="language-python"> import torch
 import torch.nn as nn
 class NetflixRnn(nn.Module):
   def __init__(self):
     super().__init__()
     #RNN 계층: 입력 feature의 수 / batch_first: 입력의 모양을 배치우선으로 (B, Seq_len, input_size) 로 만든다는 뜻
     self.rnn = nn.RNN(input_size=3, hidden_size = 10,num_layers=5,batch_first=True)
     # RNN 출력 (batch_size, seq_size,hidden_size) (32,30,10)

     # RNN 출력 전체를 flatten 후 Linear 통과
     self.linear1 = nn.Linear(in_features=30*10, out_features=100)
     self.linear2 = nn.Linear(in_features=100, out_features=1) #값을 예측하고 있으니까 출력은 1개

     self.relu = nn.ReLU()

   def forward(self,x,h0): #h0는 초기 은닉 상태
       # RNN 통과: x -&gt; 모든 시점의 hidden output, hn -&gt; 마지막 hidden state들
     x, hn = self.rnn(x,h0) # x shape: (batch_size, 30, 10)

     x = torch.flatten(x,start_dim=1) # x shape: (batch_size, 300)

     # 분류기 부분 통과
     x = self.relu(self.linear1(x))
     x = self.linear2(x)
     return x</code></pre>
</li>
<li><p>모델 생성 및 학습</p>
<pre><code class="language-python"> from tqdm import tqdm

 #모델 생성
 netflix = NetflixRnn()
 device = &quot;cuda&quot; if torch.cuda.is_available() else &#39;cpu&#39;

 # 손실 함수: 평균 제곱 오차(회귀 문제이므로)
 loss_fn = nn.MSELoss()
 # 학습률, 에포크 설정 
 lr = 1e-4
 epocs = 200
 # 옵티마이저: Adam 사용
 optim = torch.optim.Adam(netflix.parameters(),lr=lr)
 # 모델을 디바이스에 할당
 netflix = netflix.to(device)

 # 모델 학습 루프 
 for epoch in range(epocs):
   iterator = tqdm(netflix_dataloader)
   epoch_loss = 0.0
   for data, label in iterator:
     # 텐서의 학습은 기본인 torch.float32 타입, 형태: (batch_size, 1)
     label = label.reshape(-1,1).to(torch.float32).to(device)
     # 입력 데이터도 float32 
     data = data.clone().detach().to(torch.float32).to(device)  # float -&gt; 32bit
     # 초기 은닉 상태 0으로 초기화
     h0 = torch.zeros(5,data.shape[0],10).to(device)  # num_layers, batch_size, hidden_size
     # 예측
     pred = netflix(data,h0)
     # 손실 계산 및 역전파
     loss = loss_fn(pred,label)
     loss.backward()
     # 가중치 업데이트
     optim.step()
     optim.zero_grad()

     epoch_loss += loss.item()
     iterator.set_description(f&quot;loss : {loss.item()}&quot;)
   # 에포크별 평균 손실 출력
   print(f&#39;epoch : {epoch + 1}  loss : {epoch_loss / len(netflix_dataloader)}&#39;)
 # 학습된 모델 저장
 torch.save(netflix.state_dict(), &quot;netflix.pth&quot;)</code></pre>
</li>
<li><p>평가</p>
<pre><code class="language-python"> # 저장된 모델 불러오기
 loaded_model = NetflixRnn()
 loaded_model.load_state_dict(torch.load(&#39;netflix.pth&#39;, map_location=device))
 loaded_model.eval()

 pred_lists = []
 total_loss = 0.0
 # 평가 시 batch_size=1로 설정
 loader = DataLoader(netflix_dataset,batch_size=1)

 # 평가 루프 
 with torch.no_grad():
   for data ,label in loader:
     h0 = torch.zeros(5,data.shape[0],10).to(device)
     # 예측 수행
     predict = loaded_model(data,h0)
     # 예측 결과 저장
     pred_lists.extend([p.item() for p in predict])
     # 손실 누적
     loss = loss_fn(predict,label)
     total_loss += loss.item()
 # 전체 평균 손실 출력
 print(f&quot;loss : {total_loss / len(loader.dataset)}&quot;)</code></pre>
 <aside>

<h3 id="평가-시-batch_size--1-인-이유"> 평가 시 batch_size = 1 인 이유</h3>
<pre><code class="language-python"> loader = DataLoader(netflix_dataset, batch_size=1)</code></pre>
<p> 이 코드는 평가 시 모든 샘플을 <code>하나씩</code> 모델에 넣는다는 뜻.</p>
<p> 보통 시계열 예측에서는 “입력 → 예측 → 그 다음” 식으로 시간 순서를 따라가면서 예측한 값을 차례대로 저장하고 비교하기 때문에</p>
<p> <code>batch_size =1</code> 로 하면 예측값이 시간 순서대로 <code>pred_lists</code> 에 쌓이기 때문에 나중에 분석하기에 용이하다</p>
<p> (정확도 평가만 빠르게 하고 싶다면 <code>batch_size &gt; 1</code> 로 해도 문제되지 않는다. 하지만 시계열 예측 결과를 하나씩 저장하거나 시각화하는 것이 목적이라면 <code>1</code> 로 하는게 안정적이다)</p>
 </aside>
</li>
<li><p>시각화</p>
<pre><code class="language-python"> import matplotlib.pyplot as plt
 # 전체 데이터 비교
 plt.figure(figsize=(15,5))
 plt.subplot(1,2,1)
 plt.plot(pred_lists,label=&quot;prediction&quot;)
 plt.plot(netflix_dataset.label[30:], label=&#39;real&#39;)
 plt.legend()

 # 일부 영역 확대
 plt.subplot(1,2,2)
 plt.plot(pred_lists,label=&quot;prediction&quot;)
 plt.plot(netflix_dataset.label[30:], label=&#39;real&#39;)
 plt.xlim(200,400)
 plt.legend()
 plt.show()</code></pre>
<p> <img src="https://velog.velcdn.com/images/c_haha_e/post/fa976e8f-6d18-4655-bf07-bdb8517d7faa/image.png" alt=""></p>
</li>
</ol>
<h2 id="lstmlong-short-term-memory">LSTM(Long Short-Term Memory)</h2>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/f7bf0a70-a600-466f-830c-acfa8a47772f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/4eb000d6-6462-478f-b5eb-4b67c504fb0d/image.png" alt=""></p>
<p>단기 기억을 오래 보존하기 위해(RNN의 단점 보완) 고안되었다. </p>
<blockquote>
<p>Input gate(입력 게이트): 얼마나 새 정보를 셀 상태에 반영할지
Forget gate(망각 게이트): 얼마나 기존 셀 상태를 유지할지 결정
Output gate(출력 게이트): 어떤 정보를 은닉 상태로 보낼지</p>
</blockquote>
<p> 차이점</p>
<ul>
<li><p>은닉 상태에 활성화 함수를 통과시켜 다음 은닉 상태로 만들 때, <code>sigmoid</code> 함수를 사용한다. 또, <code>tanh</code> 함수를 통과한 어떤 값과 곱해져서 은닉 상태를 만든다</p>
</li>
<li><p>LSTM은 순환되는 상태가 2가지: 은닉 상태(<code>h</code>), 셀 상태(<code>c</code>)</p>
<ul>
<li><p>셀 상태: 은닉층과 달리 다음 층으로 전달되지 않고 LSTM 셀에서 순환만 하는 값</p>
</li>
<li><p>두 값에 곱해지는 가중치 처리 방식이 다르다(셀 상태는 별도의 가중치 행렬을 통해 선형변환되지 않고, 게이트 값과 단순 곱셉으로만 업데이트된다)</p>
<table>
<thead>
<tr>
<th>항목</th>
<th>은닉 상태 (<code>h</code>)</th>
<th>셀 상태 (<code>c</code>)</th>
</tr>
</thead>
<tbody><tr>
<td>가중치 곱?</td>
<td><code>U_f</code>, <code>U_i</code>, <code>U_o</code>, <code>U_c</code> 등 <strong>가중치 있음</strong></td>
<td><strong>가중치 없음</strong>, 단순 곱(<code>f_t ⊙ c_{t-1}</code>)</td>
</tr>
<tr>
<td>정보 흐름</td>
<td>출력을 위한 정보</td>
<td>장기 기억 유지용 정보</td>
</tr>
<tr>
<td>업데이트 방식</td>
<td>게이트 출력과 tanh, σ 등 다양한 연산</td>
<td>forget/input 게이트와 원소곱으로 조절</td>
</tr>
</tbody></table>
</li>
</ul>
</li>
</ul>
<pre><code class="language-python">from tensorflow import keras
model = keras.Sequential()
model.add(keras.layers.Embedding(500,16,input_shape=(100,)))
model.add(keras.layers.LSTM(8))
model.add(keras.layers.Dense(1,activation=&#39;sigmoid&#39;))</code></pre>
<p>→ 파라미터 수: SimpleRNN의 4배(LSTM안에 작은 셀 4개 있어서)</p>
<ul>
<li><p> LSTM → LSTM 넘어갈 때는 첫 번째 층이 return_sequences=True, 마지막 층은 False 여야 함 !</p>
<p>  from 문영님</p>
<h2 id="2개의-층을-연결하기">2개의 층을 연결하기</h2>
<ul>
<li><p>케라스의 순환층에서 모든 타임스텝의 은닉 상태를 출력하려면 마지막을 제외한 다른 모든 순환층에서 return_sequences 매개변수를 True로 지정하면 됨</p>
<pre><code class="language-python">model3 = keras.Sequential()
model3.add(keras.layers.Embedding(500, 16, input_shape=(100,)))
model3.add(keras.layers.LSTM(8, dropout=0.3, return_sequences=True))
model3.add(keras.layers.LSTM(8, dropout=0.3))
model3.add(keras.layers.Dense(1, activation=&#39;sigmoid&#39;))

model3.summary()</code></pre>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/da806554-2172-4ae6-a297-82b68b0fd895/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>- 첫 번째 LSTM 층은 모든 타임스텝(100개)의 은닉 상태를 출력하기 때문에 출력 크기가 (None, 100, 8)로 표시됨. 그러나 두 번째 LSTM 층의 출력 크기는 마지막 타임스텝의 은닉 상태만 출력하기 때문에 (None, 8)으로 표시됨.
- 첫 번째 LSTM : 시퀀스 전체 정보 유지
두 번째 LSTM : 그 시퀀스를 종합해서 최종 정보 하나로 요약
LSTM → LSTM 넘어갈 때는 첫 번째 층이 return_sequences=True, 마지막 층은 False 여야 함 !</code></pre><h2 id="gru">GRU</h2>
<p>LSTM을 간소화한 버전으로, 성능은 비슷한데 구조는 더 단순하다.</p>
<ul>
<li>은닉 상태와 입력에 가중치를 곱하고 절편을 더하는 작은 셀 3개(2개는 <code>sigmoid</code> , 1개는 <code>tanh</code> )</li>
</ul>
<blockquote>
<p>Update gate
Reset gate
Candidate hidden state</p>
</blockquote>
<pre><code class="language-python">from tensorflow import keras
model = keras.Sequential()
model.add(keras.layers.Embedding(500,16,input_shape=(100,)))
model.add(keras.layers.GRU(8))
model.add(keras.layers.Dense(1,activation=&#39;sigmoid&#39;))</code></pre>
<p>→ 파라미터 수: 624개</p>
<ul>
<li>하나의 게이트를 계산할 때 필요한 파라미터 : 200개<ul>
<li>입력에 곱하는 가중치 16 x 8 = 128개</li>
<li>은닉 상태에 곱하는 가중치 8 x 8 = 64개</li>
<li>절편은 뉴런마다 하나씩이므로 8개</li>
</ul>
</li>
<li>이러한 작은 셀(게이트)가 3개이므로 200 x 3 = 600개</li>
<li>keras 내부 동작으로 bias가 추가되어서 + 24개 !</li>
</ul>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/321b1e64-3f5f-40c0-b457-010f23f639d3/image.png" alt=""></p>
<h2 id="gan캡챠">GAN(캡챠)</h2>
<p>CNN + RNN 의 구조로, 이미지나 시계열에서 공간적 특징과 순차적 흐름을 함께 처리하는 모델이다. 캡차 인식처럼, 이미지로 된 문자가 들어오면 CNN으로 문자 특징을 추출한 다음 RNN으로 문자의 순서를 해석해서 예측하는 것이다.</p>
<aside>

<ul>
<li><strong>CNN (합성곱)</strong>: 입력 이미지에서 특징 추출</li>
<li><strong>RNN (GRU)</strong>: CNN의 출력 시퀀스를 기반으로 시계열 처리</li>
<li><strong>FC (MLP)</strong>: 각 시점마다 어떤 문자인지 분류</li>
<li><strong>CTC 손실 대응</strong>: 최종 출력에 <code>log_softmax</code> 적용</aside>

</li>
</ul>
<p><img src="https://velog.velcdn.com/images/flowinq414/post/c7c5275e-ffc8-4154-b0ac-7a86b2e914db/image.png" alt=""></p>
<pre><code class="language-python">class CRNN(nn.Module):
  def __init__(self,output_size):
    super().__init__()
    # batch_size 모르니까 None으로
    # CNN 계층: (None, 3, 50, 200)
    self.block = nn.Sequential(
        BasicBlock(3,64), # (None, 64, 24, 196)
        BasicBlock(64,64), # (None, 64, 11, 192)
        BasicBlock(64,64), # (None, 64, 5, 188)
        BasicBlock(64,64), # (None, 64, 2, 184)
        #세로 방향의 정보를 한줄(1픽셀)로 압축 -&gt; 가로축만 남아서 시퀀스로 사용 가능
        nn.Conv2d(64,64,kernel_size=(2,5)) #(None, 64, 1, 180)
        # kernel_size 에서 w:5 는 단어 또는 문자 패턴 뽑기 위함이다(약 5개 안에 하나의 단어가 들어올거다 라고 가정하고)
    )

    # GRU 정의
    self.gru = nn.GRU(64,64, batch_first=False) 
    # 입력: (seq_len=180, batch, input_size=64) 
    # (H,B,input_size)

    #분류 MLP
    self.fc = nn.Sequential(
        nn.Linear(64,128),
        nn.ReLU(),
        nn.Linear(128,output_size) # 각 시점마다 문자 예측 
    )

  def forward(self,x):
      x = self.block(x) # CNN 통과: (1, 3, 50, 200) -&gt; (1, 64, 1, 180) 
      # (B, C, H, W) -&gt; 1,64,180(B,C,W)(0,1,2) 하려면 permute(2,0,1) 필요
      x = x.squeeze(2) # 세로(H) 제거 : (1, 64, 180)
      x = x.permute(2,0,1) # (180, 1, 64) GRU 입력 형태로 변환

      #초기 은닉층(num_layers, batch_size, hidden_size)
      h0 = torch.zeros(1,x.size(1), 64)
      # GRU 처리
      x, _ = self.gru(x,h0)
      # 각 시점마다 문자 분류
      x = self.fc(x)
      #CTC 손실계산
      x = F.log_softmax(x, dim=-1)
      return x</code></pre>
<aside>

<h3 id="데이터-처리-단계-요약"> 데이터 처리 단계 요약</h3>
<ul>
<li>CNN 거치기 전 이미지는 <code>(B,C,H,W)</code></li>
<li>합성곱 층을 전부 통과하면 <code>(B, 64, 1, 180)</code> : 텍스트 이미지의 가로 방향 흐름이 180개의 &#39;타임스텝&#39;이 된다</li>
<li>GRU 입력 형태로 변환하면 <code>(180, B, 64)</code></li>
<li>MLP : 각 가로 픽셀 하나가 어떤 문자(class)에 속하는지 예측</aside>

</li>
</ul>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/d03b8f15-a85b-4955-88cc-9d1f91c7f34b/image.png" alt=""></p>
<ul>
<li><p>chatgpt: 왜 reshape이 필요한가</p>
<p>  아주 좋은 질문이에요! 👏</p>
<p>  &quot;차원을 맞추기 위해 <code>flatten()</code> 하는 것&quot;과 &quot;GRU 입력 형태로 맞추기 위해 세로길이를 <code>squeeze()</code> 하는 것&quot;은 <strong>비슷한 맥락도 있고, 중요한 차이점도 있어요.</strong></p>
<p>  아래에서 둘을 비교해서 설명드릴게요:</p>
<hr>
<h2 id="공통점">공통점:</h2>
<p>  둘 다 <strong>모델에 맞는 입력 차원</strong>으로 <strong>데이터를 reshape(재구성)</strong> 하기 위한 작업입니다.</p>
<table>
<thead>
<tr>
<th>목적</th>
<th>차원 조정</th>
</tr>
</thead>
<tbody><tr>
<td>모델이 원하는 입력 형태에 맞추기 위해</td>
<td>차원을 줄이거나, 바꾸거나, 펼치는 작업</td>
</tr>
</tbody></table>
<hr>
<h2 id="차이점">차이점:</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th><code>flatten()</code></th>
<th><code>squeeze()</code> (or <code>permute</code>, reshape for RNN)</th>
</tr>
</thead>
<tbody><tr>
<td>목적</td>
<td>완전히 1D 벡터로 만들어 MLP(선형 계층)에 넣기 위함</td>
<td>시퀀스 데이터로 바꾸기 위해 차원을 재배열</td>
</tr>
<tr>
<td>사용 위치</td>
<td>CNN → MLP 연결 전에 주로 사용</td>
<td>CNN → RNN 연결 전에 사용</td>
</tr>
<tr>
<td>결과</td>
<td><code>(B, C×H×W)</code> 형태의 벡터</td>
<td><code>(Seq_len, B, Feature)</code> 또는 <code>(B, Seq_len, Feature)</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="예시-비교">예시 비교</h2>
<h3 id="①-flatten">① <code>flatten()</code>:</h3>
<pre><code class="language-python">  x = x.view(batch_size, -1)  # or torch.flatten(x, start_dim=1)
</code></pre>
<ul>
<li><p>예: <code>(B, 64, 7, 7)</code> → <code>(B, 3136)</code></p>
</li>
<li><p>목적: MLP (<code>nn.Linear</code>)에 넣기 위해 <strong>1차원 벡터</strong>로 펼침</p>
<h3 id="②-squeeze--permute-for-rnn-like-gru">② <code>squeeze()</code> + <code>permute()</code> (for RNN like GRU):</h3>
<pre><code class="language-python">x = x.squeeze(2)         # (B, 64, 1, 180) → (B, 64, 180)
x = x.permute(2, 0, 1)   # → (180, B, 64)
</code></pre>
</li>
<li><p>목적: <strong>가로 방향 픽셀을 시간 축</strong>으로 보고 GRU에 넣기 위한 변형</p>
</li>
<li><p>여기서는 <code>flatten</code> 하지 않고 <strong>&quot;시퀀스 처리&quot;에 적합한 구조로만 바꿈</strong></p>
</li>
</ul>
<hr>
<h2 id="핵심-요약">핵심 요약</h2>
<table>
<thead>
<tr>
<th>개념</th>
<th>flatten</th>
<th>squeeze &amp; permute</th>
</tr>
</thead>
<tbody><tr>
<td>쓰는 위치</td>
<td>CNN → MLP</td>
<td>CNN → RNN</td>
</tr>
<tr>
<td>결과 형태</td>
<td>(B, Feature)</td>
<td>(Seq_len, B, Feature)</td>
</tr>
<tr>
<td>목적</td>
<td>벡터로 펼쳐서 선형계층에 넣기</td>
<td>시퀀스 구조로 변환해서 RNN에 넣기</td>
</tr>
<tr>
<td>데이터 의미 유지 여부</td>
<td>공간 구조 무시</td>
<td>시퀀스 의미 유지 (예: 가로 방향 문자 순서)</td>
</tr>
</tbody></table>
<hr>
<h3 id="비유로-설명하면">비유로 설명하면:</h3>
<ul>
<li><code>flatten()</code>은 <strong>이미지를 일렬로 쫙 펼치는 것</strong> (의미 상실 가능)</li>
<li><code>squeeze()</code> + <code>permute()</code>는 <strong>시퀀스 구조를 유지한 채로 배치</strong>하는 것 (의미 보존)</li>
</ul>
<hr>
<p>  필요하다면 <code>flatten</code>, <code>view</code>, <code>reshape</code>, <code>permute</code> 등의 차이도 더 정리해드릴 수 있어요!</p>
<p>  좋은 질문이에요!</p>
<ul>
<li>*&quot;가로 방향 픽셀을 시간축으로 본다&quot;<strong>는 말을 이해하려면 먼저 GRU 같은 순환 신경망이 **입력을 어떻게 처리하는지</strong>를 이해해야 해요.</li>
</ul>
<hr>
<h2 id="gru의-입력-형태">GRU의 입력 형태</h2>
<p>  GRU는 입력을 보통 다음과 같은 형태로 받습니다:</p>
<pre><code>  (seq_len, batch_size, input_size)
</code></pre><p>  즉, <strong>하나의 시퀀스 = 여러 개의 시점(time step)</strong> 으로 구성되어 있고,</p>
<p>  각 시점마다 <strong>하나의 벡터 (input_size)</strong> 를 입력받습니다.</p>
<hr>
<h2 id="cnn의-출력-예-문자-이미지">CNN의 출력 (예: 문자 이미지)</h2>
<p>  CNN을 통과한 뒤의 출력 텐서:</p>
<pre><code>  (B, C, H, W) = (batch_size, channel, height, width)
</code></pre><p>  이제 이걸 <strong>RNN에 연결</strong>해야 하니까, 어느 방향을 시퀀스로 볼지 정해야 해요.</p>
<hr>
<h2 id="왜-가로w를-시간축으로-보는가">왜 &quot;가로(W)를 시간축&quot;으로 보는가?</h2>
<p>  문자나 문장의 이미지를 보면 보통 <strong>글자들이 가로 방향으로 나열</strong>되어 있죠?</p>
<pre><code>  예시: &quot;CRNN&quot; -&gt; 이미지에서 왼쪽부터 C → R → N → N
</code></pre><ul>
<li>그래서 <strong>가로 방향(W)</strong> 을 <strong>시간 순서</strong>로 보고,</li>
<li><strong>세로 방향(H)</strong> 은 글자의 세부적인 <strong>시각적 정보</strong> (높이, 세로 모양 등)라고 보면 됩니다.</li>
</ul>
<hr>
<h2 id="그럼-왜-세로h를-삭제squeeze하나">그럼 왜 세로(H)를 삭제(squeeze)하나?</h2>
<p>  CNN을 거친 후에는 보통 다음처럼 나옵니다:</p>
<pre><code>  (B, 64, 1, 180)
</code></pre><p>  여기서:</p>
<ul>
<li><p><code>64</code>: 채널 (특징 맵의 개수)</p>
</li>
<li><p><code>1</code>: 세로 방향 (높이)</p>
</li>
<li><p><code>180</code>: 가로 방향 (폭, 시퀀스 길이)</p>
<p>즉, CNN을 통해 <strong>세로 방향 정보는 이미 모두 요약</strong>되었고,</p>
<p><code>H = 1</code> 이 되어 더 이상 시퀀스 정보로서 쓸모가 없습니다.</p>
<p>그래서 이걸 <code>squeeze(2)</code> 해서 차원을 없애주면:</p>
<pre><code>(B, 64, 180)
</code></pre><p>이제 이걸 <strong>GRU에 넣기 위해</strong> permute 하면:</p>
<pre><code>(180, B, 64)  # → 시퀀스 길이 180, 배치 B, 특성 64
</code></pre><p>이렇게 되면 각 가로 픽셀 위치가 <strong>하나의 시점(time step)</strong> 이 되고,</p>
<p>그 시점마다의 정보가 <strong>64차원의 벡터</strong>로 표현되는 거예요.</p>
</li>
</ul>
<hr>
<h2 id="정리">정리</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>왜 가로(W)가 시간축인가?</td>
<td>문자가 가로로 나열되니까 시간 순서로 볼 수 있음</td>
</tr>
<tr>
<td>세로(H)는 왜 1인가?</td>
<td>CNN에서 세로 방향을 다 통합했기 때문</td>
</tr>
<tr>
<td>그래서 squeeze(H)?</td>
<td>쓸모 없는 차원이니까 없애서 RNN에 넣기 좋게 만듦</td>
</tr>
</tbody></table>
<hr>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[딥러닝]신경망]]></title>
            <link>https://velog.io/@c_haha_e/%EB%94%A5%EB%9F%AC%EB%8B%9D</link>
            <guid>https://velog.io/@c_haha_e/%EB%94%A5%EB%9F%AC%EB%8B%9D</guid>
            <pubDate>Mon, 25 Aug 2025 09:48:13 GMT</pubDate>
            <description><![CDATA[<h1 id="sklearn으로-신경망-구현">sklearn으로 신경망 구현</h1>
<blockquote>
<p>tensorflow - keras 라이브러리와 fashion_mnist 데이터 불러오기</p>
</blockquote>
<pre><code class="language-py">from tensorflow import keras
(train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data()
# 애초에 4덩이로 구분되어있어서 train_input, train_target, test_input, test_target 변수로 받을 수 있음</code></pre>
<blockquote>
<p>train 데이터와 test 데이터 구조확인</p>
</blockquote>
<pre><code class="language-py">print(train_input.shape, train_target.shape)
#(60000, 28, 28) (60000,)</code></pre>
<pre><code class="language-py">print(test_input.shape, test_target.shape)
#(10000, 28, 28) (10000,)</code></pre>
<pre><code>각 변수에 들어있는 데이터 구조를 확인.
train_input 은 (60000, 28, 28)인데 이건 28*28 이미지 데이터가 60000개 있는것.
  (전체 이미지 개수(1차원), 이미지의 세로 픽셀 수(2차원), 이미지의 가로 픽셀 수(3차원))


train_target 은 (60000, )인데 타겟 데이터는 60000개의 라벨</code></pre><blockquote>
<p>fashion_mnist 데이터 시각화 확인하기</p>
</blockquote>
<pre><code class="language-py">import matplotlib.pyplot as plt
fig, axs = plt.subplots(1, 10, figsize=(10,10))
for i in range(10):
  axs[i].imshow(train_input[i], cmap=&#39;gray_r&#39;)
  axs[i].axis(&#39;off&#39;)
plt.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/64b1889a-4a9a-4d60-a0e0-e97bb85fbf77/image.png" alt=""></p>
<pre><code>fig, axs = plt.subplots(1, 10, figsize=(10,10))
1행 10열의 서브플롯을 생성


fig =&gt; 서브플롯(axes)을 포함하는 가장 바깥의 컨테이너. 캔버스(도화지)라고 보면 됨.
axes =&gt; 캔버스(도화지)안의 작은 네모칸 하나를 의미
axs =&gt; 서브플롯(axes)에 들어갈 데이터
subplot() =&gt; 도화지를 나누는 방식
  1행 10열의 서브플롯을 생성
fig = Figure(1000 * 1000)
figsize=(10, 10) -&gt; 10인치, 10인치
  픽셀로 바꾸면 10인치 X 100dpi = 1000픽셀, 10인치 X 100dpi = 1000픽셀</code></pre><pre><code class="language-py">import numpy as np
print(np.unique(train_target, return_counts=True))

#(array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8), array([6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000]))</code></pre>
<pre><code>np.unique(train_target, return_counts=True)

return_counts = True 는
train_target의 unique한 값을 count해서 돌려줌.
-&gt; 각 요소마다 몇 번 나오는지 알 수 있음

이 데이터에서는
10개의 카테고리가있고
각 카테고리별로 6000개씩 train데이터가 들어있음</code></pre><blockquote>
<p>train데이터 정규화</p>
</blockquote>
<pre><code class="language-py">train_scaled = train_input / 255.0
train_scaled = train_scaled.reshape(-1, 28*28)</code></pre>
<pre><code>픽셀은 0~255까지 있는데
SGDClassifier에서는 특성마다 범위가 많이 다르면 적용시키기 애매함.
0~1 사이로 정해주는것이 좋음
이런 이유로 0~1사이로 만들어주기위해 255로 나눠줌


또한
SGDClassifier는 2차원 배열은 다룰 수 없으므로
2차원 배열인 각 샘플(28, 28)을 1차원 배열로 맞춰줘야함
reshape()를 이용

reshape(-1, 28*28)
-1 : 알아서 맞춤
28*28 : 샘플데이터의 2,3차원을 1차원으로 합침
   -&gt; 그러면 1차원의 샘플개수는 변화없이 60000개!!!</code></pre><blockquote>
<p>모델만들기</p>
</blockquote>
<pre><code class="language-py">from sklearn.model_selection import cross_validate
from sklearn.linear_model import SGDClassifier
sc = SGDClassifier(loss = &#39;log_loss&#39;, max_iter = 5, random_state = 42)
scores = cross_validate(sc, train_scaled, train_target, n_jobs = -1)
print(np.mean(scores[&#39;test_score&#39;]))
#0.8194166666666666</code></pre>
<pre><code>확률적 경사 하강법(SGD)를 이용
  (loss = &#39;log_loss&#39;, max_iter = 5, random_state = 42)
    loss = &#39;log_loss&#39; : 로지스틱 회귀를 의미
    max_iter = 5 : 한번 학습할때 최대5번만 데이터 반복


교차 검증(Cross Validation)
  -&gt; 데이터를 여러 조각으로 나눠서 여러번 학습/검증하여 평균 성능을 계산

  작동흐름(기본 5-fold)
    데이터를 5등분
    4개는 훈련, 1개는 검증
    이걸 총 5번 바꿔가며 훈련/검증
    각각의 test_score 저장

      혹시 fold설정하고싶으면
        from sklearn.model_selection import KFold

        cv=KFold(n_splits=7, shuffle=True, random_state=42)  
          -&gt; 7등분 + 섞기
        scores = cross_validate(model, X, y, cv=cv)  으로 사용 가능

  (sc, train_scaled, train_target, n_jobs = -1)
    sc : 사용할 모델
    train_scaled : 입력데이터 (X)
    train_target : 정답데이터 (y)
    n_jobs = -1 : CPU병렬처리(모든코어사용)

  scores = cross_validate(...)
    결과는 딕셔너리 형식으로 반환
    ex)
      scores.keys()
      # dict_keys([&#39;fit_time&#39;, &#39;score_time&#39;, &#39;test_score&#39;])

      scores[&#39;test_score&#39;]-&gt;5개의 검증 정확도 리스트가 들어있음

  print(np.mean(scores[&#39;test_score&#39;]))
    다섯 번 검증한 결과의 평균 정확도 출력


전체 흐름 정리
  - train_scaled, train_target으로
  - SGDClassifier 모델을 5번 훈련 + 검증하면서
  - test_score에 성능 저장
  - 평균 정확도를 print로 출력</code></pre><h1 id="덴서플로의-케라스-사용하며-인공신경망-모델-만들기">덴서플로의 케라스 사용하며 인공신경망 모델 만들기</h1>
<blockquote>
<p>모델 구조정의</p>
</blockquote>
<pre><code class="language-py"># (케라스의 Dense클래스를 사용해 밀집층만들기)
from tensorflow import keras
dense = keras.layers.Dense(10, activation = &#39;softmax&#39;, input_shape = (784,))</code></pre>
<pre><code># (케라스의 Dense클래스를 사용해 밀집층만들기)

Dense(10, activation = &#39;softmax&#39;, input_shape = (784,))
  (출력층의 개수, 출력에 적용할 함수, 입력의 크기)
  -&gt; 입력의 크기는 784, 출력에 적용할 함수는 softmax, 출력층의 갯수는 10개


********Dense는 무조건 2차원으로 입력을 받아야함. 고로 3차원인 데이터는 평탄화 필요</code></pre><pre><code class="language-py"># 신경망 모델을 Sequential클래스로 만들기
# Sequential 클래스는 밀집층인 danse를 받음.

model = keras.Sequential([dense])</code></pre>
<pre><code># 신경망 모델을 Sequential클래스로 만들기
# Sequential 클래스는 밀집층인 danse를 받음.




Sequential 모델은 언제 사용???
  입력 → 은닉층 → 출력층
  레이어가 순서대로만 흘러가는 구조일 때
  복잡한 연결(분기, 병합 등)이 없을 때 적합



model = keras.Sequential(dense)  # 에러 발생 / 책이 잘못나옴

* 이유
여기서 dense는 레이어 하나인데,
Sequential()은 내부적으로 레이어들을 반복(iterate) 해서 쌓기 때문에,
리스트 형태로 넣어줘야 함.</code></pre><blockquote>
<p>최신 권장 방식</p>
</blockquote>
<pre><code class="language-py">from tensorflow import keras
inputs = keras.Input(shape=(784,))  # 입력 정의 (명시적인 Input)
outputs = keras.layers.Dense(10, activation=&#39;softmax&#39;)(inputs)  # Dense는 입력을 받아서 연결
model = keras.Model(inputs=inputs, outputs=outputs)</code></pre>
<p>또는, </p>
<pre><code class="language-py">model = keras.Sequential([
    keras.Input(shape=(784,)),                      # 명시적 입력
    keras.layers.Dense(10, activation=&#39;softmax&#39;)    # Dense는 입력만 받음
])</code></pre>
<blockquote>
<p>모델 학습설정</p>
</blockquote>
<pre><code>model.compile(loss = &#39;sparse_categorical_crossentropy&#39;, metrics = [&#39;accuracy&#39;])</code></pre><pre><code>keras에서 모델 학습설정은
model.compile() 사용


model.compile(loss = &#39;sparse_categorical_crossentropy&#39;, metrics = [&#39;accuracy&#39;])
  loss = 손실함수
    손실함수
      이진 분류 -&gt; binary_crossentropy
      다중 분류 -&gt;
        원핫인코딩 후 사용
          categorical_crossentropy
        원핫인코딩 안된 데이터에 사용
          sparse_categorical_crossentropy

  metrics = [&#39;accuracy&#39;]
    Keras는 metrics에 여러 개의 평가 지표를 넣을 수 있게 설계!!
    ********항상 리스트 형태로 받음



나와있지않지만 강사님이 많이 쓰신 파라(07-2에서 나옴)
optimizer = &#39;adam&#39;
  optimizer :
    - 모델이 오답을 줄이기 위해 가중치를 조금씩 조정하는 방법
    - 딥러닝 모델이 **손실(loss)**을 줄이기 위해 가중치를 어떻게 바꿀지 결정하는 알고리즘,
    즉 **최적화 함수(Optimizer)**

  adam :
    - Adaptive Moment Estimation의 줄임말
    - 많이 쓰이는 최적화 알고리즘 중 하나
    - 학습 속도도 빠르고 성능도 좋아서 대부분의 모델에서 기본값처럼 자주 사용
</code></pre><ul>
<li>Adam 특징</li>
</ul>
<table>
<thead>
<tr>
<th>특징</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>학습률 자동 조절</td>
<td>학습률을 각 가중치마다 자동으로 조정</td>
</tr>
<tr>
<td>빠르고 안정적</td>
<td>초반에 빠르게 수렴하면서 진동도 적음</td>
</tr>
<tr>
<td>모멘텀 + RMSProp 결합</td>
<td>과거 기울기 방향 + 변화량까지 고려</td>
</tr>
</tbody></table>
<blockquote>
<p>실제 모델 학습</p>
</blockquote>
<pre><code class="language-py">model.fit(train_scaled, train_target, epochs = 5)</code></pre>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/98f67894-2608-45d0-8d56-f76baa749ef7/image.png" alt=""></p>
<pre><code>.fit() : 케라스에서 모델의 학습을 하는 메서드
sklearn과 비슷하나 epochs가 차이남.
  model.fit(입력데이터, 정답데이터, epochs = 반복할 횟수)</code></pre><blockquote>
<p>모델 검증</p>
</blockquote>
<pre><code class="language-py">model.evaluate(val_scaled, val_target)</code></pre>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/d5895062-f1f7-463e-893b-595de6ed6206/image.png" alt=""></p>
<pre><code>evaluate() : 케라스에서 모델의 성능을 평가하는 메서드
  model.evaluate(입력데이터, 정답데이터)</code></pre><h1 id="정리">정리</h1>
<p>사이킷런 모델</p>
<pre><code>모델 -&gt; sc = SGDClassifier(loss=&#39;log_loss(손실함수)&#39;, max_iter = 5(반복횟수))
훈련 -&gt; sc.fit(train_scaled, train_target)
평가 -&gt; sc.score(val_scaled, val_target)</code></pre><p>케라스 모델</p>
<pre><code>층생성 -&gt; dense = keras.layers.Dense(10(출력층 개수), activation=&#39;softmax&#39;(함수설정), input_shape=(784,)(입력 개수))
모델 -&gt; model = keras.Sequential(dense)
        model.compile(loss = &#39;sparse_categorical_crossentropy&#39;, metrics = [&#39;accuracy&#39;])
훈련 -&gt; model.fit(train_scaled, train_target, epochs = 5(반복횟수))
평가 -&gt; model.evaludte(val_sacled, val_target)</code></pre><hr>
<h1 id="활성화-함수">활성화 함수</h1>
<blockquote>
<p>소프트맥스 함수</p>
</blockquote>
<ul>
<li>여러 클래스 중 하나를 선택할 수 있도록 출력을 확률처럼 정규화</li>
<li>출력값들이 모두 0~1 사이이며, 총합이 1이 되는 확률 벡터
(softmax([2.0, 1.0, 0.1]) -&gt; [0.659, 0.242, 0.099] -&gt; 전체 합이 1 )</li>
<li>각 클래스에 대해 예측된 확률을 명확히 해석 가능</li>
<li>다중 분류 문제의 출력층</li>
<li>예측 결과를 확률로 해석할 수 있어 직관적이고 분석이 쉬움</li>
</ul>
<blockquote>
<p>시그모이드 함수</p>
</blockquote>
<ul>
<li><p>초창기 인공신경망에 많이 사용된 활성화 함수</p>
</li>
<li><p>입력 값을 0~1 사이의 확률처럼 변환</p>
</li>
<li><p>출력이 항상 부드럽고 연속적</p>
</li>
<li><p>입력이 매우 크거나 작으면 기울기 소실(Vanishing Gradient) 발생
올바른 출력을 만드는데 신속한 대응이 안됨.</p>
</li>
<li><p>층이 많을수록 그래디언트가 누적되며 학습이 잘 안 됨</p>
</li>
<li><p>은닉층 또는 이진분류의 출력층에 사용
(과거에는 은닉층에서 사용, 현재는 이진 분류의 출력층에서만 주로 사용)</p>
<blockquote>
<p>렐루함수</p>
</blockquote>
</li>
<li><p>입력이 양수일 경우 마치 활성화함수가 없는 것처럼 입력을 통과시키고,
입력이 음수일 경우 0으로 만듦</p>
</li>
<li><p>계산 빠름, 기울기 소실이 없음 (그래디언트 유지됨)</p>
</li>
<li><p>심층 신경망에서 빠른 학습, 효과적인 수렴</p>
</li>
<li><p>이미지 처리, CNN, DNN에 기본 활성화 함수처럼 사용됨</p>
</li>
<li><p>은닉층에서 매우 널리 사용</p>
</li>
</ul>
<hr>
<h1 id="심층신경망dnn">심층신경망(DNN)</h1>
<p> 심층 신경망(DNN)</p>
<pre><code>  입력층(Input layer)과 출력층(Output layer) 사이에
  은닉층(Hidden layers)이 2개 이상 존재하는 인공 신경망



[예시 구조]

[입력층]
   ↓
[은닉층1]  ← Dense
   ↓
[은닉층2]  ← Dense
   ↓
[출력층]   ← Softmax
</code></pre><ul>
<li>얕은 신경망 vs 심층 신경망 비교표</li>
</ul>
<table>
<thead>
<tr>
<th>항목</th>
<th>얕은 신경망 (Shallow NN)</th>
<th>심층 신경망 (Deep NN)</th>
</tr>
</thead>
<tbody><tr>
<td><strong>정의</strong></td>
<td>은닉층이 1개 이하</td>
<td>은닉층이 2개 이상</td>
</tr>
<tr>
<td><strong>구조 예시</strong></td>
<td>입력 → 은닉 1개 → 출력</td>
<td>입력 → 은닉 1 → 은닉 2 → ... → 출력</td>
</tr>
<tr>
<td><strong>복잡도</strong></td>
<td>구조가 단순</td>
<td>구조가 복잡</td>
</tr>
<tr>
<td><strong>표현력</strong></td>
<td>제한적</td>
<td>복잡한 패턴 표현 가능</td>
</tr>
<tr>
<td><strong>학습 난이도</strong></td>
<td>쉽고 빠름</td>
<td>느리고 튜닝 필요</td>
</tr>
<tr>
<td><strong>적합 문제</strong></td>
<td>간단한 문제</td>
<td>복잡한 문제 (이미지, 자연어 등)</td>
</tr>
<tr>
<td><strong>예시</strong></td>
<td>퍼셉트론, 간단한 MLP</td>
<td>CNN, RNN, Transformer 등</td>
</tr>
</tbody></table>
<h3 id="신경망분류">신경망(분류)</h3>
<ul>
<li><p><strong>출력층의 활성화 함수</strong></p>
<pre><code>- 이진분류 : 시그모이드 함수
- 다중분류 : 소프트맥스 함수</code></pre></li>
<li><p><strong>은닉층의 활성화 함수</strong></p>
<pre><code>- 시그모이드 함수
- 렐루 함수</code></pre></li>
</ul>
<h3 id="신경망회귀">신경망(회귀)</h3>
<ul>
<li>활성화 함수가 필요없음<pre><code>-&gt; 회귀는 Dense층의 activation 매개변수에 아무런 값을 지정하지 않음.</code></pre></li>
</ul>
<h1 id="모델에-층-추가하는-방법">모델에 층 추가하는 방법</h1>
<blockquote>
<p>방법 1</p>
</blockquote>
<pre><code class="language-py">dense1 = keras.layers.Dense(100, activation = &#39;sigmoid&#39;, input_shape = (784, ))
dense2 = keras.layers.Dense(10, activation = &#39;sigmoid&#39;)</code></pre>
<pre><code>두 번째 층부터는 Keras가 자동으로 입력 shape를 추론
즉, dense1의 출력이 dense2의 입력이 되기 때문에 input_shape가 필요 없음.</code></pre><pre><code class="language-py">model = keras.Sequential([dense1, dense2])
model.summary()</code></pre>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/31e4c587-d91f-47f8-a950-9749670be6aa/image.png" alt=""></p>
<ul>
<li><p>model.summary()</p>
<pre><code>케라스는 모델의 summary() 메서드를 호출하면 층에 대한 정보를 얻을 수 있음</code></pre></li>
<li><p>Dense 층의 파라미터 수 공식</p>
<pre><code>파라미터 수 = (입력 노드 수 × 출력 노드 수) + 출력 노드 수</code></pre></li>
<li><p>name을 매개변수로 지정할 수 있음</p>
<pre><code>from tensorflow import keras
dense1 = keras.layers.Dense(100, activation=&#39;relu&#39;, input_shape=(784,), name=&#39;hidden_layer_1&#39;)
dense2 = keras.layers.Dense(10, activation=&#39;softmax&#39;, name=&#39;output_layer&#39;)
model = keras.Sequential([dense1, dense2])</code></pre></li>
<li><p>출력 크기가 None인 이유</p>
<pre><code>- (None, 100) = (배치 크기, 뉴런 수)
None → 입력 데이터가 한 번에 몇 개 들어올지는 아직 모른다
   (fit() 할 때 batch_size = .. 로 설정 가능)
- 100 → 이 레이어에서 나가는 출력 뉴런 수</code></pre></li>
<li><p>batch_size</p>
<pre><code>케라스에서 기본 미니 batch_size = 32
모델이 다양한 크기의 입력을 받을 수 있도록(유연하게 사용하기 위해) None으로 남겨 둠.
fit()할때 사용
1개만 넣어도 되고 (배치=1), 64개 넣어도 되고 (배치=64), 전부 넣어도 됨</code></pre></li>
</ul>
<blockquote>
<p>방법 2</p>
</blockquote>
<pre><code class="language-py">model = keras.Sequential([
    keras.layers.Dense(100, activation=&#39;sigmoid&#39;, input_shape=(784, ), name = &#39;hidden&#39;),
    keras.layers.Dense(10, activation=&#39;softmax&#39;, name = &#39;output&#39;)
], name = &#39;패션 MNIST 모델&#39;)
model.summary()</code></pre>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/79ce0aac-e5e3-478b-8b59-a2db88af5d28/image.png" alt=""></p>
<blockquote>
<p>방법 3</p>
</blockquote>
<pre><code class="language-py">model = keras.Sequential()
model.add(keras.layers.Dense(100, activation=&#39;sigmoid&#39;, input_shape=(784,), name = &#39;hidden&#39;))
model.add(keras.layers.Dense(10, activation=&#39;softmax&#39;, name = &#39;output&#39;))
model.summary()</code></pre>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/fa6795f8-2061-4445-af52-c016ca8dde89/image.png" alt=""></p>
<pre><code>방법 3은
- Dense 클래스의 객체를 따로 변수에 담지않고 바로 add()메서드로 전달할 수 있음.
- 추가되는 층을 한눈에 볼 수 있음
- 실행시 동적으로 층을 선택하여 추가할 수 있음.</code></pre><blockquote>
<p> Flatten 층</p>
</blockquote>
<ul>
<li>Flatten 클래스는 배치차원을 제외하고 나머지 입력 차원을 모두 일렬로 펼치는 역할</li>
<li>Flatten클래스를 층처럼 입력층과 은닉층 사이에 추가하기 때문에 층이라고 부름.</li>
<li>위 코드처럼 입력층 바로 뒤에 추가</li>
<li>Flatten을 사용하면 입력값의 차원을 짐작하기 쉬움.<pre><code class="language-py">model = keras.Sequential([
  keras.Input(shape=(28, 28)),               # ← 입력층 명시
  keras.layers.Flatten(),                    # ← Flatten은 평탄화만 함
                                             # 앞에서 데이터 전처리시 reshape() 필요없음
  keras.layers.Dense(100, activation=&#39;relu&#39;),
  keras.layers.Dense(10, activation=&#39;softmax&#39;)
])
model.summary()</code></pre>
<img src="https://velog.velcdn.com/images/c_haha_e/post/358a5565-b057-4b8b-9182-75fece421df5/image.png" alt=""></li>
</ul>
<h4 id="모델-설정--훈련--검증">모델 설정 &amp; 훈련 &amp; 검증</h4>
<pre><code class="language-py">from tensorflow import keras
(train_input, train_target), (test_input, test_tergat) = keras.datasets.fashion_mnist.load_data()
train_scaled = train_input / 255.0
train_scaled, val_scaled, train_target, val_target = train_test_split(
    train_scaled, train_target, test_size = 0.2, random_state = 42
)

model.compile(loss = &#39;sparse_categorical_crossentropy&#39;, metrics = [&#39;accuracy&#39;])
model.fit(train_scaled, train_target, epochs = 5)</code></pre>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/e8fba0d9-69d0-4e32-9717-67fad7bee761/image.png" alt=""></p>
<pre><code class="language-py">model.evaluate(val_scaled, val_target)</code></pre>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/04a5a171-4f9c-4a6b-80fa-480a47c68db4/image.png" alt=""></p>
<h4 id="하이퍼파라미터">하이퍼파라미터</h4>
<ul>
<li>모델이 학습하지않아 사람이 직접 지정해줘야하는 파라미터
(은닉층의 수, 은닉층의 뉴런의 수, 활성화함수, 층의 종류, 배치 사이즈의 크기, 에포크의 수, 옵티마이저 등..)</li>
</ul>
<blockquote>
<p>옵티마이저 ( Adam 중요 )</p>
</blockquote>
<ul>
<li><p>손실 함수의 값을 최소화(minimize)하기 위해 가중치를 어떻게 업데이트할지 결정하는 알고리즘</p>
</li>
<li><p>대표 옵티마이저</p>
</li>
</ul>
<table>
<thead>
<tr>
<th>Optimizer</th>
<th>핵심 아이디어</th>
<th>수식 요약</th>
<th>대표 특징</th>
</tr>
</thead>
<tbody><tr>
<td><strong>SGD</strong></td>
<td>순수 경사하강법</td>
<td>$\theta = \theta - \eta \cdot \nabla L$</td>
<td>단순하지만 진동 심하고 느림</td>
</tr>
<tr>
<td><strong>Momentum</strong></td>
<td>이전 속도(모멘텀)를 이용한 가속</td>
<td>$v_t = \gamma v_{t-1} + \eta \nabla L$</td>
<td>진동 줄이고 빠른 수렴 가능</td>
</tr>
<tr>
<td><strong>Nesterov</strong></td>
<td>모멘텀 + 미리 한 발 앞으로 가서 기울기 확인</td>
<td>$v_t = \gamma v_{t-1} + \eta \nabla L(\theta - \gamma v_{t-1})$</td>
<td>더 정교한 방향 제어</td>
</tr>
<tr>
<td><strong>Adagrad</strong></td>
<td>각 가중치별로 학습률 자동 조절</td>
<td>$\theta = \theta - \frac{\eta}{\sqrt{G + \epsilon}} \nabla L$</td>
<td>희소 데이터에 유리 (텍스트 등)</td>
</tr>
<tr>
<td><strong>RMSprop</strong></td>
<td>Adagrad의 단점 보완 (최근 기울기에 가중치)</td>
<td>$G_t = \rho G_{t-1} + (1-\rho)g^2$</td>
<td>RNN 계열에 잘 작동</td>
</tr>
<tr>
<td><strong>Adam</strong></td>
<td>Momentum + RMSprop 조합</td>
<td>$m_t, v_t$로 평균과 제곱평균 반영</td>
<td>대부분의 문제에 기본값처럼 사용됨</td>
</tr>
<tr>
<td><strong>Nadam</strong></td>
<td>Adam + Nesterov</td>
<td>복잡한 결합식</td>
<td>Adam보다 빠른 수렴 가능</td>
</tr>
</tbody></table>
<blockquote>
<p>SGD (Stochastic Gradient Descent)</p>
</blockquote>
<ul>
<li>가장 기본적인 옵티마이저, 간단하고 직관적</li>
<li>단순하지만,기울기 방향만 보고 이동하기 때문에
손실이 들쭉날쭉하게 줄어들고 진동이 심할 수 있음</li>
<li>매 반복마다 일부 데이터(batch)로 손실을 계산해 가중치 갱신<pre><code class="language-py">optimizer = keras.optimizers.SGD(learning_rate=0.1)
model.compile(optimizer = optimizer, loss = &#39;sparse_categorical_crossentropy&#39;, metrics = [&#39;accuracy&#39;])</code></pre>
</li>
</ul>
<blockquote>
<p>Momentum</p>
</blockquote>
<ul>
<li>관성 개념을 사용해 이전 방향으로 더 강하게 이동</li>
<li>진동 감소 + 수렴 속도 증가<pre><code class="language-py">optimizer = keras.optimizers.SGD(momentum=0.9, nesterov = True)
model.compile(optimizer = optimizer, loss = &#39;sparse_categorical_crossentropy&#39;, metrics = [&#39;accuracy&#39;])</code></pre>
</li>
</ul>
<blockquote>
<p>Nesterov (Nesterov Accelerated Gradient, NAG)</p>
</blockquote>
<ul>
<li>모멘텀을 적용하기 전에 미리 한 걸음 앞서서 기울기를 계산하는 방식</li>
<li>더 정확한 방향 제어</li>
<li>수렴이 더 안정적이고 빠를 수 있음<pre><code class="language-py">optimizer = keras.optimizers.SGD(learning_rate=0.01, momentum=0.9, nesterov=True)</code></pre>
</li>
</ul>
<blockquote>
<p>RMSprop</p>
</blockquote>
<ul>
<li>Adagrad의 단점(학습률 소멸)을 해결</li>
<li>최근 기울기에 지수적으로 가중치를 줘서 더 안정적 (지수평균)</li>
<li>RNN, LSTM에 매우 적합</li>
<li>빠른 수렴<pre><code class="language-py">optimizer = keras.optimizers.RMSprop(learning_rate=0.001)
model.compile(optimizer = optimizer, loss = &#39;sparse_categorical_crossentropy&#39;, metrics = [&#39;accuracy&#39;])</code></pre>
</li>
</ul>
<blockquote>
<p>Adagrad</p>
</blockquote>
<ul>
<li>각 파라미터마다 학습률을 자동 조절</li>
<li>자주 바뀌는 가중치는 더 천천히 학습
→ 희소 데이터에 효과적(ex. 텍스트)</li>
<li>단점: 학습률이 너무 작아져서 금방 멈춰버릴 수 있음<pre><code class="language-py">optimizer = keras.optimizers.Adagrad(learning_rate=0.01)
model.compile(optimizer = optimizer, loss = &#39;sparse_categorical_crossentropy&#39;, metrics = [&#39;accuracy&#39;])</code></pre>
</li>
</ul>
<blockquote>
<p>Nadam (Nesterov + Adam)</p>
</blockquote>
<ul>
<li>Adam에 Nesterov 모멘텀을 추가한 방식</li>
<li>최신 최적화 기법 중 하나</li>
<li>이론적으로 Adam보다 빠르게 수렴할 수도 있음  (실험적으로 사용됨)<pre><code class="language-py">optimizer = keras.optimizers.Nadam(learning_rate=0.001)
model.compile(optimizer = optimizer, loss = &#39;sparse_categorical_crossentropy&#39;, metrics = [&#39;accuracy&#39;])</code></pre>
</li>
</ul>
<blockquote>
<p>Adam (Adaptive Moment Estimation) 중요</p>
</blockquote>
<ul>
<li>Momentum + RMSprop 결합</li>
<li>Momentum (기울기의 평균)</li>
<li>RMSprop (기울기의 제곱 평균)</li>
<li>가장 널리 쓰임, 대부분의 문제에서 잘 동작<pre><code class="language-py">optimizer = keras.optimizers.Adam(learning_rate=0.001)
model.compile(optimizer = optimizer, loss = &#39;sparse_categorical_crossentropy&#39;, metrics = [&#39;accuracy&#39;])</code></pre>
</li>
</ul>
<h2 id="정리-1">정리</h2>
<table>
<thead>
<tr>
<th>옵티마이저</th>
<th>계산 방식</th>
<th>장점</th>
<th>대표 용도</th>
</tr>
</thead>
<tbody><tr>
<td>SGD</td>
<td>순수 경사 하강</td>
<td>단순, 느림</td>
<td>실험, 비교용</td>
</tr>
<tr>
<td>Momentum</td>
<td>+ 속도</td>
<td>빠른 수렴</td>
<td>CNN 등</td>
</tr>
<tr>
<td>Nesterov</td>
<td>+ 더 앞서 보기</td>
<td>정교한 이동</td>
<td>고급 CNN</td>
</tr>
<tr>
<td>Adagrad</td>
<td>개별 학습률</td>
<td>희소 데이터에 강함</td>
<td>텍스트</td>
</tr>
<tr>
<td>RMSprop</td>
<td>최근 기울기 반영</td>
<td>빠름, RNN에 좋음</td>
<td>시계열</td>
</tr>
<tr>
<td>Adam</td>
<td>Momentum + RMSprop</td>
<td>👍가장 널리 쓰임</td>
<td>거의 모든 문제</td>
</tr>
<tr>
<td>Nadam</td>
<td>Adam + Nesterov</td>
<td>더 빠를 수 있음</td>
<td>실험적 최적화</td>
</tr>
</tbody></table>
<blockquote>
<pre><code>model.fit(train_scaled, train_target, epochs = 5)</code></pre></blockquote>
<pre><code>![](https://velog.velcdn.com/images/c_haha_e/post/70567af1-3e77-4608-8ee6-01868c51b9a9/image.png)</code></pre><p>model.evaluate(val_scaled, val_target)00</p>
<pre><code>![](https://velog.velcdn.com/images/c_haha_e/post/378ca539-a8e3-423d-8914-dd1cab96b4e9/image.png)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[어간 추출(Stemming) & 표제어 추출(Lemmatization)]]></title>
            <link>https://velog.io/@c_haha_e/%EC%96%B4%EA%B0%84-%EC%B6%94%EC%B6%9CStemming-%ED%91%9C%EC%A0%9C%EC%96%B4-%EC%B6%94%EC%B6%9CLemmatization</link>
            <guid>https://velog.io/@c_haha_e/%EC%96%B4%EA%B0%84-%EC%B6%94%EC%B6%9CStemming-%ED%91%9C%EC%A0%9C%EC%96%B4-%EC%B6%94%EC%B6%9CLemmatization</guid>
            <pubDate>Sat, 16 Aug 2025 16:08:21 GMT</pubDate>
            <description><![CDATA[<h2 id="1-어간-추출stemming이란"><strong>1. 어간 추출(Stemming)이란?</strong></h2>
<p><strong>어간 추출이란?</strong></p>
<p>단어에서 변하지 않는 뿌리(어간)만 남기고 접사(변형, 굴절, 어미 등)는 <strong>기계적으로 잘라내는 작업</strong></p>
<hr>
<h3 id="why-왜-해야-할까"><strong>WHY? (왜 해야 할까?)</strong></h3>
<ul>
<li><strong>의미는 거의 같은데, 단어 형태만 달라서</strong><ul>
<li>데이터 분석/검색/분류할 때 비슷한 단어를 한 덩어리로 보고 싶으니까!</li>
</ul>
</li>
</ul>
<p>예시:</p>
<ul>
<li>“study”, “studies”, “studying”, “studied” → 전부 “studi”로 자름</li>
</ul>
<hr>
<h3 id="실전-예시와-코드영어"><strong>실전 예시와 코드(영어)</strong></h3>
<h3 id="1-nltk의-porterstemmer-사용">(1) <strong>NLTK의 PorterStemmer 사용</strong></h3>
<pre><code class="language-python">from nltk.stem import PorterStemmer

stemmer = PorterStemmer()
words = [&quot;study&quot;, &quot;studies&quot;, &quot;studying&quot;, &quot;studied&quot;, &quot;studious&quot;]
for w in words:
    print(w, &quot;-&gt;&quot;, stemmer.stem(w))</code></pre>
<p><strong>결과:</strong></p>
<pre><code>study     -&gt; study
studies   -&gt; studi
studying  -&gt; studi
studied   -&gt; studi
studious  -&gt; stud</code></pre><p><strong>해설:</strong></p>
<ul>
<li>어간(stem)은 “study”에서 “y”까지,</li>
<li>다른 단어는 접미사(ies, ing, ed, ious)만 자르고</li>
<li>남은 부분 “studi”만 똑같이 반환</li>
</ul>
<hr>
<h3 id="2-영어의-어간-추출-단점">(2) <strong>영어의 어간 추출 단점</strong></h3>
<ul>
<li>너무 기계적으로 자름! → 뜻이 다르거나 어색한 줄기까지 뽑히기도 함</li>
<li>예: “studious”(공부하는, 근면한)도 “studi”로 잘림 → 실제론 ‘study’와 다르지만 같은 그룹 취급</li>
</ul>
<hr>
<h3 id="한글에서의-어간-추출"><strong>한글에서의 어간 추출</strong></h3>
<ul>
<li><p>한글은 “동사/형용사 어간”이 활용(변형)될 때</p>
<p>  형태소 분석기(예: Okt, Kkma 등)가 ‘어간(동사 기본형)’을 자동 추출함</p>
</li>
</ul>
<h3 id="예시">예시)</h3>
<pre><code class="language-python">from konlpy.tag import Okt
okt = Okt()
print(okt.morphs(&quot;먹었다&quot;))  # [&#39;먹&#39;, &#39;었다&#39;]
print(okt.morphs(&quot;가는 중이다&quot;))  # [&#39;가&#39;, &#39;는&#39;, &#39;중&#39;, &#39;이다&#39;]</code></pre>
<ul>
<li><strong>“먹었다”</strong> → [‘먹’, ‘었다’] (먹: 어간, 었다: 어미)</li>
<li><strong>“가는 중이다”</strong> → [‘가’, ‘는’, ‘중’, ‘이다’] (가: 어간)</li>
</ul>
<hr>
<hr>
<h2 id="2-표제어-추출lemmatization이란"><strong>2. 표제어 추출(Lemmatization)이란?</strong></h2>
<p><strong>표제어 추출이란?</strong></p>
<p>단어를 사전에 등록된 정확한 기본형(표제어)로 바꿔주는 작업 → 즉, 단어를 진짜 원래 단어로 맞춰주는 것!</p>
<hr>
<h3 id="why-왜-표제어"><strong>WHY? (왜 표제어?)</strong></h3>
<ul>
<li>단어의 정확한 본래 의미를 <strong>영어 사전/국어사전</strong> 기준으로 통일</li>
<li>검색, 분류, 의미 비교, 번역 등에서 가장 ‘정확한 단어’만 남기고 싶을 때 사용</li>
</ul>
<hr>
<h3 id="실전-예시와-코드영어-1"><strong>실전 예시와 코드(영어)</strong></h3>
<h3 id="1-nltk의-wordnetlemmatizer-사용">(1) <strong>NLTK의 WordNetLemmatizer 사용</strong></h3>
<pre><code class="language-python">from nltk.stem import WordNetLemmatizer

lemmatizer = WordNetLemmatizer()
words = [&quot;study&quot;, &quot;studies&quot;, &quot;studying&quot;, &quot;studied&quot;, &quot;studious&quot;, &quot;went&quot;, &quot;going&quot;]
for w in words:
    print(w, &quot;-&gt;&quot;, lemmatizer.lemmatize(w, pos=&#39;v&#39;))</code></pre>
<p><strong>결과:</strong></p>
<pre><code>study     -&gt; study
studies   -&gt; study
studying  -&gt; study
studied   -&gt; study
studious  -&gt; studious
went      -&gt; go
going     -&gt; go</code></pre><p><strong>해설:</strong></p>
<ul>
<li>“study” 계열 → 전부 “study”(기본형)</li>
<li>“went” “going” → “go”(동사 원형)</li>
<li>“studious”는 형용사(근면한)라 “study”로 안 바뀜</li>
</ul>
<hr>
<h3 id="2-어간-추출-vs-표제어-추출-차이점">(2) <strong>어간 추출 vs 표제어 추출 차이점</strong></h3>
<table>
<thead>
<tr>
<th></th>
<th>어간 추출(Stemming)</th>
<th>표제어 추출(Lemmatization)</th>
</tr>
</thead>
<tbody><tr>
<td><strong>방식</strong></td>
<td>기계적으로 접사만 자름</td>
<td>사전(국어/영어) 기반, 실제 단어만 남김</td>
</tr>
<tr>
<td><strong>정확도</strong></td>
<td>낮음(오류, 오용 가능)</td>
<td>높음(진짜 단어만 남김)</td>
</tr>
<tr>
<td><strong>속도</strong></td>
<td>빠름</td>
<td>느림(사전 검색 필요)</td>
</tr>
<tr>
<td><strong>예시</strong></td>
<td>studies → studi</td>
<td>studies → study</td>
</tr>
<tr>
<td></td>
<td>went → went</td>
<td>went → go</td>
</tr>
</tbody></table>
<hr>
<h3 id="한글에서의-표제어-추출"><strong>한글에서의 표제어 추출</strong></h3>
<ul>
<li><p>한글 형태소 분석기는</p>
<p>  ‘동사/형용사’의 기본형(표제어)을</p>
<p>  자동으로 태깅해줌</p>
</li>
</ul>
<h3 id="예시-1">예시)</h3>
<pre><code class="language-python">from konlpy.tag import Okt
print(okt.pos(&quot;아름다웠던 순간을 잊지 못해요.&quot;))
# [(&#39;아름답&#39;, &#39;Adjective&#39;), (&#39;었던&#39;, &#39;Eomi&#39;), ...]</code></pre>
<ul>
<li><strong>“아름다웠던”</strong> → ‘아름답’(표제어), ‘었던’(어미)</li>
</ul>
<hr>
<hr>
<h2 id="3-실제-실무실전에서의-활용"><strong>3. 실제 실무/실전에서의 활용</strong></h2>
<ul>
<li><p><strong>어간 추출:</strong></p>
<ul>
<li><p>속도가 매우 중요하고,</p>
<p>  ‘비슷하면 한 그룹’만 필요할 때 (검색, 대용량 데이터)</p>
</li>
</ul>
</li>
<li><p><strong>표제어 추출:</strong></p>
<ul>
<li>의미, 정확성이 더 중요한 작업 (번역, 감정분석, 요약 등)</li>
</ul>
</li>
</ul>
<hr>
<h2 id="4-실습-결과-해설"><strong>4. 실습 결과 해설</strong></h2>
<h3 id="1-어간-추출의-단점">(1) 어간 추출의 단점</h3>
<ul>
<li><p>엉뚱한 줄기(studi, go, runn 등)만 남아</p>
<p>  <strong>진짜 뜻이 사라지기도 함!</strong></p>
</li>
<li><p>“meeting” → “meet” (OK)</p>
<p>  “better” → “better” (표제어는 “good”)</p>
</li>
</ul>
<h3 id="2-표제어-추출의-단점">(2) 표제어 추출의 단점</h3>
<ul>
<li><strong>속도가 느림</strong></li>
<li><strong>사전 없는 단어는 안 바뀜(신조어, 오타 등)</strong></li>
</ul>
<hr>
<h2 id="5-입문자용-체크-퀴즈"><strong>5. 입문자용 체크 퀴즈</strong></h2>
<ol>
<li><strong>어간 추출이랑 표제어 추출의 큰 차이는?</strong></li>
<li><strong>“studied”를 어간/표제어 추출하면 각각 뭐가 되나?</strong></li>
<li><strong>한글 문장(“먹었다”)에서 어간/표제어는 각각?</strong></li>
<li><strong>실제 뉴스 기사/리뷰 분석에서는 어떤 방식을 더 쓸까? 그 이유는?</strong></li>
</ol>
<hr>
<h2 id="-한줄정리">** 한줄정리**</h2>
<blockquote>
<p>어간 추출은 단어에서 “뿌리”만 남기는 ‘가지치기’,
표제어 추출은 사전 기준 “진짜 본래 단어”만 남기는 ‘본명 맞추기’!
정확성 중요하면 표제어, 속도/단순 그룹이면 어간 추출!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[정제(Cleansing)와 정규화(Normalization)]]></title>
            <link>https://velog.io/@c_haha_e/%EC%A0%95%EC%A0%9CCleansing%EC%99%80-%EC%A0%95%EA%B7%9C%ED%99%94Normalization</link>
            <guid>https://velog.io/@c_haha_e/%EC%A0%95%EC%A0%9CCleansing%EC%99%80-%EC%A0%95%EA%B7%9C%ED%99%94Normalization</guid>
            <pubDate>Sat, 16 Aug 2025 16:07:38 GMT</pubDate>
            <description><![CDATA[<hr>
<h2 id="1-정제cleansing--개념"><strong>1. 정제(Cleansing) – 개념</strong></h2>
<p><strong>정제란?</strong></p>
<ul>
<li><p>“텍스트에서 <strong>불필요하거나 방해되는 내용(노이즈)</strong>를 깨끗하게 지워내는 작업”</p>
</li>
<li><p>갖고 있는 코퍼스로부터 노이즈 데이터를 제거</p>
</li>
<li><p><strong>예시:</strong></p>
<ul>
<li>“ㅋㅋㅋ”, “ㅎㅎ”, “^_^”, “<del>~</del>”, “특수문자” 등</li>
<li>광고/스팸성 멘트, 욕설, HTML 태그, 이메일, 링크, 숫자 등</li>
</ul>
</li>
<li><p><strong>WHY(왜 필요?)</strong></p>
<p>  → 방해되는 불순물이 많으면 <strong>진짜 뜻, 핵심 단어, 감정</strong>을 제대로 분석할 수 없음</p>
</li>
</ul>
<hr>
<h2 id="정제-실습코드-예시"><strong>정제 실습(코드 예시)</strong></h2>
<pre><code class="language-python">
import re
text = &quot;안녕하세요^^ 오늘 날씨 짱좋음ㅋㅋㅋ #해시태그 http://link.com&quot;
# 1. 특수문자 제거
text = re.sub(r&#39;[^가-힣0-9\s]&#39;, &#39;&#39;, text)
# 2. 한글/숫자/띄어쓰기만 남기기
print(text)
# 결과: 안녕하세요 오늘 날씨 짱좋음 해시태그 linkcom
</code></pre>
<ul>
<li>필요에 따라 이메일/링크/광고만 따로 지울 수도 있음</li>
</ul>
<hr>
<h2 id="2-정규화normalization--개념"><strong>2. 정규화(Normalization) – 개념</strong></h2>
<p><strong>정규화란?</strong></p>
<ul>
<li><p>“<strong>비슷한 뜻인데 여러 가지로 적힌 표현</strong>들을 <strong>하나의 표준(기본) 형태로 통일</strong>시키는 작업”</p>
</li>
<li><p>정규화(normalization) : 표현 방법이 다른 단어들을 통합시켜서 같은 단어로 만듦</p>
</li>
<li><p><strong>예시:</strong></p>
<ul>
<li>“짜증나”, “짜증난다”, “짜증남” → “짜증나다”</li>
<li>“핵꿀잼”, “꿀잼”, “재밌다”, “아주 재미있다” → “재미있다”</li>
<li>“굿굿”, “good”, “좋아요” → “좋다”</li>
</ul>
</li>
<li><p><strong>WHY(왜 필요?)</strong></p>
<p>  → 똑같은 의미가 여러 형태로 있으면 </p>
<pre><code>  “진짜 중요 단어” 개수가 필요 이상으로 늘어나고 분석 결과가 흐려짐</code></pre></li>
</ul>
<hr>
<h2 id="정규화-실습코드-예시"><strong>정규화 실습(코드 예시)</strong></h2>
<pre><code class="language-python">
import re

text = &quot;굿굿! 오늘 핵꿀잼ㅋㅋㅋ 날씨 짱좋음 ㅎㅎㅎ&quot;
# 1. 반복 문자(ㅋㅋㅋ, ㅎㅎㅎ 등) 제거
text = re.sub(r&#39;[ㅋㅎ]+&#39;, &#39;&#39;, text)
# 2. 은어/신조어/약어 통일
text = text.replace(&#39;굿굿&#39;, &#39;좋다&#39;)
text = text.replace(&#39;핵꿀잼&#39;, &#39;재미있다&#39;)
text = text.replace(&#39;짱좋음&#39;, &#39;아주 좋음&#39;)
print(text)
# 결과: 좋다! 오늘 재미있다 날씨 아주 좋음
</code></pre>
<hr>
<h2 id="실제-실무-적용-포인트"><strong>실제 실무 적용 포인트</strong></h2>
<ul>
<li><p><strong>정제</strong>:</p>
<ul>
<li>데이터 품질 ↑</li>
<li>스팸, 광고, 욕설, 쓸데없는 특수문자 ↓</li>
<li>모델이 진짜 필요한 정보만 배울 수 있음</li>
</ul>
</li>
<li><p><strong>정규화</strong>:</p>
<ul>
<li>단어 종류 ↓</li>
<li>진짜 ‘중요 키워드’만 정확히 잡힘</li>
<li>한글 SNS 신조어, 채팅방, 커뮤니티 텍스트에 꼭 필요!</li>
<li></li>
</ul>
</li>
<li><p><strong>실무에서는:</strong></p>
<ul>
<li><p>반복문, 사전(Dictionary) 만들어서 여러 신조어/은어/줄임말 한꺼번에 통일 가능!</p>
</li>
<li><p>데이터 양이 많을수록</p>
<p>  <strong>정제·정규화가 모델 성능에 “지분율 50%”</strong></p>
</li>
<li><p>실전에서는 “욕설, 광고, 신조어 사전” 등</p>
<p>  <strong>따로 관리하는 경우 많음</strong></p>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="-한줄정리">** 한줄정리**</h2>
<blockquote>
<p>정제(Cleansing)는 ‘필요 없는 것들’을 지우고,
정규화(Normalization)는 ‘비슷한 의미’를 한 가지 표준 형태로 맞추는 것!</p>
</blockquote>
<hr>
<h1 id="정제와-정규화에-사용되는-대표-라이브러리"><strong>정제와 정규화에 사용되는 대표 라이브러리</strong></h1>
<hr>
<h2 id="1-정제cleansing에-자주-쓰는-라이브러리">1. <strong>정제(Cleansing)에 자주 쓰는 라이브러리</strong></h2>
<h3 id="①-python-내장-re정규표현식">① <strong>Python 내장 re(정규표현식)</strong></h3>
<ul>
<li><p><strong>특징:</strong></p>
<ul>
<li><p>텍스트에서 불필요한 문자, 패턴(특수문자, 숫자, URL, 이메일, 광고 등)</p>
<p>  <strong>자동으로 찾아서 삭제/치환</strong></p>
</li>
<li><p>한글/영어 모두 가능</p>
</li>
</ul>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-python">
  import re
  text = &quot;굿굿! 오늘 핵꿀잼ㅋㅋㅋ #해시태그 http://link.com&quot;
  # 특수문자, URL 등 제거
  clean = re.sub(r&#39;[^가-힣0-9\s]&#39;, &#39;&#39;, text)
  print(clean)
  # 결과: 굿굿 오늘 핵꿀잼 해시태그 http://linkcom
</code></pre>
</li>
</ul>
<h3 id="②-beautifulsoup-html-정제">② <strong>BeautifulSoup (HTML 정제)</strong></h3>
<ul>
<li><p><strong>특징:</strong></p>
<ul>
<li>웹 페이지에서 HTML 태그, 스크립트 등 삭제</li>
<li>크롤링/뉴스 기사/블로그 등에서 주로 사용</li>
</ul>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-python">
  from bs4 import BeautifulSoup
  html = &quot;&lt;html&gt;&lt;body&gt;안녕하세요! &lt;b&gt;반갑습니다.&lt;/b&gt;&lt;/body&gt;&lt;/html&gt;&quot;
  soup = BeautifulSoup(html, &#39;html.parser&#39;)
  print(soup.get_text())
  # 결과: 안녕하세요! 반갑습니다.
</code></pre>
</li>
</ul>
<h3 id="③-kss-soynlp-konlpy-한국어용">③ <strong>kss, soynlp, KoNLPy (한국어용)</strong></h3>
<ul>
<li><p><strong>특징:</strong></p>
<ul>
<li>한국어에서 문장 분리, 맞춤법/중복 문자 등 정제에 활용</li>
</ul>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-python">
  import kss
  text = &quot;안녕하세요.오늘은 날씨가 참 좋아요ㅋㅋㅋ&quot;
  print(list(kss.split_sentences(text)))
  # 결과: [&#39;안녕하세요.&#39;, &#39;오늘은 날씨가 참 좋아요ㅋㅋㅋ&#39;]
</code></pre>
</li>
</ul>
<hr>
<h2 id="2-정규화normalization에-자주-쓰는-라이브러리">2. <strong>정규화(Normalization)에 자주 쓰는 라이브러리</strong></h2>
<h3 id="①-soynlp">① <strong>soynlp</strong></h3>
<ul>
<li><p><strong>특징:</strong></p>
<ul>
<li>한글 신조어, 반복 문자(ㅋㅋㅋ, ㅎㅎㅎ), 띄어쓰기 정규화</li>
<li>오타 교정 등 자동화 기능</li>
</ul>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-python">
  from soynlp.normalizer import repeat_normalize
  text = &quot;우와아아아아 짱재밌엉ㅋㅋㅋㅋ&quot;
  print(repeat_normalize(text, num_repeats=2))
  # 결과: 우와아 짱재밌엉ㅋㅋ
</code></pre>
</li>
</ul>
<h3 id="②-python-내장-re--사용자-정의-사전">② <strong>Python 내장 re + 사용자 정의 사전</strong></h3>
<ul>
<li><p><strong>특징:</strong></p>
<ul>
<li><p>신조어, 약어, 줄임말, 은어 등</p>
<p>  직접 만든 “정규화 사전”과 함께 사용</p>
</li>
</ul>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-python">  text = &quot;굿굿! 오늘 핵꿀잼 짱좋음&quot;
  replace_dict = {&#39;굿굿&#39;:&#39;좋다&#39;, &#39;핵꿀잼&#39;:&#39;재미있다&#39;, &#39;짱좋음&#39;:&#39;아주 좋음&#39;}
  for k, v in replace_dict.items():
      text = text.replace(k, v)
  print(text)
  # 결과: 좋다! 오늘 재미있다 아주 좋음
</code></pre>
</li>
</ul>
<h3 id="③-ekphrasis-영어-정규화-특화">③ <strong>Ekphrasis (영어 정규화 특화)</strong></h3>
<ul>
<li><p><strong>특징:</strong></p>
<ul>
<li>영어 약어, 이모티콘, 채팅체 등을 표준 영어로 정규화</li>
<li>영어 SNS, 트위터 등에서 많이 씀</li>
</ul>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-python">
  # 설치: pip install ekphrasis
  from ekphrasis.classes.preprocessor import TextPreProcessor

  text_processor = TextPreProcessor(
      normalize=[&#39;url&#39;, &#39;email&#39;, &#39;percent&#39;, &#39;money&#39;, &#39;phone&#39;, &#39;user&#39;],
      annotate={&#39;hashtag&#39;, &#39;allcaps&#39;, &#39;elongated&#39;, &#39;repeated&#39;},
      fix_html=True, segmenter=&quot;twitter&quot;, corrector=&quot;twitter&quot;
  )
  print(&quot; &quot;.join(text_processor.pre_process_doc(&quot;I looooveee Python!!! #awesome @user http://site.com&quot;)))
  # (URL, 이모티콘, 반복 문자, 태그 등 표준화)
</code></pre>
</li>
</ul>
<hr>
<h2 id="3-기타-실무-보조-라이브러리">3. <strong>기타 실무 보조 라이브러리</strong></h2>
<ul>
<li><strong>pyspellchecker</strong> : 영어 맞춤법 교정</li>
<li><strong>hanspell</strong> : 한글 맞춤법 교정 (pip로 설치 필요)</li>
<li><strong>ftfy</strong> : 인코딩 깨짐/이상한 문자 복원 (영어 등)</li>
<li><strong>pandas</strong> : 데이터프레임 내 결측값, 중복값 등 정제</li>
</ul>
<hr>
<h1 id="정리"><strong>정리</strong></h1>
<table>
<thead>
<tr>
<th>용도</th>
<th>대표 라이브러리/방법</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td>정제</td>
<td>re, BeautifulSoup, kss</td>
<td>특수문자/HTML/중복문자/노이즈 삭제</td>
</tr>
<tr>
<td>정규화</td>
<td>soynlp, re+사전, Ekphrasis</td>
<td>반복/신조어/약어/띄어쓰기/이모티콘 표준화</td>
</tr>
<tr>
<td>맞춤법</td>
<td>hanspell, pyspellchecker</td>
<td>한국어/영어 맞춤법/오타 교정</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[토큰화(Tokenization) ]]></title>
            <link>https://velog.io/@c_haha_e/%ED%86%A0%ED%81%B0%ED%99%94Tokenization</link>
            <guid>https://velog.io/@c_haha_e/%ED%86%A0%ED%81%B0%ED%99%94Tokenization</guid>
            <pubDate>Sat, 16 Aug 2025 16:05:41 GMT</pubDate>
            <description><![CDATA[<h1 id="토큰화tokenization">토큰화(Tokenization)</h1>
<hr>
<h2 id="1-개념">1. 개념</h2>
<p><strong>토큰화란?</strong></p>
<p>글(문장, 댓글, 기사 등)을 “뜻이 있는 가장 작은 덩어리(보통 ‘단어’나 ‘형태소’라고 부름)”로 잘게 쪼개는 작업</p>
<ul>
<li>영어는 띄어쓰기 기준으로 “apple is good” → [‘apple’, ‘is’, ‘good’]</li>
<li>한글은 조사(을/는/이/가 등), 어미(했다/하다 등) 때문에 조금 더 세밀하게 쪼개야 함</li>
</ul>
<hr>
<h2 id="2-why">2. WHY?</h2>
<ul>
<li>컴퓨터는 글자 그대로 “사람의 뜻”을 이해 못 함</li>
<li>그래서, “글을 의미 있는 단위로 쪼개서” 숫자나 규칙으로 바꿔야 함</li>
<li>이게 “자연어 처리의 첫 단계”, 이게 잘 돼야 “빈도 세기, 감정 분석, 요약, 번역 등”이 가능해짐!</li>
</ul>
<hr>
<h2 id="3-필요-라이브러리">3. 필요 라이브러리</h2>
<pre><code class="language-python">from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
from konlpy.tag import Okt
from konlpy.tag import Kkma
from nltk.tokenize import sent_tokenize
from nltk.tokenize import word_tokenize
from nltk.tokenize import WordPunctTokenizer
from nltk.tokenize import TreebankWordTokenizer
from tensorflow.keras.preprocessing.text import text_to_word_sequence

!pip install kss
import kss</code></pre>
<h3 id="1-nltktokenizeword_tokenize">1. <code>nltk.tokenize.word_tokenize</code></h3>
<ul>
<li><strong>영어 문장용</strong></li>
<li><strong>기능:</strong> 문장을 ‘단어’ 단위로 쪼갬</li>
<li><strong>특징:</strong> 영어 띄어쓰기, 구두점(마침표, 콤마 등)까지 잘 분리</li>
</ul>
<h3 id="2-nltktagpos_tag">2. <code>nltk.tag.pos_tag</code></h3>
<ul>
<li><strong>영어 문장용</strong></li>
<li><strong>기능:</strong> 각 단어의 품사(명사, 동사 등) 태깅</li>
<li><strong>특징:</strong> 영어 품사 태그를 붙임</li>
</ul>
<h3 id="3-konlpytagokt">3. <code>konlpy.tag.Okt</code></h3>
<ul>
<li><strong>한글 전용 형태소 분석기</strong></li>
<li><strong>기능:</strong> 한글 문장 → ‘형태소’ 단위로 분리 &amp; 품사 태깅</li>
<li><strong>특징:</strong><ul>
<li>띄어쓰기, 조사, 어미 등 잘 분리</li>
<li>&#39;명사&#39;, &#39;동사&#39;, &#39;형용사&#39; 등 품사정보 제공</li>
</ul>
</li>
</ul>
<h3 id="4-konlpytagkkma">4. <code>konlpy.tag.Kkma</code></h3>
<ul>
<li><strong>한글 전용, 더 정교한 형태소 분석기</strong></li>
<li><strong>기능:</strong> 한글 문장 → 더 세밀한 형태소 분리 &amp; 품사 태깅</li>
<li><strong>특징:</strong><ul>
<li>긴 복합문장도 잘게 쪼갬</li>
<li>품사 태그 종류가 더 세분화됨</li>
<li>(Okt보다 느리지만, 더 복잡한 문장에 강함)</li>
</ul>
</li>
</ul>
<h3 id="5-nltktokenizesent_tokenize">5. <code>nltk.tokenize.sent_tokenize</code></h3>
<ul>
<li><strong>영어 ‘문장 단위’로 쪼개기</strong></li>
<li><strong>기능:</strong> 여러 문장이 있는 텍스트 → 문장별 리스트</li>
<li><strong>특징:</strong> 마침표 등 기준으로 문장 나눔</li>
</ul>
<h3 id="6-nltktokenizeword_tokenize">6. <code>nltk.tokenize.word_tokenize</code></h3>
<ul>
<li><strong>영어 문장(글, 텍스트)을 ‘단어’ 단위로 쪼개서 단어(및 구두점)를 ‘리스트’형태로 반환</strong></li>
<li><strong>기능: 여러문장이 있는 텍스트 → 문장별 리스트</strong></li>
<li><strong>특징: 단어와 구두점이 분리</strong></li>
</ul>
<h3 id="7-nltktokenizewordpuncttokenizer">7. <code>nltk.tokenize.WordPunctTokenizer</code></h3>
<ul>
<li><strong>영어, 구두점 기준으로 더 세게 쪼갬</strong></li>
<li><strong>기능:</strong> 단어 + 구두점 따로따로 분리</li>
<li><strong>특징:</strong> “won&#39;t” → [‘won’, “&#39;”, ‘t’] 등 아주 세밀하게 쪼갬</li>
</ul>
<h3 id="8-nltktokenizetreebankwordtokenizer">8. <code>nltk.tokenize.TreebankWordTokenizer</code></h3>
<ul>
<li><strong>영어, 미국 Treebank 코퍼스 표준 규칙 사용</strong></li>
<li><strong>기능:</strong> 영어 문장 쪼개기, 어포스트로피, 하이픈 등도 신경 써서 분리</li>
</ul>
<h3 id="9-tensorflowkeraspreprocessingtexttext_to_word_sequence">9. <code>tensorflow.keras.preprocessing.text.text_to_word_sequence</code></h3>
<ul>
<li><strong>영어, Keras에서 자주 씀(딥러닝용 전처리)</strong></li>
<li><strong>기능:</strong> 소문자 변환, 구두점 자동 제거 후 단어만 남김</li>
<li><strong>특징:</strong> 신경망에 바로 넣기 적합</li>
</ul>
<h3 id="10-kss-korean-sentence-splitter">10. <code>kss</code> (Korean Sentence Splitter)</h3>
<ul>
<li><strong>한글 문장 분리 특화</strong></li>
<li><strong>설치:</strong> <code>!pip install kss</code></li>
<li><strong>기능:</strong> 긴 한글 글을 “문장 단위”로 정확하게 쪼갬</li>
<li><strong>특징:</strong> 뉴스, 블로그, 카톡 등 실생활 한글 문장에 강함</li>
</ul>
<hr>
<h1 id="언어에-따른-사용">언어에 따른 사용</h1>
<h2 id="1-한글-문장용-라이브러리">1. <strong>한글 문장용 라이브러리</strong></h2>
<h3 id="1-konlpy-패키지"><strong>(1) KoNLPy 패키지</strong></h3>
<ul>
<li><p><strong>종류:</strong> <code>Okt</code>, <code>Kkma</code>, <code>Mecab</code>, <code>Hannanum</code>, <code>Komoran</code></p>
</li>
<li><p><strong>특징:</strong></p>
<ul>
<li>한국어 형태소(어근, 조사, 어미) 분석 가능</li>
<li>품사 정보까지 태깅 가능</li>
<li>긴 문장도 띄어쓰기/조사/어미 구분 잘함</li>
</ul>
</li>
<li><p><strong>사용법 예시 (Okt)</strong></p>
<pre><code class="language-python">
  from konlpy.tag import Okt
  okt = Okt()
  text = &quot;나는 오늘 집에서 공부를 했다.&quot;
  print(okt.morphs(text))   # [&#39;나&#39;, &#39;는&#39;, &#39;오늘&#39;, &#39;집&#39;, &#39;에서&#39;, &#39;공부&#39;, &#39;를&#39;, &#39;했다&#39;, &#39;.&#39;]
  print(okt.pos(text))      # [(&#39;나&#39;, &#39;Noun&#39;), (&#39;는&#39;, &#39;Josa&#39;), ...]
</code></pre>
</li>
</ul>
<h3 id="2-kss-문장-분리"><strong>(2) KSS (문장 분리)</strong></h3>
<ul>
<li><p><strong>특징:</strong></p>
<ul>
<li>한글 긴 텍스트를 문장 단위로 분리</li>
<li>실생활 대화/뉴스 등에서 문장 끝 추정 정확</li>
</ul>
</li>
<li><p><strong>사용법 예시</strong></p>
<pre><code class="language-python">
  import kss
  text = &quot;안녕하세요. 오늘도 공부합시다! 네, 알겠어요.&quot;
  print(list(kss.split_sentences(text)))
  # [&#39;안녕하세요.&#39;, &#39;오늘도 공부합시다!&#39;, &#39;네, 알겠어요.&#39;]
</code></pre>
</li>
</ul>
<h3 id="3konlpy-형태소-분석기-사용">(3)KoNLPy 형태소 분석기 사용</h3>
<pre><code class="language-python">
from konlpy.tag import Okt

text = &quot;나는 학교에 갔다.&quot;
okt = Okt()
tokens = okt.morphs(text)
print(tokens)
# 결과: [&#39;나&#39;, &#39;는&#39;, &#39;학교&#39;, &#39;에&#39;, &#39;갔다&#39;, &#39;.&#39;]
</code></pre>
<hr>
<h2 id="2-영어-문장용-라이브러리">2. <strong>영어 문장용 라이브러리</strong></h2>
<h3 id="1-nltk"><strong>(1) NLTK</strong></h3>
<ul>
<li><p><strong>종류:</strong></p>
<ul>
<li><code>word_tokenize</code>: 단어 토큰화</li>
<li><code>sent_tokenize</code>: 문장 토큰화</li>
<li><code>pos_tag</code>: 품사 태깅</li>
</ul>
</li>
<li><p><strong>특징:</strong></p>
<ul>
<li>영어 띄어쓰기 기준 분리, 구두점·약어 등도 구별</li>
<li>영어 품사 정보 태깅 가능</li>
</ul>
</li>
<li><p><strong>사용법 예시</strong></p>
<pre><code class="language-python">
  from nltk.tokenize import word_tokenize, sent_tokenize
  from nltk.tag import pos_tag

  text = &quot;Hello, I&#39;m ChatGPT! Are you learning Python?&quot;
  print(sent_tokenize(text))     # [&#39;Hello, I&#39;m ChatGPT!&#39;, &#39;Are you learning Python?&#39;]
  print(word_tokenize(text))     # [&#39;Hello&#39;, &#39;,&#39;, &#39;I&#39;, &quot;&#39;m&quot;, &#39;ChatGPT&#39;, &#39;!&#39;, ...]
  print(pos_tag(word_tokenize(text)))
  # [(&#39;Hello&#39;, &#39;NNP&#39;), (&#39;,&#39;, &#39;,&#39;), ...]
</code></pre>
</li>
</ul>
<h3 id="2-keras"><strong>(2) Keras</strong></h3>
<ul>
<li><p><strong>특징:</strong></p>
<ul>
<li><code>text_to_word_sequence</code>: 구두점 자동 제거, 소문자 변환, 영어 딥러닝용</li>
</ul>
</li>
<li><p><strong>사용법 예시</strong></p>
<pre><code class="language-python">
  from tensorflow.keras.preprocessing.text import text_to_word_sequence
  text = &quot;Hello, Deep Learning! Let&#39;s tokenize this.&quot;
  print(text_to_word_sequence(text))
  # [&#39;hello&#39;, &#39;deep&#39;, &#39;learning&#39;, &#39;lets&#39;, &#39;tokenize&#39;, &#39;this&#39;]
</code></pre>
</li>
</ul>
<h3 id="3-영어-토큰화-띄어쓰기-기준">(3) 영어 토큰화 (띄어쓰기 기준)</h3>
<pre><code class="language-python">
sentence = &quot;I am happy.&quot;
tokens = sentence.split()
print(tokens)
# 결과: [&#39;I&#39;, &#39;am&#39;, &#39;happy.&#39;]
</code></pre>
<hr>
<h2 id="3-한글영어-혼합-문장용-라이브러리">3. <strong>한글+영어 혼합 문장용 라이브러리</strong></h2>
<h3 id="1-konlpy-특히-okt-mecab"><strong>(1) KoNLPy (특히 Okt, Mecab)</strong></h3>
<ul>
<li><p><strong>특징:</strong></p>
<ul>
<li><p>한글/영어/숫자 혼합 문장에서</p>
<p>  한글 형태소, 영어 단어, 숫자까지 분리</p>
</li>
</ul>
</li>
<li><p><strong>사용법 예시</strong></p>
<pre><code class="language-python">  python
  복사편집
  from konlpy.tag import Okt
  okt = Okt()
  text = &quot;ChatGPT는 인공지능 AI입니다. 파이썬으로 코딩해요!&quot;
  print(okt.morphs(text))
  # [&#39;ChatGPT&#39;, &#39;는&#39;, &#39;인공지능&#39;, &#39;AI&#39;, &#39;입니다&#39;, &#39;.&#39;, &#39;파이썬&#39;, &#39;으로&#39;, &#39;코딩&#39;, &#39;해요&#39;, &#39;!&#39;]
</code></pre>
</li>
</ul>
<h3 id="2-kss"><strong>(2) KSS</strong></h3>
<ul>
<li><p><strong>특징:</strong></p>
<ul>
<li>한글/영어 섞인 텍스트에서 문장 단위 분리 가능</li>
</ul>
</li>
<li><p><strong>예시</strong></p>
<pre><code class="language-python">  python
  복사편집
  import kss
  text = &quot;오늘은 AI 세미나! Let&#39;s study together. 네, 좋아요.&quot;
  print(list(kss.split_sentences(text)))
  # [&#39;오늘은 AI 세미나!&#39;, &quot;Let&#39;s study together.&quot;, &#39;네, 좋아요.&#39;]
</code></pre>
</li>
</ul>
<h3 id="3-nltk의-word_tokenize--한글-라이브러리-병행"><strong>(3) NLTK의 <code>word_tokenize</code> + 한글 라이브러리 병행</strong></h3>
<ul>
<li><p><strong>특징:</strong></p>
<ul>
<li>영어는 nltk로, 한글은 konlpy로 따로 분리해서 조합</li>
</ul>
</li>
<li><p><strong>예시</strong></p>
<pre><code class="language-python">  python
  복사편집
  from nltk.tokenize import word_tokenize
  from konlpy.tag import Okt

  text_ko = &quot;파이썬과 ChatGPT를 공부해요.&quot;
  text_en = &quot;Let&#39;s learn Python and ChatGPT.&quot;

  okt = Okt()
  print(okt.morphs(text_ko))        # [&#39;파이썬&#39;, &#39;과&#39;, &#39;ChatGPT&#39;, &#39;를&#39;, &#39;공부&#39;, &#39;해요&#39;, &#39;.&#39;]
  print(word_tokenize(text_en))     # [&#39;Let&#39;, &quot;&#39;s&quot;, &#39;learn&#39;, &#39;Python&#39;, &#39;and&#39;, &#39;ChatGPT&#39;, &#39;.&#39;]
</code></pre>
</li>
</ul>
<hr>
<h1 id="정리"><strong>정리</strong></h1>
<table>
<thead>
<tr>
<th>언어/혼합</th>
<th>주요 라이브러리</th>
<th>특징/추천 상황</th>
</tr>
</thead>
<tbody><tr>
<td>한글</td>
<td>KoNLPy (Okt, Kkma 등)</td>
<td>형태소 분석(단어, 조사, 어미, 품사)</td>
</tr>
<tr>
<td></td>
<td>kss</td>
<td>문장 단위 분리</td>
</tr>
<tr>
<td>영어</td>
<td>nltk</td>
<td>문장/단어 토큰화, 품사 태깅</td>
</tr>
<tr>
<td></td>
<td>keras</td>
<td>딥러닝용 전처리, 구두점 제거</td>
</tr>
<tr>
<td>혼합(한+영)</td>
<td>KoNLPy (Okt)</td>
<td>한글/영어/숫자/특수기호 모두 단위별 분리</td>
</tr>
<tr>
<td></td>
<td>kss</td>
<td>문장 단위 분리(혼합문장 포함)</td>
</tr>
<tr>
<td></td>
<td>(nltk+konlpy) 병행</td>
<td>영어/한글 파트별로 따로따로 분석</td>
</tr>
</tbody></table>
<h2 id="토크나이저와의-차이">토크나이저와의 차이</h2>
<table>
<thead>
<tr>
<th>함수명</th>
<th>주요 특징</th>
<th>추천 용도</th>
</tr>
</thead>
<tbody><tr>
<td><strong>word_tokenize</strong></td>
<td>영어 단어 + 구두점 분리</td>
<td>영어 일반 텍스트</td>
</tr>
<tr>
<td>WordPunctTokenizer</td>
<td>더 세밀하게 구두점 분리</td>
<td>영어, 구두점 강조할 때</td>
</tr>
<tr>
<td>TreebankWordTokenizer</td>
<td>미국 Treebank 코퍼스 기준</td>
<td>영어 자연어처리 표준용</td>
</tr>
<tr>
<td>sent_tokenize</td>
<td>“문장 단위”로 쪼개기</td>
<td>영어 여러 문장 나눌 때</td>
</tr>
<tr>
<td><strong>Okt.morphs/pos</strong></td>
<td>한글 형태소 분석</td>
<td>한글(조사, 어미까지 분리)</td>
</tr>
<tr>
<td>kss.split_sentences</td>
<td>한글 “문장 단위” 분리</td>
<td>한글 뉴스/댓글 등</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[정규 표현식(Regular Expression)]]></title>
            <link>https://velog.io/@c_haha_e/%EC%A0%95%EA%B7%9C-%ED%91%9C%ED%98%84%EC%8B%9DRegular-Expression</link>
            <guid>https://velog.io/@c_haha_e/%EC%A0%95%EA%B7%9C-%ED%91%9C%ED%98%84%EC%8B%9DRegular-Expression</guid>
            <pubDate>Sat, 16 Aug 2025 16:03:58 GMT</pubDate>
            <description><![CDATA[<h1 id="정규-표현식regular-expression">정규 표현식(Regular Expression)</h1>
<h2 id="1-정규-표현식-문법">1) 정규 표현식 문법</h2>
<table>
<thead>
<tr>
<th>특수 문자</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>.</code></td>
<td>한개의 임의의 문자를 나타낸다.</td>
</tr>
<tr>
<td><code>?</code></td>
<td>앞의 문자가 존재할 수 도 있고, 존재하지 않을수도 있다.(문자가 0개 또는 1개)</td>
</tr>
<tr>
<td><code>*</code></td>
<td>앞의 문자가 무한개로 존재할 수도 있고, 존재하지 않을수 도 있다. (문자가 0개이상)</td>
</tr>
<tr>
<td><code>+</code></td>
<td>앞의 문자가 최소한개이상 존재한다.(문자가 1개이상)</td>
</tr>
<tr>
<td><code>^</code></td>
<td>뒤의 문자열로 문자열이 시작된다</td>
</tr>
<tr>
<td><code>$</code></td>
<td>앞의 문자열로 문자열이 끝난다.</td>
</tr>
<tr>
<td><code>{숫자}</code></td>
<td>숫자 만큼 반복</td>
</tr>
<tr>
<td><code>{숫자1, 숫자2}</code></td>
<td>숫자1 이상 숫자2 이하만큼 반복한다. <code>?</code>, <code>*</code>,<code>+</code>를 이것으로 대체 가능</td>
</tr>
<tr>
<td><code>{숫자,}</code></td>
<td>숫자 이상만큼 반복한다.</td>
</tr>
<tr>
<td><code>[]</code></td>
<td>대괄호 안의 문자들 중 한개의 문자와 매치</td>
</tr>
<tr>
<td><code>[^문자]</code></td>
<td>해당 문자를 제외한 문자를 매치</td>
</tr>
<tr>
<td><code>l</code></td>
<td><code>AlB</code> 와 같이 쓰이며 A 또는 B의 의미를 갖음</td>
</tr>
</tbody></table>
<h2 id="2-역슬래쉬를-이용한-문자-규칙">2) 역슬래쉬()를 이용한 문자 규칙</h2>
<table>
<thead>
<tr>
<th>문자규칙</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>\\</code></td>
<td>역 슬래쉬 문자 자체를 의미함</td>
</tr>
<tr>
<td><code>\d</code></td>
<td>모든 숫자를 의미함 <code>[0-9]</code> 와 동일</td>
</tr>
<tr>
<td><code>\D</code></td>
<td>숫자를 제외한 모든 문자를 의미한다 <code>[^0-9]</code> 와 동일</td>
</tr>
<tr>
<td><code>\s</code></td>
<td>공백을 의미함 <code>[\t\n\r\f\v]</code> 와 동일</td>
</tr>
<tr>
<td><code>\S</code></td>
<td>공백을 제외한 문자를 의미 <code>[^\t\n\r\f\v]</code>와 동일</td>
</tr>
<tr>
<td><code>\w</code></td>
<td>문자 또는 숫자를 의미함 <code>[a-zA-Z0-9]</code> 와 동일</td>
</tr>
<tr>
<td><code>\W</code></td>
<td>문자 또는 숫자가 아닌 문자를 의미함 <code>[^a-zA-Z0-9]</code>와 동일</td>
</tr>
</tbody></table>
<h2 id="3-정규표현식-모듈-함수">3) 정규표현식 모듈 함수</h2>
<table>
<thead>
<tr>
<th>모듈 함수</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>re.compile()</code></td>
<td>정규표현식을 컴파일 하는 함수, 파이썬에 미리 컴파일을 해놓고 사용하여 속도 측면에서 유리함</td>
</tr>
<tr>
<td><code>re.search()</code></td>
<td>문자열 전체에 대해 정규표현식과 매치되는지 검색한다.</td>
</tr>
<tr>
<td><code>re.match()</code></td>
<td>문자열의 처음이 정규표현식과 매치되는지 검색</td>
</tr>
<tr>
<td><code>re.split()</code></td>
<td>정규 표현식을 기준으로 문자열을 분리하여 리스트로 리턴</td>
</tr>
<tr>
<td><code>re.findall()</code></td>
<td>문자열에 정규 표현식과 매치되는 모든 경우의 문자열을 찾아서 리스트로 리턴 만약 리턴되는 값이 없을 경우 빈 리스트로 리턴</td>
</tr>
<tr>
<td><code>re.finditer()</code></td>
<td>문자열에서 정규 표현식과 매치되는 모든 경우의 문자열에 대한 이터레이터 객체를 리턴 ex) a= re.finditer() —&gt; next(iter(a))</td>
</tr>
<tr>
<td><code>re.sub()</code></td>
<td>문자열에서 정규 표현식과 일치하는 부분에 대해서 다른 문자열로 대체</td>
</tr>
</tbody></table>
<ul>
<li>r prefix : 문자열 앞에 붙이는 <code>r</code> 은 <code>raw string</code> 의 의미를 가지며 역슬래쉬 <code>\</code> 을 탈출 문자로 보지 않고, 아무 역할도 하지 않는 평범한 문자열로 간주한다.  <code>\s</code> 는 탈출문자에 해당하지 않기 때문에 추가적인 pattern에 넣어줘야함</li>
</ul>
<p>예시 ) </p>
<pre><code class="language-python">print(&quot;Hello World!\n&quot;)
print(r&quot;Hello World!\n&quot;)</code></pre>
<pre><code class="language-python">&gt;&gt; Hello World!
&gt;&gt; 
&gt;&gt; Hello World!\n</code></pre>
<p>연습용 사이트(정규식표현) —&gt; <a href="https://regexr.com/5mhou">https://regexr.com/5mhou</a></p>
<p>-필수 패키지 설치</p>
<pre><code class="language-python">pip install nltk konlpy pandas numpy matplotlib seaborn scikit-learn torch 
pip install JPype1-0.6.3-cp36-cp36m-win_amd64.whl # 설치 주소 https://github.com/jpype-project/jpype/releases * 디렉토리에 파일이 있어야 설치 가능 
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[딥러닝]PyTorch, TensorFlow, Keras]]></title>
            <link>https://velog.io/@c_haha_e/%EB%94%A5%EB%9F%AC%EB%8B%9DPyTorch-TensorFlow-Keras</link>
            <guid>https://velog.io/@c_haha_e/%EB%94%A5%EB%9F%AC%EB%8B%9DPyTorch-TensorFlow-Keras</guid>
            <pubDate>Sat, 16 Aug 2025 15:48:20 GMT</pubDate>
            <description><![CDATA[<h2 id="1-pytorch-tensorflow-keras란">1. <strong>PyTorch, TensorFlow, Keras란?</strong></h2>
<table>
<thead>
<tr>
<th>프레임워크</th>
<th>주요 특징/설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>PyTorch</strong></td>
<td>- Facebook 개발- <strong>코드가 Pythonic, 직관적</strong>- 연구, 실험, 최신 모델 구현에 강점</td>
</tr>
<tr>
<td><strong>TensorFlow</strong></td>
<td>- Google 개발- 기업/대규모 서비스, 배포에 강점- 확장성, 생산성, 복잡한 모델에 강함</td>
</tr>
<tr>
<td><strong>Keras</strong></td>
<td>- 원래 독립 프레임워크(현재는 TensorFlow에 통합, <code>tf.keras</code>)- <strong>가장 쉬운 딥러닝 인터페이스</strong>- 빠른 프로토타이핑, 교육, 직관적 설계</td>
</tr>
</tbody></table>
<hr>
<h2 id="2-어디서-언제-어떻게-쓰나">2. <strong>어디서, 언제, 어떻게 쓰나?</strong></h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>추천 프레임워크</th>
<th>비고</th>
</tr>
</thead>
<tbody><tr>
<td><strong>딥러닝 연구/논문/최신 실험</strong></td>
<td>PyTorch</td>
<td>코드 자유도/유연성 최고</td>
</tr>
<tr>
<td><strong>서비스 배포, 대규모 생산환경</strong></td>
<td>TensorFlow</td>
<td>서버, 모바일, 확장성 강점</td>
</tr>
<tr>
<td><strong>쉽고 빠른 딥러닝 모델링/교육</strong></td>
<td>Keras(tf.keras)</td>
<td>가장 간단, 직관적 코드</td>
</tr>
<tr>
<td><strong>이미지/텍스트/시계열 등 복잡 데이터</strong></td>
<td>셋 다 가능</td>
<td>직접 신경망 설계(회귀/분류 자유자재)</td>
</tr>
<tr>
<td><strong>기존 모델 활용, 튜토리얼 학습</strong></td>
<td>Keras(tf.keras), PyTorch</td>
<td>예제 많음, 실습/입문에 적합</td>
</tr>
</tbody></table>
<hr>
<h2 id="3-딥러닝-회귀분류시계열-모델-직접-설계">3. <strong>딥러닝 회귀/분류/시계열 모델 직접 설계</strong></h2>
<ul>
<li><strong>회귀</strong>: 마지막 출력층에 활성화함수 없이 Dense(1)</li>
<li><strong>분류</strong>: 마지막 출력층에 소프트맥스/시그모이드 등 사용</li>
<li><strong>이미지, 자연어, 시계열</strong>: Conv2D, LSTM 등 다양한 레이어 자유롭게 조합</li>
</ul>
<hr>
<h2 id="4-주요-사용법간단-예시">4. <strong>주요 사용법(간단 예시)</strong></h2>
<h3 id="1-pytorch">(1) <strong>PyTorch</strong></h3>
<pre><code class="language-python">
import torch
import torch.nn as nn

class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10, 64)
        self.fc2 = nn.Linear(64, 1)  # 회귀: 1, 분류: 클래스 수
    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x

model = Net()
# optimizer, loss 함수 등 자유롭게 정의
</code></pre>
<hr>
<h3 id="2-tensorflow--keras">(2) <strong>TensorFlow / Keras</strong></h3>
<pre><code class="language-python">
from tensorflow import keras

model = keras.Sequential([
    keras.layers.Dense(64, activation=&#39;relu&#39;, input_shape=(10,)),
    keras.layers.Dense(1)  # 회귀: 1, 분류: 클래스 수+softmax
])
model.compile(optimizer=&#39;adam&#39;, loss=&#39;mse&#39;)
</code></pre>
<hr>
<h2 id="5-주요-파라미터설정">5. <strong>주요 파라미터/설정</strong></h2>
<ul>
<li><strong>layers.Dense/nn.Linear</strong>: 신경망 레이어(입력, 은닉, 출력 등)</li>
<li><strong>activation</strong>: relu, sigmoid, softmax 등</li>
<li><strong>optimizer</strong>: adam, sgd, rmsprop 등</li>
<li><strong>loss</strong>: mse(회귀), crossentropy(분류) 등</li>
<li><strong>epochs, batch_size</strong>: 학습 반복 수, 배치 크기 등</li>
<li><strong>callbacks, regularization</strong>: 얼리스탑, 드롭아웃 등 추가 설정도 가능</li>
</ul>
<hr>
<h2 id="6-비교-요약-표">6. <strong>비교 요약 표</strong></h2>
<table>
<thead>
<tr>
<th>프레임워크</th>
<th>유연성/직관성</th>
<th>대규모/서비스</th>
<th>교육/입문</th>
<th>실무/연구</th>
<th>추천 상황</th>
</tr>
</thead>
<tbody><tr>
<td>PyTorch</td>
<td>★★★★★</td>
<td>★★★★☆</td>
<td>★★★★☆</td>
<td>★★★★★</td>
<td>최신 논문, 복잡 모델, 실험</td>
</tr>
<tr>
<td>TensorFlow</td>
<td>★★★★☆</td>
<td>★★★★★</td>
<td>★★★☆☆</td>
<td>★★★★☆</td>
<td>기업, 대규모 배포, 복합 서비스</td>
</tr>
<tr>
<td>Keras(tf.keras)</td>
<td>★★★★☆</td>
<td>★★★★☆</td>
<td>★★★★★</td>
<td>★★★★☆</td>
<td>입문, 프로토타입, 쉬운 사용</td>
</tr>
</tbody></table>
<hr>
<h2 id="7-결론실전-tip">7. <strong>결론/실전 TIP</strong></h2>
<ul>
<li><p><strong>딥러닝/신경망 모델을 직접 설계하고 싶을 때</strong></p>
<p>  → PyTorch, TensorFlow, Keras 중 자유롭게 선택</p>
</li>
<li><p><strong>실무/생산/최고성능</strong></p>
<p>  → TensorFlow, PyTorch</p>
</li>
<li><p><strong>입문, 실습, 빠른 개발</strong></p>
<p>  → Keras(tf.keras)</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[인공신경망]]></title>
            <link>https://velog.io/@c_haha_e/%EC%9D%B8%EA%B3%B5%EC%8B%A0%EA%B2%BD%EB%A7%9D</link>
            <guid>https://velog.io/@c_haha_e/%EC%9D%B8%EA%B3%B5%EC%8B%A0%EA%B2%BD%EB%A7%9D</guid>
            <pubDate>Sat, 16 Aug 2025 15:47:01 GMT</pubDate>
            <description><![CDATA[<h2 id="1-인공신경망ann">1. 인공신경망(ANN)</h2>
<p><img src="https://velog.velcdn.com/images/flowinq414/post/d433f0d4-e1c1-4e90-9f5d-f47e7b902864/image.png" alt=""></p>
<p>가장 기본적인 인공 신경망으로, 그 형태는 확률적 경사하강법을 사용하는 로지스틱 회귀와 매우 유사하다. 인공신경망은 보다 높은 성능을 가진 새로운 종류의 머신러닝 알고리즘일 뿐, 정말 우리 뇌에 있는 뉴런과 같지 않다는 것을 항상 인지해야한다.</p>
<blockquote>
<p>입력층: x값, 픽셀값 그 자체이고 특별한 계산수행 없이 원시 데이터를 받아 전달만 한다.</p>
<p><strong>은닉층</strong>: 입력층과 출력층 사이에 있는 모든 층으로, 입력값에 가중치를 곱하고 비선형 함수(활성화 함수)를 적용해 특징을 추출한다.</p>
<p><strong>출력층</strong>: z값을 계산하고 이를 바탕으로 클래스 예측하여 신경망의 최종 결과를 만든다.</p>
<p>cf) 밀집층(Dense Layer): 모든 뉴런이 앞층의 뉴런과 연결된 구조</p>
<p>ANN은 단일 신경망으로, Dense가 하나로 구성되어있으며, 다층 신경망은 Dense가 여러 개인 신경망이다.</p>
</blockquote>
<h3 id="keras의-클래스">keras의 클래스</h3>
<ul>
<li><strong><code>Dense</code></strong>: 신경망의 밀집층(fully connected layer)을 만드는 클래스로, 각 뉴런이 이전 층의 모든 뉴런과 연결되며,<code>activation</code> 매개변수로 활성화 함수를 지정할 수 있다.</li>
<li><strong><code>Sequential()</code></strong>: 순차적으로 층을 쌓는 모델. 신경망 모델을 만드는 클래스로, 객체 생성 시 신경망 모델에 추가할 층을 지정할 수 있다. 1개 이상일 경우, 리스트의 형태 <code>[]</code> 로 전달한다.</li>
<li><strong><code>dropout</code></strong>: 모델이 과대적합되지 않도록 일부 뉴런을 랜덤하게 끄는(출력=<code>0</code>) 정규화 기법이다.</li>
<li><strong><code>Early Stopping</code></strong>: 모델 훈련 중에 자동으로 특정 동작을 수행하게 해주는 도구인 <code>call back</code> 의 클래스 중 하나로, 검증 성능이 더 이상 좋아지지 않으면 훈련을 중단하여 과대적합을 줄여준다.</li>
</ul>
<h3 id="옵티마이저optimizer">옵티마이저(<code>optimizer</code>)</h3>
<p>손실함수를 최소화하기 위해 모델의 가중치를 조정하는 알고리즘</p>
<table>
<thead>
<tr>
<th>이름</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td><code>SGD</code> (Stochastic Gradient Descent)</td>
<td>기본적인 옵티마이저. 단순하지만 느릴 수 있음</td>
</tr>
<tr>
<td><code>Momentum</code></td>
<td>이전 단계의 이동을 고려해 속도를 붙임</td>
</tr>
<tr>
<td><code>RMSprop</code></td>
<td>학습률을 개별 파라미터마다 조절</td>
</tr>
<tr>
<td><code>Adam</code></td>
<td><strong>가장 많이 쓰임. 빠르고 안정적</strong></td>
</tr>
<tr>
<td><code>Adagrad</code> / <code>Adadelta</code></td>
<td>희귀 특성 학습에 유리함</td>
</tr>
</tbody></table>
<h2 id="2-활성화-함수activation-function">2. 활성화 함수(Activation function)</h2>
<p><img src="https://velog.velcdn.com/images/flowinq414/post/a9d16f88-b8a6-4f49-b5ff-59b732a84787/image.jpg" alt=""></p>
<p>뉴런의 선형 방정식 결과에 적용되는 함수로, 선형을 비선형으로 바꿔서 신경망이 곡선적인 분리/예측을 가능케 하고 더 복잡한 문제를 해결할 수 있도록 도와준다. 용도에 맞게 골라 써야한다.</p>
<p>어떻게 복잡한 문제를 해결하느냐?</p>
<p>→ <code>ReLU</code> : 입력이 양수일 경우, 활성화 함수가 없는 것처럼 그냥 입력을 통과시키고 음수일 경우 0으로 만든다</p>
<p>→ <code>sigmoid</code> : 입력값을 0과 1 사이로 변환해서 확률처럼 해석이 가능하다(양수는 1에 가깝고, 음수는 0에 가깝다)</p>
<p>→ <code>softmax</code> : 여러 출력값들을 확률분포처럼 바꿔서 전체 합이 1이 되도록 조정한다</p>
<h2 id="3-손실곡선">3. 손실곡선</h2>
<p>두 그래프가 비슷하게 낮게 유지되면(=두 그래프가 같을 때), 모델의 일반화 능력(=성능)이 좋다고 할 수 있다. </p>
<p>두 그래프의 간격이 과적합을 의미해서 차이가 적을수록 과적합이 없다</p>
<p>⇒ 간격이 좁고, 그래프가 낮다</p>
<p><img src="attachment:cc75049d-68cc-44e8-8487-14cba5da7f3d:Screenshot_2025-05-11_at_1.59.41_PM.png" alt="Screenshot 2025-05-11 at 1.59.41 PM.png"></p>
<h2 id="4-합성곱-신경망cnn">4. 합성곱 신경망(CNN)</h2>
<p><img src="https://velog.velcdn.com/images/flowinq414/post/cb8e57e9-3d2c-440c-8def-69f2d930664e/image.jpg" alt=""></p>
<p>도장 찍어내듯이 출력(특징)이 하나씩 생겨나는 신경망 구조로 도장의 크기, 즉 커널(kernel)의 크기는 하이퍼 파라미터로서 우리가 지정해줘야한다. 입력의 배열 차원과 커널의 차원이 동일해야한다.</p>
<p>여러 가중치들로 계산된 필터(커널)들이 있고, 각 필터별로 나온 출력값들을 모은 것이다. 이 하나의 출력 행렬을 특징맵(<code>feature maps</code>)이라고 한다.</p>
<p>CNN은 여러 개의 필터를 사용하므로, 여러 개의 출력 행렬이 생기는 것이다. 그 여러 <code>feature map</code>을 쌓은 것이 합성곱 층의 출력이다.</p>
<h3 id="feature-map-만드는-과정">feature map 만드는 과정</h3>
<p><img src="https://velog.velcdn.com/images/c_haha_e/post/b8c3e078-fa3d-42d6-9554-16bec47be613/image.gif" alt=""></p>
<p>노란색이 필터 = 도장 / 빨간 <code>x1</code>,<code>x0</code> 글씨는 가중치(w) </p>
<p>전 은닉층의 뉴런 개수 x 출력층의 뉴런 개수 만큼 가중치의 개수가 생긴다. 인공신경망의 개념</p>
<p>합성: 출력층의 개수가 정해지면 그 전 은닉층에서의 가중치 개수가 정해짐 </p>
<h3 id="conv2d합성곱-층--maxpool2d최대-풀링">Conv2D(합성곱 층) / MaxPool2D(최대 풀링)</h3>
<table>
<thead>
<tr>
<th>층 이름</th>
<th>역할 요약</th>
</tr>
</thead>
<tbody><tr>
<td><code>Conv2D</code></td>
<td>이미지를 스캔하며 <strong>특징(패턴)</strong>을 뽑음 (모서리, 선, 윤곽 등)</td>
</tr>
<tr>
<td>→ 필터를 이미지에 돋보기(🔍) 처럼 움직이며 적용(특정 모양을 응시)</td>
<td></td>
</tr>
<tr>
<td><code>MaxPool2D</code></td>
<td>추출한 특징 중 <strong>가장 중요한 것만 남기고</strong> 크기를 줄임</td>
</tr>
<tr>
<td>→ 이미지에서 가장 강한 특징만 출력하는 역할</td>
<td></td>
</tr>
</tbody></table>
<pre><code>[입력 이미지]
↓ Conv2D
[특징맵]  ← 가장자리, 윤곽선, 패턴 등
↓ MaxPool2D
[축소된 특징맵] ← 정보는 유지하되 크기는 절반
</code></pre><h3 id="항상-conv-→-maxpool-순서여야하는가">항상 Conv → MaxPool 순서여야하는가?</h3>
<p>No. 일반적인 패턴이긴 하지만 항상 붙여다녀야하는 건 아니다.</p>
<table>
<thead>
<tr>
<th>패턴</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>Conv → MaxPool</code></td>
<td>가장 일반적인 구조</td>
<td>간단한 CNN</td>
</tr>
<tr>
<td><code>Conv → Conv → MaxPool</code></td>
<td>더 많은 특징 추출 후 축소</td>
<td>VGG</td>
</tr>
<tr>
<td><code>Conv(stride=2)</code></td>
<td>풀링 없이 직접 축소</td>
<td>ResNet 등</td>
</tr>
<tr>
<td><code>Conv</code>만 연속</td>
<td>임시적으로 특징 추출만</td>
<td>성능 조정 목적</td>
</tr>
</tbody></table>
<p><a href="https://colab.research.google.com/drive/1P9NCB3MQX5QrCf93VHYfPGa0R1V4qD1y?usp=sharing">https://colab.research.google.com/drive/1P9NCB3MQX5QrCf93VHYfPGa0R1V4qD1y?usp=sharing</a></p>
<p>01 - <a href="https://colab.research.google.com/drive/1P9NCB3MQX5QrCf93VHYfPGa0R1V4qD1y?usp=drive_link">https://colab.research.google.com/drive/1P9NCB3MQX5QrCf93VHYfPGa0R1V4qD1y?usp=drive_link</a></p>
<p>02 - <a href="https://colab.research.google.com/drive/1Mu5kBwfkfCIRRQ3nvOF4a3wMaz5Cmebz?usp=drive_link">https://colab.research.google.com/drive/1Mu5kBwfkfCIRRQ3nvOF4a3wMaz5Cmebz?usp=drive_link</a></p>
<p>03 - <a href="https://colab.research.google.com/drive/1gpLfy1YFGLyHNLdaA1zVnFN4iPCC4kuo?usp=sharing">https://colab.research.google.com/drive/1gpLfy1YFGLyHNLdaA1zVnFN4iPCC4kuo?usp=sharing</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[회귀 / 분류에 사용하는 라이브러리]]></title>
            <link>https://velog.io/@c_haha_e/%ED%9A%8C%EA%B7%80-%EB%B6%84%EB%A5%98%EC%97%90-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</link>
            <guid>https://velog.io/@c_haha_e/%ED%9A%8C%EA%B7%80-%EB%B6%84%EB%A5%98%EC%97%90-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</guid>
            <pubDate>Wed, 13 Aug 2025 12:37:05 GMT</pubDate>
            <description><![CDATA[<h2 id="1-회귀에-사용하는-라이브러리">1. 회귀에 사용하는 라이브러리</h2>
<h3 id="1-scikit-learn-사이킷런">(1) <strong>scikit-learn (사이킷런)</strong></h3>
<ul>
<li><strong>LinearRegression</strong> (선형회귀)</li>
<li><strong>Ridge, Lasso, ElasticNet</strong> (정규화 회귀)</li>
<li><strong>SVR</strong> (Support Vector Regression)</li>
<li><strong>RandomForestRegressor, GradientBoostingRegressor</strong></li>
<li><strong>DecisionTreeRegressor</strong></li>
</ul>
<pre><code class="language-python">
from sklearn.linear_model import LinearRegression, Ridge, Lasso, ElasticNet
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.svm import SVR
from sklearn.tree import DecisionTreeRegressor
</code></pre>
<h3 id="2-statsmodels">(2) <strong>statsmodels</strong></h3>
<ul>
<li>통계적 회귀 분석에 특화 (해석이 필요할 때)</li>
</ul>
<pre><code class="language-python">
import statsmodels.api as sm
</code></pre>
<h3 id="3-xgboost-lightgbm-catboost">(3) <strong>XGBoost, LightGBM, CatBoost</strong></h3>
<ul>
<li>고성능 트리 기반 회귀 (분류도 가능)</li>
</ul>
<pre><code class="language-python">
from xgboost import XGBRegressor
from lightgbm import LGBMRegressor

pip install catboost
from catboost import CatBoostRegressor
</code></pre>
<h3 id="4-pytorch-tensorflow-keras">(4) <strong>PyTorch, TensorFlow, Keras</strong></h3>
<ul>
<li>딥러닝 기반 회귀 (신경망)</li>
</ul>
<pre><code class="language-python">import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset

import tensorflow as tf
from tensorflow import keras

from tensorflow import keras
from keras.models import Sequential
from keras.layers import Dense</code></pre>
<h3 id="회귀-라이브러리별-사용-상황-정리-표"><strong>회귀 라이브러리별 사용 상황 정리 표</strong></h3>
<table>
<thead>
<tr>
<th>라이브러리</th>
<th>주로 사용하는 상황/특징</th>
<th>강점</th>
<th>단점/주의점</th>
</tr>
</thead>
<tbody><tr>
<td><strong>scikit-learn</strong></td>
<td>- 표준 회귀/기초 회귀- 데이터가 적거나 중간 규모- 다양한 알고리즘 빠른 실험</td>
<td>다양한 기본 모델, 사용법 단순, 빠름</td>
<td>초대용량, 딥러닝 비효율적</td>
</tr>
<tr>
<td><strong>statsmodels</strong></td>
<td>- 통계 해석/설명 필요- p값, 신뢰구간 등 통계적 결과 중요- 논문/연구/설명</td>
<td>회귀 계수 해석, 상세 통계 지원</td>
<td>속도 느림, 대용량/딥러닝 미지원</td>
</tr>
<tr>
<td><strong>XGBoost/LightGBM/ CatBoost</strong></td>
<td>- 복잡/비선형/변수간 상호작용- 대규모 데이터- Kaggle, 실무에서 정확도 우선</td>
<td>성능 우수, 결측치/범주형 변수 지원</td>
<td>파라미터 튜닝 필요, 해석 약간 어려움</td>
</tr>
<tr>
<td><strong>PyTorch/TF/Keras</strong></td>
<td>- 딥러닝, 복잡한 패턴, 이미지/텍스트/시계열 등- 신경망/비선형관계 학습- 큰 데이터/커스텀 모델</td>
<td>매우 유연, 딥러닝/비선형패턴 강점</td>
<td>코드 복잡, 대용량/튜닝 필요</td>
</tr>
</tbody></table>
<hr>
<h2 id="2-분류에-사용하는-라이브러리">2. 분류에 사용하는 라이브러리</h2>
<h3 id="1-scikit-learn">(1) <strong>scikit-learn</strong></h3>
<ul>
<li><strong>LogisticRegression</strong> (로지스틱 분류)</li>
<li><strong>SVC</strong> (Support Vector Classifier)</li>
<li><strong>RandomForestClassifier, GradientBoostingClassifier</strong></li>
<li><strong>DecisionTreeClassifier</strong></li>
<li><strong>KNeighborsClassifier</strong></li>
</ul>
<pre><code class="language-python">
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.svm import SVC
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
</code></pre>
<h3 id="2-xgboost-lightgbm-catboost">(2) <strong>XGBoost, LightGBM, CatBoost</strong></h3>
<ul>
<li>강력한 분류기 (회귀도 지원)</li>
</ul>
<pre><code class="language-python">
from xgboost import XGBClassifier
from lightgbm import LGBMClassifier

pip install catboost
from catboost import CatBoostClassifier</code></pre>
<h3 id="3-pytorch-tensorflow-keras">(3) <strong>PyTorch, TensorFlow, Keras</strong></h3>
<ul>
<li>딥러닝 기반 분류 (분류용 출력층, 예: Softmax)</li>
</ul>
<pre><code class="language-python">import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Dataset

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

from keras.models import Sequential
from keras.layers import Dense</code></pre>
<h3 id="분류-라이브러리별-사용-상황-정리-표"><strong>분류 라이브러리별 사용 상황 정리 표</strong></h3>
<table>
<thead>
<tr>
<th>라이브러리</th>
<th>주로 사용하는 상황/특징</th>
<th>강점</th>
<th>단점/주의점</th>
</tr>
</thead>
<tbody><tr>
<td><strong>scikit-learn</strong></td>
<td>- 표준 분류/입문- 데이터 적거나 중간 규모- 다양한 분류 알고리즘 빠른 실험</td>
<td>다양한 기본 분류 모델, 쉬운 사용법</td>
<td>대용량/딥러닝에는 부적합</td>
</tr>
<tr>
<td><strong>XGBoost/LightGBM/ CatBoost</strong></td>
<td>- 비선형/복잡/상호작용 변수 많음- 대규모 데이터- Kaggle, 실무에서 정확도 우선</td>
<td>성능 우수, 결측치/범주형 변수 지원</td>
<td>파라미터 튜닝 필요, 해석 약간 어려움</td>
</tr>
<tr>
<td><strong>PyTorch/TF/Keras</strong></td>
<td>- 딥러닝, 이미지/텍스트/시계열/고차원- 커스텀 신경망 구조- 대용량 데이터, 비선형 분류</td>
<td>매우 유연, 딥러닝/비선형패턴 강점</td>
<td>코드 복잡, 데이터 준비, 튜닝 필요</td>
</tr>
</tbody></table>
<table>
<thead>
<tr>
<th>상황</th>
<th>추천 라이브러리</th>
<th>비고</th>
</tr>
</thead>
<tbody><tr>
<td>기본/표준 분류, 로지스틱/트리/랜덤포레스트</td>
<td>scikit-learn</td>
<td>빠르고 해석 쉬움</td>
</tr>
<tr>
<td>변수 많고, 비선형/상호작용, 대규모 데이터</td>
<td>XGBoost, LightGBM, CatBoost</td>
<td>실무, 대회 등 강력</td>
</tr>
<tr>
<td>딥러닝, 이미지/텍스트, 복잡 신경망</td>
<td>PyTorch, TensorFlow, Keras</td>
<td>커스텀/비선형/대용량</td>
</tr>
<tr>
<td>범주형 변수 많음, 자동처리 원함</td>
<td>CatBoost</td>
<td>전처리 편리</td>
</tr>
<tr>
<td>실전에서 높은 예측 성능 필요</td>
<td>XGBoost, LightGBM, CatBoost</td>
<td>Kaggle/실무 표준</td>
</tr>
</tbody></table>
<h3 id="요약-표"><strong>요약 표</strong></h3>
<table>
<thead>
<tr>
<th>라이브러리</th>
<th>해석/설명</th>
<th>성능</th>
<th>대용량/복잡</th>
<th>딥러닝/비선형</th>
<th>추천 상황</th>
</tr>
</thead>
<tbody><tr>
<td>scikit-learn</td>
<td>★★★★☆</td>
<td>★★★</td>
<td>★★☆☆☆</td>
<td>★★☆☆☆</td>
<td>입문, 실험, 표준 분류</td>
</tr>
<tr>
<td>XGBoost 등</td>
<td>★★☆☆☆</td>
<td>★★★★★</td>
<td>★★★★★</td>
<td>★★★★☆</td>
<td>실무, 고성능, 변수많음</td>
</tr>
<tr>
<td>PyTorch/TF</td>
<td>★★☆☆☆</td>
<td>★★★★★</td>
<td>★★★★★</td>
<td>★★★★★</td>
<td>딥러닝, 비선형, 대용량</td>
</tr>
</tbody></table>
<hr>
<h3 id="실전-팁"><strong>실전 팁</strong></h3>
<ul>
<li><strong>빠른 실험/기본 분류:</strong> <code>scikit-learn</code></li>
<li><strong>고성능/비선형/대용량:</strong> <code>XGBoost</code>, <code>LightGBM</code>, <code>CatBoost</code></li>
<li><strong>딥러닝, 이미지/텍스트:</strong> <code>PyTorch</code>, <code>TensorFlow</code>, <code>Keras</code></li>
</ul>
<h3 id="세부-모델별-추천-상황"><strong>세부 모델별 추천 상황</strong></h3>
<table>
<thead>
<tr>
<th>모델</th>
<th>강점/적합 데이터</th>
</tr>
</thead>
<tbody><tr>
<td>LogisticRegression</td>
<td>기본 이진/다중 분류, 해석 쉬움</td>
</tr>
<tr>
<td>SVC(SVM)</td>
<td>마진 큰 경계, 고차원/비선형</td>
</tr>
<tr>
<td>RandomForest/GBM</td>
<td>비선형, 변수간 상호작용, 변수 중요도 해석</td>
</tr>
<tr>
<td>DecisionTree</td>
<td>규칙/설명성, 소규모 데이터</td>
</tr>
<tr>
<td>KNeighborsClassifier</td>
<td>간단, 소규모, 거리 기반</td>
</tr>
<tr>
<td>XGBoost/LightGBM</td>
<td>실무 표준, 예측력 최고, 결측치/범주형 강점</td>
</tr>
<tr>
<td>CatBoost</td>
<td>범주형 변수 자동, 파라미터 튜닝 편리</td>
</tr>
<tr>
<td>PyTorch/TF/Keras</td>
<td>이미지/텍스트, 복잡한 신경망, 딥러닝 분야</td>
</tr>
</tbody></table>
<p><a href="https://www.notion.so/sklearn-Linear-Regression-1e03d7545f0880dfb72ed39dc0ad4ed3?pvs=21">[예측]회귀(sklearn) - 선형회귀(Linear Regression)</a></p>
<p><a href="https://www.notion.so/sklearn-Ridge-Lasso-ElasticNet-1e03d7545f0880dc956dfd24e379fa33?pvs=21">[예측]회귀(sklearn) - <strong>Ridge, Lasso, ElasticNet</strong> (정규화 회귀)</a></p>
<p><a href="https://www.notion.so/sklearn-SVR-Support-Vector-Regression-1e03d7545f088097aa28e4f7421dab6a?pvs=21">[예측]회귀(sklearn) - SVR(Support Vector Regression)</a></p>
<p><a href="https://www.notion.so/sklearn-DecisionTreeRegressor-1e03d7545f08803590f9f86455b5c21f?pvs=21">[예측]회귀(sklearn) -<strong>DecisionTreeRegressor(의사결정 트리)</strong></a></p>
<p><a href="https://www.notion.so/sklearn-RandomForestRegressor-GradientBoostingRegressor-1e03d7545f0880ba93dee3755c7d0bc0?pvs=21">[예측]<strong>회귀(sklearn) - RandomForestRegressor, GradientBoostingRegressor</strong></a></p>
<p><a href="https://www.notion.so/sklearn-Logistic-Regression-1e03d7545f0880cb8e2cd3b8d0344943?pvs=21">[예측]분류(sklearn) - Logistic Regression</a></p>
<p><a href="https://www.notion.so/sklearn-SVC-Support-Vector-Classifier-1e03d7545f08807b920def76c31c996f?pvs=21"><strong>[예측]분류(sklearn) - SVC (Support Vector Classifier)</strong></a></p>
<p><a href="https://www.notion.so/sklearn-RandomForestClassifier-GradientBoostingClassifier-1e03d7545f08802190f4f748b6f6d2c2?pvs=21">[예측]분류(sklearn) - RandomForestClassifier, GradientBoostingClassifier</a></p>
<p><a href="https://www.notion.so/sklearn-DecisionTreeClassifier-1e03d7545f088039b1dcf8f640600e94?pvs=21"><strong>[예측]분류(sklearn) - DecisionTreeClassifier (의사결정나무 분류기)</strong></a></p>
<p><a href="https://www.notion.so/XGBoost-LightGBM-CatBoost-1e03d7545f0880048437f143fee6bca8?pvs=21">[예측]회귀&amp;분류 - <strong>XGBoost, LightGBM, CatBoost</strong></a></p>
<p><a href="https://www.notion.so/statsmodels-1e03d7545f088043a333e47cb7389f20?pvs=21">[해석]회귀(<strong>statsmodels</strong>)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[cross-validation (교차검증)]]></title>
            <link>https://velog.io/@c_haha_e/cross-validation-%EA%B5%90%EC%B0%A8%EA%B2%80%EC%A6%9D</link>
            <guid>https://velog.io/@c_haha_e/cross-validation-%EA%B5%90%EC%B0%A8%EA%B2%80%EC%A6%9D</guid>
            <pubDate>Wed, 13 Aug 2025 12:32:35 GMT</pubDate>
            <description><![CDATA[<h1 id="cross-validation-교차검증란"><strong>cross-validation (교차검증)란?</strong></h1>
<hr>
<h2 id="1-개념쉬운-정의">1. <strong>개념(쉬운 정의)</strong></h2>
<ul>
<li><p><strong>전체 데이터를 여러 조각(폴드, fold)으로 나눠서</strong></p>
<p>  <strong>여러 번 반복해서 모델 성능을 평가</strong>하는 방법이야.</p>
</li>
</ul>
<hr>
<h2 id="2-왜-필요할까">2. <strong>왜 필요할까?</strong></h2>
<ul>
<li><strong>모델의 정확하게 평가</strong>하려고!</li>
<li>한 번만 테스트하면 <strong>우연히 쉬운/어려운 데이터가 걸릴 수 있어서</strong> 검증이 불안정할 수 있음.</li>
<li>여러 번 데이터 섞어가며 평가하면 평균 성능이 훨씬 믿을만해짐.</li>
</ul>
<hr>
<h2 id="3-실전에서-가장-많이-쓰는-방식-k-fold-교차검증">3. <strong>실전에서 가장 많이 쓰는 방식: K-Fold 교차검증</strong></h2>
<ul>
<li><p><strong>K-Fold(대표적으로 5-Fold, 10-Fold):</strong></p>
<p>  ① 데이터를 K개(예: 5개)로 똑같이 나눔</p>
<p>  ② 한 번은 4조각으로 학습, 1조각으로 평가</p>
<p>  ③ 이걸 조각마다 테스트 조각을 바꿔가며 K번 반복</p>
<p>  ④ <strong>K번 평가한 점수의 평균</strong>이 진짜 성능!</p>
</li>
</ul>
<hr>
<h2 id="4-코드-예시">4. <strong>코드 예시</strong></h2>
<pre><code class="language-python">
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris

X, y = load_iris(return_X_y=True)
model = LogisticRegression(max_iter=200)
scores = cross_val_score(model, X, y, cv=5)  # 5-Fold
print(scores)        # [0.96, 0.98, 0.94, 0.96, 1.0]  (폴드별 점수)
print(scores.mean()) # 평균 성능
</code></pre>
<h1 id="cross_val_score-파라미터"><strong>cross_val_score 파라미터</strong></h1>
<table>
<thead>
<tr>
<th>파라미터명</th>
<th>의미/역할</th>
<th>예시/설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>estimator</code></td>
<td><strong>모델(분류기/회귀기)</strong>실제로 평가할 모델 객체</td>
<td><code>LogisticRegression()</code>, <code>SVC()</code> 등</td>
</tr>
<tr>
<td><code>X</code></td>
<td><strong>입력 데이터(피처, 독립변수)</strong></td>
<td><code>train_X</code>, <code>X</code></td>
</tr>
<tr>
<td><code>y</code></td>
<td><strong>정답 데이터(타깃, 레이블, 종속변수)</strong></td>
<td><code>train_y</code>, <code>y</code></td>
</tr>
<tr>
<td><code>cv</code></td>
<td><strong>폴드 수(몇 조각으로 나눌지)</strong></td>
<td><code>5</code>(5-Fold), <code>10</code> 등</td>
</tr>
<tr>
<td><code>scoring</code></td>
<td><strong>성능 평가 방식</strong>(기본: accuracy)</td>
<td><code>&#39;accuracy&#39;</code>, <code>&#39;f1&#39;</code>, <code>&#39;roc_auc&#39;</code> 등</td>
</tr>
</tbody></table>
<hr>
<h2 id="대표-예시"><strong>대표 예시</strong></h2>
<pre><code class="language-python">
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression

model = LogisticRegression()
X = [[1,2],[2,3],[3,4],[4,5]]
y = [0,0,1,1]

scores = cross_val_score(
    estimator=model,  # 사용할 모델
    X=X,              # 입력 데이터(피처)
    y=y,              # 정답 데이터(라벨)
    cv=3,             # 3-Fold 교차검증
    scoring=&#39;accuracy&#39;# 평가 방식(정확도)
)
print(scores)</code></pre>
<hr>
<h2 id="결론-요약"><strong>결론 요약</strong></h2>
<ul>
<li><strong>필수:</strong><ul>
<li><strong>모델(estimator)</strong></li>
<li><strong>입력 데이터(X)</strong></li>
<li><strong>정답/라벨(y)</strong></li>
</ul>
</li>
<li><strong>옵션:</strong><ul>
<li><strong>cv(폴드 수, 기본 5)</strong></li>
<li><strong>scoring(평가방식, 기본은 정확도)</strong></li>
</ul>
</li>
</ul>
<hr>
<h2 id="6-실무에서의-역할">6. <strong>실무에서의 역할</strong></h2>
<ul>
<li>진짜 성능 일반화 성능 과적합 방지에 꼭 필요</li>
<li>모델/파라미터/데이터 튜닝 전 성능 비교에도 표준</li>
</ul>
<hr>
<h2 id="한줄-정리"><strong>한줄 정리</strong></h2>
<blockquote>
<p>cross-validation은 데이터를 여러 번 섞어서 훈련/평가를 반복하고, 그 평균 성능을 모델의 실력으로 삼는 방법! 실험/공모전/논문/실무에서 모델 비교, 파라미터 튜닝의 표준!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[fit() vs transform() vs fit_transform() 차이점]]></title>
            <link>https://velog.io/@c_haha_e/fit-vs-transform-vs-fittransform-%EC%B0%A8%EC%9D%B4%EC%A0%90</link>
            <guid>https://velog.io/@c_haha_e/fit-vs-transform-vs-fittransform-%EC%B0%A8%EC%9D%B4%EC%A0%90</guid>
            <pubDate>Wed, 13 Aug 2025 12:29:01 GMT</pubDate>
            <description><![CDATA[<h2 id="fit-vs-transform-vs-fit_transform-차이점"><code>fit()</code> vs <code>transform()</code> vs <code>fit_transform()</code> 차이점</h2>
<table>
<thead>
<tr>
<th>메서드</th>
<th>하는 일</th>
<th>사용 시기</th>
</tr>
</thead>
<tbody><tr>
<td><code>fit()</code></td>
<td>데이터를 보고 <strong>학습(파라미터 저장)</strong></td>
<td><strong>처음</strong> 학습할 때</td>
</tr>
<tr>
<td><code>transform()</code></td>
<td>저장한 파라미터로 <strong>변환</strong>만 함</td>
<td><strong>이미 fit된 후</strong>, 새로운 데이터 변환 시</td>
</tr>
<tr>
<td><code>fit_transform()</code></td>
<td><strong>fit + transform</strong> 한 번에 실행</td>
<td>처음 데이터 변환 시 빠르게 처리할 때</td>
</tr>
</tbody></table>
<hr>
<h3 id="예제-1-polynomialfeatures">예제 1: <code>PolynomialFeatures</code></h3>
<pre><code class="language-python">from sklearn.preprocessing import PolynomialFeatures

X = [[2, 3]]

poly = PolynomialFeatures(degree=2)
X_poly = poly.fit_transform(X)
</code></pre>
<ul>
<li><code>fit()</code>은 어떤 조합 항들을 만들어야 할지 규칙(차수, 변수 수 등)을 파악</li>
<li><code>transform()</code>은 그 규칙에 따라 실제 값을 계산</li>
<li>그래서 <code>fit_transform()</code>으로 한 번에 처리 가능 (→ 전처리에서는 주로 많이 씀)</li>
</ul>
<hr>
<h3 id="예제-2-모델-학습-예-linearregression">예제 2: 모델 학습 (예: LinearRegression)</h3>
<pre><code class="language-python">from sklearn.linear_model import LinearRegression

model = LinearRegression()
model.fit(X_train, y_train)      # 학습
pred = model.predict(X_test)     # 예측
</code></pre>
<ul>
<li><code>fit()</code>은 모델이 가중치 학습하는 과정</li>
<li><code>transform()</code>은 없음 (회귀 모델은 변환하는 게 아니라 예측만 함)</li>
<li>따라서 이 경우엔 <strong><code>fit()</code>만</strong> 사용하고, 나중에 *<code>predict()</code>를 씁니다</li>
</ul>
<hr>
<h2 id="전처리기-vs-모델-비교-요약">전처리기 vs 모델 비교 요약</h2>
<table>
<thead>
<tr>
<th>타입</th>
<th>예시</th>
<th><code>fit()</code> 필요?</th>
<th><code>transform()</code> 있음?</th>
<th><code>fit_transform()</code> 사용?</th>
</tr>
</thead>
<tbody><tr>
<td>전처리기</td>
<td><code>PolynomialFeatures</code>, <code>StandardScaler</code></td>
<td>✅ 예 (파라미터 학습)</td>
<td>✅ 예 (변환용)</td>
<td>✅ 보통 사용</td>
</tr>
<tr>
<td>모델</td>
<td><code>LinearRegression</code>, <code>LogisticRegression</code>, <code>SVC</code></td>
<td>✅ 예 (가중치 학습)</td>
<td>❌ 없음</td>
<td>❌ 사용 안 함</td>
</tr>
</tbody></table>
<hr>
<h2 id="자주-쓰는-전처리기-정리">자주 쓰는 전처리기 정리</h2>
<table>
<thead>
<tr>
<th>클래스</th>
<th>설명</th>
<th>fit 필요?</th>
<th>transform 있음?</th>
</tr>
</thead>
<tbody><tr>
<td><code>PolynomialFeatures</code></td>
<td>다항 특성 생성</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td><code>StandardScaler</code></td>
<td>평균 0, 표준편차 1 정규화</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td><code>MinMaxScaler</code></td>
<td>0~1 스케일링</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td><code>PCA</code></td>
<td>차원 축소</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td><code>OneHotEncoder</code></td>
<td>범주형 인코딩</td>
<td>✅</td>
<td>✅</td>
</tr>
</tbody></table>
<p>이 전처리기들은 <strong>fit → transform</strong>이 필요하기 때문에,</p>
<p><strong><code>fit_transform()</code>을 자주 사용</strong>합니다.</p>
<hr>
<h2 id="정리-요약">정리 요약</h2>
<table>
<thead>
<tr>
<th>질문</th>
<th>답변</th>
</tr>
</thead>
<tbody><tr>
<td><code>fit()</code>은 언제?</td>
<td>데이터를 보고 규칙(평균, 차수 등)을 학습할 때</td>
</tr>
<tr>
<td><code>transform()</code>은 언제?</td>
<td>학습된 규칙으로 변환할 때</td>
</tr>
<tr>
<td><code>fit_transform()</code>은 언제?</td>
<td>둘 다 처음에 한 번에 처리하고 싶을 때</td>
</tr>
<tr>
<td>모델은?</td>
<td>주로 <code>fit()</code>만 하고, 나중엔 <code>predict()</code>만 함</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[머신러닝 - [2단계] 모델 익히기 ]]></title>
            <link>https://velog.io/@c_haha_e/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-2%EB%8B%A8%EA%B3%84-%EB%AA%A8%EB%8D%B8-%EC%9D%B5%ED%9E%88%EA%B8%B0</link>
            <guid>https://velog.io/@c_haha_e/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-2%EB%8B%A8%EA%B3%84-%EB%AA%A8%EB%8D%B8-%EC%9D%B5%ED%9E%88%EA%B8%B0</guid>
            <pubDate>Tue, 12 Aug 2025 16:00:50 GMT</pubDate>
            <description><![CDATA[<h2 id="전체-분류-요약">전체 분류 요약</h2>
<table>
<thead>
<tr>
<th>분류</th>
<th>포함 모델</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>회귀 모델</strong></td>
<td>Linear, Ridge, Lasso, SVR, XGBoostRegressor 등</td>
<td><strong>숫자 예측</strong> 목적 (ex. 집값)</td>
</tr>
<tr>
<td><strong>분류 모델</strong></td>
<td>Logistic, RandomForest, CatBoost, SVM, KNN 등</td>
<td><strong>카테고리 분류</strong> 목적 (ex. 스팸 여부)</td>
</tr>
<tr>
<td><strong>비지도 학습</strong></td>
<td>KMeans, DBSCAN, PCA, TSNE 등</td>
<td>정답 없이 <strong>구조/군집/차원</strong> 탐색</td>
</tr>
<tr>
<td><strong>앙상블</strong></td>
<td>RandomForest, GradientBoosting, Voting, Stacking 등</td>
<td>여러 모델 결합으로 성능 향상</td>
</tr>
<tr>
<td><strong>신경망 기반</strong></td>
<td>MLPClassifier/Regressor</td>
<td>기초적인 다층 퍼셉트론 모델</td>
</tr>
<tr>
<td><strong>기타 도구</strong></td>
<td>DummyClassifier, GridSearchCV 등</td>
<td>비교, 평가, 튜닝용</td>
</tr>
</tbody></table>
<h2 id="제외되는-것-머신러닝-x">제외되는 것 (머신러닝 X)</h2>
<table>
<thead>
<tr>
<th>타입</th>
<th>예시</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td>딥러닝 전용</td>
<td>CNN, RNN, BERT</td>
<td>일반 머신러닝보다는 딥러닝 범주</td>
</tr>
<tr>
<td>규칙 기반 시스템</td>
<td>if-else, 룰 엔진</td>
<td>학습이 아닌 직접 규칙 지정</td>
</tr>
<tr>
<td>통계모델</td>
<td>ARIMA, OLS</td>
<td>통계적 추정 기반, 머신러닝과 다소 다름</td>
</tr>
</tbody></table>
<h2 id="회귀-regression-모델">회귀 (Regression) 모델</h2>
<table>
<thead>
<tr>
<th>모델명</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Ridge Regression</strong></td>
<td>선형 회귀 + <strong>L2 정규화</strong> (과적합 방지)</td>
</tr>
<tr>
<td><strong>Lasso Regression</strong></td>
<td>선형 회귀 + <strong>L1 정규화</strong> (불필요한 변수 제거)</td>
</tr>
<tr>
<td><strong>ElasticNet</strong></td>
<td>Ridge + Lasso 혼합</td>
</tr>
<tr>
<td><strong>SVR</strong></td>
<td>SVM 기반 회귀 (마진 기반 회귀)</td>
</tr>
<tr>
<td><strong>GradientBoostingRegressor</strong></td>
<td>부스팅 기반 회귀 (예측 성능 높음)</td>
</tr>
<tr>
<td><strong>XGBoostRegressor / LightGBMRegressor</strong></td>
<td>고성능 부스팅 회귀</td>
</tr>
<tr>
<td><strong>KNeighborsRegressor</strong></td>
<td>KNN의 회귀 버전</td>
</tr>
</tbody></table>
<h3 id="회귀">회귀</h3>
<h1 id="ridge-regression">Ridge Regression</h1>
<p><strong>개념</strong></p>
<ul>
<li>선형 회귀 + <strong>L2 정규화</strong></li>
<li>계수를 작게 만들어 <strong>과적합 방지</strong></li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>다중공선성(피처 간 상관)이 있을 때 효과적</li>
<li>계수 전체를 줄이되 제거는 하지 않음</li>
</ul>
<p><strong>언제 사용하나?</strong></p>
<ul>
<li>피처가 많고, 과적합이 우려될 때</li>
<li>변수 제거보다 <strong>안정적인 예측</strong>이 중요할 때</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">from sklearn.linear_model import Ridge
model = Ridge(alpha=1.0)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<p><strong>결과</strong> </p>
<pre><code class="language-python">[1.53, 2.15, 2.88, 3.02, 2.61]</code></pre>
<hr>
<h1 id="lasso-regression">Lasso Regression</h1>
<p><strong>개념</strong></p>
<ul>
<li>선형 회귀 + <strong>L1 정규화</strong></li>
<li>일부 계수를 0으로 만들어 <strong>변수 선택 기능</strong></li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>중요한 피처만 남기는 데 유용</li>
<li>과적합 + 차원 축소 효과</li>
</ul>
<p><strong>언제 사용하나?</strong></p>
<ul>
<li>고차원 데이터</li>
<li>중요 피처만 뽑아내고 싶을 때</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">from sklearn.linear_model import Lasso
model = Lasso(alpha=0.1)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<p><strong>결과</strong></p>
<pre><code class="language-python">[1.47, 2.12, 2.76, 3.00, 2.54]</code></pre>
<hr>
<h1 id="elasticnet">ElasticNet</h1>
<p><strong>개념</strong></p>
<ul>
<li><strong>L1 + L2</strong> 혼합한 정규화 회귀</li>
<li>Lasso와 Ridge의 중간 모델</li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>Lasso처럼 변수 선택</li>
<li>Ridge처럼 안정성 확보</li>
</ul>
<p><strong>언제 사용하나?</strong></p>
<ul>
<li>피처가 많고 일부는 중요할 때</li>
<li>Lasso와 Ridge 사이에서 절충점을 찾고 싶을 때</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">from sklearn.linear_model import ElasticNet
model = ElasticNet(alpha=0.1, l1_ratio=0.5)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<p><strong>결과</strong></p>
<pre><code class="language-python">[1.50, 2.10, 2.80, 2.95, 2.57]</code></pre>
<hr>
<h1 id="svr-support-vector-regressor">SVR (Support Vector Regressor)</h1>
<p><strong>개념</strong></p>
<ul>
<li><strong>SVM의 회귀 버전</strong></li>
<li>마진 내 오차는 무시, 마진 바깥 오차만 패널티(<strong>모든 데이터를 정확히 맞추는 것보다, ε (엡실론) 오차 내에 들어오면 그걸 무시하고</strong>, 최대한 평탄한(일반화된) 모델을 만드는 것)</li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>안정성 있음</li>
<li>커널로 비선형 회귀 가능</li>
<li>학습 느릴 수 있음</li>
</ul>
<p><strong>언제 사용하나?</strong></p>
<ul>
<li><p><strong>고차원 소규모 데이터셋</strong>에 적합</p>
</li>
<li><p>마진 기반 예측이 필요할 때</p>
</li>
<li><p><strong>비선형 회귀</strong>가 필요한 경우 → 커널 트릭(kernel trick) 사용 가능</p>
</li>
<li><p><strong>이상치가 일부 있는 회귀 문제</strong>에서 사용 (ε 튜브로 무시 가능)</p>
</li>
<li><p>일반적으로 <strong>성능은 좋지만 느릴 수 있음</strong> (큰 데이터에 비효율적)</p>
</li>
<li><p><strong>자세히</strong></p>
<h2 id="예시로-이해하기">예시로 이해하기</h2>
<h3 id="원래-데이터-저차원-비선형">원래 데이터 (저차원, 비선형)</h3>
<pre><code class="language-python">  X = [[-2], [-1], [0], [1], [2]]
  y = [4, 1, 0, 1, 4]  # 즉, y = x² 형태</code></pre>
<p>  이 데이터를 선형 회귀로는 맞출 수 없음</p>
<p>  하지만 <strong>SVR(kernel=&#39;rbf&#39;)</strong> 을 사용하면 내부적으로 고차원 공간으로 옮겨서 다음처럼 동작</p>
<ul>
<li><p><code>X</code>는 그대로지만, 내부적으로 $x \rightarrow x^2$ 변환한 후 선형 SVR 수행</p>
<p>결과적으로 비선형 회귀처럼 작동</p>
<h2 id="svr의-주요-커널-종류">SVR의 주요 커널 종류</h2>
<table>
<thead>
<tr>
<th>커널 이름</th>
<th>설명</th>
<th>사용 예</th>
</tr>
</thead>
<tbody><tr>
<td><code>&#39;linear&#39;</code></td>
<td>선형 회귀 (직선)</td>
<td>단순한 관계</td>
</tr>
<tr>
<td><code>&#39;poly&#39;</code></td>
<td>다항 회귀 (곡선)</td>
<td>곡선 형태 데이터</td>
</tr>
<tr>
<td><code>&#39;rbf&#39;</code></td>
<td>가우시안 커널 (비선형 대응 가장 강력)</td>
<td>대부분 비선형 상황에서 기본 선택</td>
</tr>
<tr>
<td><code>&#39;sigmoid&#39;</code></td>
<td>신경망 유사 커널</td>
<td>실험적 사용</td>
</tr>
</tbody></table>
<h2 id="rbf-커널-사용한-비선형-회귀">RBF 커널 사용한 비선형 회귀</h2>
<pre><code class="language-python">import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVR

# 비선형 데이터
X = np.linspace(-5, 5, 100).reshape(-1, 1)
y = np.sin(X).ravel()

# SVR with RBF kernel
svr_rbf = SVR(kernel=&#39;rbf&#39;, C=100, epsilon=0.1)
svr_rbf.fit(X, y)
y_pred = svr_rbf.predict(X)

# 시각화
plt.plot(X, y, label=&#39;True Function (sin)&#39;, color=&#39;gray&#39;)
plt.plot(X, y_pred, label=&#39;SVR with RBF Kernel&#39;, color=&#39;red&#39;)
plt.legend()
plt.title(&quot;비선형 회귀 with 커널 트릭&quot;)
plt.show()
</code></pre>
<h2 id="c-파라미터의-뜻"><code>C</code> 파라미터의 뜻</h2>
<blockquote>
<p>C는 오차에 대한 패널티의 크기(엄격함)를 결정하는 값</p>
</blockquote>
</li>
<li><p><strong>C 값이 클수록</strong>:</p>
<p>  → ε 범위를 벗어난 오차를 <strong>엄하게 처벌</strong>함</p>
<p>  → <strong>오차를 줄이려는 경향</strong>이 강함 → 훈련 데이터에 더 민감함 → <strong>과적합(overfitting) 위험</strong> 증가</p>
</li>
<li><p><strong>C 값이 작을수록</strong>:</p>
<p>  → ε 범위를 벗어난 오차를 <strong>관대하게 허용</strong>함</p>
<p>  → <strong>일반화 성능</strong>이 좋아짐 (훈련 데이터에 덜 민감함) → <strong>과소적합(underfitting) 가능성</strong></p>
</li>
</ul>
</li>
</ul>
<pre><code>## `epsilon`: **오차 무시 범위 (ε-튜브의 폭)**

&gt; 예측값이 실제값과 ε 이내로 차이가 나면, 그 오차는 벌점 없이 무시
&gt; 

즉, SVR은 모든 오차를 줄이는 게 아니라, &quot;ε만큼은 무시하고 넘어가자&quot;는 방식

---

### 예시

```python
SVR(epsilon=0.1)  # 0.1 만큼의 오차는 그냥 무시
```

- ε=0.1 → 실제값과 예측값이 0.1보다 작게 차이 나면 &quot;잘 맞춘 거&quot;로 간주
- ε가 작을수록 → 더 민감하게 맞추려 함
- ε가 클수록 → 더 많은 오차를 무시 → 더 부드러운 모델

---

### 시각적 설명

| epsilon 값 | 설명 | 예측 결과 |
| --- | --- | --- |
| ε = 0.01 | 거의 모든 데이터 포인트를 감싸려 함 | 복잡하고 민감한 회귀선 |
| ε = 0.5 | 많은 오차를 무시하고, 부드럽고 단순한 회귀선 | 일반화 ↑ |

## `gamma`: **RBF 커널에서 거리의 영향력**

&gt; 커널 함수(RBF 등)에서 하나의 데이터 포인트가 영향을 미치는 범위를 결정
&gt; 

**RBF 커널 함수 정의**:

$K(x_i, x_j) = \exp(-\gamma \|x_i - x_j\|^2)$

→ `gamma`는 **데이터 간의 거리 차이를 얼마나 민감하게 볼 것인가**를 결정

---

### gamma 해석

| gamma 값 | 설명 | 결과 |
| --- | --- | --- |
| **작은 값 (e.g. 0.01)** | 넓은 범위의 데이터를 참고함 | 더 부드럽고 단순 |
| **큰 값 (e.g. 10)** | 가까운 데이터에만 반응 | 복잡하고 민감 (과적합 가능) |

---

### 실습 예

```python
from sklearn.svm import SVR

SVR(kernel=&#39;rbf&#39;, gamma=0.1)  # RBF 커널의 반응 범위 설정
```

- `gamma=0.1` → 곡선이 부드럽고 천천히 변화
- `gamma=100` → 아주 민감하게 휘어짐, 노이즈에 민감 → 과적합 가능

## 요약

| 하이퍼파라미터 | 역할 | 영향 |
| --- | --- | --- |
| **C** | ε를 벗어난 오차에 대한 패널티 강도 | ↑: 과적합 가능 / ↓: 과소적합 가능 |
| **epsilon** | 오차를 무시할 수 있는 범위 (ε-튜브 폭) | ↑: 더 많은 오차 무시 / ↓: 더 민감 |
| **gamma** | RBF 커널에서 영향 범위 (곡선의 유연성) | ↑: 복잡, 민감 / ↓: 단순, 부드러움 |</code></pre><hr>
<h1 id="gradientboostingregressor">GradientBoostingRegressor</h1>
<p><strong>개념</strong></p>
<ul>
<li>약한 트리 모델을 순차적으로 학습시켜 <strong>오차 보정</strong></li>
<li>부스팅 기법</li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>고성능 예측</li>
<li>과적합에 강함</li>
<li>느리지만 성능 우수</li>
</ul>
<p><strong>언제 사용하나?</strong></p>
<ul>
<li>고정밀 회귀</li>
<li>트리 기반이 유리한 데이터셋</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">from sklearn.ensemble import GradientBoostingRegressor
model = GradientBoostingRegressor(n_estimators=100)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<p><strong>결과 예시</strong></p>
<pre><code class="language-python">[1.55, 2.18, 2.89, 3.01, 2.65]</code></pre>
<ul>
<li><p><strong>n_estimators</strong></p>
<h2 id="n_estimators란">n_estimators란?</h2>
<blockquote>
<p>“모델 안에 몇 개의 결정 트리(decision tree)를 만들 건지”를 뜻</p>
</blockquote>
<p>  즉, n_estimators는 <strong>앙상블을 구성하는 기본 모델(보통 트리)의 개수</strong>를 의미</p>
<h2 id="트리-개수가-많을수록">트리 개수가 많을수록?</h2>
<table>
<thead>
<tr>
<th>n_estimators 값</th>
<th>의미</th>
<th>장단점</th>
</tr>
</thead>
<tbody><tr>
<td><strong>작은 값 (e.g. 10~50)</strong></td>
<td>빠름, 계산 적음</td>
<td>예측 불안정, 성능 낮을 수 있음</td>
</tr>
<tr>
<td><strong>기본값 (100)</strong></td>
<td>적절한 타협</td>
<td>성능/속도 균형</td>
</tr>
<tr>
<td><strong>큰 값 (500~1000)</strong></td>
<td>더 안정적, 과적합 방지 가능</td>
<td>속도 느림, 메모리 사용 ↑</td>
</tr>
</tbody></table>
<blockquote>
<p>주의: 너무 많이 늘려도 성능은 크게 좋아지지 않고 시간만 오래 걸릴 수 있음</p>
</blockquote>
<h2 id="n_estimators가-쓰이는-대표-앙상블-모델들"><code>n_estimators</code>가 쓰이는 대표 앙상블 모델들</h2>
<table>
<thead>
<tr>
<th>모델명</th>
<th>라이브러리</th>
<th>모델 종류</th>
<th><code>n_estimators</code> 의미</th>
</tr>
</thead>
<tbody><tr>
<td><strong>RandomForestClassifier / Regressor</strong></td>
<td><code>sklearn.ensemble</code></td>
<td>배깅 (Bagging)</td>
<td>생성할 결정 트리 수</td>
</tr>
<tr>
<td><strong>BaggingClassifier / Regressor</strong></td>
<td><code>sklearn.ensemble</code></td>
<td>배깅</td>
<td>Base 모델 복사 수</td>
</tr>
<tr>
<td><strong>ExtraTreesClassifier / Regressor</strong></td>
<td><code>sklearn.ensemble</code></td>
<td>배깅 + 완전 랜덤 분할</td>
<td>매우 빠른 랜덤 포레스트</td>
</tr>
<tr>
<td><strong>GradientBoostingClassifier / Regressor</strong></td>
<td><code>sklearn.ensemble</code></td>
<td>부스팅</td>
<td>순차적 학습 단계 수</td>
</tr>
<tr>
<td><strong>AdaBoostClassifier / Regressor</strong></td>
<td><code>sklearn.ensemble</code></td>
<td>부스팅</td>
<td>약한 학습기의 수</td>
</tr>
<tr>
<td><strong>XGBClassifier / XGBRegressor</strong></td>
<td><code>xgboost</code></td>
<td>부스팅</td>
<td>트리 개수</td>
</tr>
<tr>
<td><strong>LGBMClassifier / LGBMRegressor</strong></td>
<td><code>lightgbm</code></td>
<td>부스팅</td>
<td>트리 개수</td>
</tr>
<tr>
<td><strong>CatBoostClassifier / Regressor</strong></td>
<td><code>catboost</code></td>
<td>부스팅</td>
<td>트리 개수</td>
</tr>
<tr>
<td><strong>HistGradientBoostingClassifier / Regressor</strong></td>
<td><code>sklearn.ensemble</code></td>
<td>고속 히스토그램 기반 부스팅</td>
<td>트리 개수</td>
</tr>
</tbody></table>
</li>
</ul>
<hr>
<h1 id="xgboostregressor">XGBoostRegressor</h1>
<p><strong>개념</strong></p>
<ul>
<li>Gradient Boosting 개선 버전</li>
<li>속도 + 성능 모두 우수</li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>정형 데이터 대회에서 자주 사용</li>
<li>과적합 제어 기능 탁월</li>
</ul>
<p><strong>언제 사용하나?</strong></p>
<ul>
<li>대규모 데이터</li>
<li>대회용/실무용 예측 모델</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">from xgboost import XGBRegressor
model = XGBRegressor(n_estimators=100)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<p><strong>결과 예시</strong></p>
<pre><code class="language-python">[1.57, 2.21, 2.91, 3.03, 2.66]</code></pre>
<hr>
<h1 id="lightgbmregressor">LightGBMRegressor</h1>
<p><strong>개념</strong></p>
<ul>
<li>XGBoost보다 <strong>더 빠르고 메모리 효율적인 부스팅 모델</strong></li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>고속 학습</li>
<li>대규모/고차원 데이터 처리에 탁월</li>
</ul>
<p><strong>언제 사용하나?</strong></p>
<ul>
<li>XGBoost보다 더 빠른 학습이 필요할 때</li>
<li>실시간 예측 환경</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">
from lightgbm import LGBMRegressor
model = LGBMRegressor(n_estimators=100)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<p><strong>결과</strong></p>
<pre><code class="language-python">[1.56, 2.20, 2.88, 3.02, 2.64]</code></pre>
<hr>
<h1 id="kneighborsregressor">KNeighborsRegressor</h1>
<p><strong>개념</strong></p>
<ul>
<li><strong>KNN의 회귀 버전</strong></li>
<li>주변 K개의 평균값으로 예측</li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>단순하고 직관적</li>
<li>정규화 필요</li>
<li>느릴 수 있음 (lazy learner)</li>
</ul>
<p><strong>언제 사용하나?</strong></p>
<ul>
<li>소규모, 복잡한 형태의 데이터</li>
<li>선형 관계가 없을 때</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">from sklearn.neighbors import KNeighborsRegressor
model = KNeighborsRegressor(n_neighbors=5)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<p><strong>결과</strong> </p>
<pre><code class="language-python">[1.49, 2.16, 2.77, 2.95, 2.60]</code></pre>
<ul>
<li><p><strong>지도학습 + 앙상블</strong></p>
<ul>
<li><p>Random Forest</p>
<h1 id="random-forest">Random Forest</h1>
<blockquote>
<p>Random Forest는 여러 개의 결정 트리를 만들고 그 결과를 앙상블하여 예측하는 지도학습 모델</p>
<p>Bagging 기반 앙상블 기법이며, <strong>과적합을 줄이고 예측 성능을 높이는 데 매우 강력</strong>.</p>
</blockquote>
<hr>
<table>
<thead>
<tr>
<th>용어</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Tree</strong></td>
<td>결정 트리 (Decision Tree) 하나</td>
</tr>
<tr>
<td><strong>Forest</strong></td>
<td>여러 트리를 모은 숲 → 여러 모델의 앙상블</td>
</tr>
<tr>
<td><strong>Random</strong></td>
<td>트리를 만들 때 <strong>데이터와 피처를 랜덤하게 샘플링</strong>해서 다양성을 확보</td>
</tr>
</tbody></table>
<hr>
<h2 id="작동-원리">작동 원리</h2>
<h3 id="핵심-bagging-bootstrap-aggregating">핵심: <strong>Bagging (Bootstrap Aggregating)</strong></h3>
<ol>
<li><p>원본 데이터에서 중복 허용 샘플링 (bootstrap)</p>
</li>
<li><p>각 샘플로 <strong>결정 트리</strong> 학습</p>
</li>
<li><p>예측 시:</p>
<ul>
<li><strong>분류</strong>: 트리들의 <strong>다수결</strong></li>
<li><strong>회귀</strong>: 트리들의 <strong>평균값</strong></li>
</ul>
<h3 id="➕-추가로-random-forest는">➕ 추가로 Random Forest는…</h3>
</li>
</ol>
<ul>
<li><strong>각 노드 분할 시 사용할 피처도 랜덤하게 선택</strong> → 트리 간 상관성↓, 분산↓</li>
<li>이것이 <strong>&quot;Random&quot;</strong> Forest의 핵심 차별점</li>
</ul>
<hr>
<h2 id="분류-vs-회귀에서의-작동">분류 vs 회귀에서의 작동</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>분류 (RandomForestClassifier)</th>
<th>회귀 (RandomForestRegressor)</th>
</tr>
</thead>
<tbody><tr>
<td>예측값</td>
<td>클래스 (0, 1, 2...)</td>
<td>연속적인 수치 (실수)</td>
</tr>
<tr>
<td>결합 방식</td>
<td>다수결 (majority vote)</td>
<td>평균 (mean)</td>
</tr>
<tr>
<td>출력 함수</td>
<td><code>predict_proba()</code>, <code>predict()</code></td>
<td><code>predict()</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="장단점">장단점</h2>
<table>
<thead>
<tr>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>과적합에 강함 (트리 평균 덕분)</td>
<td>모델 크기 큼 (트리 많음)</td>
</tr>
<tr>
<td>특성 중요도 파악 가능</td>
<td>예측 해석 어려움 (블랙박스)</td>
</tr>
<tr>
<td>높은 정확도</td>
<td>느릴 수 있음 (트리 많으면)</td>
</tr>
<tr>
<td>결측치·스케일링 영향 적음</td>
<td>고차원 데이터선 느림</td>
</tr>
</tbody></table>
<hr>
<h2 id="수식구조-요약">수식/구조 요약</h2>
<h3 id="예측-함수">예측 함수</h3>
<ul>
<li><p>회귀일 때:</p>
<p>$\hat{y} = \frac{1}{n} \sum_{i=1}^{n} T_i(x)$</p>
</li>
<li><p>분류일 때:</p>
<p>$\hat{y} = \mathrm{mode} { T_1(x), T_2(x), \dots, T_n(x) }$</p>
<p>여기서 Ti(x)T_i(x)Ti(x)는 i번째 결정 트리의 예측 결과</p>
</li>
</ul>
<hr>
<h2 id="파라미터-설명">파라미터 설명</h2>
<table>
<thead>
<tr>
<th>파라미터</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>n_estimators</code></td>
<td>트리의 개수 (많을수록 성능↑, 속도↓)</td>
</tr>
<tr>
<td><code>max_depth</code></td>
<td>각 트리의 최대 깊이</td>
</tr>
<tr>
<td><code>max_features</code></td>
<td>노드 분할 시 고려할 최대 피처 수</td>
</tr>
<tr>
<td><code>bootstrap</code></td>
<td>부트스트랩 샘플링 여부 (True 권장)</td>
</tr>
<tr>
<td><code>random_state</code></td>
<td>랜덤 시드 고정</td>
</tr>
<tr>
<td><code>n_jobs</code></td>
<td>병렬 처리 사용 개수 (-1이면 모든 코어 사용)</td>
</tr>
</tbody></table>
<hr>
<h2 id="예시">예시</h2>
<h3 id="1-분류-randomforestclassifier">(1) 분류: RandomForestClassifier</h3>
<pre><code class="language-python">
  from sklearn.ensemble import RandomForestClassifier
  from sklearn.datasets import load_iris
  from sklearn.model_selection import train_test_split

  X, y = load_iris(return_X_y=True)
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

  model = RandomForestClassifier(n_estimators=100, random_state=42)
  model.fit(X_train, y_train)

  print(&quot;예측 결과:&quot;, model.predict(X_test))
  print(&quot;정확도:&quot;, model.score(X_test, y_test))
</code></pre>
<hr>
<h3 id="2-회귀-randomforestregressor">(2) 회귀: RandomForestRegressor</h3>
<pre><code class="language-python">
  from sklearn.ensemble import RandomForestRegressor
  from sklearn.datasets import make_regression

  X, y = make_regression(n_samples=1000, n_features=10, noise=10)
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

  model = RandomForestRegressor(n_estimators=100, random_state=42)
  model.fit(X_train, y_train)

  from sklearn.metrics import r2_score
  y_pred = model.predict(X_test)
  print(&quot;R2 Score:&quot;, r2_score(y_test, y_pred))
</code></pre>
<hr>
<h2 id="특성-중요도feature-importance">특성 중요도(Feature Importance)</h2>
<pre><code class="language-python">
  import matplotlib.pyplot as plt

  importances = model.feature_importances_
  plt.bar(range(len(importances)), importances)
  plt.title(&quot;Feature Importances&quot;)
  plt.show()
</code></pre>
<p>  → 어떤 피처가 예측에 영향을 많이 줬는지 시각적으로 파악 가능</p>
<hr>
<h2 id="언제-쓰면-좋을까">언제 쓰면 좋을까?</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td>과적합 위험이 있는 트리 모델</td>
<td>여러 트리 평균으로 완화</td>
</tr>
<tr>
<td>해석보단 성능이 중요한 경우</td>
<td>앙상블이 정확도 높음</td>
</tr>
<tr>
<td>피처 수 많거나 이상치 있음</td>
<td>트리는 자동 처리에 강함</td>
</tr>
<tr>
<td>기본 베이스라인 모델로</td>
<td>튜닝 없이도 잘 동작함</td>
</tr>
</tbody></table>
<hr>
<h2 id="정리-요약">정리 요약</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>분류</td>
<td><code>RandomForestClassifier</code></td>
</tr>
<tr>
<td>회귀</td>
<td><code>RandomForestRegressor</code></td>
</tr>
<tr>
<td>핵심 기법</td>
<td>Bagging + Random Subspace</td>
</tr>
<tr>
<td>결합 방식</td>
<td>다수결 or 평균</td>
</tr>
<tr>
<td>트리 수</td>
<td><code>n_estimators</code>로 설정</td>
</tr>
<tr>
<td>장점</td>
<td>과적합 방지, 성능 높음, 중요도 출력</td>
</tr>
<tr>
<td>단점</td>
<td>느림, 블랙박스 해석 어려움</td>
</tr>
</tbody></table>
</li>
<li><p>Gradient Boosting</p>
<h1 id="gradient-boosting-그래디언트-부스팅">Gradient Boosting (그래디언트 부스팅)</h1>
<blockquote>
<p>Gradient Boosting은 약한 모델(보통 얕은 트리)을 순차적으로 학습시켜 오차를 줄여가는 방식의 앙상블 학습법</p>
</blockquote>
<ul>
<li><strong>Boosting</strong>: 모델을 <strong>순차적으로</strong> 쌓으며 보완</li>
<li><strong>Gradient</strong>: 오차(loss)의 <strong>기울기(gradient)</strong>를 따라 보완 방향을 결정</li>
</ul>
<hr>
<table>
<thead>
<tr>
<th>분류 기준</th>
<th>포함 여부</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>지도학습</strong></td>
<td>✅</td>
<td>X → y 예측</td>
</tr>
<tr>
<td><strong>앙상블 학습</strong></td>
<td>✅</td>
<td>여러 모델을 결합</td>
</tr>
<tr>
<td><strong>Boosting 방식</strong></td>
<td>✅</td>
<td>순차적으로 모델을 학습시킴</td>
</tr>
</tbody></table>
<hr>
<h2 id="핵심-개념-boosting">핵심 개념 (Boosting)</h2>
<ul>
<li>여러 약한 모델(weak learner)을 순차적으로 학습</li>
<li>각 모델은 이전 모델의 <strong>오차를 보완</strong></li>
<li>최종 예측은 모든 모델의 예측을 <strong>가중 합</strong></li>
</ul>
<hr>
<h2 id="작동-순서">작동 순서</h2>
<h3 id="예시-회귀-문제-기준">예시: 회귀 문제 기준</h3>
<ol>
<li>처음에는 단순한 예측 (예: 평균값)</li>
<li>오차(잔차 residual)를 계산</li>
<li>그 오차를 잘 예측하는 <strong>결정 트리 모델</strong>을 하나 학습</li>
<li>새 예측 = 기존 예측 + 학습된 트리의 출력</li>
<li>다시 오차 계산 → 또 트리 학습 → 반복…</li>
</ol>
<hr>
<h2 id="수식적으로-설명">수식적으로 설명</h2>
<h3 id="최종-예측-함수final-prediction-function">최종 예측 함수(Final Prediction Function)</h3>
<p>  $\hat{y} = F_M(x) = \sum_{m=1}^{M} \gamma_m h_m(x)$</p>
<ul>
<li><p>$h_m(x)$: m번째 약한 모델 (보통 결정 트리)</p>
</li>
<li><p>$γm$: 학습률(learning rate)</p>
</li>
<li><p>$F_M(x)$: M번째 단계까지 누적된 최종 예측값</p>
<h3 id="각-단계에서-학습-목표-잔차--기울기">각 단계에서 학습 목표 (잔차 = 기울기)</h3>
<p>$r_i^{(m)} = -\left[ \frac{\partial L(y_i, F(x_i))}{\partial F(x_i)} \right]{F(x)=F{m-1}(x)}$</p>
</li>
<li><p>$r_i^{(m)}$  :  i번째 데이터 샘플에 대한 손실 함수의 <strong>기울기 (잔차)</strong></p>
</li>
<li><p>${L(y_i, F(x_i))}$  :  손실 함수 (예: MSE, 로그손실 등)</p>
</li>
<li><p>${F_{m-1}(x)}$  :  이전 단계까지의 누적 예측</p>
<p>→ 이 <strong>잔차를 예측하도록</strong> $hm(x)$ (새로운 트리) 를 학습</p>
<p>→ 그래서 이름이 <strong>Gradient</strong> Boosting (기울기를 따라가며 개선)</p>
</li>
</ul>
<hr>
<h2 id="장점과-단점">장점과 단점</h2>
<table>
<thead>
<tr>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>높은 예측 성능</td>
<td>학습 시간 오래 걸림</td>
</tr>
<tr>
<td>다양한 손실 함수 사용 가능</td>
<td>과적합 가능성 있음 (너무 깊거나 많으면)</td>
</tr>
<tr>
<td>특성 중요도 파악 가능</td>
<td>직관적 해석 어려움</td>
</tr>
<tr>
<td>회귀, 분류 모두 가능</td>
<td>하이퍼파라미터 튜닝 필요</td>
</tr>
</tbody></table>
<hr>
<h2 id="주요-하이퍼파라미터">주요 하이퍼파라미터</h2>
<table>
<thead>
<tr>
<th>파라미터</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>n_estimators</code></td>
<td>학습할 트리 개수</td>
</tr>
<tr>
<td><code>learning_rate</code></td>
<td>학습률 (각 트리 기여 정도)</td>
</tr>
<tr>
<td><code>max_depth</code></td>
<td>트리의 최대 깊이</td>
</tr>
<tr>
<td><code>loss</code></td>
<td>손실 함수 (회귀: MSE, 분류: log-loss 등)</td>
</tr>
<tr>
<td><code>subsample</code></td>
<td>샘플 일부만 학습 (과적합 방지용)</td>
</tr>
</tbody></table>
<hr>
<h2 id="예시-gradientboostingregressor">예시 (GradientBoostingRegressor)</h2>
<pre><code class="language-python">
  from sklearn.ensemble import GradientBoostingRegressor
  from sklearn.datasets import make_regression
  from sklearn.model_selection import train_test_split
  from sklearn.metrics import r2_score

  # 데이터 생성
  X, y = make_regression(n_samples=1000, n_features=10, noise=15)
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

  # 모델 학습
  model = GradientBoostingRegressor(n_estimators=100, learning_rate=0.1, max_depth=3)
  model.fit(X_train, y_train)

  # 예측 및 평가
  y_pred = model.predict(X_test)
  print(&quot;R2 Score:&quot;, r2_score(y_test, y_pred))</code></pre>
<hr>
<h2 id="다른-boosting-계열과의-비교">다른 Boosting 계열과의 비교</h2>
<table>
<thead>
<tr>
<th>모델</th>
<th>특징</th>
<th>라이브러리</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Gradient Boosting (GBM)</strong></td>
<td>기본적인 부스팅 모델</td>
<td><code>sklearn</code></td>
</tr>
<tr>
<td><strong>XGBoost</strong></td>
<td>속도 향상 + 정규화 추가</td>
<td><code>xgboost</code></td>
</tr>
<tr>
<td><strong>LightGBM</strong></td>
<td>대용량 데이터에 특화, 속도 매우 빠름</td>
<td><code>lightgbm</code></td>
</tr>
<tr>
<td><strong>CatBoost</strong></td>
<td>범주형 자동 처리</td>
<td><code>catboost</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="실전-사용-시-팁">실전 사용 시 팁</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>추천 설정</th>
</tr>
</thead>
<tbody><tr>
<td>과적합 우려</td>
<td><code>learning_rate ↓</code>, <code>n_estimators ↑</code></td>
</tr>
<tr>
<td>훈련 속도 느릴 때</td>
<td><code>subsample &lt; 1.0</code>, <code>max_depth ↓</code></td>
</tr>
<tr>
<td>변수 중요도 분석</td>
<td><code>feature_importances_</code> 사용</td>
</tr>
<tr>
<td>파라미터 튜닝</td>
<td><code>GridSearchCV</code> or <code>RandomizedSearchCV</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="요약">요약</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>학습 방식</td>
<td>지도학습 + Boosting 앙상블</td>
</tr>
<tr>
<td>구성 모델</td>
<td>결정 트리(보통 작은 트리)</td>
</tr>
<tr>
<td>결합 방식</td>
<td>잔차 보완식 순차 학습</td>
</tr>
<tr>
<td>최종 예측</td>
<td>모든 트리의 출력값 가중합</td>
</tr>
<tr>
<td>대표 구현</td>
<td><code>GradientBoostingRegressor</code>, <code>GradientBoostingClassifier</code></td>
</tr>
<tr>
<td>대표 라이브러리</td>
<td><code>sklearn</code>, <code>xgboost</code>, <code>lightgbm</code>, <code>catboost</code></td>
</tr>
</tbody></table>
</li>
<li><p>XGBoost</p>
<h1 id="xgboost-extreme-gradient-boosting">XGBoost (eXtreme Gradient Boosting)</h1>
<blockquote>
<p>XGBoost는 여러 약한 결정 트리를 순차적으로 학습하고, 잔차를 줄이도록 가중 합산하는</p>
<p><strong>Boosting 기반의 고성능 앙상블 모델</strong></p>
<p>Gradient Boosting에 <strong>정규화 + 병렬화 + 가지치기 + 결측처리</strong>를 더해 성능을 극대화한 형태</p>
</blockquote>
<hr>
<h2 id="왜-xgboost">왜 &quot;XGBoost&quot;?</h2>
<table>
<thead>
<tr>
<th>용어</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Boost</strong></td>
<td>이전 모델이 틀린 걸 고쳐나가는 방식 (잔차 보정)</td>
</tr>
<tr>
<td><strong>Gradient</strong></td>
<td>손실 함수의 기울기를 이용해 최적화</td>
</tr>
<tr>
<td><strong>eXtreme</strong></td>
<td>속도/성능 모두 향상 (병렬화 + 최적화)</td>
</tr>
<tr>
<td><strong>Tree</strong></td>
<td>약한 학습기로 CART 트리 사용</td>
</tr>
</tbody></table>
<hr>
<h2 id="작동-원리-1">작동 원리</h2>
<p>  <strong>Gradient Boosting + 정규화 + 병렬 분할</strong></p>
<p>  잔차(residual)를 예측하도록 다음 트리를 학습</p>
<ul>
<li><p>각 트리는 이전까지의 예측값을 보정함</p>
</li>
<li><p>트리마다 분할 기준은 <strong>손실 감소 + 복잡도 규제</strong>를 같이 고려</p>
</li>
<li><p>학습은 다음과 같은 방식으로 이뤄짐:</p>
<p>$\hat{y}_i^{(t)} = \hat{y}_i^{(t-1)} + \eta \cdot f_t(x_i)$</p>
</li>
</ul>
<hr>
<h2 id="분류-vs-회귀에서의-작동-1">분류 vs 회귀에서의 작동</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>분류 (XGBClassifier)</th>
<th>회귀 (XGBRegressor)</th>
</tr>
</thead>
<tbody><tr>
<td>예측값</td>
<td>클래스</td>
<td>연속 수치</td>
</tr>
<tr>
<td>손실 함수</td>
<td>logloss / softmax</td>
<td>MSE / MAE</td>
</tr>
<tr>
<td>결합 방식</td>
<td>클래스 확률 평균 후 최빈값</td>
<td>예측값 평균</td>
</tr>
<tr>
<td>출력 함수</td>
<td><code>predict_proba()</code> / <code>predict()</code></td>
<td><code>predict()</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="장단점-1">장단점</h2>
<table>
<thead>
<tr>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>높은 정확도</td>
<td>구조 복잡함</td>
</tr>
<tr>
<td>과적합 방지 정규화 내장</td>
<td>해석 어려움</td>
</tr>
<tr>
<td>결측치 자동 처리</td>
<td>학습 시간 긴 경우 있음</td>
</tr>
<tr>
<td>다양한 손실 함수 지원</td>
<td>파라미터 많아 튜닝 필요</td>
</tr>
<tr>
<td>빠른 학습 (C++ 백엔드)</td>
<td>기울기/헤시안 계산 필요</td>
</tr>
</tbody></table>
<hr>
<h2 id="언제-쓰면-좋은가">언제 쓰면 좋은가?</h2>
<table>
<thead>
<tr>
<th>사용 조건</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td>예측 정확도가 매우 중요</td>
<td>캐글 1위 모델 다수</td>
</tr>
<tr>
<td>과적합 걱정되는 복잡한 데이터</td>
<td>정규화 + 가지치기 내장</td>
</tr>
<tr>
<td>대용량 데이터</td>
<td>병렬 처리, GPU 지원</td>
</tr>
<tr>
<td>결측값 존재</td>
<td>자동 처리 지원</td>
</tr>
<tr>
<td>분류, 회귀, 랭킹 문제</td>
<td>전용 손실 함수 지원</td>
</tr>
</tbody></table>
<hr>
<h2 id="내부-동작-구조-요약">내부 동작 구조 요약</h2>
<ul>
<li><p><strong>기본 구조</strong>는 Gradient Boosting과 동일:</p>
<p>  → 오차를 줄이도록 새로운 트리를 순차적으로 추가</p>
</li>
<li><p>하지만 XGBoost는 다음을 추가함:</p>
<ul>
<li>정규화 (L1/L2)</li>
<li>가지치기 (Pruning)</li>
<li>병렬 최적화</li>
<li>2차 테일러 근사</li>
</ul>
</li>
</ul>
<hr>
<h2 id="주요-파라미터">주요 파라미터</h2>
<table>
<thead>
<tr>
<th>파라미터</th>
<th>의미</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>n_estimators</code></td>
<td>트리 수</td>
<td>많을수록 복잡도 ↑</td>
</tr>
<tr>
<td><code>learning_rate</code></td>
<td>학습률</td>
<td>작을수록 안정적</td>
</tr>
<tr>
<td><code>max_depth</code></td>
<td>트리 깊이</td>
<td>깊을수록 복잡</td>
</tr>
<tr>
<td><code>subsample</code></td>
<td>샘플 비율</td>
<td>과적합 방지</td>
</tr>
<tr>
<td><code>colsample_bytree</code></td>
<td>피처 비율</td>
<td>다양성 증가</td>
</tr>
<tr>
<td><code>gamma</code></td>
<td>최소 분할 손실</td>
<td>가지치기 기준</td>
</tr>
<tr>
<td><code>reg_alpha</code>, <code>reg_lambda</code></td>
<td>L1/L2 정규화</td>
<td>과적합 방지</td>
</tr>
</tbody></table>
<hr>
<h2 id="예시-1">예시</h2>
<h3 id="1-회귀용-xgbregressor">(1) 회귀용 XGBRegressor</h3>
<pre><code class="language-python">  python
  복사편집
  from xgboost import XGBRegressor
  from sklearn.datasets import make_regression
  from sklearn.model_selection import train_test_split
  from sklearn.metrics import r2_score

  X, y = make_regression(n_samples=1000, n_features=10, noise=15)
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

  model = XGBRegressor(
      n_estimators=100,
      learning_rate=0.1,
      max_depth=4,
      random_state=42
  )
  model.fit(X_train, y_train)
  y_pred = model.predict(X_test)
  print(&quot;R2 Score:&quot;, r2_score(y_test, y_pred))
</code></pre>
<hr>
<h3 id="2-분류용-xgbclassifier">(2) 분류용 XGBClassifier</h3>
<pre><code class="language-python">  python
  복사편집
  from xgboost import XGBClassifier
  from sklearn.datasets import load_breast_cancer
  from sklearn.model_selection import train_test_split
  from sklearn.metrics import accuracy_score

  X, y = load_breast_cancer(return_X_y=True)
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

  clf = XGBClassifier(
      n_estimators=100,
      max_depth=3,
      learning_rate=0.1,
      use_label_encoder=False,
      eval_metric=&#39;logloss&#39;
  )
  clf.fit(X_train, y_train)
  y_pred = clf.predict(X_test)
  print(&quot;Accuracy:&quot;, accuracy_score(y_test, y_pred))
</code></pre>
<h2 id="특성-중요도-시각화">특성 중요도 시각화</h2>
<pre><code class="language-python">
  from xgboost import plot_importance
  import matplotlib.pyplot as plt

  plot_importance(model)
  plt.title(&quot;Feature Importance&quot;)
  plt.show()
</code></pre>
<h3 id="변수-중요도-확인">변수 중요도 확인</h3>
<pre><code class="language-python">
  from xgboost import plot_importance
  plot_importance(model)
  plt.show()
</code></pre>
<hr>
<h2 id="결과값-해석">결과값 해석</h2>
<table>
<thead>
<tr>
<th>모델</th>
<th>주요 평가 지표</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td>XGBRegressor</td>
<td>R² Score</td>
<td>1에 가까울수록 예측 정확</td>
</tr>
<tr>
<td>XGBClassifier</td>
<td>Accuracy, F1 Score</td>
<td>높을수록 분류 잘함</td>
</tr>
</tbody></table>
<hr>
<h2 id="회귀-vs-분류-요약-비교">회귀 vs 분류 요약 비교</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>회귀</th>
<th>분류</th>
</tr>
</thead>
<tbody><tr>
<td>클래스</td>
<td><code>XGBRegressor</code></td>
<td><code>XGBClassifier</code></td>
</tr>
<tr>
<td>손실 함수</td>
<td>MSE, MAE 등</td>
<td>logloss, softmax</td>
</tr>
<tr>
<td>출력</td>
<td>실수 값</td>
<td>클래스 확률 또는 라벨</td>
</tr>
<tr>
<td>예측 함수</td>
<td><code>predict()</code></td>
<td><code>predict()</code>, <code>predict_proba()</code></td>
</tr>
<tr>
<td>평가지표</td>
<td>R², RMSE</td>
<td>Accuracy, F1, AUC</td>
</tr>
</tbody></table>
<hr>
<h2 id="마무리-요약">마무리 요약</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>핵심 모델</td>
<td>XGBRegressor, XGBClassifier</td>
</tr>
<tr>
<td>구조</td>
<td>Gradient Boosting + 정규화 + 최적화</td>
</tr>
<tr>
<td>특징</td>
<td>정확도 높음, 과적합 억제, 속도 빠름</td>
</tr>
<tr>
<td>입력</td>
<td>X, y → 지도학습 기반</td>
</tr>
<tr>
<td>핵심 수식</td>
<td>기울기 + 헤시안 기반 손실 최소화</td>
</tr>
<tr>
<td>활용</td>
<td>분류/회귀/랭킹 전반에서 성능 최강</td>
</tr>
</tbody></table>
</li>
<li><p>LightGBM</p>
<h2 id="개념">개념</h2>
<p>  <strong>LightGBM</strong>은 <strong>Gradient Boosting 계열</strong>의 <strong>트리 기반 머신러닝 알고리즘</strong>으로,</p>
<p>  여러 개의 약한 모델(결정 트리)을 순차적으로 학습시켜 <strong>예측 정확도를 높이는 앙상블 기법</strong></p>
<p>  특히 <strong>학습 속도</strong>와 <strong>메모리 효율성</strong>을 극대화를 위한 최적화된 구조</p>
<blockquote>
<p>&quot;Light&quot; = 빠르고 가볍다</p>
<p>&quot;GBM&quot; = Gradient Boosting Machine</p>
</blockquote>
<h3 id="주요-특징">주요 특징</h3>
<ul>
<li><strong>Leaf-wise 성장 방식</strong>: 가장 손실이 큰 리프 노드만 분기 → 더 정확</li>
<li><strong>Histogram 기반 학습</strong>: 연산량 줄이기 → 더 빠름</li>
<li><strong>GOSS</strong>: 중요한 데이터 위주로 학습</li>
<li><strong>EFB</strong>: 희소 feature들을 묶어 처리</li>
</ul>
<hr>
<h2 id="언제-사용">언제 사용?</h2>
<table>
<thead>
<tr>
<th>조건</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>대규모 데이터셋</strong></td>
<td>수십~수백만 행 이상의 테이블</td>
</tr>
<tr>
<td><strong>고차원 데이터</strong></td>
<td>수천 개 이상의 컬럼</td>
</tr>
<tr>
<td><strong>희소 데이터</strong></td>
<td>원-핫 인코딩된 데이터, 결측치가 많은 데이터</td>
</tr>
<tr>
<td><strong>속도가 중요한 경우</strong></td>
<td>실시간 추천 시스템, 대용량 서비스 등</td>
</tr>
<tr>
<td>- <strong>이진 분류</strong>: 예) 스팸 이메일 분류, 암/정상 진단</td>
<td></td>
</tr>
<tr>
<td>- <strong>다중 분류</strong>: 예) 손글씨 숫자 분류</td>
<td></td>
</tr>
<tr>
<td>- <strong>회귀</strong>: 예) 집값 예측, 수요 예측</td>
<td></td>
</tr>
<tr>
<td>- <strong>랭킹</strong>: 예) 검색 결과 정렬, 추천 시스템</td>
<td></td>
</tr>
<tr>
<td>- <strong>이상치 탐지</strong></td>
<td></td>
</tr>
</tbody></table>
<hr>
<h2 id="내부-동작-방식">내부 동작 방식</h2>
<h3 id="🔸-31-leaf-wise-성장-방식">🔸 3.1 Leaf-wise 성장 방식</h3>
<p>  LightGBM은 트리를 키울 때 <strong>전체 트리의 depth를 일정하게 늘리는 것이 아니라</strong>,</p>
<p>  <strong>가장 손실(loss)을 많이 줄일 수 있는 리프 노드 하나만 골라 분기</strong>합니다.</p>
<p>  이 방식의 장점은 더 정밀한 학습이 가능하다는 것이고,</p>
<p>  단점은 트리가 불균형하게 커져서 <strong>과적합 가능성이 높아진다</strong>는 것입니다.</p>
<hr>
<h3 id="🔸-32-histogram-기반-학습">🔸 3.2 Histogram 기반 학습</h3>
<p>  LightGBM은 feature 값을 일정 구간(bin)으로 나눠서 <strong>히스토그램</strong>을 만들고,</p>
<p>  이 히스토그램을 기반으로 분할 기준을 정합니다.</p>
<p>  예를 들어, 연속적인 수치형 feature를 256개 구간으로 나누면,</p>
<p>  원래 값들이 정수든 실수든 구간(bin) 번호로 대체하여 처리하므로 훨씬 빠릅니다.</p>
<hr>
<h3 id="🔸-33-goss-gradient-based-one-side-sampling">🔸 3.3 GOSS (Gradient-based One-Side Sampling)</h3>
<p>  Gradient 값이 큰 샘플은 모델이 틀린 예측을 한 것이므로 중요도가 높습니다.</p>
<p>  LightGBM은 <strong>Gradient 값이 큰 샘플은 모두 포함하고</strong>, 작은 값의 샘플은 일부만 샘플링해서 학습에 사용합니다.</p>
<p>  즉, 중요한 정보는 유지하면서 학습 속도를 크게 줄이는 전략입니다.</p>
<hr>
<h3 id="🔸-34-efb-exclusive-feature-bundling">🔸 3.4 EFB (Exclusive Feature Bundling)</h3>
<p>  많은 feature들이 희소한 경우, 예를 들어 one-hot encoding된 경우,</p>
<p>  같은 row에서 둘 다 1이 될 일이 없는 feature들끼리 묶어서 하나처럼 처리합니다.</p>
<p>  예) [0, 1, 0], [0, 0, 1] 같은 feature들 → 하나의 컬럼으로 압축</p>
<hr>
<h2 id="주요-하이퍼파라미터-1">주요 하이퍼파라미터</h2>
<table>
<thead>
<tr>
<th>파라미터</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>num_leaves</code></td>
<td>하나의 트리에서 사용할 최대 리프 노드 수</td>
<td>과적합 방지: 보통 31~100</td>
</tr>
<tr>
<td><code>max_depth</code></td>
<td>트리의 최대 깊이</td>
<td>너무 깊으면 과적합</td>
</tr>
<tr>
<td><code>learning_rate</code></td>
<td>학습률</td>
<td>작게 잡을수록 더 정밀</td>
</tr>
<tr>
<td><code>n_estimators</code></td>
<td>트리의 개수</td>
<td>많을수록 성능↑ (시간↑)</td>
</tr>
<tr>
<td><code>min_data_in_leaf</code></td>
<td>리프 노드가 가져야 할 최소 데이터 수</td>
<td>과적합 방지</td>
</tr>
<tr>
<td><code>feature_fraction</code></td>
<td>학습에 사용할 feature 비율</td>
<td>0.8이면 무작위 80% 사용</td>
</tr>
<tr>
<td><code>bagging_fraction</code></td>
<td>학습에 사용할 샘플 비율</td>
<td>랜덤샘플링 효과</td>
</tr>
<tr>
<td><code>boosting_type</code></td>
<td>부스팅 알고리즘 종류</td>
<td>기본값: ‘gbdt’</td>
</tr>
<tr>
<td><code>lambda_l1</code>, <code>lambda_l2</code></td>
<td>정규화 계수 (L1/L2)</td>
<td>과적합 방지용</td>
</tr>
</tbody></table>
<hr>
<h2 id="사용-라이브러리-및-설치">사용 라이브러리 및 설치</h2>
<pre><code class="language-bash">  pip install lightgbm</code></pre>
<pre><code class="language-python">  import lightgbm as lgb</code></pre>
<p>  또는 GPU 지원 버전:</p>
<pre><code class="language-bash">  pip install lightgbm --install-option=--gpu</code></pre>
<hr>
<h2 id="예시-이진-분류">예시 (이진 분류)</h2>
<pre><code class="language-python">  import lightgbm as lgb
  from sklearn.datasets import load_breast_cancer
  from sklearn.model_selection import train_test_split
  from sklearn.metrics import accuracy_score

  # 데이터 로드
  X, y = load_breast_cancer(return_X_y=True)
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

  # 모델 정의
  model = lgb.LGBMClassifier(
      n_estimators=100,
      num_leaves=31,
      learning_rate=0.1,
      max_depth=-1
  )

  # 학습
  model.fit(X_train, y_train)

  # 예측
  y_pred = model.predict(X_test)

  # 평가
  print(&quot;정확도:&quot;, accuracy_score(y_test, y_pred))</code></pre>
<hr>
<h2 id="결과-예시">결과 예시</h2>
<pre><code class="language-python">  정확도: 0.9649122807017544</code></pre>
</li>
<li><p>CatBoost</p>
</li>
<li><p>StackingRegressor</p>
<h1 id="stackingregressor">StackingRegressor</h1>
<blockquote>
<p>StackingRegressor는 여러 개의 다른 회귀 모델(base learners)을 조합하고,</p>
<p>그 결과를 다시 최종 메타 회귀 모델(meta regressor)이 학습하여 <strong>더 정확한 예측</strong>을 만드는 <strong>앙상블 회귀 기법</strong></p>
</blockquote>
<p>  → 각 회귀 모델의 예측값을 새로운 입력 특성(feature)으로 간주하고,</p>
<p>  → 그것들을 바탕으로 <strong>최종 모델이 다시 예측</strong>하는 방식</p>
<hr>
<h3 id="전체-구조">전체 구조</h3>
<pre><code>     원본 입력 (X)
           ↓
   ┌─────────────┐
   │  Base 모델 1 │──▶ 예측값1 ─┐
   ├─────────────┤             │
   │  Base 모델 2 │──▶ 예측값2 ─┼─▶  [예측값1, 예측값2, ...] → 메타 모델 → 최종 예측값
   ├─────────────┤             │
   │  Base 모델 3 │──▶ 예측값3 ─┘
   └─────────────┘
</code></pre><ul>
<li><p>Base 모델: 서로 다른 종류의 회귀 모델 (예: 결정 트리, KNN, SVR 등)</p>
</li>
<li><p>Meta 모델: Base 모델들의 예측값을 받아 다시 예측하는 회귀 모델 (보통 선형 모델이 좋음)</p>
<table>
<thead>
<tr>
<th>문제 유형</th>
<th>메타 모델 (보통 쓰는 것)</th>
</tr>
</thead>
<tbody><tr>
<td><strong>분류 문제 (classification)</strong></td>
<td>✅ <strong>로지스틱 회귀 (LogisticRegression)</strong></td>
</tr>
<tr>
<td><strong>회귀 문제 (regression)</strong></td>
<td>✅ <strong>릿지 회귀 / 선형 회귀 (RidgeCV / LinearRegression)</strong></td>
</tr>
</tbody></table>
</li>
</ul>
<hr>
<h2 id="언제-사용-1">언제 사용?</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>다양한 회귀 모델의 예측을 조합하고 싶을 때</td>
<td>서로 다른 특성을 가진 모델이 잘 보완해줌</td>
</tr>
<tr>
<td>하나의 모델이 완벽하지 않을 때</td>
<td>서로 다른 편향을 가진 모델을 합치면 시너지 가능</td>
</tr>
<tr>
<td>캐글(Kaggle) 등 대회에서 성능 극대화</td>
<td>실제 우승 솔루션에서 자주 등장</td>
</tr>
</tbody></table>
<hr>
<h2 id="예제-scikit-learn-기반">예제 (scikit-learn 기반)</h2>
<pre><code class="language-python">  from sklearn.ensemble import StackingRegressor
  from sklearn.linear_model import RidgeCV
  from sklearn.tree import DecisionTreeRegressor
  from sklearn.neighbors import KNeighborsRegressor
  from sklearn.datasets import make_regression
  from sklearn.model_selection import train_test_split

  # 1. 데이터 생성
  X, y = make_regression(n_samples=1000, n_features=20, noise=0.1, random_state=42)
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

  # 2. Base 모델 정의
  base_models = [
      (&#39;tree&#39;, DecisionTreeRegressor(max_depth=5)),
      (&#39;knn&#39;, KNeighborsRegressor(n_neighbors=10))
  ]

  # 3. 메타 모델 정의 (보통 선형 회귀나 릿지 회귀 사용)
  meta_model = RidgeCV()

  # 4. StackingRegressor 정의
  stacking = StackingRegressor(
      estimators=base_models,
      final_estimator=meta_model,
      cv=5  # base 모델 훈련 시 교차검증용
  )

  # 5. 학습 및 예측
  stacking.fit(X_train, y_train)
  y_pred = stacking.predict(X_test)

  # 6. 결과 확인
  from sklearn.metrics import r2_score
  print(&quot;R2 Score:&quot;, r2_score(y_test, y_pred))</code></pre>
<hr>
<h2 id="주요-파라미터-설명">주요 파라미터 설명</h2>
<table>
<thead>
<tr>
<th>파라미터</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>estimators</code></td>
<td>리스트 형태로 base 모델들을 정의 (<code>(이름, 모델)</code> 튜플)</td>
</tr>
<tr>
<td><code>final_estimator</code></td>
<td>메타 모델 (보통 간단한 회귀 모델 사용)</td>
</tr>
<tr>
<td><code>cv</code></td>
<td>base 모델 학습 시 내부에서 사용할 교차검증 폴드 수</td>
</tr>
<tr>
<td><code>n_jobs</code></td>
<td>병렬 처리용 (CPU 코어 병렬 실행)</td>
</tr>
<tr>
<td><code>passthrough=True</code></td>
<td>메타 모델에게 원본 X도 함께 전달 (성능 향상 가능)</td>
</tr>
</tbody></table>
<h2 id="주의사항--팁">주의사항 / 팁</h2>
<table>
<thead>
<tr>
<th>주의사항</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>Meta 모델은 너무 복잡하지 않게!</td>
<td>보통 <code>LinearRegression</code>, <code>RidgeCV</code> 등 추천</td>
</tr>
<tr>
<td>Base 모델은 서로 다른 성격의 모델로 구성</td>
<td>서로 다른 성능, 편향을 가진 모델을 조합해야 효과적</td>
</tr>
<tr>
<td><code>cv</code>는 꼭 지정할 것</td>
<td>메타 모델이 과적합되지 않게 하기 위해 중요</td>
</tr>
<tr>
<td>원본 X도 함께 주고 싶다면 <code>passthrough=True</code> 사용</td>
<td>예측 성능이 더 좋아질 수 있음</td>
</tr>
</tbody></table>
<h2 id="확장-가능">확장 가능</h2>
<ul>
<li><p><code>StackingRegressor</code> 안에 넣는 base 모델은 반드시 <strong>회귀 모델</strong>이어야 함.</p>
</li>
<li><p>최종 meta 모델도 회귀여야 함.</p>
<p>예시:</p>
<pre><code class="language-python">from sklearn.linear_model import Lasso
from sklearn.svm import SVR
from sklearn.ensemble import GradientBoostingRegressor

base = [
  (&#39;lasso&#39;, Lasso(alpha=0.01)),
  (&#39;svr&#39;, SVR(C=10))
]
meta = GradientBoostingRegressor(n_estimators=100)

model = StackingRegressor(estimators=base, final_estimator=meta, cv=5)</code></pre>
</li>
</ul>
<hr>
<h2 id="정리-요약-1">정리 요약</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td><strong>정의</strong></td>
<td>여러 회귀 모델의 예측을 조합해 최종 회귀 예측을 수행하는 앙상블 모델</td>
</tr>
<tr>
<td><strong>사용 라이브러리</strong></td>
<td><code>sklearn.ensemble.StackingRegressor</code></td>
</tr>
<tr>
<td><strong>장점</strong></td>
<td>다양한 모델의 장점을 종합해 성능 극대화</td>
</tr>
<tr>
<td><strong>구성 요소</strong></td>
<td>Base 모델들 + 메타 회귀 모델</td>
</tr>
<tr>
<td><strong>추천 구조</strong></td>
<td>서로 다른 성격의 base 모델 + 간단한 메타 모델</td>
</tr>
<tr>
<td><strong>적합한 문제</strong></td>
<td>일반적인 회귀, 캐글 대회, 성능이 중요한 프로젝트</td>
</tr>
</tbody></table>
</li>
<li><p>BaggingRegressor</p>
<h2 id="baggingregressor">BaggingRegressor</h2>
<blockquote>
<p>Bagging = Bootstrap Aggregating</p>
<p>→ 여러 개의 <strong>회귀 모델을 무작위로 다르게 학습</strong>시키고,</p>
<p>그 결과를 <strong>평균</strong>해서 <strong>더 안정적이고 일반화된 예측</strong>을 만드는 앙상블 회귀 모델</p>
</blockquote>
<p>  개념</p>
<ul>
<li>훈련 데이터를 <strong>중복 허용 샘플링 (bootstrap)</strong> 으로 여러 개 생성</li>
<li>각 샘플에 <strong>별도의 회귀 모델</strong> 학습</li>
<li>예측값은 → <strong>평균(회귀)</strong> 으로 결합</li>
</ul>
<hr>
<h2 id="언제-사용-2">언제 사용?</h2>
<table>
<thead>
<tr>
<th>사용 시점</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td>단일 회귀 모델이 과적합되는 경우</td>
<td>Bagging은 분산을 줄여 과적합을 완화함</td>
</tr>
<tr>
<td>예측값의 <strong>안정성</strong>이 중요한 경우</td>
<td>평균값을 사용해 노이즈에 덜 민감</td>
</tr>
<tr>
<td>비선형적이거나 복잡한 관계가 있는 데이터</td>
<td>결정 트리 기반 회귀 모델이 잘 작동함</td>
</tr>
<tr>
<td>모델 간 <strong>병렬 처리</strong>가 가능해야 할 때</td>
<td>Base 모델이 독립적이므로 병렬화 쉬움</td>
</tr>
</tbody></table>
<hr>
<h2 id="전체-구조-1">전체 구조</h2>
<pre><code>  훈련 데이터 X
   ├─ bootstrap 샘플링 → 모델1 학습 → 예측1
   ├─ bootstrap 샘플링 → 모델2 학습 → 예측2
   ├─ bootstrap 샘플링 → 모델3 학습 → 예측3
   ...
   └─ 예측 결과 평균 → 최종 예측값</code></pre><hr>
<h2 id="예시-2">예시</h2>
<h3 id="기본-예제-decisiontreeregressor--baggingregressor">기본 예제: <code>DecisionTreeRegressor</code> + <code>BaggingRegressor</code></h3>
<pre><code class="language-python">  from sklearn.ensemble import BaggingRegressor
  from sklearn.tree import DecisionTreeRegressor
  from sklearn.datasets import make_regression
  from sklearn.model_selection import train_test_split
  from sklearn.metrics import r2_score

  # 1. 데이터 생성
  X, y = make_regression(n_samples=1000, n_features=10, noise=20, random_state=42)
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

  # 2. 모델 정의
  base_model = DecisionTreeRegressor()
  bagging = BaggingRegressor(
      base_estimator=base_model,
      n_estimators=100,        # 몇 개의 모델을 만들 것인지
      bootstrap=True,          # bootstrap 샘플링 여부
      max_samples=1.0,         # 각 모델에 사용할 샘플 비율
      max_features=1.0,        # 각 모델에 사용할 특성 비율
      random_state=42,
      n_jobs=-1                # 병렬 처리
  )

  # 3. 학습 및 평가
  bagging.fit(X_train, y_train)
  y_pred = bagging.predict(X_test)

  print(&quot;R² Score:&quot;, r2_score(y_test, y_pred))</code></pre>
<hr>
<h2 id="주요-파라미터-정리">주요 파라미터 정리</h2>
<table>
<thead>
<tr>
<th>파라미터</th>
<th>설명</th>
<th>기본값</th>
</tr>
</thead>
<tbody><tr>
<td><code>base_estimator</code></td>
<td>사용할 회귀 모델 (예: <code>DecisionTreeRegressor</code>)</td>
<td><code>None</code> → <code>DecisionTree</code></td>
</tr>
<tr>
<td><code>n_estimators</code></td>
<td>앙상블할 모델 수</td>
<td><code>10</code></td>
</tr>
<tr>
<td><code>bootstrap</code></td>
<td>샘플링 시 중복 허용 여부</td>
<td><code>True</code></td>
</tr>
<tr>
<td><code>max_samples</code></td>
<td>각 base 모델에 줄 샘플 수 (비율 또는 정수)</td>
<td><code>1.0</code></td>
</tr>
<tr>
<td><code>max_features</code></td>
<td>각 모델에 사용할 특성 수</td>
<td><code>1.0</code></td>
</tr>
<tr>
<td><code>oob_score</code></td>
<td>OOB 평가 여부 (훈련에 쓰이지 않은 샘플로 검증)</td>
<td><code>False</code></td>
</tr>
<tr>
<td><code>n_jobs</code></td>
<td>병렬 처리할 코어 수 (<code>-1</code>: 전부 사용)</td>
<td><code>None</code></td>
</tr>
<tr>
<td><code>random_state</code></td>
<td>재현 가능성 위한 시드</td>
<td><code>None</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="bagging-vs-단일-모델">Bagging vs 단일 모델</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>단일 모델</th>
<th>BaggingRegressor</th>
</tr>
</thead>
<tbody><tr>
<td>예측 성능</td>
<td>불안정하거나 과적합 가능</td>
<td>더 안정적, 분산 감소</td>
</tr>
<tr>
<td>과적합</td>
<td>발생 가능</td>
<td>완화됨</td>
</tr>
<tr>
<td>노이즈에 민감</td>
<td>높음</td>
<td>낮음</td>
</tr>
<tr>
<td>병렬 처리</td>
<td>❌</td>
<td>가능</td>
</tr>
<tr>
<td>속도</td>
<td>빠름</td>
<td>느릴 수 있음 (n_estimators ↑)</td>
</tr>
</tbody></table>
<hr>
<h2 id="다양한-base_estimator-사용가능">다양한 base_estimator 사용가능</h2>
<pre><code class="language-python">  from sklearn.svm import SVR
  from sklearn.linear_model import Ridge
  from sklearn.neighbors import KNeighborsRegressor

  BaggingRegressor(base_estimator=SVR())
  BaggingRegressor(base_estimator=Ridge())
  BaggingRegressor(base_estimator=KNeighborsRegressor())</code></pre>
<p>  단, 각 base 모델은 <strong>회귀 모델</strong>이어야 함!</p>
<hr>
<h2 id="oob-out-of-bag-평가">OOB (Out-of-Bag) 평가</h2>
<pre><code class="language-python">  bagging = BaggingRegressor(oob_score=True)
  bagging.fit(X_train, y_train)
  print(&quot;OOB R² Score:&quot;, bagging.oob_score_)</code></pre>
<ul>
<li>Bootstrap에서 빠진 샘플로 내부 검증</li>
<li>추가적인 검증 세트 없이도 <strong>성능을 간접 평가</strong> 가능</li>
</ul>
<hr>
<h2 id="성능-비교-실험-선택">성능 비교 실험 (선택)</h2>
<table>
<thead>
<tr>
<th>모델</th>
<th>R² Score</th>
</tr>
</thead>
<tbody><tr>
<td>DecisionTreeRegressor</td>
<td>0.74</td>
</tr>
<tr>
<td>BaggingRegressor</td>
<td>0.86 (훨씬 향상)</td>
</tr>
</tbody></table>
<hr>
<h2 id="정리">정리</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>정의</td>
<td>여러 회귀 모델을 샘플링된 데이터로 학습시켜 평균하는 앙상블</td>
</tr>
<tr>
<td>대표 클래스</td>
<td><code>sklearn.ensemble.BaggingRegressor</code></td>
</tr>
<tr>
<td>기본 모델</td>
<td><code>DecisionTreeRegressor</code> (기본값)</td>
</tr>
<tr>
<td>장점</td>
<td>과적합 완화, 일반화 성능 ↑, 병렬화 가능</td>
</tr>
<tr>
<td>사용 시점</td>
<td>단일 모델이 불안정하거나, 고차원 / 복잡한 데이터</td>
</tr>
</tbody></table>
</li>
<li><p>VotingRegressor</p>
<h1 id="votingregressor">VotingRegressor</h1>
<blockquote>
<p>여러 개의 서로 다른 회귀 모델들의 예측값을 평균해서</p>
<p><strong>최종 예측값을 계산하는 앙상블 모델</strong></p>
</blockquote>
<ul>
<li><strong>분류</strong>에서는 <code>VotingClassifier</code>가 다수결(Majority voting)을 사용</li>
<li><strong>회귀</strong>에서는 <code>VotingRegressor</code>가 <strong>예측값의 평균(Averaging)</strong> 을 사용</li>
</ul>
<hr>
<h2 id="구조">구조</h2>
<pre><code>        X 입력
          ↓
   ┌──────────────┐
   │  모델1 예측   │ → 예측값1
   │  모델2 예측   │ → 예측값2
   │  모델3 예측   │ → 예측값3
   └──────────────┘
          ↓
    최종 예측 = (예측1 + 예측2 + 예측3) / 3</code></pre><hr>
<h2 id="언제-사용하나">언제 사용하나?</h2>
<table>
<thead>
<tr>
<th>사용 조건</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td>다양한 회귀 모델을 조합하고 싶을 때</td>
<td>서로 다른 모델 특성이 시너지를 낼 수 있음</td>
</tr>
<tr>
<td>단순하면서 안정적인 앙상블을 원할 때</td>
<td>평균만 사용하므로 과적합 위험 낮음</td>
</tr>
<tr>
<td>Boosting처럼 순차 학습이 필요 없는 구조</td>
<td>병렬화 가능하고 빠름</td>
</tr>
</tbody></table>
<hr>
<h2 id="실습-예제">실습 예제</h2>
<pre><code class="language-python">  from sklearn.ensemble import VotingRegressor
  from sklearn.linear_model import Ridge
  from sklearn.tree import DecisionTreeRegressor
  from sklearn.svm import SVR
  from sklearn.datasets import make_regression
  from sklearn.model_selection import train_test_split

  # 데이터 생성
  X, y = make_regression(n_samples=1000, n_features=20, noise=15, random_state=42)
  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

  # 모델 정의
  model1 = Ridge(alpha=1.0)
  model2 = DecisionTreeRegressor(max_depth=5)
  model3 = SVR()

  # VotingRegressor 정의
  voting_model = VotingRegressor(estimators=[
      (&#39;ridge&#39;, model1),
      (&#39;tree&#39;, model2),
      (&#39;svr&#39;, model3)
  ])

  # 학습 및 예측
  voting_model.fit(X_train, y_train)
  y_pred = voting_model.predict(X_test)
</code></pre>
<hr>
<h2 id="주요-파라미터-1">주요 파라미터</h2>
<table>
<thead>
<tr>
<th>파라미터</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>estimators</code></td>
<td>사용할 회귀 모델 리스트 (이름, 모델) 튜플</td>
</tr>
<tr>
<td><code>n_jobs</code></td>
<td>병렬 처리 (기본: <code>None</code>, 전체 CPU: <code>-1</code>)</td>
</tr>
<tr>
<td><code>weights</code></td>
<td>각 모델의 가중치 지정 가능</td>
</tr>
</tbody></table>
<hr>
<h2 id="가중치-지정-예시">가중치 지정 예시</h2>
<pre><code class="language-python">  VotingRegressor(
      estimators=[(&#39;ridge&#39;, model1), (&#39;tree&#39;, model2), (&#39;svr&#39;, model3)],
      weights=[1, 2, 1]  # tree 모델에 더 높은 비중
  )</code></pre>
<ul>
<li>비중 조정해서 더 신뢰하는 모델에 <strong>가중치 부여</strong> 가능</li>
</ul>
<hr>
<h2 id="votingregressor-vs-다른-앙상블">VotingRegressor vs 다른 앙상블</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>VotingRegressor</th>
<th>BaggingRegressor</th>
<th>StackingRegressor</th>
</tr>
</thead>
<tbody><tr>
<td>예측 방식</td>
<td>평균</td>
<td>각 모델 독립 학습 후 평균</td>
<td>메타 모델이 다시 예측</td>
</tr>
<tr>
<td>모델 다양성</td>
<td>높음 (여러 모델 가능)</td>
<td>보통 같은 모델</td>
<td>가장 다양함</td>
</tr>
<tr>
<td>학습 방식</td>
<td>병렬, 단순</td>
<td>병렬, 부트스트랩</td>
<td>병렬 + 메타 학습</td>
</tr>
<tr>
<td>해석력</td>
<td>높음</td>
<td>중간</td>
<td>낮음</td>
</tr>
<tr>
<td>성능</td>
<td>보통</td>
<td>안정적</td>
<td>가장 높을 수 있음</td>
</tr>
</tbody></table>
<hr>
<h2 id="정리-1">정리</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>용도</td>
<td>여러 회귀 모델의 예측 평균값을 사용해 안정적 예측</td>
</tr>
<tr>
<td>구조</td>
<td>병렬 예측 + 단순 평균</td>
</tr>
<tr>
<td>라이브러리</td>
<td><code>sklearn.ensemble.VotingRegressor</code></td>
</tr>
<tr>
<td>추천 사용 상황</td>
<td>단순하고 빠른 앙상블, baseline 비교할 때 유용</td>
</tr>
</tbody></table>
</li>
</ul>
</li>
</ul>
<hr>
<h1 id="분류-classification-모델">분류 (Classification) 모델</h1>
<table>
<thead>
<tr>
<th>모델명</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>RidgeClassifier</strong></td>
<td>선형 분류 + L2 정규화</td>
</tr>
<tr>
<td><strong>GradientBoostingClassifier</strong></td>
<td>순차적 학습으로 성능 향상</td>
</tr>
<tr>
<td><strong>XGBoostClassifier</strong></td>
<td>Kaggle 1등 단골 모델, 빠르고 강력</td>
</tr>
<tr>
<td><strong>LightGBMClassifier</strong></td>
<td>대용량 데이터에 매우 빠름</td>
</tr>
<tr>
<td><strong>CatBoostClassifier</strong></td>
<td>범주형 데이터 자동 처리 가능</td>
</tr>
<tr>
<td><strong>BaggingClassifier</strong></td>
<td>트리 기반 Bagging 앙상블</td>
</tr>
<tr>
<td><strong>VotingClassifier</strong></td>
<td>여러 모델의 결과를 투표로 결정</td>
</tr>
<tr>
<td><strong>StackingClassifier</strong></td>
<td>여러 모델을 층으로 쌓아 결합</td>
</tr>
</tbody></table>
<h3 id="분류">분류</h3>
<h1 id="ridgeclassifier">RidgeClassifier</h1>
<p><strong>개념</strong></p>
<ul>
<li>선형 분류 모델 + <strong>L2 정규화(가중치 패널티)</strong></li>
<li>LogisticRegression과 비슷하지만 loss 함수가 다름</li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>빠르고 단순함</li>
<li>이진/다중 분류 모두 가능</li>
<li>과적합 완화</li>
</ul>
<p><strong>언제 사용하나?</strong></p>
<ul>
<li>피처 수가 많고, 빠른 선형 분류가 필요할 때</li>
<li>baseline 모델로 적합</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">
from sklearn.linear_model import RidgeClassifier
model = RidgeClassifier()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<p><strong>결과</strong></p>
<pre><code class="language-python">[0, 1, 2, 2, 1]</code></pre>
<h1 id="gradientboostingclassifier">GradientBoostingClassifier</h1>
<p> <strong>개념</strong></p>
<ul>
<li><p>약한 분류기(예: 작은 트리)를 순차적으로 학습시켜</p>
<p>  이전 모델의 오류를 보완하는 <strong>부스팅 방식</strong> 분류기</p>
</li>
</ul>
<p> <strong>특징</strong></p>
<ul>
<li><p>과적합에 비교적 강함</p>
</li>
<li><p>성능이 우수하지만 학습 속도는 느린 편</p>
</li>
<li><p>하이퍼파라미터가 많아 튜닝 필요</p>
<p><strong>언제 사용하나?</strong></p>
</li>
<li><p>복잡한 분류 문제</p>
</li>
<li><p>과적합 방지 + 높은 예측력이 필요한 경우</p>
</li>
<li><p>LogisticRegression, 트리 기반 모델보다 더 강력한 모델이 필요할 때</p>
<p><strong>사용 코드</strong></p>
</li>
</ul>
<pre><code class="language-python">from sklearn.ensemble import GradientBoostingClassifier
model = GradientBoostingClassifier(n_estimators=100, learning_rate=0.1)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<p>🔹 <strong>결과 예시</strong></p>
<pre><code class="language-python">[1, 0, 0, 2, 2]</code></pre>
<hr>
<h1 id="xgboostclassifier">XGBoostClassifier</h1>
<p><strong>개념</strong></p>
<ul>
<li><strong>Gradient Boosting</strong>을 기반으로 한 <strong>고속/고성능</strong> 분류기</li>
<li>학습 속도와 정확도 모두 우수, 실무/대회에서 많이 사용</li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>과적합 제어 기능 탁월 (<code>gamma</code>, <code>lambda</code>, <code>eta</code>)</li>
<li>missing value 자동 처리</li>
<li>GPU 지원 가능</li>
</ul>
<p><strong>언제 사용하나?</strong></p>
<ul>
<li>Kaggle, AI 경진대회</li>
<li>정형 데이터 예측 (카테고리 중심의 데이터셋)</li>
<li>복잡한 관계 학습이 필요할 때</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">from xgboost import XGBClassifier
model = XGBClassifier(n_estimators=100, use_label_encoder=False, eval_metric=&#39;mlogloss&#39;)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<p>🔹 <strong>결과 예시</strong></p>
<pre><code class="language-python">[1, 0, 2, 2, 1]</code></pre>
<hr>
<h1 id="lightgbmclassifier">LightGBMClassifier</h1>
<p><strong>개념</strong></p>
<ul>
<li><strong>XGBoost보다 더 빠르게 학습되는 부스팅 모델</strong></li>
<li>Leaf-wise 트리 성장 방식으로 성능 향상</li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>고속 처리, 적은 메모리</li>
<li>대규모, 고차원 데이터에 강함</li>
<li>범주형 변수 자동 인식 가능 (특정 설정 시)</li>
</ul>
<p><strong>언제 사용하나?</strong></p>
<ul>
<li>대용량 데이터</li>
<li>빠른 예측/학습이 필요한 온라인 서비스</li>
<li>실시간 분류기</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">from lightgbm import LGBMClassifier
model = LGBMClassifier(n_estimators=100)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<p>🔹 <strong>결과 예시</strong></p>
<pre><code class="language-python">[0, 1, 1, 2, 0]</code></pre>
<hr>
<h1 id="catboostclassifier">CatBoostClassifier</h1>
<p><strong>개념</strong></p>
<ul>
<li><strong>범주형 데이터 자동 처리</strong>가 가능한 부스팅 기반 분류기</li>
<li>전처리 없이도 범주형 피처를 인식하고 처리 가능</li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>Label Encoding 없이도 학습 가능</li>
<li>성능 우수 + 학습 속도 빠름</li>
<li>파라미터 튜닝 없이도 좋은 성능</li>
</ul>
<p><strong>언제 사용하나?</strong></p>
<ul>
<li>범주형 변수가 많은 데이터셋</li>
<li>전처리 부담 줄이고 싶을 때</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">from catboost import CatBoostClassifier
model = CatBoostClassifier(verbose=0)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<p>🔹 <strong>결과 예시</strong></p>
<pre><code class="language-python">[1, 0, 1, 1, 2]</code></pre>
<h1 id="baggingclassifier">BaggingClassifier</h1>
<p><strong>개념</strong></p>
<ul>
<li><p>동일한 분류 모델(기본적으로 결정트리)을 여러 개 학습한 뒤,</p>
<p>  각 모델의 예측을 평균(분류에선 투표)하여 최종 예측</p>
<p>  → Bagging(Bootstrap Aggregating)</p>
</li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>과적합 감소</li>
<li>데이터의 일부만 샘플링 (부트스트랩)</li>
<li>병렬 처리 가능</li>
</ul>
<p><strong>언제 사용하나?</strong></p>
<ul>
<li>데이터가 작고 과적합이 우려될 때</li>
<li>단일 트리보다 안정적인 성능을 원할 때</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier

base_model = DecisionTreeClassifier()
model = BaggingClassifier(base_estimator=base_model, n_estimators=10)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<p><strong>결과 예시</strong></p>
<pre><code class="language-python">[0, 1, 1, 2, 1]</code></pre>
<hr>
<h1 id="votingclassifier">VotingClassifier</h1>
<p><strong>개념</strong></p>
<ul>
<li><p><strong>여러 다른 종류의 분류 모델</strong>을 학습</p>
<p>  각 모델의 예측을 투표 방식(다수결)으로 결합하는 앙상블</p>
</li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>다양한 모델의 강점을 결합 가능</li>
<li>보통 <code>Logistic + Tree + SVM</code> 조합 추천</li>
<li><code>hard</code> vs <code>soft</code> voting 선택 가능</li>
</ul>
<p><strong>언제 사용?</strong></p>
<ul>
<li>개별 모델 간 예측이 상이할 때</li>
<li>서로 다른 성격의 모델을 조합하고 싶을 때</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">from sklearn.ensemble import VotingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC

model1 = LogisticRegression()
model2 = DecisionTreeClassifier()
model3 = SVC(probability=True)

ensemble = VotingClassifier(
    estimators=[(&#39;lr&#39;, model1), (&#39;dt&#39;, model2), (&#39;svc&#39;, model3)],
    voting=&#39;soft&#39;
)
ensemble.fit(X_train, y_train)
y_pred = ensemble.predict(X_test)</code></pre>
<p>🔹 <strong>결과 예시</strong></p>
<pre><code class="language-python">[1, 0, 2, 2, 1]</code></pre>
<hr>
<h1 id="stackingclassifier">StackingClassifier</h1>
<p><strong>개념</strong></p>
<ul>
<li><p>여러 개의 기반 모델(base learners)이 예측한 결과를</p>
<p>  다시 하나의 메타 모델(meta learner)에 입력하여 최종 예측</p>
</li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li>복잡하지만 성능 우수</li>
<li>Voting보다 예측력이 더 높을 수 있음</li>
<li>예측 결과를 재학습하는 방식</li>
</ul>
<p><strong>언제 사용?</strong></p>
<ul>
<li>다양한 모델을 계층적으로 결합하고 싶을 때</li>
<li>대회, 앙상블 기반 고정밀 예측이 필요할 때</li>
</ul>
<p><strong>사용 코드</strong></p>
<pre><code class="language-python">from sklearn.ensemble import StackingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC

base_models = [
    (&#39;dt&#39;, DecisionTreeClassifier()),
    (&#39;svc&#39;, SVC(probability=True))
]
meta_model = LogisticRegression()

stack = StackingClassifier(estimators=base_models, final_estimator=meta_model)
stack.fit(X_train, y_train)
y_pred = stack.predict(X_test)</code></pre>
<p><strong>결과 예시</strong></p>
<pre><code class="language-python">[0, 1, 1, 2, 2]</code></pre>
<p><strong>전체적인 코드 순서</strong></p>
<p>base_models  →  </p>
<p>meta_model  →  </p>
<p>StackingClassifier(estimators=base_models, final_estimator=meta_model)</p>
<table>
<thead>
<tr>
<th>파라미터 이름</th>
<th>하는 일</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>estimators</code></td>
<td><strong>기본 모델들(base learners)</strong> 정의</td>
<td>여러 모델들의 이름 + 인스턴스 리스트</td>
</tr>
<tr>
<td><code>final_estimator</code></td>
<td><strong>메타 모델</strong> 정의</td>
<td>base 모델의 예측 결과를 받아 <strong>최종 판단</strong>하는 모델</td>
</tr>
</tbody></table>
<p><code>estimators</code> : 여러 개의 모델(로지스틱, 트리, SVM 등)이 <strong>원래 입력 데이터를 보고 각각 예측</strong>하는 역할</p>
<p><code>final_estimator</code> : 각 모델이 낸 예측값을 모아서 <strong>최종적으로 “이게 정답이다!” 라고 판단하는 역할</strong></p>
<table>
<thead>
<tr>
<th>문제 유형</th>
<th>메타 모델 (보통 쓰는 것)</th>
</tr>
</thead>
<tbody><tr>
<td><strong>분류 문제 (classification)</strong></td>
<td>✅ <strong>로지스틱 회귀 (LogisticRegression)</strong></td>
</tr>
<tr>
<td><strong>회귀 문제 (regression)</strong></td>
<td>✅ <strong>릿지 회귀 / 선형 회귀 (RidgeCV / LinearRegression)</strong></td>
</tr>
</tbody></table>
<hr>
<h2 id="비지도-학습-unsupervised-learning---핵심">비지도 학습 (Unsupervised Learning) - 핵심</h2>
<table>
<thead>
<tr>
<th>모델명</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>KMeans</strong></td>
<td>대표적인 군집화 알고리즘</td>
</tr>
<tr>
<td><strong>DBSCAN</strong></td>
<td>밀도 기반 클러스터링</td>
</tr>
<tr>
<td><strong>PCA</strong></td>
<td>차원 축소 (주성분 분석)</td>
</tr>
<tr>
<td><strong>TSNE, UMAP</strong></td>
<td>시각화용 고급 차원 축소</td>
</tr>
<tr>
<td><strong>IsolationForest</strong></td>
<td>이상치 탐지 (비지도)</td>
</tr>
<tr>
<td>- KMeans</td>
<td></td>
</tr>
</tbody></table>
<pre><code>## 개념

- **KMeans**는 데이터를 **K개의 군집으로 분할**하는 알고리즘
- 각 군집은 하나의 중심점(centroid)을 가지고, 데이터는 이 중심점에 가장 가까운 군집에 속함
- 반복적으로 중심점과 군집을 재조정하면서 최적화

### 동작 과정:

1. 임의로 K개의 중심점(centroids)을 선택
2. 각 데이터를 가장 가까운 중심점에 할당
3. 각 군집의 평균값으로 중심점 업데이트
4. 중심점 변화가 거의 없거나 최대 반복 횟수 도달 시 종료

## 언제 사용하나?

- 데이터를 **명확히 K개의 그룹으로 나눌 수 있다고 가정**할 때
- 데이터의 **중심이 존재**하는 군집이 있을 때
- 고객 세분화, 문서 분류, 이미지 압축 등에서 자주 사용

## 사용 라이브러리 및 코드 예시

```python
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt

# 예시 데이터 생성
X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.6, random_state=42)

# KMeans 모델 생성 및 학습
kmeans = KMeans(n_clusters=4, random_state=42)
kmeans.fit(X)

# 예측 결과
y_pred = kmeans.predict(X)

# 군집 중심점
centroids = kmeans.cluster_centers_

# 시각화
plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap=&#39;viridis&#39;, alpha=0.6)
plt.scatter(centroids[:, 0], centroids[:, 1], s=200, c=&#39;red&#39;, marker=&#39;X&#39;, label=&#39;Centroids&#39;)
plt.title(&#39;KMeans Clustering&#39;)
plt.legend()
plt.show()
```

---

## 결과 해석

- 산점도 위에 각 데이터 포인트는 색깔로 군집이 구분됨
- 빨간 X는 각 군집의 중심 (centroid)
- 군집이 잘 나눠진 형태일 경우, 비슷한 성향의 데이터를 같은 군집으로 묶음

## 특징 요약

| 항목 | 설명 |
| --- | --- |
| **장점** | 단순, 빠름, 대규모 데이터에 잘 작동 |
| **단점** | K를 사전에 알아야 함, 이상치에 민감 |
| **가정** | 각 군집이 원형이고, 같은 분산을 가짐 |

## 참고: 최적의 K 찾는 방법 (엘보우 방법)

```python
inertias = []
for k in range(1, 10):
    km = KMeans(n_clusters=k, random_state=42)
    km.fit(X)
    inertias.append(km.inertia_)  # 군집 내 거리합 (작을수록 군집 잘 됨)

plt.plot(range(1, 10), inertias, marker=&#39;o&#39;)
plt.title(&#39;Elbow Method&#39;)
plt.xlabel(&#39;K&#39;)
plt.ylabel(&#39;Inertia&#39;)
plt.show()
```

- 그래프에서 **급격히 감소하다가 완만해지는 지점**이 최적의 K</code></pre><ul>
<li><p><strong>DBSCAN → 필수</strong></p>
<h2 id="개념-1">개념</h2>
<ul>
<li><p><strong>DBSCAN</strong>은 <strong>밀도 기반</strong> 군집화 알고리즘</p>
</li>
<li><p><strong>밀도가 높은 지역은 군집으로 묶고</strong>, 밀도가 낮은 지역은 이상치(노이즈)로 처리</p>
<h3 id="핵심-아이디어">핵심 아이디어</h3>
</li>
<li><p>어떤 점의 주변 반경(ε, 입실론) 안에 최소 n개의 이웃(min_samples)이 있으면, 이 점은 <strong>코어 포인트(Core Point)</strong> 라고 부름.</p>
</li>
<li><p>코어 포인트 주변에 연결된 점들을 <strong>같은 군집</strong>으로 묶음.</p>
</li>
<li><p>밀도가 낮은 지역에 있는 점들은 <strong>노이즈 (Noise)</strong> 로 간주됨.</p>
</li>
</ul>
<hr>
<h2 id="언제-사용하나-1">언제 사용하나?</h2>
<table>
<thead>
<tr>
<th>사용 시점</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td><strong>클러스터 개수를 모르거나 정하기 어렵다</strong></td>
<td>DBSCAN은 군집 수를 자동으로 결정해줘</td>
</tr>
<tr>
<td><strong>복잡한 모양의 군집이 있을 때</strong></td>
<td>KMeans는 원형 군집만 잘 나누지만, DBSCAN은 자유로운 모양 가능</td>
</tr>
<tr>
<td><strong>이상치를 잘 처리하고 싶을 때</strong></td>
<td>노이즈 포인트를 따로 분류해줌</td>
</tr>
</tbody></table>
<hr>
<h2 id="주요-파라미터-2">주요 파라미터</h2>
<table>
<thead>
<tr>
<th>파라미터</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>eps</code></td>
<td>점 주변의 반경 (이 거리 안에 몇 개의 점이 있는지 봄)</td>
</tr>
<tr>
<td><code>min_samples</code></td>
<td>eps 거리 내에 있어야 할 최소 이웃 수 (이 수 이상이면 Core Point)</td>
</tr>
</tbody></table>
<hr>
<h2 id="사용-코드-scikit-learn">사용 코드 (Scikit-learn)</h2>
<pre><code class="language-python">  from sklearn.datasets import make_moons
  from sklearn.cluster import DBSCAN
  import matplotlib.pyplot as plt
  import numpy as np

  # 데이터 생성 (복잡한 모양)
  X, _ = make_moons(n_samples=300, noise=0.05, random_state=0)

  # DBSCAN 모델 생성 및 학습
  db = DBSCAN(eps=0.2, min_samples=5)
  y_db = db.fit_predict(X)

  # 시각화
  plt.scatter(X[:, 0], X[:, 1], c=y_db, cmap=&#39;plasma&#39;, s=50)
  plt.title(&quot;DBSCAN Clustering Result&quot;)
  plt.xlabel(&quot;X&quot;)
  plt.ylabel(&quot;Y&quot;)
  plt.show()</code></pre>
<hr>
<h2 id="결과-예시-1">결과 예시</h2>
<ul>
<li><p><strong>같은 색깔</strong> → 같은 군집</p>
</li>
<li><p><strong>1로 라벨링된 점들</strong> → 노이즈로 간주된 점들</p>
<blockquote>
<p>DBSCAN은 fit_predict()로 바로 군집 번호를 예측</p>
<ul>
<li><code>1</code>은 이상치(노이즈)로 판별된 데이터 포인트를 의미</li>
</ul>
</blockquote>
</li>
</ul>
<hr>
<h2 id="예시-결과-y_db-값-일부">예시 결과 (y_db 값 일부)</h2>
<pre><code class="language-python">  array([0, 1, 1, 0, 0, 0, 1, 1, -1, 1, 1, 0, 0, ...])</code></pre>
<ul>
<li><code>0, 1</code> → 군집 번호</li>
<li><code>1</code> → 노이즈</li>
</ul>
<hr>
<h2 id="장단점-정리">장단점 정리</h2>
<table>
<thead>
<tr>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>군집 수 자동 결정 (K 설정 X)</td>
<td>eps와 min_samples 설정이 어렵고 민감함</td>
</tr>
<tr>
<td>이상치 탐지 기능 포함</td>
<td>고차원에서는 성능 저하 가능</td>
</tr>
<tr>
<td>비원형, 복잡한 모양도 잘 클러스터링</td>
<td>밀도가 균일하지 않으면 잘 안 나뉨</td>
</tr>
</tbody></table>
<hr>
<h2 id="적절한-eps-찾는-방법-k-distance-plot">적절한 eps 찾는 방법 (K-distance plot)</h2>
<pre><code class="language-python">  from sklearn.neighbors import NearestNeighbors

  neigh = NearestNeighbors(n_neighbors=5)
  nbrs = neigh.fit(X)
  distances, indices = nbrs.kneighbors(X)

  # 거리 정렬 후 시각화
  distances = np.sort(distances[:, 4])
  plt.plot(distances)
  plt.title(&quot;K-distance Graph (5-NN)&quot;)
  plt.xlabel(&quot;Points&quot;)
  plt.ylabel(&quot;5th Nearest Distance&quot;)
  plt.show()</code></pre>
<ul>
<li>꺾이는 지점(엘보우)을 <strong>eps 값</strong>으로 사용하면 좋음.</li>
</ul>
<hr>
<h2 id="dbscan-요약">DBSCAN 요약</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>군집 수 지정?</td>
<td>불필요</td>
</tr>
<tr>
<td>이상치 감지</td>
<td>가능</td>
</tr>
<tr>
<td>자유로운 군집 모양</td>
<td>가능</td>
</tr>
<tr>
<td>복잡한 데이터</td>
<td>매우 적합</td>
</tr>
<tr>
<td>대표 활용</td>
<td>지리정보(위치기반), 이상탐지, 이미지 분석</td>
</tr>
</tbody></table>
</li>
<li><p><strong>PCA(차원축소)</strong></p>
<h2 id="pca란">PCA란?</h2>
<blockquote>
<p>PCA는 고차원 데이터를 저차원으로 줄이되, 데이터의 분산(정보)을 최대한 보존하는 방식의 차원 축소 기법</p>
</blockquote>
<ul>
<li>PCA는 데이터를 회전시켜 가장 잘 퍼져 있는 방향(=주성분)을 찾아</li>
<li>원래 데이터의 축 대신 새 축(주성분 축)으로 데이터를 표현</li>
</ul>
<hr>
<h3 id="예시-3">예시</h3>
<p>  2차원 데이터</p>
<pre><code>
  x축 →
  ⬛      ⬛
     ⬛  ⬛
       ⬛
     ⬛  ⬛
  ⬛      ⬛
                    ↖  주성분 방향 (제일 넓게 퍼진 방향)
</code></pre><p>  → PCA는 이 <strong>대각선 방향</strong>을 새로운 x축으로 잡고,</p>
<p>  이 위에 데이터를 <strong>투영해서</strong> 1차원으로 줄이는 거예요.</p>
<hr>
<h2 id="2-언제-사용하는가">2. 언제 사용하는가?</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>피처 수가 너무 많아서 연산이 느릴 때</td>
<td>→ 불필요한 정보를 줄이고 빠르게 처리 가능</td>
</tr>
<tr>
<td>데이터 시각화가 필요할 때</td>
<td>→ 2D, 3D로 축소하여 시각화</td>
</tr>
<tr>
<td>머신러닝 전처리로 과적합 줄이고 싶을 때</td>
<td>→ 불필요한 노이즈 제거</td>
</tr>
<tr>
<td>피처 간 상관관계가 높을 때</td>
<td>→ 새로운 축은 서로 직교함 (상관 X)</td>
</tr>
</tbody></table>
<hr>
<h2 id="3-pca-내부-동작-원리-수학-포함">3. PCA 내부 동작 원리 (수학 포함)</h2>
<ol>
<li><p><strong>데이터 정규화 (평균 0, 분산 1)</strong></p>
<p> → StandardScaler 등으로 먼저 스케일 조정</p>
</li>
<li><p><strong>공분산 행렬 계산</strong>Cov(X)=n−11XTX</p>
<p> Cov(X)=1n−1XTX\text{Cov}(X) = \frac{1}{n-1} X^T X</p>
<p> → 어떤 방향으로 데이터가 가장 잘 퍼져 있는지를 확인</p>
</li>
<li><p><strong>고유값 분해 (Eigen Decomposition)</strong></p>
<p> → 공분산 행렬을 분해해서 <strong>고유값 + 고유벡터</strong>를 얻음</p>
<p> → 고유벡터가 <strong>주성분 방향</strong>, 고유값은 <strong>분산의 크기</strong></p>
</li>
<li><p><strong>고유값이 큰 순으로 주성분 선택</strong></p>
<p> → 정보를 많이 담은 축부터 순서대로 사용</p>
</li>
<li><p><strong>원 데이터를 주성분 축으로 투영 (변환)</strong></p>
<p> → 차원 축소된 새로운 데이터 완성</p>
</li>
</ol>
</li>
</ul>
<pre><code>---

## 4. 파이썬 코드 예제

```python

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA

# 1. 데이터 로딩
data = load_iris()
X = data.data
y = data.target

# 2. 스케일링 (PCA 전에 꼭 필요!)
X_scaled = StandardScaler().fit_transform(X)

# 3. PCA 적용 (2차원으로 축소)
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)

# 4. 시각화
plt.figure(figsize=(8,6))
plt.scatter(X_pca[:, 0], X_pca[:, 1], c=y, cmap=&#39;viridis&#39;)
plt.xlabel(&#39;PC 1&#39;)
plt.ylabel(&#39;PC 2&#39;)
plt.title(&#39;PCA - Iris Dataset&#39;)
plt.colorbar(label=&#39;Target&#39;)
plt.show()

```

---

## 5. 출력 결과 예시

- `X_pca.shape` → `(150, 2)` ← 원래는 4차원 → 2차원으로 줄어듦
- 시각화: 군집별로 **잘 분리된 결과 확인 가능** (꽃 종류에 따라 나뉨)

---

## 6. 주요 속성 및 메서드

| 속성 / 메서드 | 설명 |
| --- | --- |
| `pca.components_` | 주성분 축 (고유벡터들) |
| `pca.explained_variance_` | 각 주성분의 고유값 (분산 크기) |
| `pca.explained_variance_ratio_` | 각 주성분이 설명하는 전체 분산의 비율 |
| `pca.singular_values_` | 특이값 분해 시 사용하는 값 |
| `fit()` | 주성분 방향 계산만 함 |
| `transform()` | 이미 계산된 축으로 데이터 변환 |
| `fit_transform()` | 위 둘을 한 번에 실행 |

---

## 7. `explained_variance_ratio_`로 몇 개의 차원만 쓸지 결정 가능!

```python
print(pca.explained_variance_ratio_)
print(sum(pca.explained_variance_ratio_))  # 총 분산 설명량
```

&gt; 예: [0.72, 0.23] → 총 95% 설명 → 2개만 써도 충분!
&gt; 

- **??????????????**

    &gt; pca.explained_variance_ratio_는
    &gt; 
    &gt; 
    &gt; 각 **주성분 축(PC1, PC2, …)** 이 **원본 데이터의 분산을 얼마나 설명하는지를 비율로** 나타낸 거야.
    &gt; 

    ---

    ## 예시

    원래 데이터가 **4차원**이었다고 해보자.

    그럼 PCA는 이렇게 물어봐요:

    &gt; &quot;이 4개의 축(컬럼)을 새로운 축으로 바꿔서, **정보(분산)**를 압축하고 싶은데...
    &gt; 
    &gt; 
    &gt; 그럼 새로 만든 축(PCA 축)들이 원래 정보를 **얼마나 잘 담고 있는지** 확인해보자!&quot;
    &gt; 

    ---

    ## 실제 출력

    ```python

    from sklearn.decomposition import PCA
    from sklearn.preprocessing import StandardScaler
    from sklearn.datasets import load_iris

    data = load_iris()
    X = data.data

    # 표준화 → PCA 필수!
    X_scaled = StandardScaler().fit_transform(X)

    # PCA 전체 축 계산 (4개 원래 차원 전부)
    pca = PCA()
    X_pca = pca.fit_transform(X_scaled)

    print(pca.explained_variance_ratio_)
    print(sum(pca.explained_variance_ratio_))

    ```

    출력 예:

    ```

    [0.72962445 0.22850762 0.03668922 0.00517871]
    0.9999999999999999
    ```

    ---

    ### 이게 무슨 뜻이야?

    | 주성분 축 (PC) | 설명 비율 (%) |
    | --- | --- |
    | PC1 (1번째 축) | **72.96%** |
    | PC2 (2번째 축) | **22.85%** |
    | PC3 | 3.66% |
    | PC4 | 0.52% |
    | **총합** | 100% (모든 정보 포함) |

    ---

    ## 핵심 포인트! 왜 중요한가?

    &gt; 주성분들은 정보를 많이 담은 순서대로 정렬돼 있어요.
    &gt; 
    &gt; 
    &gt; 즉,
    &gt; 
    - **PC1이 가장 중요**
    - **PC2는 그 다음**
    - …
    - **PC4는 거의 쓸모 없음**

    ---

    ## 그래서 `n_components`를 어떻게 결정해?

    예를 들어:

    ```python
    pca = PCA(n_components=2)
    ```

    이렇게 하면:

    → **PC1 + PC2만 사용**

    → 위 예에서 72.96% + 22.85% = **약 95.8%** 정보 유지됨

    즉! **2개 축만 사용해도 거의 모든 정보(95%)가 보존되는 것!**

    그래서:

    ```python
    print(pca.explained_variance_ratio_)
    print(sum(pca.explained_variance_ratio_))  # 총 분산 설명량
    ```

    이걸 출력해서 &quot;**몇 개의 차원을 쓰면 충분한가?**&quot; 판단하는 데 쓰는 거야!

    ---

    ## 시각적으로 보면?

    | PC1 | PC2 | PC3 | PC4 |
    | --- | --- | --- | --- |
    | ▓▓▓▓▓▓▓▓▓▓▓ | ▓▓▓▓▓▓▓▓ | ▓ | ░ |
    | 72.9% | 22.8% | 3.7% | 0.5% |

    ✔️ → 그럼 우리는 &quot;PC1 + PC2만 쓰면 되겠다!&quot; 하고 `n_components=2`로 줄일 수 있어.

    ---

    ## 만약 자동으로 차원 수를 정하고 싶다면?

    ```python
    pca = PCA(n_components=0.95)
    ```

    이렇게 쓰면:

    → **자동으로 95% 이상 분산을 설명하는 최소한의 차원 수만 유지!**

    → 사람이 직접 2, 3 이렇게 안 정해도 됨

    ---

    ## 정리 요약

    | 용어 | 의미 |
    | --- | --- |
    | `explained_variance_ratio_` | 각 PCA 축이 **전체 정보(분산)** 중 얼마나 설명하는지 비율 |
    | `sum(...)` | 총 몇 %의 정보를 보존하는지 확인 |
    | `n_components=2` | 앞에서 중요한 두 개의 축만 쓰겠다 |
    | `n_components=0.95` | 전체 분산의 95% 이상 설명하는 축을 자동으로 선택 |

---

## 실제 사용 예시

| 사용 상황 | 설명 |
| --- | --- |
| 시각화 | 고차원 데이터를 2D로 축소해서 plot |
| 전처리 | 차원을 줄이고 모델 성능 향상 |
| 노이즈 제거 | 주성분만 남기고 나머지는 버려서 잡음 제거 |
| 얼굴 인식 | Eigenface 기법도 PCA 기반 |

---

## 주의점

| 주의 사항 | 이유 |
| --- | --- |
| 꼭 `StandardScaler` 등으로 정규화 먼저 | 변수 스케일이 다르면 PCA가 왜곡됨 |
| 너무 많은 차원을 줄이면 정보 손실 | `explained_variance_ratio_`로 얼마나 설명하는지 확인해야 함 |
| 해석이 어려움 | 주성분 축은 기존 피처와 다르기 때문에 의미 해석 어려움 |

---

## 정리 요약

| 항목 | 설명 |
| --- | --- |
| 이름 | PCA (Principal Component Analysis) |
| 목적 | 차원 축소 + 정보 최대 보존 |
| 내부 동작 | 공분산 → 고유값 분해 → 투영 |
| 핵심 개념 | 분산을 많이 가진 방향으로 축을 새로 정함 |
| 언제 사용 | 고차원 데이터, 시각화, 과적합 방지 |
| 필수 전처리 | StandardScaler 등으로 정규화 |
| 결과 해석 | `explained_variance_ratio_`로 정보 보존량 확인 |</code></pre><ul>
<li><p>비지도 학습( Unsupervised Learning ) - 전체</p>
<h3 id="1-군집화-clustering">1. <strong>군집화 (Clustering)</strong></h3>
<p>  비슷한 데이터끼리 <strong>그룹</strong>으로 묶는 작업</p>
<table>
<thead>
<tr>
<th>알고리즘</th>
<th>설명</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td><strong>KMeans</strong></td>
<td>중심점 기반 군집화</td>
<td>단순, 빠름. 군집 수(k) 미리 정해야 함</td>
</tr>
<tr>
<td><strong>DBSCAN</strong></td>
<td>밀도 기반 클러스터링</td>
<td>이상치 탐지 포함, 클러스터 수 미정</td>
</tr>
<tr>
<td><strong>MeanShift</strong></td>
<td>밀도 기반 클러스터링</td>
<td>자동으로 클러스터 수 찾음</td>
</tr>
<tr>
<td><strong>Agglomerative Clustering</strong></td>
<td>계층적 군집화</td>
<td>덴드로그램 시각화 가능</td>
</tr>
<tr>
<td><strong>Spectral Clustering</strong></td>
<td>그래프 기반 클러스터링</td>
<td>복잡한 경계도 잘 나눔</td>
</tr>
</tbody></table>
<h2 id="군집화-알고리즘-비교표">군집화 알고리즘 비교표</h2>
<table>
<thead>
<tr>
<th>알고리즘</th>
<th>군집 수 자동</th>
<th>이상치 감지</th>
<th>비선형 구조</th>
<th>빠름</th>
<th>복잡도</th>
</tr>
</thead>
<tbody><tr>
<td>KMeans</td>
<td>❌ 필요</td>
<td>❌ 없음</td>
<td>❌ 약함</td>
<td>✅ 빠름</td>
<td>낮음</td>
</tr>
<tr>
<td>DBSCAN</td>
<td>✅ 자동</td>
<td>✅ 강함</td>
<td>✅ 강함</td>
<td>✅ 보통</td>
<td>중간</td>
</tr>
<tr>
<td>MeanShift</td>
<td>✅ 자동</td>
<td>❌ 약함</td>
<td>✅ 강함</td>
<td>❌ 느림</td>
<td>중간</td>
</tr>
<tr>
<td>Agglomerative</td>
<td>❌ (덴드로그램으로 조절)</td>
<td>❌ 없음</td>
<td>✅ 강함</td>
<td>❌ 느림</td>
<td>중간</td>
</tr>
<tr>
<td>Spectral</td>
<td>❌ 필요</td>
<td>❌ 없음</td>
<td>✅ 매우 강함</td>
<td>❌ 느림</td>
<td>높음</td>
</tr>
<tr>
<td>- KMeans</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody></table>
<pre><code>  ## 개념

  - **KMeans**는 데이터를 **K개의 군집으로 분할**하는 알고리즘
  - 각 군집은 하나의 중심점(centroid)을 가지고, 데이터는 이 중심점에 가장 가까운 군집에 속함
  - 반복적으로 중심점과 군집을 재조정하면서 최적화

  ### 동작 과정:

  1. 임의로 K개의 중심점(centroids)을 선택
  2. 각 데이터를 가장 가까운 중심점에 할당
  3. 각 군집의 평균값으로 중심점 업데이트
  4. 중심점 변화가 거의 없거나 최대 반복 횟수 도달 시 종료

  ## 언제 사용하나?

  - 데이터를 **명확히 K개의 그룹으로 나눌 수 있다고 가정**할 때
  - 데이터의 **중심이 존재**하는 군집이 있을 때
  - 고객 세분화, 문서 분류, 이미지 압축 등에서 자주 사용

  ## 사용 라이브러리 및 코드 예시

  ```python
  from sklearn.cluster import KMeans
  from sklearn.datasets import make_blobs
  import matplotlib.pyplot as plt

  # 예시 데이터 생성
  X, _ = make_blobs(n_samples=300, centers=4, cluster_std=0.6, random_state=42)

  # KMeans 모델 생성 및 학습
  kmeans = KMeans(n_clusters=4, random_state=42)
  kmeans.fit(X)

  # 예측 결과
  y_pred = kmeans.predict(X)

  # 군집 중심점
  centroids = kmeans.cluster_centers_

  # 시각화
  plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap=&#39;viridis&#39;, alpha=0.6)
  plt.scatter(centroids[:, 0], centroids[:, 1], s=200, c=&#39;red&#39;, marker=&#39;X&#39;, label=&#39;Centroids&#39;)
  plt.title(&#39;KMeans Clustering&#39;)
  plt.legend()
  plt.show()
  ```

  ---

  ## 결과 해석

  - 산점도 위에 각 데이터 포인트는 색깔로 군집이 구분됨
  - 빨간 X는 각 군집의 중심 (centroid)
  - 군집이 잘 나눠진 형태일 경우, 비슷한 성향의 데이터를 같은 군집으로 묶음

  ## 특징 요약

  | 항목 | 설명 |
  | --- | --- |
  | **장점** | 단순, 빠름, 대규모 데이터에 잘 작동 |
  | **단점** | K를 사전에 알아야 함, 이상치에 민감 |
  | **가정** | 각 군집이 원형이고, 같은 분산을 가짐 |

  ## 참고: 최적의 K 찾는 방법 (엘보우 방법)

  ```python
  inertias = []
  for k in range(1, 10):
      km = KMeans(n_clusters=k, random_state=42)
      km.fit(X)
      inertias.append(km.inertia_)  # 군집 내 거리합 (작을수록 군집 잘 됨)

  plt.plot(range(1, 10), inertias, marker=&#39;o&#39;)
  plt.title(&#39;Elbow Method&#39;)
  plt.xlabel(&#39;K&#39;)
  plt.ylabel(&#39;Inertia&#39;)
  plt.show()
  ```

  - 그래프에서 **급격히 감소하다가 완만해지는 지점**이 최적의 K</code></pre><ul>
<li><p><strong>DBSCAN</strong></p>
<h2 id="개념-2">개념</h2>
<ul>
<li><p><strong>DBSCAN</strong>은 <strong>밀도 기반</strong> 군집화 알고리즘</p>
</li>
<li><p><strong>밀도가 높은 지역은 군집으로 묶고</strong>, 밀도가 낮은 지역은 이상치(노이즈)로 처리</p>
<h3 id="핵심-아이디어-1">핵심 아이디어</h3>
</li>
<li><p>어떤 점의 주변 반경(ε, 입실론) 안에 최소 n개의 이웃(min_samples)이 있으면, 이 점은 <strong>코어 포인트(Core Point)</strong> 라고 부름.</p>
</li>
<li><p>코어 포인트 주변에 연결된 점들을 <strong>같은 군집</strong>으로 묶음.</p>
</li>
<li><p>밀도가 낮은 지역에 있는 점들은 <strong>노이즈 (Noise)</strong> 로 간주됨.</p>
</li>
</ul>
<hr>
<h2 id="언제-사용하나-2">언제 사용하나?</h2>
<table>
<thead>
<tr>
<th>사용 시점</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td><strong>클러스터 개수를 모르거나 정하기 어렵다</strong></td>
<td>DBSCAN은 군집 수를 자동으로 결정해줘</td>
</tr>
<tr>
<td><strong>복잡한 모양의 군집이 있을 때</strong></td>
<td>KMeans는 원형 군집만 잘 나누지만, DBSCAN은 자유로운 모양 가능</td>
</tr>
<tr>
<td><strong>이상치를 잘 처리하고 싶을 때</strong></td>
<td>노이즈 포인트를 따로 분류해줌</td>
</tr>
</tbody></table>
<hr>
<h2 id="주요-파라미터-3">주요 파라미터</h2>
<table>
<thead>
<tr>
<th>파라미터</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>eps</code></td>
<td>점 주변의 반경 (이 거리 안에 몇 개의 점이 있는지 봄)</td>
</tr>
<tr>
<td><code>min_samples</code></td>
<td>eps 거리 내에 있어야 할 최소 이웃 수 (이 수 이상이면 Core Point)</td>
</tr>
</tbody></table>
<hr>
<h2 id="사용-코드-scikit-learn-1">사용 코드 (Scikit-learn)</h2>
<pre><code class="language-python">  from sklearn.datasets import make_moons
  from sklearn.cluster import DBSCAN
  import matplotlib.pyplot as plt
  import numpy as np

  # 데이터 생성 (복잡한 모양)
  X, _ = make_moons(n_samples=300, noise=0.05, random_state=0)

  # DBSCAN 모델 생성 및 학습
  db = DBSCAN(eps=0.2, min_samples=5)
  y_db = db.fit_predict(X)

  # 시각화
  plt.scatter(X[:, 0], X[:, 1], c=y_db, cmap=&#39;plasma&#39;, s=50)
  plt.title(&quot;DBSCAN Clustering Result&quot;)
  plt.xlabel(&quot;X&quot;)
  plt.ylabel(&quot;Y&quot;)
  plt.show()</code></pre>
<hr>
<h2 id="결과-예시-2">결과 예시</h2>
<ul>
<li><p><strong>같은 색깔</strong> → 같은 군집</p>
</li>
<li><p><strong>1로 라벨링된 점들</strong> → 노이즈로 간주된 점들</p>
<blockquote>
<p>DBSCAN은 fit_predict()로 바로 군집 번호를 예측</p>
<ul>
<li><code>1</code>은 이상치(노이즈)로 판별된 데이터 포인트를 의미</li>
</ul>
</blockquote>
</li>
</ul>
<hr>
<h2 id="예시-결과-y_db-값-일부-1">예시 결과 (y_db 값 일부)</h2>
<pre><code class="language-python">  array([0, 1, 1, 0, 0, 0, 1, 1, -1, 1, 1, 0, 0, ...])</code></pre>
<ul>
<li><code>0, 1</code> → 군집 번호</li>
<li><code>1</code> → 노이즈</li>
</ul>
<hr>
<h2 id="장단점-정리-1">장단점 정리</h2>
<table>
<thead>
<tr>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>군집 수 자동 결정 (K 설정 X)</td>
<td>eps와 min_samples 설정이 어렵고 민감함</td>
</tr>
<tr>
<td>이상치 탐지 기능 포함</td>
<td>고차원에서는 성능 저하 가능</td>
</tr>
<tr>
<td>비원형, 복잡한 모양도 잘 클러스터링</td>
<td>밀도가 균일하지 않으면 잘 안 나뉨</td>
</tr>
</tbody></table>
<hr>
<h2 id="적절한-eps-찾는-방법-k-distance-plot-1">적절한 eps 찾는 방법 (K-distance plot)</h2>
<pre><code class="language-python">  from sklearn.neighbors import NearestNeighbors

  neigh = NearestNeighbors(n_neighbors=5)
  nbrs = neigh.fit(X)
  distances, indices = nbrs.kneighbors(X)

  # 거리 정렬 후 시각화
  distances = np.sort(distances[:, 4])
  plt.plot(distances)
  plt.title(&quot;K-distance Graph (5-NN)&quot;)
  plt.xlabel(&quot;Points&quot;)
  plt.ylabel(&quot;5th Nearest Distance&quot;)
  plt.show()</code></pre>
<ul>
<li>꺾이는 지점(엘보우)을 <strong>eps 값</strong>으로 사용하면 좋음.</li>
</ul>
<hr>
<h2 id="dbscan-요약-1">DBSCAN 요약</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>군집 수 지정?</td>
<td>불필요</td>
</tr>
<tr>
<td>이상치 감지</td>
<td>가능</td>
</tr>
<tr>
<td>자유로운 군집 모양</td>
<td>가능</td>
</tr>
<tr>
<td>복잡한 데이터</td>
<td>매우 적합</td>
</tr>
<tr>
<td>대표 활용</td>
<td>지리정보(위치기반), 이상탐지, 이미지 분석</td>
</tr>
</tbody></table>
</li>
<li><p><strong>MeanShift</strong></p>
<h2 id="개념-3">개념</h2>
<ul>
<li><p><strong>MeanShift</strong>는 데이터의 <strong>밀도(density)가 높은 방향으로 중심점을 이동</strong>시켜서 군집을 찾는 알고리즘</p>
</li>
<li><p>이름 그대로, <strong>“평균(Mean)” 방향으로 이동(Shift)”</strong> 한다는 의미!</p>
<h3 id="핵심-아이디어-2">핵심 아이디어</h3>
</li>
<li><p>각 데이터 포인트에서 주변 데이터를 살펴보고, <strong>그들의 평균으로 계속 이동</strong>한다.</p>
</li>
<li><p>이 과정을 반복하면서 밀도가 높은 지점으로 중심이 이동 → 결국 <strong>데이터 밀집된 지점들이 군집의 중심점</strong>이 됨.</p>
</li>
</ul>
<hr>
<h2 id="언제-사용-3">언제 사용?</h2>
<table>
<thead>
<tr>
<th>사용 상황</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td>군집 수를 <strong>사전에 정하기 어려운 경우</strong></td>
<td>MeanShift는 자동으로 군집 수를 결정함</td>
</tr>
<tr>
<td><strong>데이터 밀집 정도가 중요할 때</strong></td>
<td>중심이 자동으로 조정되어 밀도가 높은 지점을 중심으로 클러스터 형성</td>
</tr>
<tr>
<td>군집 모양이 복잡하거나 <strong>비선형적인 경우</strong></td>
<td>KMeans와 달리 원형이 아니어도 잘 작동함</td>
</tr>
</tbody></table>
<hr>
<h2 id="파라미터">파라미터</h2>
<table>
<thead>
<tr>
<th>파라미터</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>bandwidth</code></td>
<td>중심점이 이웃을 인식하는 반경 (kernel window size)</td>
</tr>
<tr>
<td>→ 클수록 더 큰 지역 평균, 작을수록 세밀한 군집화</td>
<td></td>
</tr>
<tr>
<td><code>bin_seeding</code></td>
<td>빠른 계산을 위해 bin 기반 시드 사용 여부 (True로 하면 속도 ↑)</td>
</tr>
</tbody></table>
<blockquote>
<p>bandwidth는 전체 밀도에 영향을 주는 핵심 하이퍼파라미터.
  너무 크면 군집 수 적고, 너무 작으면 과도한 군집이 나옴.</p>
</blockquote>
<hr>
<h2 id="코드-예시-scikit-learn">코드 예시 (scikit-learn)</h2>
<pre><code class="language-python">  from sklearn.cluster import MeanShift, estimate_bandwidth
  from sklearn.datasets import make_blobs
  import matplotlib.pyplot as plt

  # 예시 데이터 생성
  X, _ = make_blobs(n_samples=300, centers=3, cluster_std=0.7, random_state=42)

  # bandwidth 자동 추정
  bandwidth = estimate_bandwidth(X, quantile=0.2)

  # MeanShift 모델 정의
  ms = MeanShift(bandwidth=bandwidth)
  ms.fit(X)

  # 결과
  labels = ms.labels_
  cluster_centers = ms.cluster_centers_

  # 시각화
  plt.scatter(X[:, 0], X[:, 1], c=labels, cmap=&#39;rainbow&#39;, s=50)
  plt.scatter(cluster_centers[:, 0], cluster_centers[:, 1], c=&#39;black&#39;, s=200, marker=&#39;X&#39;, label=&#39;Centers&#39;)
  plt.title(&#39;MeanShift Clustering&#39;)
  plt.legend()
  plt.show()</code></pre>
<hr>
<h2 id="예시-결과">예시 결과</h2>
<ul>
<li>데이터 밀집도가 높은 지역 중심으로 <strong>자동 군집화</strong></li>
<li><strong>X 마커</strong>가 군집의 중심점 (centroid)</li>
<li>군집 수는 따로 지정하지 않아도 <code>bandwidth</code>에 따라 자동 결정됨</li>
</ul>
<hr>
<h2 id="결과-출력-예시">결과 출력 예시</h2>
<pre><code class="language-python">  print(&quot;군집 수:&quot;, len(np.unique(labels)))
  print(&quot;레이블:&quot;, labels[:10])</code></pre>
<p>  예시 출력:</p>
<pre><code>  군집 수: 3
  레이블: [2 1 1 2 0 2 1 1 1 0]</code></pre><hr>
<h2 id="장점--단점">장점 &amp; 단점</h2>
<table>
<thead>
<tr>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>군집 수 자동 결정</td>
<td>느림 (특히 데이터 많을 때)</td>
</tr>
<tr>
<td>비원형, 복잡한 군집도 탐지 가능</td>
<td>bandwidth 설정에 민감</td>
</tr>
<tr>
<td>이상치에 어느 정도 강함</td>
<td>고차원에서는 성능 저하</td>
</tr>
</tbody></table>
<hr>
<h2 id="meanshift-요약">MeanShift 요약</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>군집 수 자동 결정</td>
<td>O</td>
</tr>
<tr>
<td>이상치 감지</td>
<td>직접적으로는 안됨</td>
</tr>
<tr>
<td>군집 모양</td>
<td>자유로움 (비선형 가능)</td>
</tr>
<tr>
<td>중심 계산 방식</td>
<td>주변 평균으로 이동 (Kernel 밀도 추정 기반)</td>
</tr>
<tr>
<td>추천 용도</td>
<td>GPS 기반 클러스터링, 이미지 분할, 복잡한 군집 탐색</td>
</tr>
</tbody></table>
</li>
<li><p><strong>Agglomerative Clustering(병합 계층적 군집화)</strong></p>
<h2 id="개념-4">개념</h2>
<ul>
<li><p><strong>Agglomerative Clustering</strong>은 <strong>계층적 군집화(Hierarchical Clustering)</strong> 방식 중 <strong>하향식(Bottom-up)</strong> 접근법</p>
</li>
<li><p>처음에는 모든 데이터를 <strong>하나씩 따로 군집으로 시작</strong>하고, 점차 서로 가까운 군집끼리 병합해서 하나의 트리 구조(덴드로그램)를 형성</p>
<blockquote>
<p>데이터들 간의 유사도(거리)를 기준으로 군집을 병합해 나가는 방식.</p>
<p>최종적으로 <strong>사용자가 자르는 지점에 따라 군집 수를 정할 수 있음.</strong></p>
</blockquote>
</li>
</ul>
<hr>
<h2 id="작동-과정-bottom-up-병합-방식">작동 과정 (Bottom-Up 병합 방식)</h2>
<ol>
<li>모든 데이터 포인트를 <strong>자기 자신만 포함하는 군집</strong>으로 시작</li>
<li>가장 가까운 두 군집을 찾아 <strong>병합</strong></li>
<li>이 과정을 하나의 군집이 남을 때까지 반복</li>
<li>군집 수는 최종 덴드로그램을 <strong>어디서 자르냐에 따라 정해짐</strong></li>
</ol>
<hr>
<h2 id="언제-사용-4">언제 사용?</h2>
<table>
<thead>
<tr>
<th>상황</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td><strong>군집 수를 직접 조절하거나 시각적으로 판단</strong>하고 싶을 때</td>
<td>덴드로그램으로 군집 수를 결정 가능</td>
</tr>
<tr>
<td><strong>군집 간의 관계나 계층적 구조가 있는 데이터</strong></td>
<td>예: 문서 분류, 생물 분류, 유전자 분석</td>
</tr>
<tr>
<td>KMeans처럼 중심점 가정이 어색한 경우</td>
<td>중심점 기반이 아님, 거리 기반이라 자유로움</td>
</tr>
</tbody></table>
<hr>
<h2 id="주요-파라미터-4">주요 파라미터</h2>
<table>
<thead>
<tr>
<th>파라미터</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>n_clusters</code></td>
<td>최종적으로 남길 군집 수 (덴드로그램 자르는 위치)</td>
</tr>
<tr>
<td><code>linkage</code></td>
<td>군집 간 거리 측정 방법 (<code>ward</code>, <code>average</code>, <code>complete</code>, <code>single</code>)</td>
</tr>
<tr>
<td><code>affinity</code></td>
<td>거리 계산 방식 (<code>euclidean</code>, <code>manhattan</code> 등)</td>
</tr>
</tbody></table>
<h3 id="linkage-설명">linkage 설명</h3>
<table>
<thead>
<tr>
<th>linkage 종류</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>ward</code></td>
<td>군집 내 분산을 최소화 (기본값)</td>
</tr>
<tr>
<td><code>average</code></td>
<td>군집 간 모든 점의 평균 거리</td>
</tr>
<tr>
<td><code>complete</code></td>
<td>군집 간 가장 먼 점끼리 거리</td>
</tr>
<tr>
<td><code>single</code></td>
<td>군집 간 가장 가까운 점끼리 거리 (연결만 잘 돼도 묶임)</td>
</tr>
</tbody></table>
<hr>
<h2 id="예제-코드-sklearn--scipy-for-dendrogram">예제 코드 (sklearn + scipy for dendrogram)</h2>
<pre><code class="language-python">  from sklearn.datasets import make_blobs
  from sklearn.cluster import AgglomerativeClustering
  import matplotlib.pyplot as plt
  import scipy.cluster.hierarchy as sch

  # 예시 데이터 생성
  X, _ = make_blobs(n_samples=200, centers=4, random_state=42)

  # 덴드로그램 그리기
  plt.figure(figsize=(10, 5))
  dendro = sch.dendrogram(sch.linkage(X, method=&#39;ward&#39;))
  plt.title(&quot;Dendrogram&quot;)
  plt.xlabel(&quot;Data Index&quot;)
  plt.ylabel(&quot;Distance&quot;)
  plt.show()</code></pre>
<blockquote>
<p>위 그래프에서 수직선이 길게 그려진 곳을 수평으로 자르면 군집 수가 정해짐. 예: 4개의 긴 가지 전에서 자르면 4개 군집.</p>
</blockquote>
<hr>
<h2 id="클러스터링-적용-코드">클러스터링 적용 코드</h2>
<pre><code class="language-python">  # 군집 수 4개로 클러스터링
  cluster = AgglomerativeClustering(n_clusters=4, affinity=&#39;euclidean&#39;, linkage=&#39;ward&#39;)
  y_pred = cluster.fit_predict(X)

  # 시각화
  plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap=&#39;rainbow&#39;)
  plt.title(&quot;Agglomerative Clustering Result&quot;)
  plt.show()</code></pre>
<hr>
<h2 id="결과-예시-해석">결과 예시 해석</h2>
<ul>
<li>각 군집은 색상으로 구분됨</li>
<li>덴드로그램으로 <strong>얼마나 유사한 군집끼리 먼저 병합됐는지</strong> 시각적으로 확인 가능</li>
<li><code>ward</code> linkage는 KMeans와 비슷하게 <strong>원형 구조에 강함</strong>, <code>complete</code>, <code>average</code>는 다양한 모양 처리 가능</li>
</ul>
<hr>
<h2 id="결과-출력">결과 출력</h2>
<pre><code class="language-python">  import numpy as np
  print(&quot;군집 레이블:&quot;, np.unique(y_pred))  # → [0 1 2 3]
  print(&quot;예측값 일부:&quot;, y_pred[:10])
</code></pre>
<hr>
<h2 id="장점--단점-요약">장점 &amp; 단점 요약</h2>
<table>
<thead>
<tr>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>덴드로그램으로 군집 수 조절 쉬움</td>
<td>큰 데이터셋엔 느림 (거리 계산이 많음)</td>
</tr>
<tr>
<td>다양한 linkage 전략 사용 가능</td>
<td>거리 기반이라 고차원엔 어려움</td>
</tr>
<tr>
<td>비선형, 다양한 군집 가능</td>
<td>이상치에 다소 민감</td>
</tr>
</tbody></table>
<hr>
<h2 id="agglomerative-clustering-요약">Agglomerative Clustering 요약</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>군집 수 자동 결정</td>
<td>없음. 덴드로그램에서 수동 조정 필요</td>
</tr>
<tr>
<td>이상치 감지</td>
<td>직접 탐지 기능 없음</td>
</tr>
<tr>
<td>군집 모양</td>
<td>자유롭고 계층적 구조 탐색 가능</td>
</tr>
<tr>
<td>중심점 사용</td>
<td>없음 (거리 기반 병합)</td>
</tr>
<tr>
<td>추천 용도</td>
<td>문서 분류, 유전자 분석, 소셜 네트워크 분석, 텍스트 마이닝</td>
</tr>
</tbody></table>
</li>
<li><p><strong>Spectral Clustering</strong></p>
<h2 id="개념-5">개념</h2>
<ul>
<li><p>스펙트럴(Spectral)이란 말 그대로 “스펙트럼 = 고유값(eigenvalue)” 기반의 클러스터링 기법</p>
</li>
<li><p>데이터 간 유사도(similarity)로 만든 <strong>그래프 구조</strong>를 기반으로</p>
<p>  → 그래프의 라플라시안 행렬(Laplacian Matrix)을 분해한 뒤,</p>
<p>  → 얻은 고유벡터들을 새로운 축으로 사용해서 군집화</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code>    ### 한마디로 요약

    &gt; 복잡한 구조의 데이터라도, 데이터 간 유사도만 정의할 수 있다면 그래프 형태로 표현해서, **비선형 구조**도 잘 클러스터링할 수 있음
    &gt; 

    ---

    ## 작동 원리 요약

    1. **유사도 행렬(Similarity Matrix)** 생성 (ex. 가우시안 커널, 거리 기반)
    2. 이걸로 **그래프 라플라시안 행렬**을 만든 뒤,
    3. **고유값 분해 (Eigen Decomposition)** 수행
    4. 주요 고유벡터들을 새로운 좌표(저차원 특징 공간)로 사용
    5. 이 특징 공간에서 **KMeans** 같은 방법으로 클러스터링 수행

    ---

    ## 언제 사용?

    | 사용 상황 | 이유 |
    | --- | --- |
    | 데이터의 구조가 **비선형 경계**일 때 | KMeans처럼 단순한 원형 분리가 불가능한 경우 |
    | **정확한 군집 수(K)를 알고 있고**, 복잡한 구조일 때 | 복잡한 경계의 데이터를 선형으로 잘 나눌 수 있음 |
    | **이미 유사도나 거리 정보가 있는 경우** | 유사도 기반이므로 다양한 입력 가능 |

    ---

    ## 장점 &amp; 단점

    | 장점 | 단점 |
    | --- | --- |
    | 비선형 경계도 잘 나눔 | 계산 복잡도 높음 (대규모 데이터엔 느림) |
    | 유사도 정의만 가능하면 매우 유연 | 클러스터 수 K 필요 |
    | 라플라시안 그래프 기반 | 수학적으로 직관 어렵고 구현 비용 ↑ |

    ---

    ## Scikit-learn 사용 코드

    ```python
    from sklearn.datasets import make_circles
    from sklearn.cluster import SpectralClustering
    import matplotlib.pyplot as plt

    # 데이터 생성 (KMeans로는 분리 어려운 원형 구조)
    X, _ = make_circles(n_samples=300, factor=0.5, noise=0.05, random_state=42)

    # 스펙트럴 클러스터링 적용
    sc = SpectralClustering(n_clusters=2, affinity=&#39;rbf&#39;, random_state=42)
    y_sc = sc.fit_predict(X)

    # 시각화
    plt.scatter(X[:, 0], X[:, 1], c=y_sc, cmap=&#39;plasma&#39;, s=50)
    plt.title(&quot;Spectral Clustering (비선형 구조 분리)&quot;)
    plt.xlabel(&quot;X1&quot;)
    plt.ylabel(&quot;X2&quot;)
    plt.show()
    ```

    ---

    ## 예시 결과 해석

    - **내부 원과 외부 원**이 잘 분리됨 → 일반적인 KMeans로는 불가능한 분리 구조
    - Spectral은 데이터 간 **유사도 기반으로 변형된 공간에서 클러스터링**하기 때문에 이런 것도 가능

    ---

    ## 주요 파라미터 설명

    | 파라미터 | 설명 |
    | --- | --- |
    | `n_clusters` | 군집 수 K |
    | `affinity` | 유사도 방식 (`rbf`, `nearest_neighbors`, `precomputed`) |
    | `assign_labels` | 클러스터링 방법 (`kmeans`, `discretize`) |
    | `gamma` | RBF 커널 계수 (affinity=&#39;rbf&#39;일 때 사용됨) |

    ---

    ## affinity 종류

    | 방식 | 설명 |
    | --- | --- |
    | `rbf` | 가우시안 커널 기반 거리 유사도 (기본값) |
    | `nearest_neighbors` | K-최근접 이웃 기반 그래프 생성 |
    | `precomputed` | 유사도 행렬 직접 전달 |

    ---

    ## 예시 출력

    ```python
    import numpy as np
    print(&quot;클러스터 레이블:&quot;, np.unique(y_sc))  # → [0 1]
    print(&quot;예측값 일부:&quot;, y_sc[:10])
    ```

    ---

    ## Spectral Clustering 요약

    | 항목 | 내용 |
    | --- | --- |
    | 군집 수 자동 설정 | 안됨. K 필요 |
    | 이상치 감지 | 지원 X |
    | 장점 | 복잡한 형태 분리 가능 (비선형, 복잡한 구조에 매우 강함) |
    | 핵심 기술 | 그래프 라플라시안 + 고유값 분해 + KMeans |
    | 추천 사용 | 이미지 분할, 원형·비선형 데이터, 정형화 어려운 문제 구조 |

    ---


---

### 2. **차원 축소 (Dimensionality Reduction)**

고차원 데이터를 **저차원**으로 압축하면서 **핵심 정보 유지**

| 알고리즘 | 설명 | 사용 용도 |
| --- | --- | --- |
| **PCA (주성분 분석)** | 선형 차원 축소 | 설명력 유지, 속도 빠름 |
| **t-SNE** | 비선형 축소, 시각화에 특화 | 데이터 구조 시각화 |
| **UMAP** | 시각화 + 군집 유지 | t-SNE보다 빠름, 군집형태 보존 |
| **TruncatedSVD** | 희소 행렬용 PCA | LSA에 사용 (텍스트) |
| **AutoEncoder** | 신경망 기반 차원 축소 | 비선형 축소, 재구성 가능 |
- **PCA**:
    - 가장 **기본적이면서도 강력**한 차원 축소 기법
    - 특히 머신러닝 전처리, 시각화 전 단계, 피처 압축에 자주 사용
- **t-SNE**:
    - 시각화 목적에 **매우 자주 사용**, 특히 **2D/3D 표현**
    - 단점: 속도 느리고, 새로운 데이터에 일반화 불가
- **UMAP**:
    - t-SNE 대체로 **요즘 인기 상승**
    - 시각화뿐 아니라 군집을 더 잘 유지함 (군집 기반 분석에 유리)
- **TruncatedSVD**:
    - **텍스트 데이터에 특화**, `CountVectorizer`, `TF-IDF` 결과에 사용
    - LSA (Latent Semantic Analysis)의 핵심 구성요소
- **AutoEncoder**:
    - 비선형 구조를 잘 잡아내지만, **신경망 설계 필요**
    - 실험적 분석이나 이상치 탐지, 이미지/신호 복원에 적합

### **많이 쓰는 경우 요약**

| 알고리즘 | 실제 사용 빈도 | 많이 쓰는 목적 |
| --- | --- | --- |
| **PCA** | 매우 높음 | 데이터 전처리, 속도 개선, 노이즈 제거 |
| **t-SNE** | 중간 | 고차원 데이터 시각화 (특히 논문/보고서용) |
| **UMAP** | 증가 추세 | 시각화 + 군집 형태 분석 (t-SNE 대체) |
| **TruncatedSVD** | 높음 (텍스트) | 희소 텍스트 데이터의 차원 축소 (LSA) |
| **AutoEncoder** | 실험적/깊이 있는 분석 | 비선형 차원 축소, 재구성/이상탐지 |
- **일반적인 데이터 전처리**: `PCA`
- **텍스트 (희소 행렬)**: `TruncatedSVD`
- **시각화**: `t-SNE`, `UMAP`
- **딥러닝 기반 실험/연구**: `AutoEncoder`

## PCA vs TruncatedSVD

## 1. 기본 개념 비교

| 항목 | **PCA (Principal Component Analysis)** | **TruncatedSVD (Truncated Singular Value Decomposition)** |
| --- | --- | --- |
| 목적 | 분산(설명력)이 큰 축을 기준으로 차원 축소 | SVD를 통해 주요 축만 남겨 차원 축소 |
| 입력 데이터 | **Dense (밀집)** 행렬에 적합 | **Sparse (희소)** 행렬도 처리 가능 |
| 특징 | 데이터를 **평균 중심화(mean centering)**함 | 평균 중심화하지 않음 (빠름, sparse 유지) |
| 주요 사용 | 수치 데이터 일반 차원 축소 | **텍스트 데이터**(TF-IDF 등) 차원 축소 |
| 결과 해석 | 분산 보존 기준 주성분 생성 | SVD 기반 주성분, 직관적 해석 어려움 |

---

## 2. 내부 작동 방식 차이

### PCA: 고전적인 방식

1. 입력 행렬 XXX에서 **평균 제거 (centering)**:Xcentered=X−Xˉ

    Xcentered=X−XˉX_{\text{centered}} = X - \bar{X}

2. 공분산 행렬 계산:Σ=n1X⊤X

    Σ=1nX⊤X\Sigma = \frac{1}{n} X^\top X

3. 고유값 분해 (Eigen Decomposition):Σ=VΛV⊤

    Σ=VΛV⊤\Sigma = V \Lambda V^\top

4. 고유값이 큰 순으로 일부 주성분 선택 → 저차원 투영

---

### TruncatedSVD: 희소 행렬 전용

1. 입력 행렬 XXX (희소 가능)에 대해 **SVD 수행**:X≈UkΣkVk⊤

    X≈UkΣkVk⊤X \approx U_k \Sigma_k V_k^\top

    단, 전체 SVD가 아닌 **앞부분 kkk개만 자름 (truncated)**

2. 결과로 **저차원 잠재 요인(latent semantics)** 공간 생성
3. **mean-centering을 하지 않으므로**, 텍스트처럼 0이 많은 희소 행렬의 구조 유지됨

---

## 3. 중요한 차이점 요약

| 구분 | PCA | TruncatedSVD |
| --- | --- | --- |
| **Mean-centering** | 수행함 | 수행 안 함 |
| **희소행렬 처리** | 어렵거나 비효율적 | 효율적 (희소성 유지) |
| **속도** | 느릴 수 있음 | 상대적으로 빠름 |
| **적용 예시** | 수치 데이터 | 텍스트 벡터 (TF-IDF, CountVectorizer) |
| **수학적 기반** | 공분산 행렬 고유값 분해 | SVD 분해 (특이값 분해) |
| **라이브러리** | `sklearn.decomposition.PCA` | `sklearn.decomposition.TruncatedSVD` |

---

## 4. 예제 코드 비교

### PCA 예제

```python
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
import pandas as pd

# 수치 데이터 예시
df = pd.DataFrame({
    &#39;x1&#39;: [1, 2, 3],
    &#39;x2&#39;: [4, 5, 6],
    &#39;x3&#39;: [7, 8, 9]
})

scaler = StandardScaler()
X_scaled = scaler.fit_transform(df)

pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
```

---

### TruncatedSVD 예제 (TF-IDF 전처리 후)

```python
from sklearn.decomposition import TruncatedSVD
from sklearn.feature_extraction.text import TfidfVectorizer

corpus = [
    &quot;dog cat mouse&quot;,
    &quot;dog dog tiger&quot;,
    &quot;cat tiger lion&quot;
]

vectorizer = TfidfVectorizer()
X_tfidf = vectorizer.fit_transform(corpus)

svd = TruncatedSVD(n_components=2)
X_svd = svd.fit_transform(X_tfidf)
```

---

## 5. 결론

| 목적 | 추천 방법 |
| --- | --- |
| 일반 수치 데이터의 차원 축소 | **PCA** |
| **텍스트 벡터 (희소행렬)**의 차원 축소 | **TruncatedSVD** |
| 속도/희소성 유지가 중요할 때 | **TruncatedSVD** |
| 데이터 분산 기반 축소, 해석이 중요한 경우 | **PCA** |

---

### 3. **이상치 탐지 (Outlier Detection)**

다수와 다른 데이터 탐지 → 비정상 여부 판단

| 알고리즘 | 설명 | 장점 |
| --- | --- | --- |
| **Isolation Forest** | 트리 구조 기반, 이상치 격리 | 고차원 데이터에 강함 |
| **One-Class SVM** | SVM으로 경계 생성 | 정규 데이터만 학습 |
| **Elliptic Envelope** | 가우시안 분포 가정 | 통계 기반 탐지 |
| **LOF (Local Outlier Factor)** | 주변 밀도 비교 | 지역적 이상치 탐지 |

---

### 4. **연관 규칙 학습 (Association Rule Learning)**

물건 A를 사면 B도 살 확률은? → **장바구니 분석**

| 알고리즘 | 설명 | 대표 사용처 |
| --- | --- | --- |
| **Apriori** | 항목 집합의 지지도 계산 | 마트, 추천 시스템 |
| **FP-Growth** | 빈발 패턴 트리 기반 | 대규모 데이터에 적합 |

---

### 5. **행렬 분해(Matrix Factorization)**

추천 시스템의 핵심! → 사용자-아이템 관계 예측

| 알고리즘 | 설명 | 용도 |
| --- | --- | --- |
| **SVD (Singular Value Decomposition)** | 사용자-아이템 행렬 분해 | 추천 시스템 |
| **NMF (Non-negative Matrix Factorization)** | 음수가 없는 행렬 분해 | 해석 쉬움, 추천에 활용 |</code></pre><hr>
<h1 id="강화학습">강화학습</h1>
<ul>
<li>에이전트(Agent)가 환경(Environment)과 상호작용하면서 행동(Action)을 선택하고, 보상(Reward)을 받으며 학습</li>
<li><strong>목표</strong>: 누적 보상(total reward)를 최대화하는 행동 전략(정책, policy) 학습</li>
</ul>
<h3 id="기본-구성-요소">기본 구성 요소</h3>
<table>
<thead>
<tr>
<th>구성 요소</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>State (s)</strong></td>
<td>현재 환경의 상태 (예: 로봇의 위치)</td>
</tr>
<tr>
<td><strong>Action (a)</strong></td>
<td>에이전트가 선택할 수 있는 행동</td>
</tr>
<tr>
<td><strong>Reward (r)</strong></td>
<td>행동의 결과로 받는 수치형 보상</td>
</tr>
<tr>
<td><strong>Policy (π)</strong></td>
<td>상태에서 어떤 행동을 할지 결정하는 전략</td>
</tr>
<tr>
<td><strong>Value Function (V(s), Q(s,a))</strong></td>
<td>특정 상태(또는 상태-행동)에 대한 기대 보상</td>
</tr>
<tr>
<td><strong>Environment</strong></td>
<td>상태-보상-상태 전이 구조를 가진 외부 시스템</td>
</tr>
</tbody></table>
<h3 id="구현-공통-구조">구현 공통 구조</h3>
<pre><code>1. 환경 정의 (OpenAI Gym 등)
2. 에이전트 클래스 정의 (정책, 가치 함수, Q-table, 신경망 등)
3. 행동 선택 (탐험/이용)
4. 학습(업데이트) 로직
5. 학습 루프 (에피소드 반복)
6. 성능 평가 및 시각화</code></pre><hr>
<h3 id="학습-과정-예시">학습 과정 예시</h3>
<ol>
<li>에이전트가 상태 $s_t$에서 행동 $a_t$ 선택</li>
<li>환경이 행동에 대한 보상 $r_t$와 <strong>다음 상태 $s_{t+1}$</strong> 제공</li>
<li>에이전트는 경험을 바탕으로 정책/가치 함수 업데이트</li>
<li>반복 → 최적 정책에 수렴</li>
</ol>
<hr>
<table>
<thead>
<tr>
<th>알고리즘</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Q-Learning</strong></td>
<td>테이블 방식 Q(s, a) 업데이트</td>
</tr>
<tr>
<td><strong>SARSA</strong></td>
<td>행동 후 보상 기반 Q 업데이트 (on-policy)</td>
</tr>
<tr>
<td><strong>DQN (Deep Q-Network)</strong></td>
<td>Q-Learning + 딥러닝</td>
</tr>
<tr>
<td><strong>Policy Gradient</strong></td>
<td>정책 함수를 직접 학습</td>
</tr>
<tr>
<td><strong>REINFORCE</strong></td>
<td>가장 기본적인 정책 경사법</td>
</tr>
<tr>
<td><strong>Actor-Critic</strong></td>
<td>정책(Actor) + 가치(Critic)를 분리</td>
</tr>
<tr>
<td><strong>PPO (Proximal Policy Optimization)</strong></td>
<td>안정적이고 최근 가장 널리 사용</td>
</tr>
<tr>
<td><strong>DDPG / TD3 / SAC</strong></td>
<td>연속적인 행동 공간 지원 (로봇 제어 등)</td>
</tr>
</tbody></table>
<h3 id="가치기반">가치기반</h3>
<ul>
<li><p><strong>Q-Learning (Off-policy)</strong></p>
<ul>
<li><p>에이전트는 행동을 <strong>탐험(랜덤)으로 선택</strong>하더라도,</p>
<p>  학습할 때는 항상 <strong>가장 좋은 행동을 했다고 가정</strong>해서 학습합니다.</p>
</li>
<li><p>즉, <strong>현재 정책이 아닌 이상적인 정책으로 학습 → Off-policy</strong></p>
</li>
<li><p>Q-table로 Q(s,a)Q(s,a)Q(s,a) 값을 업데이트</p>
</li>
<li><p>업데이트 공식:</p>
<p>$Q(s, a) \leftarrow Q(s, a) + \alpha \left[ r + \gamma \max_{a&#39;} Q(s&#39;, a&#39;) - Q(s, a) \right]$</p>
</li>
<li><p>탐험 vs 이용: ε-greedy 전략 사용</p>
<h3 id="q-learning-작동-방식">Q-Learning 작동 방식</h3>
</li>
</ul>
<ol>
<li>상태 s에서 시작</li>
<li><strong>행동 a</strong>선택 (탐험/이용 → ε-greedy)</li>
<li>보상 r, 다음 상태 s′받기</li>
<li>Q-값 업데이트</li>
<li>상태를 s′s&#39;s′로 옮기고 반복</li>
</ol>
<p>  <strong>예시</strong></p>
<pre><code class="language-python">  # 환경 준비
  import gym  #gym: 강화학습 환경을 제공하는 라이브러리
  import numpy as np

  env = gym.make(&quot;FrozenLake-v1&quot;, is_slippery=False)
  # is_slippery=False   -&gt;   내가 선택한 행동이 정확하게 실행
  # is_slippery=True (기본값)  -&gt;  행동이 확률적으로 빗나감(실행하려던 방향이 아닐 수 있음)

  q_table = np.zeros((env.observation_space.n, env.action_space.n))

  # 학습 파라미터
  alpha = 0.1  # 학습률 : 새 정보 반영 비율 (0: 안 바꿈, 1: 완전 반영)
  gamma = 0.99  # 할인률 : 미래 보상의 중요도 (0: 현재만, 1: 미래도 중시)
  epsilon = 0.1  # 탐험 확률 : 무작위 행동을 선택할 확률 (0: 탐험X, 1: 항상 탐험) 
  # 10% 확률로 탐험 (random action)
  # 90% 확률로 이용 (가장 Q값이 큰 action)

  # 학습 루프
  for episode in range(1000):
      state = env.reset()
      done = False

      while not done:
          # ε-greedy 행동 선택
          if np.random.rand() &lt; epsilon:
              action = env.action_space.sample() # 탐험
          else:
              action = np.argmax(q_table[state])
          next_state, reward, done, _ = env.step(action) # 이용

          # Q값 업데이트
          q_table[state, action] += alpha * (reward + gamma * np.max(q_table[next_state]) - q_table[state, action])

          state = next_state</code></pre>
<ul>
<li><p>is_slippery</p>
<h2 id="is_slippery-옵션의-의미"><code>is_slippery</code> 옵션의 의미</h2>
<table>
<thead>
<tr>
<th>설정</th>
<th>의미</th>
<th>행동 결과</th>
</tr>
</thead>
<tbody><tr>
<td><code>is_slippery=False</code></td>
<td><strong>미끄럽지 않음</strong></td>
<td>내가 선택한 행동이 <strong>정확하게</strong> 실행됨</td>
</tr>
<tr>
<td><code>is_slippery=True</code> (기본값)</td>
<td><strong>미끄러움</strong></td>
<td>행동이 <strong>확률적으로 빗나감</strong> (실행하려던 방향이 아닐 수도 있음)</td>
</tr>
</tbody></table>
<hr>
<h2 id="예시-상황-4방향-상-하-좌-우">예시 상황 (4방향: 상, 하, 좌, 우)</h2>
<h3 id="is_slipperyfalse"><code>is_slippery=False</code></h3>
<ul>
<li><p>내가 <code>&quot;→&quot;</code>(오른쪽)으로 이동하려고 하면,</p>
<p>  → <strong>정확히 오른쪽</strong>으로 이동함</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code>    &gt; ✔️ 초보자 실습이나 알고리즘 디버깅에 유리
    &gt; 
    &gt; 
    &gt; ✔️ 학습이 빠르고 안정적
    &gt; 

    ---

    ### `is_slippery=True` (기본값)

    - `&quot;→&quot;`로 이동하려고 해도,
        - 80% 확률: 오른쪽
        - 10% 확률: 위
        - 10% 확률: 아래

            → 즉, **원하는 방향으로 이동할 확률이 낮음**


    &gt; 더 현실적인 환경 (로봇 제어, 자율주행처럼 제어가 완벽하지 않음)
    &gt; 
    &gt; 
    &gt; 정책 학습이 더 어려워지고, Q값이 덜 안정적
    &gt; 

    ---

    ## 시각적 요약

    | 행동 시도 | `is_slippery=False` | `is_slippery=True` |
    | --- | --- | --- |
    | `&quot;→&quot;` 선택 | 무조건 오른쪽으로 감 | 대부분 오른쪽, 가끔 위/아래 |

    ---

    ## 정리: 언제 어떤 설정을 쓰나?

    | 상황 | 추천 설정 |
    | --- | --- |
    | 입문, 구조 이해, Q-table 디버깅 | `is_slippery=False` |
    | 현실성 있는 학습, 일반 RL 연구 | `is_slippery=True` |
- epsilon

    ## ε-greedy 전략

    에이전트가 행동을 선택할 때 다음 두 가지 중 하나:

    | 선택 방식 | 설명 | 발생 확률 |
    | --- | --- | --- |
    | **탐험 (exploration)** | 무작위로 행동 선택 (새로운 정보 탐색) | **ε (epsilon)** |
    | **이용 (exploitation)** | 현재 Q-table에서 가장 Q값이 큰 행동 선택 | **1 − ε** |

    즉,

    ```python
    epsilon = 0.1
    ```

    - 10% 확률로 → **탐험 (random action)**
    - 90% 확률로 → **이용 (가장 Q값이 큰 action)**

    ---

    ## ε 값의 범위 의미

    | ε 값 | 의미 | 행동 방식 |
    | --- | --- | --- |
    | `0.0` | 탐험 X → 항상 최선 행동만 | 빠르지만 **과적합 위험**, 최적 정책 못 찾을 수도 |
    | `1.0` | 항상 무작위 행동 | 계속 탐험만 → **학습이 안 됨** |
    | `0.1` | 10% 확률로 랜덤 | 일반적으로 많이 사용되는 시작 값 |

    ---

    ## 실전에서는 ε 조정도 필요해요

    보통 학습이 진행되면, ε 값을 다음처럼 **점점 줄여서**:

    ```python
    epsilon = max(0.01, epsilon * 0.995)
    ```

    - 처음엔 **많이 탐험**
    - 나중엔 **이용 중심 학습**

    ---

    ## 요약

    | ε 값 | 행동 경향 | 설명 |
    | --- | --- | --- |
    | `0` | 완전한 이용 | 탐험 전혀 안 함, 빠르지만 불완전 |
    | `1` | 완전한 탐험 | 학습 안 됨 |
    | `0.1` | 탐험 10%, 이용 90% | 일반적인 설정 |
    | 점점 감소 | 초기 탐험 → 점차 최적화 | 현실적이고 효과적 |
- env.step(action)

    ### `env.step(action)`의 반환값 구조:

    ```python
    next_state, reward, done, info = env.step(action)
    ```

    | 반환값 | 의미 | 설명 |
    | --- | --- | --- |
    | `next_state` | 다음 상태 | 에이전트가 행동한 후, **바뀐 상태** (예: 카트 위치 등) |
    | `reward` | 보상 | 현재 행동 결과로 얻은 **즉각적인 점수** |
    | `done` | 종료 여부 | 게임이 끝났는지 여부 (`True`면 종료) |
    | `info` (`_`) | 디버깅 정보 | 추가 정보(예: 이유, 시간 등). **보통 안 쓰므로 `_`로 무시** |

    ---

    ## 각 요소 자세히 설명

    ### 1. `next_state`

    - 상태는 환경에 따라 다르지만:
        - `FrozenLake`: 정수 번호 (0 ~ 15)
        - `CartPole`: 연속형 벡터 (예: [0.01, 0.04, 0.03, -0.02])
    - 이 상태는 다음 행동을 결정하는 데 사용됨

    ---

    ### 2. `reward`

    - 행동의 **즉각적인 보상값**
    - 예시:
        - `FrozenLake`: 0 (실패), 1 (성공)
        - `CartPole`: 막대가 안 쓰러지면 계속 1, 쓰러지면 종료

    ---

    ### 3. `done`

    - 에피소드가 끝났는지를 알려줌:
        - `True`: 목표에 도달하거나 실패해서 게임 종료
        - `False`: 아직 게임 진행 중

    &gt; → 이걸 while not done: 같은 조건에서 사용해요
    &gt; 

    ---

    ### 4. `info` (또는 `_`)

    - 보통 **디버깅 정보**
    - 예:
        - TimeLimit이 끝났는지
        - 에이전트가 어떤 이유로 실패했는지
        - 어떤 목표를 달성했는지
    - 대부분 학습에는 **필요 없어서 `_`로 무시**합니다.

    ---

    ## 요약표

    | 이름 | 타입 | 설명 |
    | --- | --- | --- |
    | `next_state` | 상태 (정수 또는 벡터) | 다음 상태 |
    | `reward` | 숫자 (int or float) | 행동의 즉각적인 보상 |
    | `done` | bool | 게임 종료 여부 |
    | `info` | dict | 추가 정보 (보통 무시 가능) |

    ---

    ## 예시 (FrozenLake)

    ```python
    next_state, reward, done, info = env.step(2)

    print(next_state)  # 4
    print(reward)      # 0
    print(done)        # False
    print(info)        # {&#39;prob&#39;: 1.0}
    ```


- 4x4 얼음판에서 **스타트 → 목표지점까지 이동**하는 환경
- 물에 빠지면 보상 0, 도착하면 보상 1
- Q-Learning은 최적 경로를 찾는 법을 학습함

## 장점 vs 단점

| 장점 | 단점 |
| --- | --- |
| 구현이 매우 간단함 | Q-table은 상태가 많아지면 메모리 낭비 심함 |
| 최적 정책으로 수렴함 (이론적으로) | 연속 공간에서는 사용 불가능 |
| Off-policy라 정책 변경과 분리 가능 | 고차원 문제에는 신경망 필요 (→ DQN) |

---

## 요약

- **Q-Learning은 테이블 기반의 가치 학습 알고리즘**
- 목표는 각 상태-행동 쌍의 Q값을 학습해서 최적의 행동 정책을 찾는 것
- 간단하지만 강화학습의 기본 중 기본</code></pre><ul>
<li><p><strong>SARSA (On-policy)</strong></p>
<p>  <strong>SARSA</strong>는 Q-Learning과 비슷한 <strong>테이블 기반 강화학습 알고리즘</strong></p>
<ul>
<li><p>이름은 <strong>S-A-R-S-A</strong>의 약자:</p>
<p>$\textbf{S}tate,\ \textbf{A}ction,\ \textbf{R}eward,\ \textbf{S}tate&#39;,\ \textbf{A}ction&#39;$</p>
<p>즉, <strong>현재 상태-행동 → 보상 → 다음 상태-행동까지 보고 Q값을 업데이트</strong></p>
</li>
<li><p>현재 정책을 따르는 행동 후의 Q값으로 업데이트</p>
<p>$Q(s, a) \leftarrow Q(s, a) + \alpha \left[ r + \gamma Q(s&#39;, a&#39;) - Q(s, a) \right]$</p>
</li>
<li><p>Q-Learning과 다른 점: Q-Learning은 다음 상태에서 최고 Q값(max)을 사용, SARSA는 <strong>실제 선택된 행동 Q값</strong>을 사용</p>
<h2 id="왜-on-policy">왜 On-policy?</h2>
</li>
<li><p>SARSA는 <strong>자신이 실제로 사용하는 정책에 따라 학습</strong></p>
</li>
<li><p>학습과 행동이 같은 정책을 따르므로 <strong>안정적</strong>이지만 <strong>탐험에 민감</strong></p>
<h2 id="예시-sarsa">예시 (SARSA)</h2>
<pre><code class="language-python">import numpy as np
import gym

env = gym.make(&quot;FrozenLake-v1&quot;, is_slippery=False)
q_table = np.zeros((env.observation_space.n, env.action_space.n))

alpha = 0.1
gamma = 0.99
epsilon = 0.1

for episode in range(1000):
  state = env.reset()
  # 현재 상태에서 행동 선택
  action = env.action_space.sample() if np.random.rand() &lt; epsilon else np.argmax(q_table[state])

  done = False
  while not done:
      next_state, reward, done, _ = env.step(action)

      # 다음 행동도 ε-greedy로 선택
      next_action = env.action_space.sample() if np.random.rand() &lt; epsilon else np.argmax(q_table[next_state])

      # SARSA 업데이트
      q_table[state, action] += alpha * (
          reward + gamma * q_table[next_state, next_action] - q_table[state, action]
      )

      state, action = next_state, next_action
</code></pre>
<h2 id="요약-흐름-그림">요약 흐름 그림</h2>
<pre><code>(s, a) → (s&#39;, a&#39;) → (s&#39;&#39;, a&#39;&#39;) ...
        ↑
    실제 행동</code></pre><p>Q-Learning과 비교하면:</p>
<table>
<thead>
<tr>
<th>알고리즘</th>
<th>다음 행동 기준</th>
<th>On/Off-policy</th>
</tr>
</thead>
<tbody><tr>
<td>Q-Learning</td>
<td>최대 Q값 사용 (<code>max Q(s&#39;, a&#39;)</code>)</td>
<td>Off-policy</td>
</tr>
<tr>
<td>SARSA</td>
<td><strong>실제 선택한 행동 사용</strong> (<code>Q(s&#39;, a&#39;)</code>)</td>
<td>On-policy</td>
</tr>
</tbody></table>
<h3 id="예시-상황">예시 상황</h3>
</li>
<li><p><strong>SARSA</strong>는 현실적인 환경에서,</p>
<ul>
<li><p><strong>탐험도 반영하면서 학습해야 할 때</strong></p>
</li>
<li><p><strong>에이전트가 실수를 줄이며 보수적으로 배워야 할 때</strong></p>
<p>  유리합니다.</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code>---

### 요약

- **SARSA는 실제 행동에 기반한 Q값 업데이트를 수행하는 On-policy 알고리즘**
- Q-Learning보다 **조금 더 보수적이고 안전한 학습 방식**
- 간단한 환경에서도 효과적이며, 이해하기 좋은 입문 알고리즘

## Q-Learning vs SARSA 요약 비교

| 항목 | Q-Learning | SARSA |
| --- | --- | --- |
| 정책 종류 | Off-policy | On-policy |
| 업데이트 기준 | 최대 Q값 사용 (max⁡Q(s′,a′)\max Q(s&#39;, a&#39;)maxQ(s′,a′)) | 실제 선택한 Q(s′,a′)Q(s&#39;, a&#39;)Q(s′,a′) |
| 탐험 고려 | 안 함 (가정만 함) | 함 (실제 행동 기반) |
| 수렴 속도 | 빠를 수 있음 | 더 안정적 |
| 위험성 | 과감한 선택 가능 | 보수적 학습 경향 |</code></pre><ul>
<li><p><strong>DQN (Deep Q-Network)  → 딥러닝</strong></p>
<ul>
<li>DQN(Deep Q-Network)은 다음 두 가지가 결합된 구조</li>
</ul>
<ol>
<li><strong>Q-Learning</strong>: 강화학습 알고리즘</li>
<li><strong>Deep Neural Network</strong>: Q값을 근사하기 위한 <strong>신경망(딥러닝)</strong></li>
</ol>
<ul>
<li><p>기존 Q-Learning은 <strong>Q-table</strong>을 사용 (상태/행동이 적을 때 OK)</p>
</li>
<li><p>DQN은 <strong>Q값을 예측하는 신경망</strong>을 사용 (복잡한 환경도 가능)</p>
<blockquote>
<p>즉, Q(s, a)를 일일이 저장하지 않고, 신경망이 직접 계산하는 구조.</p>
</blockquote>
</li>
<li><p>주요 기법:</p>
<ul>
<li><strong>Experience Replay</strong>: 샘플 저장 → 랜덤 학습</li>
<li><strong>Target Network</strong>: 안정성 향상</li>
</ul>
<h2 id="왜-dqn이-필요한가">왜 DQN이 필요한가?</h2>
<table>
<thead>
<tr>
<th>기존 Q-Learning 문제</th>
<th>DQN 해결 방법</th>
</tr>
</thead>
<tbody><tr>
<td>Q-table은 상태/행동이 많으면 <strong>메모리 폭발</strong></td>
<td>NN으로 Q값 근사</td>
</tr>
<tr>
<td>연속 상태, 이미지 상태는 <strong>Q-table 불가</strong></td>
<td>CNN/MLP 등으로 상태 처리 가능</td>
</tr>
<tr>
<td>학습 불안정, 진동 많음</td>
<td>경험 재플레이, 타겟 네트워크 등 도입</td>
</tr>
</tbody></table>
</li>
</ul>
<hr>
<h2 id="구조--핵심-개념">구조 &amp; 핵심 개념</h2>
<h3 id="dqn-구성-요소">DQN 구성 요소</h3>
<table>
<thead>
<tr>
<th>구성 요소</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>Q-Network</td>
<td>상태를 받아 행동별 Q값을 출력하는 NN</td>
</tr>
<tr>
<td>Experience Replay</td>
<td>과거 경험을 버퍼에 저장 &amp; 무작위 샘플링</td>
</tr>
<tr>
<td>Target Network</td>
<td>일정 주기로 Q-Network의 가중치를 복사해 학습 안정화</td>
</tr>
<tr>
<td>ε-greedy</td>
<td>행동 선택 시 탐험 vs 이용 균형</td>
</tr>
</tbody></table>
<hr>
<h3 id="dqn-학습-순서">DQN 학습 순서</h3>
<ol>
<li>상태 s를 관찰</li>
<li>NN으로 Q(s, a) 계산 → 행동 선택 (ε-greedy)</li>
<li>행동 수행 → 보상 r, 다음 상태 s′</li>
<li>경험 (s, a, r, s&#39;, done)을 버퍼에 저장</li>
<li>샘플을 꺼내서 손실 계산:</li>
<li>$Loss=(r + \gamma \max Q_{target}(s^′,a^′)−Q(s,a))^2$</li>
<li>손실로 NN 학습 (역전파)</li>
<li>일정 주기로 타겟 네트워크 업데이트</li>
</ol>
<hr>
<h2 id="핵심-수식">핵심 수식</h2>
<p>  $\hat{Q}(s, a) \leftarrow r + \gamma \max_{a&#39;} Q_{\text{target}}(s&#39;, a&#39;)$</p>
<p>  $\text{Loss} = \left( \hat{Q}(s, a) - Q(s, a) \right)^2$</p>
<hr>
<h3 id="간단한-pytorch-코드-구조-의사코드">간단한 PyTorch 코드 구조 (의사코드)</h3>
<pre><code class="language-python">  # Q-Network
  class DQN(nn.Module):
      def __init__(self, state_dim, action_dim):
          super().__init__()
          self.fc = nn.Sequential(
              nn.Linear(state_dim, 128), nn.ReLU(),
              nn.Linear(128, action_dim)
          )
      def forward(self, x):
          return self.fc(x)</code></pre>
<table>
<thead>
<tr>
<th>요소</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>nn.Module</code></td>
<td>PyTorch 신경망 클래스</td>
</tr>
<tr>
<td><code>state_dim</code></td>
<td>상태 벡터의 차원 수 (입력 크기)</td>
</tr>
<tr>
<td><code>action_dim</code></td>
<td>행동의 개수 (출력 노드 수)</td>
</tr>
<tr>
<td><code>self.fc</code></td>
<td>2층 fully connected 신경망</td>
</tr>
<tr>
<td>구조</td>
<td>상태 → 128노드 은닉층(ReLU) → 행동 수만큼 Q값 출력</td>
</tr>
</tbody></table>
<p>   하나의 <strong>상태 벡터를 받아, 각 행동의 Q값을 출력</strong></p>
<pre><code class="language-python">  # 메인 루프
  for each episode:
      state = env.reset()
      while not done:
          # 행동 선택
          if random &lt; epsilon:
              action = random_action()
          else:
              action = argmax(Q(state))

                  # 행동수행
          next_state, reward, done = env.step(action)
          # 경험저장
          replay_buffer.append((state, action, reward, next_state, done))

          # 학습
          batch = sample(replay_buffer) 
          # → 버퍼에서 미니배치로 (s, a, r, s&#39;, done) 데이터를 무작위로 추출
          loss = compute_dqn_loss(batch)
          # → DQN 손실 함수 계산:
          optimizer.step()
          # → 손실을 줄이기 위해 신경망 파라미터를 업데이트 (역전파)



</code></pre>
</li>
</ul>
<pre><code>        # 타겟 네트워크 업데이트
        if step % C == 0:
            target_net.load_state_dict(q_net.state_dict())

```

- 일정 스텝마다 `q_net`의 가중치를 **타겟 네트워크에 복사**
- 이유: `max Q(s&#39;, a&#39;)`를 계산할 때 **안정된 값**을 사용하기 위함
- 타겟 네트워크는 학습하지 않고 **기준 역할만 수행**함

## 전체 구조 요약

| 단계 | 내용 |
| --- | --- |
| Q-Network 정의 | 상태 → Q값 예측 |
| ε-greedy 정책 | 탐험과 이용의 균형 |
| 경험 저장 | (s, a, r, s&#39;, done) 저장 |
| 배치 학습 | 손실 계산 + 파라미터 업데이트 |
| 타겟 네트워크 | 안정된 학습 보장 |

## 정리

| 개념 | 설명 |
| --- | --- |
| Q-Network | Q값을 예측하는 신경망 |
| Experience Replay | 샘플을 무작위로 뽑아 학습 안정화 |
| Target Network | 기준이 되는 별도 Q값 네트워크 |
| ε-greedy | 탐험과 이용 균형 조절 |
| 손실함수 | TD오차: (Q−Target)2(Q - \text{Target})^2(Q−Target)2 |

---

### 예제코드

```python
import numpy as np
import random
import gym
import torch
import torch.nn as nn
import torch.optim as optim
from collections import deque

# Q-Network 정의
class DQN(nn.Module):
    def __init__(self, state_dim, action_dim):
        super().__init__()
        self.fc = nn.Sequential(
            nn.Linear(state_dim, 128),
            nn.ReLU(),
            nn.Linear(128, action_dim)
        )
    def forward(self, x):
        return self.fc(x)

# 손실 함수 계산
def compute_loss(batch, q_net, target_net, gamma):
    states, actions, rewards, next_states, dones = batch
    states = torch.FloatTensor(states)
    actions = torch.LongTensor(actions).unsqueeze(1)
    rewards = torch.FloatTensor(rewards).unsqueeze(1)
    next_states = torch.FloatTensor(next_states)
    dones = torch.FloatTensor(dones).unsqueeze(1)

    q_values = q_net(states).gather(1, actions)
    next_q = target_net(next_states).max(1)[0].detach().unsqueeze(1)
    target = rewards + gamma * next_q * (1 - dones)
    return nn.MSELoss()(q_values, target)

# 환경 설정
env = gym.make(&quot;CartPole-v1&quot;)
state_dim = env.observation_space.shape[0]
action_dim = env.action_space.n

q_net = DQN(state_dim, action_dim)
target_net = DQN(state_dim, action_dim)
target_net.load_state_dict(q_net.state_dict())
optimizer = optim.Adam(q_net.parameters(), lr=0.001)

replay_buffer = deque(maxlen=10000)

# 하이퍼파라미터
episodes = 500
batch_size = 32
gamma = 0.99
epsilon = 0.1
target_update_freq = 10

# 학습 루프
for episode in range(episodes):
    state = env.reset()
    done = False
    total_reward = 0

    while not done:
        if random.random() &lt; epsilon:
            action = env.action_space.sample()
        else:
            with torch.no_grad():
                action = q_net(torch.FloatTensor(state).unsqueeze(0)).argmax().item()

        next_state, reward, done, _ = env.step(action)
        replay_buffer.append((state, action, reward, next_state, done))
        state = next_state
        total_reward += reward

        if len(replay_buffer) &gt;= batch_size:
            batch = random.sample(replay_buffer, batch_size)
            batch = list(zip(*batch))  # (states, actions, rewards, next_states, dones)
            loss = compute_loss(batch, q_net, target_net, gamma)

            optimizer.zero_grad()
            loss.backward()
            optimizer.step()

    if episode % target_update_freq == 0:
        target_net.load_state_dict(q_net.state_dict())

    print(f&quot;Episode {episode}, Total Reward: {total_reward}&quot;)

env.close()

```

---

## 장단점

| 장점 | 단점 |
| --- | --- |
| 고차원 상태 입력 처리 가능 (ex. 이미지) | 연속 행동공간에는 부적합 (→ DDPG, SAC) |
| Q-table 없이 근사 가능 | overestimation 문제 있음 (→ Double DQN) |
| 다양한 환경에 적용 가능 | 학습 안정화 필요 (버퍼, 타겟넷 등 중요) |

---

## DQN이 효과적인 경우

- 이미지 기반 환경 (ex. Atari Pong)
- 상태공간이 큰 문제 (CartPole, LunarLander 등)
- discrete action space (행동이 정수형)

---

## 확장형 알고리즘

| 알고리즘 | 설명 |
| --- | --- |
| Double DQN | Q값 과대평가 완화 |
| Dueling DQN | 상태의 가치와 행동의 Advantage 분리 |
| Rainbow DQN | 다양한 기법을 결합 (지금까지 최고 성능 중 하나) |
| PER | Prioritized Experience Replay (더 중요한 경험 우선 학습) |</code></pre><h3 id="정책기반">정책기반</h3>
<ul>
<li><strong>REINFORCE</strong></li>
</ul>
<pre><code>- 가장 기본적인 정책 경사법 (에피소드 단위)
- 수렴 느리지만 개념적으로 중요
- 행동 확률의 로그에 보상을 곱해서 정책을 개선

$\nabla_\theta J(\theta) = \mathbb{E}{\pi\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) \cdot R \right]$

## 구현 구조 요약

```
1. 에피소드 전체 수집 (s, a, r, s&#39;, a&#39;, ...)
2. 에피소드 종료 후 총 보상 계산
3. log(π(a|s)) * R로 정책 업데이트
```

---

## 간단한 PyTorch 스타일 예시

```python

# 정책 신경망
class PolicyNet(nn.Module):
    def __init__(self, state_dim, action_dim):
        super().__init__()
        self.fc = nn.Sequential(
            nn.Linear(state_dim, 128),
            nn.ReLU(),
            nn.Linear(128, action_dim),
            nn.Softmax(dim=-1)
        )

    def forward(self, x):
        return self.fc(x)

# 학습 루프 (REINFORCE)
log_probs = []
rewards = []

state = env.reset()
done = False
while not done:
    probs = policy(torch.tensor(state).float())
    dist = Categorical(probs)
    action = dist.sample()

    log_probs.append(dist.log_prob(action))
    state, reward, done, _ = env.step(action.item())
    rewards.append(reward)

# 전체 리턴 계산 후 역전파
G = sum(rewards)
loss = -sum([log_prob * G for log_prob in log_probs])
loss.backward()

```

---

### 이런 점에서 중요:

- **Policy Gradient 입문에 적합**
- 개념적으로 PPO, A2C 등 발전형의 뿌리가 됨
- 단점: **high variance**, 느린 수렴 속도</code></pre><ul>
<li><p><strong>Policy Gradient</strong></p>
<ul>
<li><p>정책 함수 π(a∣s)\pi(a|s)π(a∣s) 직접 학습</p>
</li>
<li><p>목표: 파라미터 θ\thetaθ에 대해 기대 보상 최대화</p>
<p>$J(\theta) = \mathbb{E}{\pi\theta}[R]$</p>
<p>$\nabla_\theta J(\theta) = \mathbb{E}{\pi\theta} \left[ \nabla_\theta \log \pi_\theta(a|s) \cdot R \right]$</p>
</li>
</ul>
</li>
</ul>
<h3 id="정책--가치-actor-critic"><strong>정책 + 가치 (Actor-Critic)</strong></h3>
<ul>
<li><p><strong>Actor-Critic</strong></p>
<ul>
<li><p><strong>Actor</strong>: 정책 학습</p>
</li>
<li><p><strong>Critic</strong>: 상태의 가치 V(s) 또는 Q(s, a) 평가</p>
<p>$V(s): \text{ 상태 } s \text{에서 기대되는 누적 보상}$</p>
<p>$Q(s, a): \text{ 상태 } s \text{에서 행동 } a \text{를 했을 때의 기대 보상}$</p>
</li>
<li><p>Advantage function 사용:</p>
<p>$A(s, a) = Q(s, a) - V(s)$</p>
</li>
</ul>
</li>
<li><p><strong>PPO (Proximal Policy Optimization)</strong></p>
<ul>
<li><p>최근 가장 널리 쓰이는 안정적인 정책 경사법</p>
</li>
<li><p>큰 업데이트를 방지하는 <strong>클리핑 함수</strong> 사용</p>
<p>$L^{CLIP}(\theta) = \mathbb{E} \left[ \min \left( r(\theta) A, \ \text{clip}(r(\theta), 1 - \epsilon, 1 + \epsilon) A \right) \right]$</p>
</li>
</ul>
</li>
</ul>
<h3 id="연속-제어"><strong>연속 제어</strong></h3>
<ul>
<li><strong>DDPG / TD3 / SAC</strong><ul>
<li><strong>연속 공간</strong>에서 사용 가능 (로봇, 자율주행 등)</li>
<li>DDPG: DQN + Actor-Critic</li>
<li>TD3: DDPG의 안정화 버전 (2개의 critic)</li>
<li>SAC: 탐험성 높은 엔트로피 기반 기법</li>
</ul>
</li>
</ul>
<hr>
<h3 id="주요-알고리즘-분류-및-비교">주요 알고리즘 분류 및 비교</h3>
<table>
<thead>
<tr>
<th>계열</th>
<th>알고리즘</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td><strong>가치 기반</strong></td>
<td>Q-Learning, SARSA, DQN</td>
<td>Q값 기반, 정책은 간접적으로</td>
</tr>
<tr>
<td><strong>정책 기반</strong></td>
<td><strong>REINFORCE</strong>, Policy Gradient</td>
<td>확률적 정책을 직접 업데이트</td>
</tr>
<tr>
<td><strong>정책 + 가치 (Actor-Critic)</strong></td>
<td>Actor-Critic, A2C, PPO</td>
<td>Actor: 정책 / Critic: 가치 평가</td>
</tr>
<tr>
<td><strong>연속 제어 + Actor-critic</strong></td>
<td>DDPG, TD3, SAC</td>
<td>연속적인 행동 공간에 사용 가능</td>
</tr>
</tbody></table>
<hr>
<h3 id="알고리즘별-구현-방식-요약">알고리즘별 구현 방식 요약</h3>
<table>
<thead>
<tr>
<th>알고리즘</th>
<th>구현 구조</th>
<th>핵심 구현 포인트</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Q-Learning</strong></td>
<td>테이블 기반</td>
<td>Q-table 업데이트, ε-greedy</td>
</tr>
<tr>
<td><strong>SARSA</strong></td>
<td>테이블 기반</td>
<td>실제 행동으로 Q 업데이트 (on-policy)</td>
</tr>
<tr>
<td><strong>REINFORCE</strong></td>
<td>신경망 기반 (정책만)</td>
<td>에피소드 단위로 로그 확률 × 보상, high variance</td>
</tr>
<tr>
<td><strong>Policy Gradient</strong></td>
<td>신경망 기반</td>
<td>REINFORCE 수식 사용, 정책 확률 업데이트</td>
</tr>
<tr>
<td><strong>DQN</strong></td>
<td>신경망 기반 (Q함수)</td>
<td>Q-Network + 경험 리플레이 + 타겟 네트워크</td>
</tr>
<tr>
<td><strong>Actor-Critic</strong></td>
<td>2개 신경망</td>
<td>Actor(정책), Critic(V or Q), Advantage 사용</td>
</tr>
<tr>
<td><strong>PPO</strong></td>
<td>신경망 기반 + 안정화</td>
<td>Clip objective, mini-batch 업데이트</td>
</tr>
<tr>
<td><strong>DDPG / TD3 / SAC</strong></td>
<td>연속 공간 + NN</td>
<td>Actor-Critic + noise 처리 + 경험 버퍼 (연속 제어에 적합)</td>
</tr>
</tbody></table>
<hr>
<h2 id="활용-분야">활용 분야</h2>
<table>
<thead>
<tr>
<th>분야</th>
<th>활용 예</th>
</tr>
</thead>
<tbody><tr>
<td>게임</td>
<td>AlphaGo, Dota2 AI, Atari 게임</td>
</tr>
<tr>
<td>로보틱스</td>
<td>팔 움직임, 드론 제어</td>
</tr>
<tr>
<td>금융</td>
<td>포트폴리오 최적화</td>
</tr>
<tr>
<td>자율주행</td>
<td>행동 선택, 조향 각도 제어</td>
</tr>
<tr>
<td>제조</td>
<td>최적화된 공정 자동화</td>
</tr>
</tbody></table>
<hr>
<h2 id="학습-흐름-요약">학습 흐름 요약</h2>
<pre><code>1. 상태 관측 → 2. 행동 선택 → 3. 보상 + 상태 전이 → 4. 정책/가치 업데이트 → 반복</code></pre><hr>
<h2 id="기타-특수-모델">기타 특수 모델</h2>
<table>
<thead>
<tr>
<th>모델명</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>DummyClassifier</strong></td>
<td>성능 비교용 더미 모델</td>
</tr>
<tr>
<td><strong>MLPClassifier / Regressor</strong></td>
<td><strong>신경망 기반 분류/회귀</strong> (다층 퍼셉트론)</td>
</tr>
<tr>
<td><strong>HistGradientBoosting</strong></td>
<td>LightGBM 비슷한 scikit-learn 내장 부스팅</td>
</tr>
</tbody></table>
<h2 id="실전에서-가장-많이-쓰이는-탑-5">실전에서 가장 많이 쓰이는 탑 5</h2>
<ol>
<li><code>RandomForestClassifier</code></li>
<li><code>XGBoostClassifier</code></li>
<li><code>LightGBMClassifier</code></li>
<li><code>LogisticRegression</code></li>
<li><code>GradientBoostingClassifier</code></li>
</ol>
<p>\hat{y}_i^{(t)} = \hat{y}_i^{(t-1)} + \eta \cdot f_t(x_i)</p>
<table>
<thead>
<tr>
<th>사용 조건</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td>예측 정확도가 매우 중요</td>
<td>캐글 1위 모델 다수</td>
</tr>
<tr>
<td>과적합 걱정되는 복잡한 데이터</td>
<td>정규화 + 가지치기 내장</td>
</tr>
<tr>
<td>대용량 데이터</td>
<td>병렬 처리, GPU 지원</td>
</tr>
<tr>
<td>결측값 존재</td>
<td>자동 처리 지원</td>
</tr>
<tr>
<td>분류, 회귀, 랭킹 문제</td>
<td>전용 손실 함수 지원</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[머신러닝 - [1단계] 머신러닝 핵심 개념 이론 정리]]></title>
            <link>https://velog.io/@c_haha_e/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-1%EB%8B%A8%EA%B3%84-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%ED%95%B5%EC%8B%AC-%EA%B0%9C%EB%85%90-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@c_haha_e/%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-1%EB%8B%A8%EA%B3%84-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%ED%95%B5%EC%8B%AC-%EA%B0%9C%EB%85%90-%EC%9D%B4%EB%A1%A0-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 12 Aug 2025 15:56:44 GMT</pubDate>
            <description><![CDATA[<h2 id="머신러닝이란-what-is-machine-learning">머신러닝이란? (What is Machine Learning?)</h2>
<h3 id="정의">정의</h3>
<p>머신러닝(Machine Learning)은 <strong>컴퓨터가 명시적 규칙을 부여받지 않고</strong>, 데이터로부터 <strong>패턴을 스스로 학습하여 예측 또는 판단</strong>을 내리는 알고리즘입니다.</p>
<h3 id="전통-프로그래밍-vs-머신러닝">전통 프로그래밍 vs 머신러닝</h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>전통 프로그래밍</th>
<th>머신러닝</th>
</tr>
</thead>
<tbody><tr>
<td>입력</td>
<td>규칙 + 데이터</td>
<td>데이터 + 정답(label)</td>
</tr>
<tr>
<td>출력</td>
<td>결과</td>
<td>학습된 모델(예측기)</td>
</tr>
<tr>
<td>- <strong>전통적 방식</strong>: &quot;키가 180cm 이상이면 농구부 추천&quot; → 사람이 직접 룰을 작성</td>
<td></td>
<td></td>
</tr>
<tr>
<td>- <strong>ML 방식</strong>: 수많은 학생의 키 + 활동 데이터를 학습 → 스스로 규칙 유추</td>
<td></td>
<td></td>
</tr>
</tbody></table>
<h3 id="실생활-예">실생활 예:</h3>
<ul>
<li>이메일 자동 분류: 스팸 or 정상?</li>
<li>넷플릭스 영화 추천: 어떤 장르를 좋아할까?</li>
<li>주가 예측: 과거 가격 → 미래 예측지도학습 / 비지도학습 / 강화학습 (학습 종류)</li>
</ul>
<hr>
<h3 id="▶-지도학습-supervised-learning">▶ 지도학습 (Supervised Learning)</h3>
<ul>
<li><em>정답(label)*</em>이 있는 데이터를 기반으로 학습</li>
</ul>
<p>→ &quot;이걸 보고 앞으로 이런 정답을 예측해&quot;</p>
<ul>
<li><p>예시:</p>
<p>  데이터 구성:</p>
<ul>
<li><p>타이타닉 생존 예측 (분류)</p>
<pre><code>입력: [나이, 성별, 티켓등급] → 정답: [생존 여부 0 or 1]</code></pre></li>
<li><p>집값 예측 (회귀)</p>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="▶-비지도학습-unsupervised-learning">▶ 비지도학습 (Unsupervised Learning)</h3>
<p><strong>정답이 없는 데이터</strong>에서 패턴이나 군집을 찾는 학습</p>
<p>→ &quot;그냥 데이터만 줄 테니, 스스로 구조를 찾아봐&quot;</p>
<ul>
<li>예시:<ul>
<li>고객 군집 분류 (군집화: KMeans)</li>
<li>차원 축소 (PCA)</li>
</ul>
</li>
</ul>
<p>데이터 구성:</p>
<hr>
<pre><code>입력: [나이, 구매수, 클릭수] → 정답 없음</code></pre><h3 id="▶-강화학습-reinforcement-learning">▶ 강화학습 (Reinforcement Learning)</h3>
<p><strong>행동(정책)을 선택하고, 보상(reward)을 받아가며 학습</strong></p>
<p>→ &quot;잘한 행동엔 보상, 못한 행동엔 패널티&quot;</p>
<ul>
<li>예시:<ul>
<li>체스/바둑 AI (알파고)</li>
<li>로봇 경로 학습</li>
<li>자율주행 차량</li>
</ul>
</li>
</ul>
<h2 id="구성-요소-5가지-강화학습의-기본-구조">구성 요소 5가지 (강화학습의 기본 구조)</h2>
<table>
<thead>
<tr>
<th>구성 요소</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Agent</strong></td>
<td>환경과 상호작용하며 학습하는 주체</td>
</tr>
<tr>
<td><strong>Environment</strong></td>
<td>에이전트가 행동하는 공간 (게임, 로봇 환경 등)</td>
</tr>
<tr>
<td><strong>State (s)</strong></td>
<td>현재 환경의 상태 (예: 체스판 상태)</td>
</tr>
<tr>
<td><strong>Action (a)</strong></td>
<td>에이전트가 선택할 수 있는 행동</td>
</tr>
<tr>
<td><strong>Reward (r)</strong></td>
<td>행동 후 환경이 주는 보상</td>
</tr>
<tr>
<td><strong>Policy (π)</strong></td>
<td>상태 → 행동을 매핑하는 함수 (학습 대상)</td>
</tr>
</tbody></table>
<h2 id="강화학습-순서">강화학습 순서</h2>
<pre><code>
초기 상태 s₀
   ↓
Agent가 Policy에 따라 행동 a₀ 선택
   ↓
Environment가 행동 결과로 보상 r₁, 다음 상태 s₁ 반환
   ↓
Agent는 r₁과 s₁을 바탕으로 Policy 수정
   ↓
이 과정을 반복하며 보상 최적화
</code></pre><h2 id="수학적-정의-mdp">수학적 정의 (MDP)</h2>
<p>강화학습은 보통 Markov Decision Process (MDP)로 모델링 됨</p>
<h3 id="mdp-구성요소">MDP 구성요소</h3>
<table>
<thead>
<tr>
<th>기호</th>
<th>이름</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>S</strong></td>
<td>상태 공간 (State Space)</td>
<td>에이전트가 존재할 수 있는 모든 상태의 집합</td>
</tr>
<tr>
<td><strong>A</strong></td>
<td>행동 공간 (Action Space)</td>
<td>에이전트가 취할 수 있는 모든 행동의 집합</td>
</tr>
<tr>
<td>**P(s′</td>
<td>s, a)**</td>
<td>상태 전이 확률 (Transition Probability)</td>
</tr>
<tr>
<td><strong>R(s, a)</strong></td>
<td>보상 함수 (Reward Function)</td>
<td>상태 <code>s</code>에서 행동 <code>a</code>를 했을 때 받는 보상</td>
</tr>
<tr>
<td><strong>γ (gamma)</strong></td>
<td>할인율 (Discount Factor)</td>
<td>미래 보상의 현재 가치 반영 정도. 0~1 사이 실수</td>
</tr>
</tbody></table>
<h2 id="주요-알고리즘-분류">주요 알고리즘 분류</h2>
<table>
<thead>
<tr>
<th>분류</th>
<th>대표 알고리즘</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td><strong>값 기반 (Value-based)</strong></td>
<td>Q-Learning, DQN</td>
<td>각 상태-행동 쌍의 가치 함수(Q)를 학습</td>
</tr>
<tr>
<td><strong>정책 기반 (Policy-based)</strong></td>
<td>REINFORCE, PPO</td>
<td>정책 π(a</td>
</tr>
<tr>
<td><strong>액터-크리틱 (Actor-Critic)</strong></td>
<td>A2C, A3C, DDPG</td>
<td>정책(Actor) + 가치함수(Critic)를 함께 학습</td>
</tr>
<tr>
<td><strong>모델 기반</strong></td>
<td>MuZero 등</td>
<td>환경 모델까지 학습해 예측</td>
</tr>
</tbody></table>
<h2 id="강화학습용-python-라이브러리">강화학습용 Python 라이브러리</h2>
<table>
<thead>
<tr>
<th>라이브러리</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>OpenAI Gym</strong></td>
<td>다양한 강화학습 환경 제공 (<code>CartPole</code>, <code>MountainCar</code> 등)</td>
</tr>
<tr>
<td><strong>Stable-Baselines3</strong></td>
<td>고수준 강화학습 알고리즘 (DQN, PPO, A2C 등)</td>
</tr>
<tr>
<td><strong>RLlib (Ray)</strong></td>
<td>대규모 강화학습 분산 프레임워크</td>
</tr>
<tr>
<td><strong>PettingZoo</strong></td>
<td>멀티에이전트 환경 전용</td>
</tr>
<tr>
<td><strong>Gymnasium</strong></td>
<td>Gym의 후속 공식 패키지</td>
</tr>
</tbody></table>
<hr>
<h2 id="지도학습supervised-vs-비지도학습-vs-강화학습">지도학습(Supervised) vs 비지도학습 vs 강화학습</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>지도학습</th>
<th>비지도학습</th>
<th>강화학습</th>
</tr>
</thead>
<tbody><tr>
<td>학습 방식</td>
<td>정답(레이블)을 보고 학습</td>
<td>정답 없이 데이터 패턴 학습</td>
<td>환경과 상호작용하며 보상을 통해 학습</td>
</tr>
<tr>
<td>출력</td>
<td>분류/회귀값</td>
<td>클러스터링, 차원 축소</td>
<td>최적의 행동(정책)</td>
</tr>
<tr>
<td>예시</td>
<td>고양이/강아지 구분</td>
<td>고객군 분류</td>
<td>게임 플레이, 로봇 제어</td>
</tr>
</tbody></table>
<hr>
<h2 id="회귀-vs-분류">회귀 vs 분류</h2>
<h3 id="▶-회귀-regression">▶ 회귀 (Regression)</h3>
<ul>
<li>목표: <strong>숫자(연속형 값)</strong> 예측</li>
<li>예시: 주택 가격, 시험 점수, 주식 가격</li>
<li>출력: 123.4, 78.5 등</li>
</ul>
<pre><code class="language-python">from sklearn.linear_model import LinearRegression
model = LinearRegression().fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<hr>
<h3 id="▶-분류-classification">▶ 분류 (Classification)</h3>
<ul>
<li>목표: <strong>카테고리(클래스)</strong> 예측</li>
<li>예시: 메일이 스팸인가?, 종양이 악성인가?</li>
<li>출력: 클래스 번호 (0, 1, 2...), 또는 확률</li>
</ul>
<pre><code class="language-python">from sklearn.linear_model import LogisticRegression
model = LogisticRegression().fit(X_train, y_train)
y_pred = model.predict(X_test)</code></pre>
<h3 id="혼동-주의">혼동 주의</h3>
<ul>
<li>회귀는 숫자 예측</li>
<li>분류는 &quot;무엇에 속하는가?&quot;를 예측</li>
</ul>
<hr>
<h2 id="과적합overfitting--과소적합underfitting">과적합(Overfitting) / 과소적합(Underfitting)</h2>
<h3 id="▶-과적합이란">▶ 과적합이란?</h3>
<blockquote>
<p>학습 데이터에 너무 집착해서 테스트 데이터에서는 엉뚱한 결과를 내는 현상</p>
</blockquote>
<p>발생 원인</p>
<ul>
<li>너무 복잡한 모델 (불필요한 규칙까지 외움)</li>
<li>훈련 데이터가 적음</li>
<li>특성 수가 너무 많음</li>
</ul>
<p>예시:</p>
<ul>
<li>훈련 정확도: 100%</li>
<li>테스트 정확도: 60%</li>
</ul>
<p>비유:</p>
<ul>
<li>시험 공부할 때 모의고사만 외우고, 개념은 이해 안 함</li>
</ul>
<hr>
<h3 id="▶-과소적합이란">▶ 과소적합이란?</h3>
<blockquote>
<p>모델이 너무 단순해서 패턴을 잡지 못하고 성능이 낮은 상태</p>
</blockquote>
<p>발생 원인</p>
<ul>
<li>너무 단순한 모델 사용</li>
<li>너무 적은 학습량</li>
<li>너무 강한 규제</li>
</ul>
<p>예시:</p>
<ul>
<li>훈련 정확도: 60%</li>
<li>테스트 정확도: 58%</li>
</ul>
<p>비유:</p>
<ul>
<li>공부를 거의 안 하고 시험을 보는 상황</li>
</ul>
<hr>
<h2 id="편향비뚤어진-단순함-vs-분산불안정한-민감성">편향(비뚤어진 단순함) vs 분산(불안정한 민감성)</h2>
<h3 id="▶-편향bias-너무-단순한-모델">▶ 편향(Bias): 너무 단순한 모델</h3>
<ul>
<li>데이터의 패턴을 무시하고 &quot;대충 평균&quot;으로 예측</li>
<li>과소적합과 연결</li>
</ul>
<h3 id="▶-분산variance-너무-민감한-모델">▶ 분산(Variance): 너무 민감한 모델</h3>
<ul>
<li>데이터에 따라 예측이 요동침</li>
<li>과적합과 연결</li>
</ul>
<h3 id="트레이드오프란">트레이드오프란?</h3>
<blockquote>
<p>복잡도 조절이 핵심!</p>
<p>→ 단순하면 성능 안 나오고, 복잡하면 오히려 망한다</p>
</blockquote>
<hr>
<h2 id="수학적으로-보기-참고">수학적으로 보기 (참고)</h2>
<p>선형 회귀 예시에서,</p>
<ul>
<li>예측 함수: 𝑦 = 𝑤𝑥 + 𝑏</li>
<li>과적합: 𝑤가 너무 커서 데이터에 휘둘림</li>
<li>과소적합: 𝑤가 0에 가까워서 거의 평균만 예측</li>
</ul>
<hr>
<h2 id="핵심-요약표-암기용">핵심 요약표 (암기용)</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>과소적합</th>
<th>적합</th>
<th>과적합</th>
</tr>
</thead>
<tbody><tr>
<td>훈련 정확도</td>
<td>낮음</td>
<td>적절</td>
<td>매우 높음</td>
</tr>
<tr>
<td>테스트 정확도</td>
<td>낮음</td>
<td>높음</td>
<td>낮음</td>
</tr>
<tr>
<td>모델 복잡도</td>
<td>너무 단순</td>
<td>적당</td>
<td>너무 복잡</td>
</tr>
</tbody></table>
<h2 id="회귀-regression-관련-모델-추가">회귀 (Regression) 관련 모델 추가</h2>
<table>
<thead>
<tr>
<th>모델명</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Ridge Regression</strong></td>
<td>선형 회귀 + <strong>L2 정규화</strong> (과적합 방지)</td>
</tr>
<tr>
<td><strong>Lasso Regression</strong></td>
<td>선형 회귀 + <strong>L1 정규화</strong> (불필요한 변수 제거)</td>
</tr>
<tr>
<td><strong>ElasticNet</strong></td>
<td>Ridge + Lasso 혼합</td>
</tr>
<tr>
<td><strong>SVR</strong></td>
<td>SVM 기반 회귀 (마진 기반 회귀)</td>
</tr>
<tr>
<td><strong>GradientBoostingRegressor</strong></td>
<td>부스팅 기반 회귀 (예측 성능 높음)</td>
</tr>
<tr>
<td><strong>XGBoostRegressor / LightGBMRegressor</strong></td>
<td>고성능 부스팅 회귀</td>
</tr>
<tr>
<td><strong>KNeighborsRegressor</strong></td>
<td>KNN의 회귀 버전</td>
</tr>
</tbody></table>
<hr>
<h2 id="분류-classification-관련-모델-추가">분류 (Classification) 관련 모델 추가</h2>
<table>
<thead>
<tr>
<th>모델명</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>RidgeClassifier</strong></td>
<td>선형 분류 + L2 정규화</td>
</tr>
<tr>
<td><strong>GradientBoostingClassifier</strong></td>
<td>순차적 학습으로 성능 향상</td>
</tr>
<tr>
<td><strong>XGBoostClassifier</strong></td>
<td>Kaggle 1등 단골 모델, 빠르고 강력</td>
</tr>
<tr>
<td><strong>LightGBMClassifier</strong></td>
<td>대용량 데이터에 매우 빠름</td>
</tr>
<tr>
<td><strong>CatBoostClassifier</strong></td>
<td>범주형 데이터 자동 처리 가능</td>
</tr>
<tr>
<td><strong>BaggingClassifier</strong></td>
<td>트리 기반 Bagging 앙상블</td>
</tr>
<tr>
<td><strong>VotingClassifier</strong></td>
<td>여러 모델의 결과를 투표로 결정</td>
</tr>
<tr>
<td><strong>StackingClassifier</strong></td>
<td>여러 모델을 층으로 쌓아 결합</td>
</tr>
</tbody></table>
<hr>
<h2 id="비지도-학습-unsupervised-learning">비지도 학습 (Unsupervised Learning)</h2>
<table>
<thead>
<tr>
<th>모델명</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>KMeans</strong></td>
<td>대표적인 군집화 알고리즘</td>
</tr>
<tr>
<td><strong>DBSCAN</strong></td>
<td>밀도 기반 클러스터링</td>
</tr>
<tr>
<td><strong>PCA</strong></td>
<td>차원 축소 (주성분 분석)</td>
</tr>
<tr>
<td><strong>TSNE, UMAP</strong></td>
<td>시각화용 고급 차원 축소</td>
</tr>
<tr>
<td><strong>IsolationForest</strong></td>
<td>이상치 탐지 (비지도)</td>
</tr>
</tbody></table>
<hr>
<h2 id="강화학습">강화학습</h2>
<table>
<thead>
<tr>
<th>알고리즘</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Q-Learning</strong></td>
<td>테이블 방식 Q(s, a) 업데이트</td>
</tr>
<tr>
<td><strong>SARSA</strong></td>
<td>행동 후 보상 기반 Q 업데이트 (on-policy)</td>
</tr>
<tr>
<td><strong>DQN (Deep Q-Network)</strong></td>
<td>Q-Learning + 딥러닝</td>
</tr>
<tr>
<td><strong>Policy Gradient</strong></td>
<td>정책 함수를 직접 학습</td>
</tr>
<tr>
<td><strong>REINFORCE</strong></td>
<td>가장 기본적인 정책 경사법</td>
</tr>
<tr>
<td><strong>Actor-Critic</strong></td>
<td>정책(Actor) + 가치(Critic)를 분리</td>
</tr>
<tr>
<td><strong>PPO (Proximal Policy Optimization)</strong></td>
<td>안정적이고 최근 가장 널리 사용</td>
</tr>
<tr>
<td><strong>DDPG / TD3 / SAC</strong></td>
<td>연속적인 행동 공간 지원 (로봇 제어 등)</td>
</tr>
</tbody></table>
<hr>
<h2 id="기타-특수-모델">기타 특수 모델</h2>
<table>
<thead>
<tr>
<th>모델명</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>DummyClassifier</strong></td>
<td>성능 비교용 더미 모델</td>
</tr>
<tr>
<td><strong>MLPClassifier / Regressor</strong></td>
<td><strong>신경망 기반 분류/회귀</strong> (다층 퍼셉트론)</td>
</tr>
<tr>
<td><strong>HistGradientBoosting</strong></td>
<td>LightGBM 비슷한 scikit-learn 내장 부스팅</td>
</tr>
</tbody></table>
<hr>
<h2 id="실전에서-가장-많이-쓰이는-탑-5">실전에서 가장 많이 쓰이는 탑 5</h2>
<ol>
<li><code>RandomForestClassifier</code></li>
<li><code>XGBoostClassifier</code></li>
<li><code>LightGBMClassifier</code></li>
<li><code>LogisticRegression</code></li>
<li><code>GradientBoostingClassifier</code></li>
</ol>
]]></description>
        </item>
    </channel>
</rss>