<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>y-hyun2.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 23 Dec 2025 07:14:55 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>y-hyun2.log</title>
            <url>https://velog.velcdn.com/images/y-hyun2/profile/5eccd01f-b960-41c6-94ea-2fb65a16ab1d/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. y-hyun2.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/y-hyun2" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[week14,15: ESG Agent 개발 프로젝트 회고록]]></title>
            <link>https://velog.io/@y-hyun2/week1415-ESG-Agent-%EA%B0%9C%EB%B0%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@y-hyun2/week1415-ESG-Agent-%EA%B0%9C%EB%B0%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Tue, 23 Dec 2025 07:14:55 GMT</pubDate>
            <description><![CDATA[<h2 id="1-프로젝트-소개">1. 프로젝트 소개</h2>
<ul>
<li><p><strong>기간</strong> 
  2025.12.02 ~ 12.11 &lt;(주말제외) 8일&gt;</p>
</li>
<li><p><strong>목적</strong></p>
</li>
<li><p><em>ESG 도메인에 특정한 AI AGENT*</em>를 만드는 것이 목적.</p>
</li>
<li><p><strong>배경</strong>
상반기에 제조업에서 유럽 규제 관련 ESG 업무 인턴을 했던 나로서는 복잡한 ESG 규제들과 관련 대응 보고서를 작성하는게 만만치 않은 일이었다. 대기업은 회계법인의 컨설팅을 받거나 ESG 담당 팀이 마련되어 있어 관련 대응에 그나마 용이할 수 있겠지만, 계열사나 협력사 등은 정보를 찾는 일 부터 관련 법규에 대응하는 일을 사람이 손수 서치해야하는게 쉽지 않다.</p>
</li>
</ul>
<p>이런 배경과 함께  Agent 개발이라는 2차 프로젝트 목적성에 아주 부합한 <strong>ESG Agent 만들기</strong>라는 주제가 빠르게 확정되었다.</p>
<ul>
<li><strong>Target</strong>
ESG 규제는 도메인(ex. 자동차, 건설사 등)에 따라 주목해서 봐야할 규제가 다르기 때문에 초기 프로젝트에서는 도메인의 범위를 <strong>건설사</strong>로 특정하기로 했다. (아무래도 우리의 멘토링 기업이 HDC 랩스, 즉 건설사이기 때문)</li>
</ul>
<hr>
<h2 id="2-기능">2. 기능</h2>
<p>ESG 목적 달성을 위해 해야할 일들은 크게 4가지로 생각해서 이 기능별로 tool을 만들기로 정했다.</p>
<h3 id="1-정책-요약비교-policy-tool">1. 정책 요약/비교 [Policy Tool]</h3>
<ul>
<li>K-ESG, SASB, GRI 등 어려운 정책 용어들을 설명해주고 자동 비교</li>
<li>건설사 맞춤 지침서 생성</li>
</ul>
<h3 id="2-리스크-진단-risk-tool">2. 리스크 진단 [Risk Tool]</h3>
<ul>
<li>프로젝트별 ESG 리스크 자동 평가</li>
<li>현장 체크리스트 생성</li>
</ul>
<h3 id="3-보고서-자동-작성-report-tool">3. 보고서 자동 작성 [Report Tool]</h3>
<ul>
<li>K-ESG 61개 항목 기반 제출 보고서 자동생성 후 PDF/DOCX 다운로드</li>
</ul>
<h3 id="4-규제-모니터링-regulation-tool">4. 규제 모니터링 [Regulation Tool]</h3>
<ul>
<li>환경부/고용부 규제 변경 감지</li>
<li>주간 요약 리포트</li>
</ul>
<hr>
<h2 id="3-기술-스택">3. 기술 스택</h2>
<pre><code class="language-yaml">Backend: FastAPI
AI: LangChain + LangGraph + GPT-4-mini
 - Embedding: bge-m3
 - Parsing: PyPDF, PyMuPDF, Tesseract
Vector DB: ChromaDB
Frontend: React</code></pre>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/38b91c3c-e4cf-4d2d-855e-239242ac54d0/image.png" alt=""></p>
<p>사실 2차 프로젝트는 10일짜리 단기 프로젝트여서 프로젝트의 목적에 맞게 AI agent 구축에만 신경을 쓸까하다가, 이 프로젝트를 단기 프로젝트로만 끝내고 싶지 않아서 backend와 frontend도 커버해보기로 했다.
멋사를 통해서 frontend로 프로젝트는 몇 번 해봐서 오랜만에 하더라도 프론트는 바이브 코딩으로도 충분했는데 백엔드는 아예 무지해서 로직을 이해하고 수정하는데 시간이 오래 걸렸다.😯</p>
<hr>
<h2 id="4-개발-과정">4. 개발 과정</h2>
<ul>
<li><strong>8일 개발 일정</strong>
<img src="https://velog.velcdn.com/images/y-hyun2/post/6b713f45-98b2-43a9-8bae-76982baddfd0/image.png" alt=""></li>
</ul>
<h3 id="ai-기능">[AI 기능]</h3>
<h3 id="1-문서-정제-및-청킹">1. 문서 정제 및 청킹</h3>
<p><strong>PyMuPDF+조건부 OCR</strong>로 텍스트 확보 → 표지·목차·헤더 제거 → source_file, source_type, year, page, ocr 등 메타데이터 포함한 chunk 생성.
    - 조건부 OCR? : 기업에서 발행한 ESG 보고서 등은 그림 및 표 자료가 많아서 PyPDF 등으로는 파싱이 잘 안 됨 → 이럴 경우 OCR 이용</p>
<pre><code>┌────────────────────────────────────────┐
│  🔵 1단계: PDF 로드 &amp; 파싱           
├────────────────────────────────────────┤
│  - PDF 파일 읽기                     │
│  - 텍스트 추출                       │   
│  - 테이블/이미지 처리 (선택)           │
└────────────┬───────────────────────────┘
             ↓
┌────────────────────────────────────────┐
│  🔵 2단계: 청킹 (Chunking)          
├────────────────────────────────────────┤
│  - 문서를 작은 조각으로 분할          
│  - 메타데이터 추가                    │
│    (회사명, 연도, 페이지, 섹션 등)     
│  - 청크 크기: 500-1000 토큰           │
└────────────┬───────────────────────────┘ </code></pre><h3 id="2-임베딩·vectordb-구축">2. 임베딩·VectorDB 구축</h3>
<p>BAAI/bge-m3 임베딩으로 chunk 벡터화 → Chroma에 collection_name 지정해 저장.</p>
<blockquote>
<p>vector_db 디렉터리(<code>vector_db/esg_all</code>)에는 ESG 보고서·규제 문서·협력사 자료를 임베딩해 놓은 Chroma 컬렉션이 저장된다.</p>
</blockquote>
<h3 id="3-retriever-구축">3. Retriever 구축</h3>
<ul>
<li><p>fetch_k·top_k·MMR 값 결정해 다양성 있는 <strong>후보 확보.</strong></p>
</li>
<li><p><strong>메타데이터 필터(기업, 연도, 영역 등)를 사전 적용</strong>해 검색 범위를 줄임.</p>
<ul>
<li><p>이미 VectorDB에 저장된 메타데이터를 검색 시 필터로 쓰임</p>
<p>  ⇒ chunk마다  Document(..., metadata=...)를 만들어 Chroma에 넣음</p>
</li>
</ul>
</li>
<li><p>LLM 기반 query rewriting으로 도메인 용어를 보강한 검색어 생성.</p>
</li>
<li><p>필요 시 cross-encoder reranker(Cohere/bge-reranker)로 top-N 재정렬.</p>
</li>
<li><p>post-filter 단계에서 도메인 규칙(메타데이터, 키워드 등)으로 최종 chunk를 정제.</p>
</li>
</ul>
<hr>
<p>  <strong>[Retriever Logic]</strong></p>
<blockquote>
<ol>
<li><strong><em>retriever/retriever_pipeline.py</em></strong>는 이미 VectorDB에 저장돼 있는 메타데이터를 <strong>검색 시 필터로 쓰도록</strong> 구성.<ol start="2">
<li><strong><em>vector_db/esg_all.py</em></strong>에서 chunk마다 <code>Document(..., metadata=...)</code>를 만들어 Chroma에 넣었기 때문에, 저장 단계에서 포함된 필드(source_file, source_type, page, ocr, 앞으로 추가할 company, year, country 등)가 VectorDB에 그대로 남는다.
리트리버는 metadata_filter에 <code>{&quot;source_type&quot;: &quot;companies&quot;, &quot;company&quot;: &quot;DL건설&quot;}</code> 같은 조건을 전달해서 <strong>“이미 저장돼 있는 메타데이터”를 기준으로 검색 범위를 좁히는 것!</strong></li>
</ol>
</li>
</ol>
</blockquote>
<p>  만약, 필드를 더 쓰고 싶으면 <strong><em>ingestion 단계</em></strong>에서 <code>metadata.update(...)</code>에 추가하고 VectorDB를 다시 생성하면 됨</p>
<p>  <strong>[ 각 TOOL 별 RAG 체인]</strong>
  각 툴(policy_tool.py, regulation_tool.py, risk/…, supplier_eval.py 등)이 <strong>동일한 벡터 DB</strong>를 직접 로드하지만, <strong>retriever 설정·프롬프트·LLM 파라미터는 서로 다름</strong>.</p>
<table>
<thead>
<tr>
<th>모듈</th>
<th>벡터 DB</th>
<th>Retriever / LLM 특성</th>
</tr>
</thead>
<tbody><tr>
<td><strong>policy_tool.py</strong></td>
<td><code>Chroma(persist_directory=&quot;vector_db/esg_all&quot;)</code></td>
<td>① <code>vector_db/esg_all.py</code> 등으로 PDF를 chunk → BGE 임베딩 후 저장<br>② 사용자 질의를 동일 모델로 벡터화해 <code>retriever.get_relevant_documents(k=5)</code>로 상위 문단을 가져옴<br>③ “정책 요약/비교/평가” 프롬프트에 <code>[관련 근거]</code> 블록 형태로 삽입해 <strong>LLM(GPT-4o mini)</strong> 을 호출하는 정석 <strong>RAG 체인</strong></td>
</tr>
<tr>
<td><strong>regulation_tool.py</strong></td>
<td><code>Chroma(collection_name=&quot;esg_regulations&quot;, persist_directory=&quot;vector_db/all_esg&quot;)</code></td>
<td><strong>Selenium + Tavily</strong> 로 최신 문서를 수집·저장 후, 필요할 때만 RAG로 규제 요약 수행<br>동일한 <strong>BGE 임베딩</strong>을 사용하지만 <strong>크롤러 히스토리</strong>, <strong>검색 범위</strong>, <strong>스케줄링 로직</strong>이 다름</td>
</tr>
<tr>
<td><strong>risk / supplier_eval</strong></td>
<td>템플릿 기반 점수 / 보고서</td>
<td><strong>RAG 의존도는 낮음</strong>, 그러나 필요 시 다문서 증거를 vector DB에서 가져와 항목별 근거를 생성</td>
</tr>
</tbody></table>
<h3 id="4-langchainlanggraph-통합">4. LangChain/LangGraph 통합</h3>
<p>위 Retriever를 그래프/체인 노드로 넣어 LLM이 항상 필터링된 chunk를 받도록 구성.</p>
<ul>
<li><strong><em>src/workflows/custom_graph.py</em></strong>: policy → regulation → risk → report 노드를 StateGraph로 구성.</li>
<li><code>run_custom_agent</code>가 LangGraph를 호출해 종합 결과를 만드는 구조.</li>
</ul>
<hr>
<h3 id="데이터-흐름">[데이터 흐름]</h3>
<ol>
<li>사용자 업로드 → <strong><em>/api/upload</em></strong> → Redis context에 파일 목록 반영.
 <em>[ Redis 기반 context 관리]</em></li>
<li>특정 에이전트 요청(<strong><em>/api/agent/*)</em></strong> → LangChain 툴 실행 → 결과를 Redis context에 저장.</li>
<li><em><strong>/api/chat/stream</strong></em> → 자동으로 custom 에이전트 실행 → 정책/규제/리스크/보고서를 컨텍스트에 추가 → LLM 프롬프트 생성 → 응답/스트리밍.</li>
</ol>
<hr>
<h2 id="5-확장성">5. 확장성</h2>
<ul>
<li><p><input disabled="" type="checkbox">  협력사 종류별 찾은 내용 분야별로 주요기능에 연결 &lt;<strong>도메인 지식</strong> 더 명확히 하기&gt;</p>
</li>
<li><p><input disabled="" type="checkbox">  <strong>로그인 서버</strong> 디비</p>
</li>
<li><p><input disabled="" type="checkbox">  채팅창이랑 보고서창이랑 동적으로 이동시킬 수 있도록 전환</p>
</li>
<li><p><input disabled="" type="checkbox">  보고서/체크리스트 <strong>templete 제작</strong></p>
</li>
<li><p><input disabled="" type="checkbox">  프론트 - <strong>파일 업로드 속도 개선</strong></p>
<ul>
<li><p>문제상황
 : 백엔드 업로드 엔드포인트가 파일을 받은 뒤 즉시 임베딩을 계산하면서 오래 막혀 버림 </p>
</li>
<li><p>해결방안</p>
<ol>
<li>더 가벼운 임베딩 모델을 사용(sentence-transformers/all-MiniLM-L6-v2 or BAAI/bge-small-en) -&gt;  CPU에서 빠르게 동작하는 모델로 교체</li>
<li>파일 업로드 시 즉시 벡터화하지 않고 백그라운드 작업으로 넘기거나, 업로드에선 파일 메타데이터만 저장하고 임베딩은 나중에 트리거하도록 비동기 처리</li>
</ol>
</li>
</ul>
</li>
</ul>
<ul>
<li><input disabled="" type="checkbox"> 단일chroma → 멀티벡터리트리버 체인지</li>
</ul>
<hr>
<h2 id="6-마무리하며">6. 마무리하며</h2>
<h3 id="🤩잘한-점">🤩잘한 점</h3>
<p>우선 <strong>Notion을 사용하여 매일 진행상황을 꼼꼼히 문서화한 것</strong>이 프로젝트 진행을 원활히 하는데 큰 도움이 되었다. 매일 아침 저녁으로 팀원마다 계획과 진행상황 점검을 하며 회의록을 작성하다보니, 나무만 보는 게 아니라 숲을 보며 프로젝트를 진행할 수 있어서 흐름이 끊기지 않아 좋았다. 3차 프로젝트를 시작하기 전까지 텀이 있을텐데, 노션을 보며 바로 상황을 파악하고 바로 진행할 수 있을 것 같다.</p>
<p>또한 깃허브의 중요성을 강조하여 팀원들 모두가 <strong>깃허브로 코드를 공유하며 협업할 수 있도록 이끈 점</strong>이 매우 뿌듯하다. 팀원 모두가 깃허브에 익숙한 것은 아니라서 사용하는데 어려움이 있었고 오류를 해결하는데 시간이 많이 걸렸지만, 그 과정에서 나 역시 깃허브에 더 익숙해졌고 각자 코드의 진행상황을 바로 공유할 수 있어서 좋았다.</p>
<h3 id="😑아쉬운-점">😑아쉬운 점</h3>
<p>도메인 특화적인 Agent였기 때문에 <strong>짧은 시간 내에 도메인 지식을 습득하고 정보와 문서를 찾아오는게 쉽지 않았다.</strong> 하루 안에 도메인 정보를 찾아오고 개발을 시작하려다 보니 그에 따라 성능이 낮아진 게 아쉬웠다. 3차 프로젝트에서는 도메인 지식을 확실히 하고 전처리나 모델의 성능들도 하나씩 테스트해가며 우리 프로젝트에 잘 맞는 모델과 기능들을 찾았으면 좋겠다. </p>
<h3 id="👩🏻🎓배운-점">👩🏻‍🎓배운 점</h3>
<p>LangGraph, LangChain을 이용하면 RAG Agent를 만드는 게 그렇게 어렵지 않다고 오만했는데, 이론과 실전은 다르다는 것을 깨달았다. <strong>문서를 파싱하여 청킹하는 것</strong>부터 깔끔하게 하는 게 쉽지 않았고, 문서를 찾아올 때도 정해진 로직을 따라서 하기만 하면 잘 찾아올 줄 알았는데 아니었다.. 넣고 싶었던 기능이 많다보니 tool 별로 retriever 설정도 다르게 해야했고, <strong>단일 retirever를 쓰다보니 정확도도 낮았다</strong>. 
그러나 여러 시행착오를 겪으며 디벨롭해나가야 할 부분이나 해결방안들이 현재로서는 명확하게 보여서 발전 가능성이 보인다. 그래도 <strong>RAG를 직접 사용해봤다는 경험</strong>에서 더 나은 성능을 내는 방법을 깨달은 것 같다. (전처리나 도메인 지식이나 이 프로젝트에 맞는 모델들은 써보면서 알 수 있다는 점 등등..) 
짧은 기간이라서 부족했던 부분이 많지만 3차 프로젝트를 진행하면서 더 높은 완성도를 가진, 내가 원했던 그런 ESG Agent를 만들어 낼 수 있으면 좋겠다!!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[DRPruning: 논문리뷰]]></title>
            <link>https://velog.io/@y-hyun2/DRPruning-%EB%85%BC%EB%AC%B8%EB%A6%AC%EB%B7%B0</link>
            <guid>https://velog.io/@y-hyun2/DRPruning-%EB%85%BC%EB%AC%B8%EB%A6%AC%EB%B7%B0</guid>
            <pubDate>Mon, 17 Nov 2025 10:28:49 GMT</pubDate>
            <description><![CDATA[<p><strong>DRPruning: Efficient Large Language Model Pruning through Distributionally Robust Optimization</strong>(Deng et al., 2025) 논문 리뷰</p>
<ul>
<li>특정 도메인의 성능 불균형을 막기 위한 Structured Pruning</li>
</ul>
<h2 id="1-introduction">1. Introduction</h2>
<ul>
<li>LLM은 뛰어난 성능을 내지만 모델 크기가 커지고 연산량이 많아지는 단점이 있다. structured pruning을 통해 모델 크기를 줄이고 추론 속도를 올릴 수 있으나, 도메인(분야)이나 작업(task)이 다양한 데이터에 대해 프루닝 후 성능이 고르게 떨어지지 않고 <strong>특정 도메인에서 상대적으로 더 나빠지는 문제가 있다</strong>. (즉 프루닝 → 도메인 간 성능 불균형 → bias가 생긴다.)</li>
<li>이를 해결하기 위해 논문은 <strong>Distriubutionally Robust Optimization(DRO) 개념</strong>을 차용하여 “ Pruning + 다도메인 데이터 분포 변화: Dynamic data distribution)을 통해 모델이 만든 <strong>도메인에서 보다 균형 있게 성능을 회복하도록 하는 방법인 DRPruning</strong>을 제안한다.</li>
</ul>
<p>Why is this important?</p>
<ul>
<li>LLM이 커질수록 비용,메모리, 연산 모두 커지고 “모델을 가볍게 하면서도 성능을 유지”하는 것이 실용적 중요성이 높다.</li>
<li>구조적 프루닝은 단순히 작은 모델을 만드는 방법이지만, 다양한 데이터 분포(도메인)에서 성능이 불균형하게 나빠지는 문제가 있다. 프루닝 후 모델이 A 도메인에선 괜찮지만 B 도메인에선 성능이 크게 떨어진다면, 실제 응용에서는 공정성, 일반화 등의 측면에서 문제가 된다.</li>
<li>본 논문은 이런 도메인 간 불균형을 해결하려는 시도로, 단순히 모델을 작게 만드는 것 이상으로 <strong>“데이터 분포를 조정하면서 프루닝”</strong> 한다는 점에서 차별성이 있다.</li>
</ul>
<h2 id="2-backgroud">2. Backgroud</h2>
<h3 id="21-structured-pruning">2.1 Structured Pruning</h3>
<p>Pruning은 Neural Network 를 경량화 하고자 할 때 사용하는 방법.</p>
<p>연결된 모든 node를, parameter가 0에 가깝다거나 훈련을 거의 안 했다는 지표를 판단하여 pruning 한다.</p>
<ul>
<li><strong>구조적 프루닝(Structured Pruning)</strong>: 모델의 일부 구조(예: 층(layer), 헤드(attention head), 중간 피드포워드 네트워크(ffn)의 hidden dimension 등)를 <strong>완전히 제거하거나 축소하는 방</strong>식이다. 이는 비구조적(unstructured) 프루닝(임의의 weight를 0으로 만드는 방식)보다 하드웨어 친화적일 수 있다. 논문에서는 Sheared Llama (Xia et al., 2024) 프루닝 방식을 기반으로 한다.</li>
</ul>
<p>모델의 각 모듈(예: attention head, FFN channel)을 <strong>mask vector</strong> $z^i∈RD$ 로 제어</p>
<ul>
<li>$z^i_j = 1:$ 유지</li>
<li>$z^i_j = 0:$ 제거</li>
</ul>
<p>→ 이 <strong>mask vector</strong> 스위치를 학습으로 자동 조정해서 어떤 걸 살리고 어떤걸 자를지 스스로 결정하게 함</p>
<ol>
<li><p><strong>L0 정규화</strong>: 모듈 제거하라고 독려</p>
<ul>
<li>더 많이 0으로 만들어 자르자라는 신호를 주는 벌칙이 L0 정규화</li>
<li>문제: <strong>mask vector <em>Z 는 0/1뿐이어서 미분 불가</em></strong></li>
</ul>
</li>
<li><p><strong>Hard- Concrete</strong> 분포: 부드러운 가짜 스위치</p>
<ul>
<li><p>그래서 학습 중엔 0/1 대신 0과 1 사이를 오가는 “가짜 스위치(Hard-concrete)” 방법을 쓰고, 마지막에 진짜 0/1로 딱 결정을 내리는 트릭을 씀.</p>
</li>
<li><p>마스크를 매개변수화하기 위해 ℓ₀-regularization (Louizos et al., 2018) + hard concrete 분포(hard concrete distribution)를 사용함.</p>
<aside>
</li>
<li><p>스위치 $z^i_j$ 는 원래 0 또는 1</p>
</li>
<li><p>학습 중엔 $\tilde z_j \in [0,1]$(hard concrete gate)로 두고 미분/학습</p>
</li>
<li><p>손실 = <strong>언어모델 손실</strong> + <strong>L0 정규화</strong>.</p>
</li>
<li><p>학습 끝나면 $\tilde z_j→z_j​∈{0,1}$ 로 딱 잘라냄</p>
</aside>
</li>
</ul>
</li>
<li><p><strong>Lagrange multipliers 라그랑주 승수 적용</strong></p>
<ul>
<li>프루닝 후 목표 구조(target configuration)를 만족시키기 위해 라그랑주 승수를 적용<ul>
<li>예를 들어 “이 층에 <strong>헤드 8개 중에 4개만 남겨</strong>” 같은 <strong>목표 개수</strong>가 있지만.</li>
<li>학습이 진행되면 스위치 합 $∑_j z_j$ 이 <strong>4와 다를 수</strong> 있음</li>
<li>그래서 “<strong>목표와 다르면 벌점</strong>”을 주는 항을 손실에 추가 → 결국 <strong>정확히 4개</strong> 근처로 맞춰짐</li>
</ul>
</li>
</ul>
</li>
</ol>
<ul>
<li>최종적으로 모델 파라미터 θ 와 마스크 z 를 함께 최적화하는 손실(loss) 함수가 구성된다. 자세히 말하면 <code>모델 언어모델링 손실 + 프루닝 제약 손실</code>이 함께 최적화된다.</li>
<li>요약하자면: 구조적 프루닝은 모델을 경량화하는 훌륭한 도구이지만, 그 자체로 <strong>도메인 간 성능 불균형</strong> 문제를 자동으로 해결하진 않는다.</li>
</ul>
<h3 id="22-분포론적-강건최적화-distributionally-robust-optimization-dro">2.2 분포론적 강건최적화 (Distributionally Robust Optimization, DRO)</h3>
<p>DRO는 머신러닝 모델이 여러 가능한 데이터 분포(distribution) 중 “가장 불리한(worst-case)” 분포에 대해서도 잘 작동하게끔 설계하는 최적화 기법이다. 예컨대, 여러 그룹(group) 또는 도메인(domain)이 있다면 그 중 가장 성능이 떨어지는 그룹을 고려해 최적화하는 방식이다.</p>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/3748e7a6-7b7c-4c62-85db-a29e45ec16a4/image.png" alt=""></p>
<p>여기서 $Di$는 도메인 i의 데이터이고, $q=(q1,…,qn)$은 각 도메인에 할당된 가중치(weight)이다.</p>
<p>$ℓ(θ;Di)$는 도메인 i의 손실,</p>
<p>$Q$ 는 가중치 벡터가 가질 수 있는 가능한 분포 집합이다.</p>
<p>→ 모델 θ를 바꿔서, worst-case 도메인도 불리하지 않게 성능이 떨어지는 것을 최소화 하자</p>
<ul>
<li>이런 방식은 일반화(generalization)와 그룹 간 불균형(group imbalance) 문제를 완화하는 데 사용되어 왔다. 하지만 <strong>하이퍼파라미터(예: 참조 손실(reference loss), 기준 데이터 비율(reference data ratio) 등)를 적절히 설정하는 것이 어렵다는 문제가</strong> 있다.</li>
</ul>
<h2 id="3-our-proposed-drpruning-method">3. Our Proposed DRPruning Method</h2>
<h3 id="31-distributionally-robust-pruning">3.1 Distributionally Robust Pruning</h3>
<p>프루닝과 이어지는 사전학습(continued pretraining) 단계에 DRO를 통합한다.</p>
<ul>
<li>먼저 프루닝을 통해 모델을 작게 만들고, 이어서 사전학습(또는 계속 학습) 단계를 통해 모델 성능을 회복시킨다. 이 과정에서 데이터가 여러 도메인에 걸쳐 있을 때, 도메인마다 회복 속도가 다르고 손실(loss)도 차이가 날 수 있다.</li>
<li>따라서 드러나는 문제: 프루닝 후 어떤 도메인은 빨리 회복하고, 어떤 도메인은 느리면 전체 모델은 도메인 간 격차가 커질 수 있다.</li>
<li>이를 막기 위해, DRPruning은 <strong>각 도메인의 평가 손실(validation loss 또는 evaluation loss)</strong> 를 이용해서 그 도메인이 얼마나 뒤처지는지를 추정하고, 그에 따라 “다음 학습 스텝에서 해당 도메인의 데이터를 더 많이 사용하도록(data proportion을 증가)” 하거나 가중치를 더 부여하는 방식으로 <strong>데이터 비율(q)과 손실 기준을 동적으로 조정한다.</strong></li>
</ul>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/3c38d6db-b055-4886-8e22-3c1915735839/image.png" alt=""></p>
<ol>
<li><p>각 도메인 i에서 현재 손실 $\mathcal{L}_i$를 계산</p>
</li>
<li><p>손실이 <strong>참조값(reference loss)</strong> 보다 크면</p>
<p> → 그 도메인의 데이터 비율 $\mathcal{q}_i$ ↑ (더 공부시킴)</p>
</li>
<li><p>손실이 참조값보다 작으면</p>
<p> → $\mathcal{q}_i$↓ (덜 공부시킴)</p>
</li>
</ol>
<p>이 과정을 반복하면서
모델은 잘린 상태에서도 <strong>모든 도메인에서 공평한 실력</strong>을 유지하게 됨</p>
<blockquote>
<ul>
<li>θ: 모델 파라미터 (가중치)</li>
</ul>
</blockquote>
<ul>
<li>z: 어떤 부분을 남길지/자를지 결정하는 마스크</li>
<li>qi: 각 도메인 데이터의 비율</li>
<li>$\mathcal{L}_i$: i번째 도메인의 손실</li>
</ul>
<p>즉, “<strong>마스크를 조정하면서 모델을 작게 만들되</strong>, 
<strong>도메인 간 성능이 고르도록(손실이 균형잡히게)</strong> 학습하자” </p>
<h3 id="32-참조-손실reference-loss-및-예측"><strong>3.2 참조 손실(Reference Loss) 및 예측</strong></h3>
<ul>
<li>여기서는 “각 도메인이 이정도 손실(loss)을 가져야 한다”라는 <strong>참조 손실(reference loss,$τ$ 등으로 표기됨)</strong> 개념을 도입한다.</li>
<li>이유: 단순히 ‘가장 손실이 큰 도메인’에 무작정 집중하면 자칫 모델이 특이 도메인에 과도하게 치우칠 수 있고, 학습이 불안정해질 수 있다. 따라서 각 도메인이 달성해야 할 ‘목표 손실치’(참조 손실)를 설정해두고, 그 손실에서 얼마나 벗어났는지에 따라 가중치 조정 및 데이터 비율 조정한다.</li>
<li>그런데 이 참조 손실을 사람이 일일이 설정하기 어렵고, 모델 크기, 데이터양, 학습 스텝 등에 따라 달라지기 때문에 본 논문에서는 <strong>스케일링 법칙(scaling laws)</strong> 을 이용해 “학습 끝나고 나면 손실이 이 정도일 것이다”라고 예측하고 그것을 참조 손실로 사용한다.</li>
<li>예컨대, 파라미터 수 $N$ 및 학습 스텝 수 $S$ 등이 주어졌을 때, 아래와 같은 형태로 손실이 감소할 것이라는 것을 가정을 두고 이를 참조 손실로 설정한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/dfdff4ff-f182-4212-8344-71377aa31c9e/image.png" alt=""></p>
<h3 id="33-dynamic-potential-distribution동적-잠재-분포">3.3 Dynamic Potential Distribution(동적 잠재 분포)</h3>
<ul>
<li>이 절은 데이터 비율(잠재 분포, potential distribution) $q$ 를 단순히 고정하거나 손실 기준만으로 바꾸는 것이 아니라, 점진적으로 <strong>도메인이 학습에서 뒤처질수록 이 도메인의 데이터 비율(reference data ratio)을 증가시키는</strong> 전략을 제시한다.</li>
<li>보다 구체적으로: 
기존 DRO 방식은 $q$ 가 가능한 모든 분포 집합$Q$안에 있다고 가정하고 최악의 경우에 대응하지만, 이는 지나치게 보수적(over-conservative)일 수 있고 결국 가장 나쁜 도메인만 집중 학습하게 될 수 있다.</li>
<li>이를 보완하기 위해, 본 논문은 $q$가 “어느 정도 참조 데이터 비율(reference data ratio) $r$” 주변의 -divergence ball 내에 있다고 가정한다. $q∈{q:D_KL​(q∥r)≤ϵ}$</li>
<li>그리고 학습이 진행됨에 따라, 만약 어떤 도메인이 손실이 크면 그 도메인의 참조 비율$r_i$ 를 조금씩 증가시켜 그 도메인 데이터 사용 비중을 높인다. 이렇게 하면 학습이 덜 된 도메인으로 자원을 점진적으로 옮겨갈 수 있다.</li>
<li>이런 방식으로 DRPruning은 프루닝된 모델이 다양하고 불균형한 도메인 분포에서도 <strong>균형 잡힌 성능(balanced performance)</strong> 을 갖게 하려 한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Week7: ML을 위한 데이터 다루기]]></title>
            <link>https://velog.io/@y-hyun2/Week7-ML%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%8B%A4%EB%A3%A8%EA%B8%B0</link>
            <guid>https://velog.io/@y-hyun2/Week7-ML%EC%9D%84-%EC%9C%84%ED%95%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%8B%A4%EB%A3%A8%EA%B8%B0</guid>
            <pubDate>Sun, 02 Nov 2025 04:24:44 GMT</pubDate>
            <description><![CDATA[<p><strong>OCT 3주차 (10/13 ~ 10/17 회고)</strong></p>
<pre><code>📍 전체 목차
Ch1. Vector, 행렬, 배열
Ch2. Data 저장
Ch3. 데이터 랭글링 (Data Wrangling)
Ch4. 수치형 Data 다루기 
Ch5. 범주형 Data 다루기
Ch6. Text 다루기 (예고)</code></pre><blockquote>
<p><strong>💡 머신러닝 기초 회고 개요</strong>
데이터를 다루려면,
→ 행렬(Matrix) 은 “보관소”
→ 자유자재로 다룰 수 있어야 함!</p>
</blockquote>
<h3 id="🧩-ch1-vector-matrix행렬-배열from-numpy">🧩 Ch1. Vector, Matrix(행렬), 배열(from NumPy)</h3>
<p>🔹 <strong>벡터</strong> = 단순히 하나의 차원을 가진 배열</p>
<p><code>vector_row = np.array([1, 2, 3])</code>
<code>vector_column = np.array([[1], [2], [3]])</code>
    → 배열은 Vector로 표현할 수 있다.</p>
<p>🔹 <strong>행렬 (Matrix)</strong> = 2차원 numpy 배열</p>
<pre><code>matrix = np.array([[1, 2, 3],
                   [1, 2, 3]])</code></pre><p><strong>🔹 희소행렬 (Sparse Matrix)</strong> = 대부분 원소가 0인 행렬을 효율적으로 저장하는 방법</p>
<pre><code class="language-python">from scipy import sparse

matrix = np.array([[0, 0, 1],
                   [0, 1, 0],
                   [3, 0, 3]])

matrix_sparse = sparse.csr_matrix(matrix)</code></pre>
<p> <code>(0,1) 0</code>
<code>(2,1) 3</code></p>
<p>역변환:
<code>matrix_sparse.toarray()</code></p>
<p>🔹 <strong>NumPy 배열 생성 함수들</strong></p>
<pre><code class="language-python">np.zeros(shape=5)     # 0으로 채운 배열 -&gt; 실수값 출력
np.ones(shape=5)      # 1로 채운 배열 -&gt; 실수값 출력
np.full(shape=(3, 3), fill_value=1)  # 지정값으로 채움 -&gt; 정수값 출력
</code></pre>
<hr>
<p>🔹 <strong>인덱싱 / 슬라이싱</strong></p>
<pre><code class="language-py">vector[::-1]      # 벡터의 원소 순서 뒤집기
matrix[:, 1:2]    # 모든 행 &amp; 두번째 열 선택</code></pre>
<p>→ 내가 헷갈리는 인덱싱</p>
<p>📘 Fancy Indexing : 인덱스 리스트만 전달
<code>matrix[[0, 2]]</code> → 1, 3번째 행만 선택</p>
<pre><code class="language-py">array([[0, 0, 1],
       [3, 0, 3]]</code></pre>
<p><code>matrix[[0, 2], [1, 3]]</code>  → (0,1), (2,0) 위치 원소 선택</p>
<p>= 괄호 안쪽 <em>첫 번째 인덱스는 행</em>, <em>두 번째 인데스는 열</em></p>
<h4 id="⚙️-벡터-연산">⚙️ 벡터 연산</h4>
<p>🔹 <strong>Broadcasting</strong> : 서로 다른 크기의 배열끼리 연산(+,-,*,/) 을 가능하게 해주는 규칙</p>
<p>NumPy의 핵심 기능: 자동으로 크기 맞춰 연산 수행</p>
<p>1️⃣ 예시: (1,3) shape 배열
<img src="https://velog.velcdn.com/images/y-hyun2/post/de6149f7-4c6a-43be-8177-99c00379425a/image.png" alt=""></p>
<p>2️⃣ 예시: 1차원 vector
<img src="https://velog.velcdn.com/images/y-hyun2/post/3c7af7ce-1411-4a3e-a034-0058743c28d4/image.png" alt=""></p>
<p>🔹 <strong>축(axis) 개념</strong></p>
<blockquote>
<p>💡 “axis가 고정되는 축” 을 뜻합니다.
<code>axis=0</code>이면 “행을 따라 계산하라 (세로로 내려가라)”
<code>axis=1</code>이면 “열을 따라 계산하라 (가로로 가라)” </p>
</blockquote>
<p><code>np.max(matrix, axis=0)</code>  # 각 열의 최댓값
<code>np.max(matrix, axis=1)</code>  # 각 행의 최댓값</p>
<p>🔹 <strong>평균, 분산, 표준편차</strong>
<code>np.mean(matrix)</code>
<code>np.var(matrix)</code>
<code>np.std(matrix, ddof=1)</code>  # 표준편차, 자유도 조정 가능</p>
<hr>
<p>🔹 <strong>배열 구조 변경</strong>
<code>matrix.reshape(2, 6)</code>      # 2x6 형태로 변경
<code>matrix.reshape(-1)</code> = <code>matrix.ravel()</code>       # 1차원으로 평탄화
<img src="https://velog.velcdn.com/images/y-hyun2/post/42ec6326-0a09-4fce-b1e5-e142d1f8b508/image.png" alt="">
 ⬆️ (1,9) shape의 2차원 배열임</p>
<p>🔹 <strong>행렬 전치(Transpose)</strong></p>
<pre><code class="language-py">matrix = np.array([[1,2,3],
                   [4,5,6],
                   [7,8,9]])

matrix.T
</code></pre>
<p>또는:</p>
<p><code>matrix.transpose()</code></p>
<ul>
<li>matrix.T와 .transpose()는 거의 동일
(다만, 여러 축이 있는 배열의 경우 <code>.transpose(axes)</code>로 지정 가능)</li>
</ul>
<p>🔹 벡터 전치 시 주의
    :1차원 벡터에는 전치가 적용되지 않음 → 2D로 바꿔야 함
<code>np.array([[1,2,3,4,5,6]]).T</code></p>
<p>📏 <strong>행렬 평탄화 &amp; 변형</strong>
<code>matrix.flatten()</code>         # 평탄화 (복사본)
<code>matrix.reshape(-1)</code>       # 평탄화 (뷰)</p>
<hr>
<p>대각선 요소 추출: <code>np.diag(matrix)</code></p>
<p><strong>⚡ Dot Product (내적)</strong></p>
<table>
<thead>
<tr>
<th>비교 항목</th>
<th><code>np.dot()</code></th>
<th><code>np.matmul()</code> / <code>@</code></th>
</tr>
</thead>
<tbody><tr>
<td>1D 벡터 연산</td>
<td>내적 (스칼라)</td>
<td>❌ 지원 안 함</td>
</tr>
<tr>
<td>2D 행렬 곱</td>
<td>✅ 동일</td>
<td>✅ 동일</td>
</tr>
<tr>
<td>3D 이상 (배치 연산)</td>
<td>❌ 비직관적 결과</td>
<td>✅ 각 배치별 행렬 곱</td>
</tr>
<tr>
<td>브로드캐스팅</td>
<td>❌ 없음</td>
<td>✅ 지원</td>
</tr>
<tr>
<td>추천도</td>
<td>구버전 호환용</td>
<td>✅ 권장 (Python 3.5+ 표준)</td>
</tr>
</tbody></table>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/290261d9-212a-4fbf-adef-432758ebe513/image.png" alt="">
행렬의 곱(일반적 개념) vs 내적(1차원 배열인 벡터 사이의 곱 = 결과: 스칼라)</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>내적 (dot product)</th>
<th>행렬 곱 (matrix multiplication)</th>
</tr>
</thead>
<tbody><tr>
<td>입력</td>
<td>두 <strong>벡터 (1D)</strong></td>
<td>두 <strong>행렬 (2D 이상)</strong></td>
</tr>
<tr>
<td>결과</td>
<td><strong>스칼라(숫자 하나)</strong></td>
<td><strong>새로운 행렬</strong></td>
</tr>
<tr>
<td>관계</td>
<td>행렬 곱의 “한 셀”을 만드는 연산</td>
<td>여러 내적의 집합</td>
</tr>
<tr>
<td>예시</td>
<td><code>[1,2,3]·[4,5,6] = 32</code></td>
<td>A(2×3)×B(3×2) = C(2×2)</td>
</tr>
</tbody></table>
<hr>
<p><strong>🎲 난수 생성 및 제어</strong>
<code>np.random.seed(0)</code>  # 랜덤 고정하여 초기값 지정
<code>np.random.random(3)</code>  # 0<del>1 사이 float 3개 생성
<code>np.random.randint(0, 11, 3)</code>  # 0</del>10 사이 정수 3개 생성
<code>np.random.normal(0.0, 1.0, 3)</code>  # 평균=0, 표준편차=1 정규분포를 따르는 float 3개 생성</p>
<hr>
<hr>
<h3 id="📂-ch2-데이터-저장-data-storage">📂 Ch2. 데이터 저장 (Data Storage)</h3>
<p><strong>2.1 샘플 데이터 불러오기</strong>
<code>from sklearn import datasets</code>
→ 사이킷런 라이브러리 이용
→ ex. <code>load_iris</code> <code>load_digits</code></p>
<p>또는 직접 생성:
<code>from sklearn.datasets import make_regression</code> :선형 회귀
<code>from sklearn.datasets import make_classification</code>: 분류
<code>from sklearn.datasets import make_blobs</code>: 군집
→ 알고리즘에 적용할 dataset 직접 생성</p>
<p><strong>2.2 CSV 파일 → DataFrame 형태로</strong></p>
<pre><code class="language-python">import pandas as pd

dataframe = pd.read_csv(url) #csv는 값들이 콤마로 구분됨 → sep 매개변수에 파일이 사용하는 구분자 지정 가능
pd.read_csv(url, skiprows = range(1,11), nrows=5) # 1~10번째 행 건너뛰고, 다음 1개 행 읽기</code></pre>
<p><strong>2.3 Excel 파일 읽기</strong></p>
<pre><code class="language-python">pd.read_excel(url, sheet_name=0, header=0)</code></pre>
<ul>
<li>sheet_name 매개변수로 엑셀의 몇 번째 시트 가져올건지 지정 가능</li>
<li>header 매개변수로 몇 번째 row가 제목인지 지정 가능</li>
</ul>
<blockquote>
<p>🔧 <code>pip install openpyxl</code> 필요</p>
</blockquote>
<p><strong>2.4 JSON 파일 읽기</strong></p>
<pre><code class="language-python">pd.read_json(url, orient=&#39;columns&#39;)
</code></pre>
<ul>
<li>orient 매개변수는 JSON 파일이 어떻게 구성되었는지 지정
  ex) &#39;columns&#39;는 JSON 파일이 {열:{인덱스:값, ...},...} 구조를 가질 것으로 기대</li>
</ul>
<blockquote>
<p>📘 JSON 정규화:
<code>from pandas import json_normalize</code></p>
</blockquote>
<p><strong>2.5 Parquet 파일 읽기</strong></p>
<pre><code class="language-python">pd.read_parquet(url)</code></pre>
<blockquote>
<p>🔧 <code>pip install pyarrow</code> 필요</p>
</blockquote>
<p><strong>2.6 SQL DB 불러오기</strong></p>
<pre><code class="language-python">import pymysql
conn = pymysql.connect(host=&#39;localhost&#39;, user=&#39;root&#39;)</code></pre>
<hr>
<hr>
<h3 id="🧹-ch3-데이터-랭글링-data-wrangling">🧹 Ch3. 데이터 랭글링 (Data Wrangling)</h3>
<p>데이터 정제하고, 사용 가능한 컬럼으로 변환하는 과정!
<strong>3.1 여러 소스에서 DF 생성</strong></p>
<p>다양한 포맷 → DataFrame으로 변환</p>
<p><strong>3.2 데이터 정보 확인</strong>
<code>dataframe.head()</code>
<code>dataframe.shape</code>
<code>dataframe.describe()</code>
<code>dataframe.info()</code></p>
<p><strong>3.3 행/열 선택 from 스라이싱</strong></p>
<ol>
<li>.iloc = 데이터 프레임 위치를 참조[인덱스 기반]
<code>dataframe.iloc[0:3, [1, 2]]</code></li>
<li>.loc = 데이터프레임 인덱스가 레이블(ex. 문자열) 일 때 사용<pre><code class="language-python"># 인덱스를 설정합니다.
dataframe = dataframe.set_index(dataframe[&#39;Name&#39;])
</code></pre>
</li>
</ol>
<h1 id="행을-확인합니다">행을 확인합니다.</h1>
<p>dataframe.loc[&#39;Allison&#39;, [&#39;Age&#39;, &#39;Sex&#39;]]</p>
<pre><code>
**3.4 조건부 선택**
``dataframe[(dataframe[&#39;sex&#39;]==&#39;female&#39;) &amp; (dataframe[&#39;age&#39;]&gt;=65)]``

**3.5 정렬**
``dataframe.sort_values(by=[&#39;Age&#39;], ascending=False)``

**3.6 값 치환**
``dataframe[&#39;sex&#39;].replace([&#39;female&#39;,&#39;male&#39;], [&#39;woman&#39;,&#39;man&#39;])``

**3.7 열 이름 바꾸기**
``dataframe.rename(columns={&#39;pclass&#39;:&#39;passenger_class&#39;,&#39;sex&#39;:&#39;gender&#39;})``

**3.8 통계치 계산**
min, max, sum, mean, count, var, std, kurt(첨도), skew(왜도), mode
- kurt(첨도): 확률 분포의 뾰족한 정도를 나타냄

- Skew (왜도): 
    - 0이면 대칭
    - 음수면 왼쪽 꼬리
    - 양수면 오른쪽 꼬리

**3.9 고유값 확인**
``dataframe[&#39;sex&#39;].unique()``
``dataframe[&#39;sex&#39;].value_counts()``
결측치 포함 시: ``dropna=False`` → 기본값은 true 임

**3.10 결측치 처리**
- 판다스: 자체적으로 NaN 구현 x
⬇️
- Numpy: np.nan으로 NaN 구현
```python
## 누락된 값을 선택하고 두 개의 행을 출력합니다.
dataframe[dataframe[&#39;Age&#39;].isnull()].head(2)
# NaN으로 값을 바꿉니다.
dataframe[&#39;Sex&#39;] = dataframe[&#39;Sex&#39;].replace(&#39;male&#39;, np.nan)</code></pre><p>dataframe.isna()
dataframe.fillna()
<img src="https://velog.velcdn.com/images/y-hyun2/post/93e8426c-fb0b-4680-800c-f983d4d09fe0/image.png" alt=""></p>
<p><strong>3.11 열 삭제</strong>
<code>dataframe.drop([&#39;Age&#39;,&#39;Sex&#39;], axis=1)</code></p>
<p><strong>3.12 행 삭제</strong></p>
<p>조건 필터링 후 drop: <code>dataframe[dataframe[&#39;sex&#39;]==&#39;male&#39;]</code></p>
<p><strong>3.13 중복 행 제거</strong>
<code>dataframe.drop_duplicates(subset=[&#39;sex&#39;], keep=&#39;last&#39;)</code>
→ 기본적으로 모든 열이 완벽히 동일한 행만 삭제
→ subset 매개변수를 사용하면 일부 열만 대상으로 중복 행 삭제
→ keep 매개변수는 남길 행을 의미
<code>dataframe.duplicated()</code>: 메서드는 행이 중복되었는지를 알려주는 불리언 시리즈를 반환</p>
<p><strong>3.14 그룹핑(Grouping)</strong>
<code>groupby</code> 메서드는 통계계산과 같이 각 그룹에 필요로 하는 연산이 필요</p>
<pre><code class="language-python">dataframe.groupby([&#39;sex&#39;,&#39;survived&#39;])[&#39;name&#39;].count()
#1st 열 그룹핑 후 2nd 열 그룹핑 가능
dataframe.groupby([&#39;sex&#39;])[&#39;age&#39;].mean()</code></pre>
<p><strong>3.15 시계열 리샘플링</strong></p>
<pre><code class="language-python">dataframe.resample(&#39;W&#39;).sum()   # 주 단위
dataframe.resample(&#39;M&#39;).count() # 월 단위
dataframe.resample(&#39;2W&#39;).mean() # 2주 단위</code></pre>
<p><strong>3.16 열단위 통계 (Aggregation)</strong></p>
<pre><code class="language-python">dataframe.agg(&#39;min&#39;) #각 열의 최솟값
dataframe.agg({&#39;Age&#39;:[&#39;mean&#39;], &#39;SexCode&#39;:[&#39;min&#39;,&#39;max&#39;]})
#age 열의 평균/ sexcode 열의 minmax 를 뱉어냄</code></pre>
<p>✳️ 그룹별 집계 예시:</p>
<pre><code class="language-python">dataframe.groupby([&#39;Pclass&#39;,&#39;Survived&#39;]).agg({&#39;Survived&#39;:[&#39;count&#39;]})</code></pre>
<p><code>groupby()</code> : 데이터를 그룹으로 묶어 통계 계산
<code>agg()</code> : 집계 함수 지정 (평균, 합계, 최솟값 등)</p>
<hr>
<hr>
<h3 id="📈-ch4-수치형-데이터-다루기-sklearn">📈 Ch4. 수치형 데이터 다루기 (Sklearn)</h3>
<h4 id="41-scaling">4.1 Scaling</h4>
<p>수치형 특성이 두 값의 범위 안에 놓이도록 스케일링</p>
<ul>
<li><p><code>MinMaxScaler</code>: 0–1 범위. NN/거리기반에서 추천.</p>
<ul>
<li><p>언제: <strong>신경망</strong>(NN → 입력이 0~1로 안정되면 학습이 빠르고 안정적)/ <strong>거리</strong>(KNN, SVM, K-means) 기반 모델, 입력 범위를 <code>0–1(또는 -1–1)</code>로 맞추고 싶을 때.</p>
</li>
<li><p>주의: 훈련 세트로만 <code>fit</code>하고, 훈련/검증/테스트는 <code>transform</code>만 해야 데이터 누수 방지.</p>
<pre><code>  (fit 메서드를 사용해 특성의 최솟값과 최댓값을 계산한 다음 transform 메서드로 특성의 스케일을 조정)</code></pre><pre><code class="language-python">    from sklearn.preprocessing import MinMaxScaler
    import numpy as np

    X = np.array([[-500.5], [-100.1], [0], [100.1], [900.9]])
    scaler = MinMaxScaler(feature_range=(0, 1)).fit(X[:3])  # train에만 fit
    X_train = scaler.transform(X[:3])
    X_test  = scaler.transform(X[3:])
</code></pre>
</li>
</ul>
</li>
</ul>
<pre><code>
- ``StandardScaler``: 평균0·표준편차1.(가장 기본)
  - 언제: **선형모델/로지스틱, PCA** 등에서 기본값처럼 먼저 시도.

  - 팁: 이상치가 많으면 평균/표준편차가 흔들린다 → 아래 RobustScaler 고려.
  ```python
    from sklearn.preprocessing import StandardScaler, RobustScaler
    X_std = StandardScaler().fit_transform(X)
    X_rob = RobustScaler().fit_transform(X)  # 중앙값/IQR 기반, 이상치에 강함

- ``Robust/Quantile``: 이상치 많거나 분포 왜곡 시.
  - 언제: 분포가 틀어져 있거나 이상치 영향 최소화하고 싶을 때(0~1 균등 분포에 가깝게).

  | Scaler                  | 기준                       | 특징                                 | 언제 쓰면 좋을까                         |
| ----------------------- | ------------------------ | ---------------------------------- | --------------------------------- |
| **StandardScaler**      | 평균 0, 표준편차 1             | 가장 기본. 데이터가 정규분포(종 모양)에 가까울 때      | 로지스틱 회귀, 선형 회귀, PCA 등 대부분의 선형 모델  |
| **RobustScaler**        | 중앙값(median)과 IQR(사분위 범위) | **이상치(outlier)에 강함**               | 이상치가 섞여 있는 데이터                    |
| **QuantileTransformer** | 분위수(percentile)로 재조정     | 데이터 분포를 **균등하게 펴줌** (0~1 사이로 매끈하게) | 분포가 한쪽으로 치우친(skewed) 경우, 이상치 많을 때 |


#### 4.2 Normalization
- 포인트: 스케일링이 **“열(특성) 단위”** 라면, 정규화는 **“행(샘플) 단위”** 길이(=L2 norm)를 1로 만듦.
즉, “한 데이터 샘플이 벡터로 봤을 때, 그 벡터의 전체 길이를 1로 맞춰주는 것.”

  | 샘플 | 원본 벡터  | 길이         | 정규화 후      |
  | -- | ------ | ---------- | ---------- |
  | A  | [3, 4] | √(3²+4²)=5 | [0.6, 0.8] |
  | B  | [6, 8] | 10         | [0.6, 0.8] |

    결과적으로 A와 B는 같은 방향을 가진 벡터가 됨 
- ``텍스트 분류/코사인 유사도`` 등에서 자주 사용.
  ![](https://velog.velcdn.com/images/y-hyun2/post/44655811-5072-4d38-a628-01fc3ed8af16/image.png)

| 구분                | 핵심 포인트                          |
| ----------------- | ------------------------------- |
| **Scaling**       | 특성(feature) 단위로 크기(단위)를 맞춤      |
| **Normalization** | 샘플(행) 단위로 **벡터의 길이를 1로** 맞춤     |
| **이유**            | 코사인 유사도처럼 **방향 중심 비교** 시 중요     |
| **활용 분야**         | 텍스트 임베딩, 추천 시스템, 문장/이미지 벡터 비교 등 |

```python
from sklearn.preprocessing import Normalizer
import numpy as np

features = np.array([[0.5, 0.5], [1.1, 3.4], [1.5, 20.2]])
l2_norm = Normalizer(norm=&quot;l2&quot;).transform(features)  # 기본
l1_norm = Normalizer(norm=&quot;l1&quot;).transform(features)  # 합=1
max_norm = Normalizer(norm=&quot;max&quot;).transform(features)  # 행 최대값으로 나눔
</code></pre><h4 id="43-polynomial--interaction">4.3 Polynomial &amp; Interaction</h4>
<ul>
<li><p><strong>언제:</strong> 비선형성을 간단히 주입하고 싶을 때 (예: 나이², x1·x2 등).
선형 회귀/로지스틱 회귀 등 선형 모델은 기본적으로 &quot;직선/평면&quot;만 학습
그러나 실제 데이터는 굽은 모양(곡선), 변수 간 상호작용이 흔함 → 다항 &amp; 교차항 추가 </p>
<p><strong>언제 쓰면 좋은가</strong></p>
<blockquote>
<ol>
<li>선형 모델(선형회귀, 로지스틱, 선형 SVM)을 쓰고 싶은데 <strong>관계가 곡선/상호작용</strong>일 때</li>
<li><strong>해석성을 유지</strong>하면서 비선형성을 조금만 추가하고 싶을 때</li>
<li><strong>데이터가 많지 않고</strong> 트리/딥러닝까지는 과하다고 느껴질 때</li>
<li>국소적 곡률을 반영하고 싶지만 스플라인/핸드메이드 변환이 번거로울 때</li>
</ol>
</blockquote>
<p><strong>언제 굳이 안 써도 되나</strong></p>
<blockquote>
<ol>
<li><strong>트리 계열</strong>(의사결정나무, 랜덤포레스트, 그레이디언트부스팅)은 자동으로 비선형/상호작용을 학습</li>
<li>커널 SVM/가우시안프로세스/딥러닝을 쓰는 경우도 <strong>모델 자체가 비선형</strong>이어서 안 써도 됨</li>
<li><strong>고차원 희소데이터(텍스트 BoW 등)</strong>에서 무분별한 교차항은 차원 폭발 위험</li>
</ol>
</blockquote>
</li>
<li><p><strong>주의:</strong> 차수/특성 수가 늘면 <strong>차원의 저주</strong> → </p>
<ol>
<li>특성 수 폭증</li>
<li>과적합 (overfitting) 위험 급증</li>
<li>계산, 메모리 비용 증가 + 해석 어려움<blockquote>
<p>   해결 팁:</p>
</blockquote>
<ul>
<li><strong>규제(Regularization)</strong>: Ridge/Lasso/ElasticNet</li>
<li><strong>부분만 확장</strong>: 중요한 열만 다항화, degree를 낮게, interaction_only 사용</li>
<li><strong>교차검증</strong>으로 적정 복잡도 선택</li>
<li><strong>표준화(Scaling)</strong>로 수치 안정화</li>
</ul>
</li>
</ol>
</li>
</ul>
<pre><code class="language-python">from sklearn.preprocessing import PolynomialFeatures
import numpy as np

X = np.array([[2, 3], [2, 3], [2, 3]])
poly = PolynomialFeatures(degree=2, include_bias=False).fit_transform(X)     # 제곱+교차항
inter = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False).fit_transform(X)  # 교차항만
</code></pre>
<h4 id="44-customcolumntransformer">4.4 Custom/ColumnTransformer</h4>
<ul>
<li><p>열별 서로 다른 변환을 깔끔하게 파이프라인.
🧱 1️⃣ 단순히 새 열 추가하는 방법의 한계</p>
<p>물론 아래처럼 직접 처리</p>
<pre><code class="language-python">df[&quot;f1_plus_10&quot;] = df[&quot;f1&quot;] + 10
df[&quot;f2_plus_100&quot;] = df[&quot;f2&quot;] + 100</code></pre>
<p> 이렇게 했을 때 문제점👇</p>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/ef931641-8796-49b7-a60f-b1a1f69bff9b/image.png" alt=""></p>
</li>
</ul>
<p>   ⚙️ 2️⃣ <code>ColumnTransformer</code>의 역할</p>
<pre><code>ColumnTransformer는 “열마다 다른 전처리기를 묶어서 하나의 통합 변환기” 로 만들어주는 도구</code></pre><p>   여러 개의 전처리 과정을 “하나의 변환기로 합쳐서”
   Pipeline 안에서 fit → transform이 자동으로 돌아가게 해줌</p>
<pre><code class="language-python">        from sklearn.compose import ColumnTransformer
        from sklearn.preprocessing import FunctionTransformer, StandardScaler, OneHotEncoder
        import pandas as pd
        import numpy as np

        df = pd.DataFrame({
            &quot;age&quot;: [20, 30, 40],
            &quot;income&quot;: [2000, 3000, 4000],
            &quot;city&quot;: [&quot;A&quot;, &quot;B&quot;, &quot;A&quot;]
        })

        def add_ten(x): return x + 10
        def log_transform(x): return np.log(x)

        ct = ColumnTransformer([
            (&quot;age_plus_10&quot;, FunctionTransformer(add_ten), [&quot;age&quot;]),
            (&quot;income_log&quot;, FunctionTransformer(log_transform), [&quot;income&quot;]),
            (&quot;city_onehot&quot;, OneHotEncoder(), [&quot;city&quot;])
        ])

        X_transformed = ct.fit_transform(df)</code></pre>
<p>이제 이 변환기를 하나의 객체처럼 모델 파이프라인에 연결하기 👇</p>
<pre><code class="language-python">    from sklearn.linear_model import LinearRegression
    from sklearn.pipeline import Pipeline

    pipe = Pipeline([
        (&quot;preprocess&quot;, ct),
        (&quot;model&quot;, LinearRegression())
    ])
    pipe.fit(df, y)</code></pre>
<p>✅ 장점 요약:</p>
<ul>
<li><p><code>fit() / transform()</code> 체계 내에서 자동 관리</p>
</li>
<li><p>훈련·검증·테스트 데이터에 일관된 변환 적용</p>
</li>
<li><p>열마다 다른 변환 지정 가능</p>
</li>
<li><p>모델 학습 파이프라인에 바로 통합 가능</p>
</li>
<li><p><code>GridSearchCV</code> / <code>cross_val_score</code> 등과 완벽 호환</p>
</li>
</ul>
<h4 id="45-outlier">4.5 Outlier</h4>
<ul>
<li><p>5-1. 감지</p>
</li>
<li><p><em>통계적 타원 가정(EllipticEnvelope)*</em> 또는 <strong>IQR 규칙(1.5×IQR)</strong>로 간단 감지.</p>
<pre><code class="language-python"> from sklearn.covariance import EllipticEnvelope
 detector = EllipticEnvelope(contamination=0.1).fit(features)
 labels = detector.predict(features)  # 1:정상, -1:이상치
</code></pre>
<pre><code class="language-python"> import numpy as np
 x = features[:,0]
 q1, q3 = np.percentile(x, [25, 75])
 iqr = q3 - q1
 out_idx = np.where((x &lt; q1 - 1.5*iqr) | (x &gt; q3 + 1.5*iqr))</code></pre>
</li>
<li><p>5-2. 다루기
전략 3가지: (1) 삭제(최후의 수단), (2) 플래그로 포함(이상치 여부 이진 특성), (3) 변환(로그 등).</p>
<pre><code class="language-python">import numpy as np, pandas as pd
houses = pd.DataFrame({
    &quot;Price&quot;:[534433,392333,293222,4322032],
    &quot;Bathrooms&quot;:[2,3.5,2,116],
    &quot;Square_Feet&quot;:[1500,2500,1500,48000]
})
houses[&quot;Outlier&quot;] = (houses[&quot;Bathrooms&quot;] &gt;= 20).astype(int)  # 이상치 플래그
houses[&quot;Log_Sqft&quot;] = np.log(houses[&quot;Square_Feet&quot;])           # 변환으로 영향 완화
</code></pre>
</li>
</ul>
<pre><code>
#### 4.6 Discretization
- 언제: 연속형을 구간으로 나눠 범주형처럼 다루고 싶을 때(의사결정트리/규칙 기반 해석 편의).

- 간단 2분할은 ``Binarizer``, 다구간은 ``np.digitize`` 또는 ``KBinsDiscretizer``(quantile·uniform).
```python
  import numpy as np
  from sklearn.preprocessing import Binarizer, KBinsDiscretizer

  age = np.array([[6],[12],[20],[36],[65]])
  bin_age = Binarizer(threshold=18).fit_transform(age)  # 0/1
  kb = KBinsDiscretizer(n_bins=4, encode=&quot;onehot-dense&quot;, strategy=&quot;quantile&quot;)
  age_oh = kb.fit_transform(age)                        # 구간 원-핫
  edges = kb.bin_edges_                                  # 경계 확인
</code></pre><h4 id="47-missing">4.7 Missing</h4>
<ul>
<li><p>8-1. 삭제
대부분의 모델은 NaN 미지원 → 삭제는 간단하지만 정보 손실/편향 가능. (MCAR/MAR/MNAR 구분 고려)</p>
</li>
<li><p>8-2. 대체(Imputation)
<code>KNNImputer</code>: 소규모 데이터에서 이웃 기반으로 더 정확한 경우 많음(대신 계산량 큼).
<code>SimpleImputer</code>: 평균/중앙값/최빈값으로 빠르게 채움(대규모에 적합).
팁: 결측치를 채운 사실을 나타내는 <strong>플래그 특성</strong>을 추가하자.</p>
<pre><code class="language-python">from sklearn.impute import KNNImputer, SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_blobs
import numpy as np

X, _ = make_blobs(n_samples=1000, n_features=2, random_state=1)
X = StandardScaler().fit_transform(X)
true_val = X[0,0]; X[0,0] = np.nan

X_knn = KNNImputer(n_neighbors=5).fit_transform(X)     # 정교하지만 느릴 수 있음
X_mean = SimpleImputer(strategy=&quot;mean&quot;).fit_transform(X)  # 빠르고 단순</code></pre>
</li>
</ul>
<hr>
<hr>
<h3 id="📈-ch5-범주형-데이터-다루기-sklearn">📈 Ch5. 범주형 데이터 다루기 (Sklearn)</h3>
<blockquote>
<p>머신러닝 모델은 수치형 데이터만 이해할 수 있기 때문에,
문자열(텍스트)로 된 범주형 데이터를 숫자로 변환(인코딩) 해야 합니다.</p>
</blockquote>
<h4 id="1️⃣-범주형-데이터란">1️⃣ 범주형 데이터란?</h4>
<table>
<thead>
<tr>
<th>구분</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><strong>명목형(Nominal)</strong></td>
<td>순서가 없는 범주</td>
<td>성별, 국가명, 브랜드명</td>
</tr>
<tr>
<td><strong>순서형(Ordinal)</strong></td>
<td>순서가 있는 범주</td>
<td>만족도(낮음-보통-높음), 등급(A-B-C)</td>
</tr>
</tbody></table>
<blockquote>
<p>범주형 데이터를 숫자로 변환할 때는 <strong>순서 유무에 따라 다른 인코딩 방법</strong>을 써야 합니다.</p>
</blockquote>
<hr>
<h4 id="2️⃣-순서가-없는-범주형-데이터-인코딩하기">2️⃣ 순서가 없는 범주형 데이터 인코딩하기</h4>
<p>(1) LabelBinarizer — 단일 클래스 원-핫 인코딩</p>
<pre><code class="language-python">import numpy as np
from sklearn.preprocessing import LabelBinarizer

feature = np.array([[&quot;Texas&quot;], [&quot;California&quot;], [&quot;Texas&quot;], [&quot;Delaware&quot;]])
one_hot = LabelBinarizer()
encoded = one_hot.fit_transform(feature)
print(encoded)
print(one_hot.classes_)  # [&#39;California&#39; &#39;Delaware&#39; &#39;Texas&#39;]</code></pre>
<blockquote>
<ul>
<li>각 클래스가 하나의 이진 열(column) 로 변환</li>
</ul>
</blockquote>
<ul>
<li>클래스 간 순서 개념을 만들지 않음</li>
<li>원-핫 인코딩 결과의 합은 1 (소속된 클래스 하나만 1)</li>
</ul>
<p>(2) MultiLabelBinarizer — 다중 클래스 원-핫 인코딩</p>
<pre><code class="language-python">from sklearn.preprocessing import MultiLabelBinarizer

multi_feature = [(&quot;Texas&quot;, &quot;Florida&quot;), (&quot;California&quot;, &quot;Alabama&quot;), (&quot;Texas&quot;, &quot;Florida&quot;)]
multi_hot = MultiLabelBinarizer()
multi_encoded = multi_hot.fit_transform(multi_feature)
print(multi_hot.classes_)</code></pre>
<blockquote>
<p>한 샘플에 여러 클래스가 있을 때 ([&quot;Comedy&quot;, &quot;Romance&quot;] 등) 사용</p>
</blockquote>
<p>(3) Pandas get_dummies — 간편한 더미 인코딩</p>
<pre><code class="language-python">import pandas as pd
pd.get_dummies([&quot;Texas&quot;, &quot;California&quot;, &quot;Texas&quot;, &quot;Delaware&quot;])</code></pre>
<blockquote>
<p>데이터프레임에 바로 적용 가능
drop_first=True로 다중공선성(선형 의존성) 방지</p>
</blockquote>
<p>(4) OneHotEncoder — 가장 일반적이고 강력한 방식</p>
<pre><code class="language-python">from sklearn.preprocessing import OneHotEncoder
import numpy as np

feature = np.array([[&quot;Texas&quot;, 1], [&quot;California&quot;, 1], [&quot;Texas&quot;, 3]])
encoder = OneHotEncoder(sparse_output=False)
encoded = encoder.fit_transform(feature)
print(encoder.categories_)  # 각 열의 클래스 목록</code></pre>
<blockquote>
<ul>
<li>문자열과 숫자 모두 처리 가능</li>
</ul>
</blockquote>
<ul>
<li>sparse_output=False → 밀집 행렬 반환</li>
<li>여러 열 중 특정 열만 인코딩하려면 → ColumnTransformer로 지정</li>
</ul>
<hr>
<h4 id="3️⃣-순서가-있는-범주형-데이터-인코딩하기">3️⃣ 순서가 있는 범주형 데이터 인코딩하기</h4>
<p>(예: Low &lt; Medium &lt; High)</p>
<p>(1) 단순 매핑 (replace)</p>
<pre><code class="language-python">import pandas as pd

df = pd.DataFrame({&quot;Score&quot;: [&quot;Low&quot;, &quot;Medium&quot;, &quot;High&quot;]})
mapper = {&quot;Low&quot;: 1, &quot;Medium&quot;: 2, &quot;High&quot;: 3}
df[&quot;Score_num&quot;] = df[&quot;Score&quot;].replace(mapper)</code></pre>
<blockquote>
<p>수동 매핑은 간단하지만,
클래스 간 간격이 균등하다고 가정하기 때문에 주의 필요.</p>
</blockquote>
<p>(2) OrdinalEncoder — 순서형 데이터 전용</p>
<pre><code class="language-python">from sklearn.preprocessing import OrdinalEncoder
import numpy as np

features = np.array([[&quot;Low&quot;, 10], [&quot;High&quot;, 50], [&quot;Medium&quot;, 3]])
encoder = OrdinalEncoder()
encoded = encoder.fit_transform(features)
print(encoder.categories_)</code></pre>
<blockquote>
<p>순서를 가진 범주를 자동으로 숫자로 변환
특정 열만 적용하려면 ColumnTransformer로 관리</p>
</blockquote>
<hr>
<h4 id="4️⃣-딕셔너리-형태-인코딩하기">4️⃣ 딕셔너리 형태 인코딩하기</h4>
<p>✅ DictVectorizer</p>
<pre><code class="language-python">from sklearn.feature_extraction import DictVectorizer

data_dict = [{&quot;Red&quot;: 2, &quot;Blue&quot;: 4}, {&quot;Red&quot;: 4, &quot;Blue&quot;: 3}, {&quot;Red&quot;: 1, &quot;Yellow&quot;: 2}]
vec = DictVectorizer(sparse=False)
features = vec.fit_transform(data_dict)
print(vec.get_feature_names_out())  # [&#39;Blue&#39;, &#39;Red&#39;, &#39;Yellow&#39;]</code></pre>
<blockquote>
<p>sparse=False → 밀집 행렬로 출력
자연어 처리에서 단어 빈도(counts) 를 벡터로 바꿀 때 자주 사용</p>
</blockquote>
<hr>
<h4 id="5️⃣-범주형-결측치-대체하기">5️⃣ 범주형 결측치 대체하기</h4>
<p>(1) KNN으로 예측하여 대체</p>
<pre><code class="language-python">import numpy as np
from sklearn.neighbors import KNeighborsClassifier

X = np.array([[0, 2.1, 1.4], [1, 1.1, 1.3], [0, 1.2, 1.2], [1, -0.2, -1.1]])
X_nan = np.array([[np.nan, 0.8, 1.3]])
clf = KNeighborsClassifier(3, weights=&quot;distance&quot;).fit(X[:,1:], X[:,0])
pred = clf.predict(X_nan[:,1:])</code></pre>
<p>(2) 최빈값으로 대체</p>
<pre><code class="language-python">from sklearn.impute import SimpleImputer

imputer = SimpleImputer(strategy=&quot;most_frequent&quot;)
imputer.fit_transform(X)</code></pre>
<blockquote>
<p>KNN은 정확하지만 느리고, SimpleImputer는 빠르지만 단순.</p>
</blockquote>
<hr>
<h4 id="6️⃣-불균형-클래스-다루기">6️⃣ 불균형 클래스 다루기</h4>
<table>
<thead>
<tr>
<th>전략</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>데이터 수집</strong></td>
<td>제일 이상적이지만 현실적으로 어려움</td>
</tr>
<tr>
<td><strong>평가지표 변경</strong></td>
<td>Accuracy 대신 Recall, F1, AUC 등 사용</td>
</tr>
<tr>
<td><strong>가중치 조정</strong></td>
<td><code>class_weight</code> 매개변수 (ex: <code>balanced</code>)</td>
</tr>
<tr>
<td><strong>다운샘플링</strong></td>
<td>다수 클래스 샘플을 줄임</td>
</tr>
<tr>
<td><strong>업샘플링</strong></td>
<td>소수 클래스를 복제하여 늘림</td>
</tr>
</tbody></table>
<pre><code class="language-python">from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(class_weight=&quot;balanced&quot;)</code></pre>
<hr>
<h4 id="7️⃣-핵심-요약">7️⃣ 핵심 요약</h4>
<table>
<thead>
<tr>
<th>주제</th>
<th>핵심 포인트</th>
</tr>
</thead>
<tbody><tr>
<td><strong>명목형 인코딩</strong></td>
<td>순서 없음 → OneHotEncoder / LabelBinarizer</td>
</tr>
<tr>
<td><strong>순서형 인코딩</strong></td>
<td>순서 있음 → OrdinalEncoder / 수동 매핑</td>
</tr>
<tr>
<td><strong>딕셔너리 데이터</strong></td>
<td>DictVectorizer로 빠른 변환</td>
</tr>
<tr>
<td><strong>결측치 처리</strong></td>
<td>KNN 또는 최빈값으로 대체</td>
</tr>
<tr>
<td><strong>불균형 클래스</strong></td>
<td><code>class_weight</code> 조정, 샘플링 전략</td>
</tr>
</tbody></table>
<hr>
<hr>
<blockquote>
<p>☁️ 이번주 정리: 행렬과 배열의 개념부터 수치형/범주형 데이터에 따라 어떤 방식으로 전처리 해야하는지 체계적으로 쭉 정리하는 시간을 가진 것 같아서 좋았다. &quot;데이터 전처리&quot; 라는 카테고리로 봤을 땐 후루룩 넘길 수 있는 내용들이지만, 세부적으로 봤을 땐 내용이 상당히 방대해서 하나씩 살펴보며 정리하기 벅찼고 수업도 빨랐다 😧
이번 주차에 정리한 내용을 바탕으로 다음 프로젝트시 참고하여 더 체계적으로 데이터를 처리할 수 있을 듯하다 ❤︎</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[A survey on Efficient Inference for Large Language Models 리뷰]]></title>
            <link>https://velog.io/@y-hyun2/A-survey-on-Efficient-Inference-for-Large-Language-Models-%EB%A6%AC%EB%B7%B0</link>
            <guid>https://velog.io/@y-hyun2/A-survey-on-Efficient-Inference-for-Large-Language-Models-%EB%A6%AC%EB%B7%B0</guid>
            <pubDate>Mon, 27 Oct 2025 13:12:48 GMT</pubDate>
            <description><![CDATA[<p><strong>A Survey on Efficient Inference for Large Language Models (Zhou et al., 2024) 논문</strong></p>
<h3 id="개요">개요</h3>
<p>이 논문은 대형 언어 모델(LLM: Large Language Models)의 <strong>추론(inference)</strong> 과정을 중심으로, 자원 제약 환경에서 더 효율적으로 작동하게 만드는 다양한 기술들을 정리한 리뷰(survey)</p>
<ol>
<li>왜 LLM 추론이 비효율적인가? 그 원인은 무엇인가? (챕터 2)</li>
<li>효율화를 위한 분류체계(taxonomy) 제시 — 데이터 수준(data-level), 모델 수준(model-level), 시스템 수준(system-level) (챕터 3)</li>
<li>각 수준별로 기존 연구와 기법들 정리 (챕터 4, 5, 6)</li>
<li>응용 시나리오 및 토의 (챕터 7)</li>
<li>결론 및 향후 연구 방향 (챕터 8)</li>
</ol>
<hr>
<h3 id="section-2-배경-및-효율성-병목-요인-background--bottlenecks">Section 2: 배경 및 효율성 병목 요인 (Background &amp; Bottlenecks)</h3>
<ul>
<li>대부분의 LLM은 <strong>Transformer 구조</strong> 기반 → <strong>Self-Attention</strong>과 <strong>Feed-Forward Network</strong>로 구성됨.</li>
<li>이 구조는 강력하지만 입력 길이에 따라 연산량이 폭증. 이 섹션은 LLM이 왜 “비효율적일 수밖에 없는지”를 수학적으로 설명함.</li>
</ul>
<h4 id="21-llm-개념-및-발전">2.1 LLM 개념 및 발전</h4>
<ul>
<li>최근 LLM들이 자연어 이해 (NLU), 생성 (NLG), 추론(reasoning), 코드 생성(code generation) 등 다양한 영역에서 뛰어난 성능을 보여주고 있음.</li>
<li>하지만 이 모델들이 커질수록 연산량, 메모리 접근비용, 저장공간 요구 등이 급격히 증가함.</li>
</ul>
<h4 id="22-효율성-지표">2.2 효율성 지표</h4>
<ul>
<li>“추론 효율”은 보통 <strong>지연(latency)</strong>, <strong>처리량(throughput)</strong>, <strong>전력/에너지 소비</strong>, <strong>메모리 사용량/저장용량</strong> 등으로 측정 가능함</li>
</ul>
<h4 id="23-병목-요인-분석">2.3 병목 요인 분석</h4>
<p>논문에서는 LLM 추론이 비효율이 되는 주된 원인 세 가지를 들고 있음:</p>
<ol>
<li><strong>모델 크기 (Model size)</strong>: 파라미터 수가 많으면 계산량·메모리 접근량이 증가함.</li>
<li><strong>어텐션 연산의 이차(Quadratic) 복잡도</strong>: Transformer 기반 모델에서 입력 길이가 늘면 self-attention 연산 비용이 입력 길이 제곱에 비례해서 증가함. </li>
<li><strong>자동회귀 디코딩(Autoregressive Decoding)</strong>: 한 토큰씩 생성하며 매 스텝마다 이전 상태(예: KV cache)를 참조해야 하므로 메모리 및 연산 오버헤드가 크다는 점. </li>
</ol>
<blockquote>
<p>이 병목들 때문에 단순히 모델을 키우거나 데이터를 많이 쓰는 방식으로는 자원 제한 환경에서 LLM을 효과적으로 운용하기 어렵다는 것.</p>
</blockquote>
<hr>
<h3 id="section-3-분류체계taxonomy">Section 3: 분류체계(Taxonomy)</h3>
<p> “어떤 차원에서 효율화를 논할 수 있는가”라는 틀을 제시</p>
<p>주요 분류 :</p>
<ul>
<li><strong>데이터 수준 (Data-level optimization)</strong>: 입력/출력에 대한 최적화, 프롬프트 입력 길이 감소, 불필요한 토큰 제거 등</li>
<li><strong>모델 수준 (Model-level optimization)</strong>: 모델 구조 변경, 파라미터 감소, 경량화, 압축, 특수 어텐션 기법 등</li>
<li><strong>시스템 수준 (System-level optimization)</strong>: 하드웨어/소프트웨어/프레임워크 수준에서의 최적화, 배치처리(batch processing), 메모리 관리, 병렬화 등</li>
</ul>
<p>이 분류는 이후 각 챕터에서 다루는 기법들을 체계적으로 정리하는 데 사용됨</p>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/bd431119-ba2d-4864-9aab-a98c6e0171e2/image.png" alt=""></p>
<hr>
<h3 id="section-4-데이터-수준-최적화-data-level-optimization">Section 4: 데이터 수준 최적화 (Data-level Optimization)</h3>
<p>입출력 데이터 최적화 전략:</p>
<ul>
<li><strong>입력 압축(Input compression)</strong>: Model에 전달하는 입력 프롬프트(prompt)나 문장 길이를 줄이거나, 불필요한 토큰을 제거해서 계산량을 줄임.<ul>
<li>대표 기법: Prompt Compression, Token Reduction, Prompt Pruning</li>
</ul>
</li>
<li><strong>출력 최적화(Output organization)</strong>: 생성(디코딩) 과정에서 생성되는 출력 토큰의 구조나 생성 방식 자체를 바꿔 효율을 높이는 방법.<ul>
<li>대표 기법: Early Exit(디코딩 중 토큰 별 혹은 레이어 별로 조기 중단하여 연산 절감) , Adaptive Sampling( 디코딩 과정의 토큰 샘플링을 동적으로 조정하여 불필요한 탐색을 줄임)</li>
</ul>
</li>
<li><strong>프리에이치(prefill) 최적화</strong>: LLM이 생성 과정 전에 입력을 처리하는 단계에서 불필요한 연산을 줄이는 기법 등.<ul>
<li>대표 기법: KV-cache 재사용, Prefix reuse, Partial batch prefill 등</li>
</ul>
</li>
</ul>
<p><strong>LLM의 추론 파이프라인 단계</strong> [입력 → 생성 → 초기 연산 ]을 기준으로 효율화를 나눈 것.</p>
<blockquote>
<p>이 챕터의 목적은 <strong>“모델 내부 구조나 하드웨어를 바꾸지 않고도, 데이터와 입력/출력 설계만으로 추론 비용을 낮출 수 있는 방법”</strong>을 설명하는 데 있음</p>
</blockquote>
<hr>
<h3 id="section-5-모델-수준-최적화-model-level-optimization">Section 5: 모델 수준 최적화 (Model-level Optimization)</h3>
<p> 모델 자체 구조나 파라미터, 연산 방식 등을 바꿔 효율화를 꾀하는 방법들을 정리:</p>
<table>
<thead>
<tr>
<th>상위 전략</th>
<th>주요 목표</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>① 경량화 구조 (Lightweight Architectures)</strong></td>
<td>모델 구조 자체를 더 효율적으로 설계</td>
<td>계산량 줄이는 아키텍처 설계 (예: 작은 FFN, 모듈화, 구조적 공유)</td>
</tr>
<tr>
<td><strong>② 어텐션 최적화 (Efficient Attention)</strong></td>
<td>Self-Attention의 이차 복잡도(O(n²)) 줄이기</td>
<td>Sparse/Linear/Low-rank 어텐션으로 연산량 감소</td>
</tr>
<tr>
<td><strong>③ 모델 압축/축소 (Model Compression / Reduction)</strong></td>
<td>기존 모델의 파라미터 수나 정밀도 줄이기</td>
<td>Pruning, Quantization 등</td>
</tr>
<tr>
<td><strong>④ 혼합 전문가 구조 (Mixture of Experts, MoE)</strong></td>
<td>입력별로 일부만 계산</td>
<td>여러 전문가 중 일부만 활성화해 효율성 향상</td>
</tr>
</tbody></table>
<table>
<thead>
<tr>
<th>기법</th>
<th>속하는 전략</th>
<th>이유 / 논문 내 분류 설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Pruning (프루닝)</strong></td>
<td><strong>3. 모델 압축/축소 (Model Compression)</strong></td>
<td>불필요한 파라미터(가중치, 뉴런, 헤드 등)를 제거하여 모델 크기와 연산량 감소.</td>
</tr>
<tr>
<td><strong>Quantization (양자화)</strong></td>
<td><strong>3. 모델 압축/축소 (Model Compression)</strong></td>
<td>32-bit → 16/8/4-bit 등으로 <strong>정밀도 낮춰 메모리 및 연산량 절감</strong>.</td>
</tr>
<tr>
<td><strong>LoRA (Low-Rank Adaptation)</strong></td>
<td><strong>1. 경량화 구조 (Lightweight Architecture)</strong> + <strong>부분적 압축(PEFT)</strong></td>
<td>모델 전체를 학습하지 않고 <strong>저랭크 행렬만 추가 학습</strong> → 구조적 경량화. 논문에서는 “parameter-efficient fine-tuning (PEFT) methods such as LoRA”를 lightweight adaptation 기법으로 분류함.</td>
</tr>
<tr>
<td><strong>Adapter</strong></td>
<td><strong>1. 경량화 구조 (Lightweight Architecture)</strong></td>
<td>LoRA와 유사하게 <strong>모델 내부에 작은 모듈 추가해 효율적으로 학습/추론</strong>. 논문에서 “adapters and prefix-tuning as lightweight extensions for efficient inference”로 포함됨.</td>
</tr>
<tr>
<td><strong>Sparse Attention / Linear Attention</strong></td>
<td><strong>2. 어텐션 최적화 (Efficient Attention)</strong></td>
<td>입력 토큰 전체가 아니라 일부(혹은 근사) 토큰만 어텐션 → O(n²) → O(n log n) 또는 O(n). 예: Linformer, Longformer, Performer.</td>
</tr>
<tr>
<td><strong>MoE (Mixture-of-Experts)</strong></td>
<td><strong>4. 혼합 전문가 구조 (Mixture of Experts)</strong></td>
<td>여러 “전문가(서브모델)” 중 일부만 활성화 → 연산량 줄이면서 성능 유지.  “MoE and sparse activation architectures for efficiency”</td>
</tr>
</tbody></table>
<blockquote>
<p>“모델이 하는 연산량 자체를 줄이거나, 같은 연산량으로 더 많은 일을 하게 만드는 구조적 개선”</p>
</blockquote>
<hr>
<h3 id="section-6-시스템-수준-최적화-system-level-optimization">Section 6: 시스템 수준 최적화 (System-level Optimization)</h3>
<p>여기서는 하드웨어/소프트웨어/시스템 설계 측면에서 LLM 추론을 더 효율적으로 만드는 접근:</p>
<ul>
<li><p><strong>배치처리(Batching) 및 병렬처리(Parallelism)</strong>: 여러 요청을 묶어서 처리하거나 여러 연산을 동시다발적으로 처리해 처리량(throughput)을 향상하고 자원 활용을 극대화함.</p>
<ul>
<li>Batching/Prefill 병렬화: 여러 입력 요청을 묶어 GPU에 올리거나, Prefill 단계(입력 처리)를 병렬 수행하여 GPU 활용도 및 처리량 향상</li>
</ul>
</li>
<li><p><strong>메모리 관리 및 캐시(KV-cache, 메모리 단편화 등)</strong>: 디코딩 과정에서 사용하는 키/값 캐시, 메모리 단편화 문제를 해결하여 디코딩 속도를 향상시키고, 중복 연산을 방지함</p>
<ul>
<li><p>KV Cache 재사용: 디코딩 중 반복되는 <strong>Key/Value 연산 결과를 캐싱</strong>하여 재활용</p>
<p>  ⇒ 중복 계산 제거, 디코딩 속도 향상.</p>
</li>
</ul>
</li>
<li><p><strong>하드웨어 가속(Hardware accelerators)</strong>: GPU, TPU, 특수 NPU에서 최적화된 커널(kernel) 사용 및 메모리 접근패턴 개선하여 하드웨어 수준에서 연산 효율을 개선함.</p>
<ul>
<li>Offloading/Paging: GPU 메모리에 다 안 들어가는 모델/캐시를 CPU 또는 디스크로 분산(offload) 시켜 관리하여 대형 모델을 효율적으로 실행 가능하게 함.</li>
</ul>
</li>
<li><p><strong>서비스 시스템 설계(Serving system design)</strong>: 엔터프라이즈 환경이나 클라우드/엣지 배포에서 요청 스케줄링, 리소스 예측, 지연시간/처리량 균형 맞추기 → 실제 LLM 서비스의 안정성 및 효율성 확보</p>
<ul>
<li>Serving Optimization: 다수의 사용자 요청을 효율적으로 스케줄링,큐잉,우선순위를 처리하여 latency와 throughput 간 트레이드오프 조절.</li>
</ul>
</li>
</ul>
<blockquote>
<p>“좋은 모델 설계만큼이나, 그것을 실제로 돌리는 시스템 환경이 중요하다”</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[week 6: AIoT 데이터 시각화 대시보드 개발 프로젝트 후기]]></title>
            <link>https://velog.io/@y-hyun2/week-6-AIoT-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%8B%9C%EA%B0%81%ED%99%94-%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C-%EA%B0%9C%EB%B0%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@y-hyun2/week-6-AIoT-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%8B%9C%EA%B0%81%ED%99%94-%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C-%EA%B0%9C%EB%B0%9C-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Mon, 27 Oct 2025 13:06:50 GMT</pubDate>
            <description><![CDATA[<h2 id="부동산-인사이트-대시보드-제작기real-estate-insight-dashboard">부동산 인사이트 대시보드 제작기(Real Estate Insight Dashboard)</h2>
<blockquote>
<p>부동산 시장 인사이트를 시각화하는 Streamlit 대시보드 프로젝트 회고록</p>
</blockquote>
<blockquote>
<p>해당 프로젝트는 국토교통부 실거래가 데이터를 중심으로, 매매·전월세 시장의 흐름, 리스크, 투자 가치, 페르소나별 분석을 대시보드를 통해 제공한다.</p>
</blockquote>
<h2 id="❤︎-들어가며">❤︎ 들어가며</h2>
<p>약 5일간 만들었던 대시보드 제작 프로젝트.
우선, 이번 6개월간 3개의 프로젝트를 진행하면서 HDC 랩스에서 제공해준 데이터를 사용할 수 있다는 것이 가장 큰 메리트였던 부트캠프였다. 5개의 주제 중 지원할 때부터 해보고 싶던 부동산 데이터를 이용하는 주제를 선택했다.
<strong>그!런!데!!!</strong>
아쉽게도 이번 1차 프로젝트에선 적절한 데이터를 준비하지 못했다는 소식을 들어 ..
손수 발품을 팔아가며 사용할 만한 데이터 찾기에 나섰다.
<strong>그!런!데!!!</strong>
때마침 데이터센터 화재로 인해 국가 통계 포털에 접근할 수 조차 없게 되었던 상황.
<img src="https://velog.velcdn.com/images/y-hyun2/post/ac47e593-f7bc-4507-9a95-304b1d5f67bb/image.png" alt=""></p>
<p>유동인구 분석, 교통량 분석 등등 부동산 데이터와 관련된 주변 도메인도 분석하여 나타내고 싶은 건 많았는데, 데이터 접근부터 문제가 생겨 ..
우선은 국토교통부 <strong>부동산 실거래가 데이터</strong>만을 이용해서 뽑아낼 수 있는 다양한 인사이트를 뽑아내기로 결정했다.</p>
<hr>
<h2 id="☁️-개발-이야기">☁️ 개발 이야기</h2>
<p>부동산 데이터를 이용하여 대시보드를 만들고 싶었던 5명이 랜덤으로 모였다.</p>
<p>기획 단계에서는 정말 많은 아이디어가 나왔다. 
<del>아이디어 회의만 5일 중 이틀을 쏟았다.</del>
하지만 그만큼 대시보드 개발에 아이디어가 절반 이상 중요하다고 생각했기 때문에 아깝지 않았다.</p>
<p>&#39;들어가며&#39;에서도 말했지만, 결국 데이터 센터 화재로 적절한 데이터를 구하는 게 어려워서 3년치 <strong>부동산 실거래가 데이터만 이용하여 유의미한 인사이트를 도출</strong>하는 걸로 결론이 났다.</p>
<p>이 프로젝트에서 특이했던 점은 우린 협업이 아니라 <strong>competition</strong>을 했다는 것 ^^</p>
<ul>
<li>모여서 아이디어 회의 끝에 대시보드 제작의 갈피가 잡혔지만</li>
<li>모델 사용조차 필요없는 너무 소규모 미니 프록젝트이며</li>
<li>이 미니 프로젝트에서 어떻게 파트분배를 나눌 것에 대한 갈피는 잡히지 않았다.</li>
</ul>
<p>아이디어 회의가 끝난 지금, 데이터 전처리를 파트 분배하는 것보다
모두가 한 번씩 데이터 전처리를 통한 대시보드 제작 과정을 경험할 필요가 있지 않는냐! 하는 의견이 있었다.
따라서 각자의 방식대로 데이터 전처리 후 각자의 것을 비교해보고 가장 나은 방식을 채택하여 대시보드를 만들기로 했다.</p>
<hr>
<h2 id="📊-데이터-전처리">📊 데이터 전처리</h2>
<p>데이터 구분:</p>
<ul>
<li>매매/전월세</li>
<li>아파트/ 연립다세대 / 단독다가구 / 오피스텔 /상업업무용</li>
</ul>
<p>매매와 전월세 데이터셋은 공통된 컬럼이 많이 없음.
➡ 매매 / 전월세로 나누어 하위 5개 유형(단독/연립/오피스텔/아파트)에 대해 <strong>형태·순서·이름 통일 완료</strong></p>
<h4 id="🏠-①-전월세-데이터셋-컬럼-구조">🏠 <strong>① 전월세 데이터셋 컬럼 구조</strong></h4>
<table>
<thead>
<tr>
<th>순서</th>
<th>통일된 컬럼명</th>
<th>설명</th>
<th>비고</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>시군구</td>
<td>행정구 단위 지역명</td>
<td>예: 서울특별시 강남구</td>
</tr>
<tr>
<td>2</td>
<td>번지</td>
<td>지번 주소</td>
<td>일부는 본번·부번 삭제 후 통합</td>
</tr>
<tr>
<td>3</td>
<td>계약년월</td>
<td>계약 체결 연월 (YYYYMM)</td>
<td>시계열 분석용</td>
</tr>
<tr>
<td>4</td>
<td>계약일</td>
<td>계약 체결 일자 (DD)</td>
<td>1~31</td>
</tr>
<tr>
<td>5</td>
<td>건축년도</td>
<td>건축 완료 연도</td>
<td></td>
</tr>
<tr>
<td>6</td>
<td>보증금(만원)</td>
<td>보증금 금액</td>
<td>정수형</td>
</tr>
<tr>
<td>7</td>
<td>월세금(만원)</td>
<td>월세 금액</td>
<td>정수형 (전세는 0 or NaN)</td>
</tr>
<tr>
<td>8</td>
<td>계약기간</td>
<td>계약 시작~종료 기간</td>
<td>예: 20230101~20240101</td>
</tr>
<tr>
<td>9</td>
<td>계약구분</td>
<td>신규 / 갱신 여부</td>
<td>신규, 갱신</td>
</tr>
<tr>
<td>10</td>
<td>전월세구분</td>
<td>전세 / 월세 / 반전세</td>
<td>주요 카테고리</td>
</tr>
<tr>
<td>11</td>
<td>전용면적(㎡)</td>
<td>실내 전용면적</td>
<td>단독의 계약면적 포함</td>
</tr>
<tr>
<td>12</td>
<td>건물명</td>
<td>건물 또는 단지 이름</td>
<td>단지명/건물명 통합</td>
</tr>
<tr>
<td>13</td>
<td>유형</td>
<td>주택 유형</td>
<td>단독, 연립, 오피스텔, 아파트 등</td>
</tr>
<tr>
<td>14</td>
<td>층</td>
<td>해당 거래의 층수</td>
<td>단독은 NaN</td>
</tr>
</tbody></table>
<blockquote>
<p>✅ 총 14개 컬럼</p>
</blockquote>
<hr>
<h4 id="🏢-②-매매-데이터셋-컬럼-구조">🏢 <strong>② 매매 데이터셋 컬럼 구조</strong></h4>
<table>
<thead>
<tr>
<th>순서</th>
<th>통일된 컬럼명</th>
<th>설명</th>
<th>비고</th>
</tr>
</thead>
<tbody><tr>
<td>1</td>
<td>시군구</td>
<td>지역명</td>
<td></td>
</tr>
<tr>
<td>2</td>
<td>지번</td>
<td>번지/지번 통합</td>
<td></td>
</tr>
<tr>
<td>3</td>
<td>계약년월</td>
<td>거래 연월 (YYYYMM)</td>
<td></td>
</tr>
<tr>
<td>4</td>
<td>계약일</td>
<td>거래 일자 (DD)</td>
<td></td>
</tr>
<tr>
<td>5</td>
<td>거래금액(만원)</td>
<td>실제 거래금액</td>
<td>정수형</td>
</tr>
<tr>
<td>6</td>
<td>건축년도</td>
<td>건축 연도</td>
<td></td>
</tr>
<tr>
<td>7</td>
<td>전용면적(㎡)</td>
<td>연면적/전용면적/전용·연면적 통합</td>
<td></td>
</tr>
<tr>
<td>8</td>
<td>대지면적(㎡)</td>
<td>대지권면적 포함</td>
<td></td>
</tr>
<tr>
<td>9</td>
<td>층</td>
<td>거래 층수</td>
<td>단독은 NaN</td>
</tr>
<tr>
<td>10</td>
<td>건물명</td>
<td>건물명/단지명 통합</td>
<td></td>
</tr>
<tr>
<td>11</td>
<td>유형</td>
<td>주택유형 통합</td>
<td>단독, 아파트, 오피스텔 등</td>
</tr>
<tr>
<td>12</td>
<td>용도지역</td>
<td>상업업무용 전용</td>
<td>선택적</td>
</tr>
<tr>
<td>13</td>
<td>건축물주용도</td>
<td>상업업무용 전용</td>
<td>선택적</td>
</tr>
<tr>
<td>14</td>
<td>매수</td>
<td>상업업무용 전용</td>
<td>선택적</td>
</tr>
<tr>
<td>15</td>
<td>매도</td>
<td>상업업무용 전용</td>
<td>선택적</td>
</tr>
<tr>
<td>16</td>
<td>해제사유발생일</td>
<td>계약 해제일</td>
<td>오피스텔/아파트만 존재</td>
</tr>
</tbody></table>
<blockquote>
<p>✅ 총 16개 컬럼</p>
</blockquote>
<hr>
<h3 id="1️⃣-결측치-확인-및-처리">1️⃣ 결측치 확인 및 처리</h3>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/3634f221-0cbd-4646-9d58-870ae517e250/image.png" alt=""></p>
<p>결측비율 계산</p>
<pre><code class="language-python"># 컬럼별 결측 비율을 계산하고 0보다 큰 항목만 확인합니다.
missing = sampled_df.isna().mean().sort_values(ascending=False)
missing = missing[missing &gt; 0]
missing
</code></pre>
<p>층       0.250000
건물명     0.250000
건축년도    0.018388
번지      0.000612
dtype: float64</p>
<table>
<thead>
<tr>
<th>컬럼</th>
<th>결측 비율</th>
<th>해석</th>
</tr>
</thead>
<tbody><tr>
<td>층</td>
<td>25.0%</td>
<td>단독·다가구는 층 정보 미입력 빈번</td>
</tr>
<tr>
<td>건물명</td>
<td>25.0%</td>
<td>단독/다가구/상가 건물명 대부분 Null</td>
</tr>
<tr>
<td>건축년도</td>
<td>1.8%</td>
<td>일부 미등기·신규건물</td>
</tr>
<tr>
<td>번지</td>
<td>0.06%</td>
<td>도로명주소 기반 거래 일부만 누락</td>
</tr>
</tbody></table>
<p>-&gt; 결측치 이유 해석하여 결측치 제거 안 하는 것으로 함.</p>
<blockquote>
<p><code>결측치</code></p>
<ul>
<li>문자열 → <code>&quot;미상&quot;</code>으로 대체</li>
<li>수치형 → <code>NaN</code> 유지</li>
</ul>
</blockquote>
<hr>
<h3 id="2️⃣-이상치-탐지-및-처리">2️⃣ 이상치 탐지 및 처리</h3>
<h4 id="✔︎-이상치-처리">✔︎ 이상치 처리</h4>
<ol>
<li>“어디가 이상한지” 숫자로 확인<ul>
<li><code>numeric_summary</code>, <code>type_numeric_summary</code>는 <strong>컬럼별 기초통계(최대값/사분위수 등)</strong>를 보여줌</li>
</ul>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/39044485-0810-4462-b18d-16a89d3c119b/image.png" alt=""></p>
<ul>
<li><p>여기에 추가로 아래처럼 <strong>유형별 상위 분위수(99%, 99.5%)</strong>를 보며 “꼬리”가 어디까지인지 감 잡기</p>
<pre><code class="language-python">sampled_df.groupby(&quot;property_type&quot;)[[&quot;보증금(만원)&quot;, &quot;월세금(만원)&quot;, &quot;전용면적(㎡)&quot;]].quantile([0.99, 0.995])</code></pre>
<blockquote>
<p>목적: <strong>현실적으로 말이 되는 상한선</strong>을 유형별로 가늠하기.</p>
</blockquote>
<table>
<thead>
<tr>
<th>유형</th>
<th>보증금(만원) 99.5%</th>
<th>월세(만원) 99.5%</th>
</tr>
</thead>
<tbody><tr>
<td>단독다가구</td>
<td>30,000</td>
<td>132</td>
</tr>
<tr>
<td>아파트</td>
<td>135,000</td>
<td>290</td>
</tr>
<tr>
<td>연립다세대</td>
<td>95,000</td>
<td>120</td>
</tr>
<tr>
<td>오피스텔</td>
<td>55,000</td>
<td>165</td>
</tr>
</tbody></table>
</li>
</ul>
<p>이 값들은 <strong>실제 거래 데이터 기준 상위 0.5% 분위수</strong> → 즉 그 이상 값은 거의 안 나오는 “꼬리 값”</p>
<p><strong>이상치(극단값) 필터링 원칙</strong></p>
<ol>
<li>“행정상 불가능”은 바로 제외/NA
ex. 보증금, 월세가 음수 or 전용면적 &lt;0 or 층이 음수 등 → 무조건 제거<ol start="2">
<li>“너무 큰 값”은 통계+ 도메인 상한으로 처리</li>
</ol>
</li>
</ol>
<ul>
<li>통계적 기준(IQR):<ul>
<li><code>upper = Q3 + 1.5*IQR</code> 로 상한선을 잡고 초과치를 <strong>잘라내거나(clip) 제외(drop)</strong><ul>
<li>도메인 기준(상식 상한):
예) <code>보증금 &gt; 20억(=200,000만원)</code> 이면 제외/clip, <code>월세 &gt; 1,000만원(=1,000만원)</code>도 동일</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="3️⃣-타입-변환-문자열범주형-정리--스케일링">3️⃣ 타입 변환, 문자열/범주형 정리 , 스케일링</h3>
<aside>

<h4 id="🔢-1-수치형-컬럼-변환">🔢 1. 수치형 컬럼 변환</h4>
<ul>
<li><strong>명시적으로 숫자형 컬럼을 지정</strong>해서 변환하는 구조 → 지정한 컬럼만 숫자로 변환</li>
<li><code>_safe_numeric()</code>
  → 쉼표(<code>,</code>) 제거 후 <code>pd.to_numeric()</code> 변환
  → 변환 실패 시 <code>NaN</code> 처리 (자동 결측)
  <img src="https://velog.velcdn.com/images/y-hyun2/post/a387aeb2-a089-4c43-809e-c090e7aaad9f/image.png" alt=""></li>
</ul>
<ul>
<li>적용 대상:<ul>
<li>보증금(만원), 월세금(만원), 거래금액(만원)</li>
<li>전용면적(㎡), 대지면적(㎡), 건축년도 등
<img src="https://velog.velcdn.com/images/y-hyun2/post/d29f9efd-fce2-4cfd-8145-ac2d6036fcfc/image.png" alt=""></li>
</ul>
</li>
</ul>
<h4 id="📅-2-날짜-파싱-및-파생-컬럼">📅 2. 날짜 파싱 및 파생 컬럼</h4>
<ul>
<li><code>_parse_year_month()</code>
  → <code>&quot;YYYYMM&quot;</code> 형식을 <code>Timestamp</code>로 변환
  → <code>계약연도</code>, <code>계약월</code> 컬럼으로 나눔
  <img src="https://velog.velcdn.com/images/y-hyun2/post/0d92ed0c-16d4-48c8-aee6-7cc68337a080/image.png" alt=""></li>
</ul>
<ul>
<li>결과:<ul>
<li>시계열 분석 및 월별 집계에 활용 (<code>summarise_*_monthly()</code>)</li>
</ul>
</li>
</ul>
<h4 id="📍-3-지역-문자열-정제">📍 3. 지역 문자열 정제</h4>
<ul>
<li><code>_parse_region()</code>
  → 주소 문자열을 <code>&quot;광역시도&quot;</code>, <code>&quot;시군구&quot;</code>, <code>&quot;세부지역&quot;</code>으로 분리
  → 규칙 기반으로 ‘동/읍/면/구’를 추출
  → 비어 있는 경우 <code>&quot;미상&quot;</code>으로 채움
  <img src="https://velog.velcdn.com/images/y-hyun2/post/4ddf3466-c600-4f51-b7b3-8d199776e4fd/image.png" alt=""></li>
</ul>
<pre><code>- 특별시: 서울특별시
- 광역시: 인천광역시, 대전광역시,대구광역시,울산광역시,부산광역시,광주광역시
- 특별자치시: 세종특별자치시
- 도: 경기도,충청북도, 충청남도, 전라남도, 경상북도, 경상남도
- 특별자치도: 강원특별자치도, 전북특별자치도, 제주특별자치도
   **서울특별시는 `‘동’` 기준으로 지역 선별, 나머지 지역은 `기초지방자치단체` 기준으로 지역 선별**

    - because) 서울시는 같은 영등포구라도 여의도동 vs 양평동 시세차이가 많이 남

 - 예시:
```
서울특별시 강남구 역삼동 → 광역시도=서울특별시, 시군구=강남구, 세부지역=역삼동
```</code></pre><ul>
<li>지역 문자열 정제 목적: 부동산 지역별 집계를 위함</li>
</ul>
<h4 id="📍-4-로그-스케일링">📍 4. 로그 스케일링</h4>
<ul>
<li><p><code>np.log1p()</code> 변환으로 왜곡 완화</p>
</li>
<li><p><code>보증금_log</code>, <code>월세_log</code>, <code>거래금액_log</code> 등 추가 (파생 컬럼으로 생성함)</p>
</li>
<li><p>목적: 대시보드에서 시각화 안정성 향상</p>
<ul>
<li><p>why?</p>
<p>부동산 데이터의 핵심 문제는 <strong>극단적 비대칭(Positive Skew)</strong> 
즉, <strong>큰 값은 줄이고, 작은 값은 상대적으로 유지</strong> → 분포가 안정됨.</p>
</aside>

</li>
</ul>
</li>
</ul>
<hr>
<h3 id="4️⃣-파생-컬럼-생성">4️⃣ 파생 컬럼 생성</h3>
<p>→ 원본 csv는 수정하지 않고, 전처리 결과 DataFrame을 파켓 파일로 저장</p>
<p><strong>평당가 컬럼 추가</strong></p>
<ul>
<li><code>평당가(만원)</code> = 거래금액 ÷ (전용면적 × 0.3025)</li>
<li>면적이 0 또는 결측이면 NaN 처리
  <img src="https://velog.velcdn.com/images/y-hyun2/post/7b4b2787-2ecd-4e90-98c9-e3b14ab604fb/image.png" alt=""></li>
</ul>
<ul>
<li>목적: 계산의 효율적 접근</li>
</ul>
<p><strong>로그 스케일링 컬럼 추가</strong></p>
<ul>
<li><code>보증금_log</code>, <code>월세_log</code>, <code>거래금액_log</code> 등 추가</li>
</ul>
<hr>
<h2 id="📈-대용량-데이터-처리-전략">📈 대용량 데이터 처리 전략</h2>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/05d6aaea-10ca-4d27-b043-95ae0facdf00/image.png" alt=""></p>
<h3 id="📂-1-파일-구조-및-로딩">📂 1. 파일 구조 및 로딩</h3>
<ul>
<li><strong>모듈 구조</strong><ul>
<li><code>modules/rent_processing.py</code> — 전월세 데이터 전처리</li>
<li><code>modules/transaction_processing.py</code> — 매매 데이터 전처리</li>
<li><code>build_dashboard_data.py</code> — 전처리 결과 통합 및 저장 (Parquet 변환)</li>
</ul>
</li>
<li><strong>입력 데이터</strong><ul>
<li><code>rent_dataset/</code>, <code>transaction_dataset/</code> 폴더 내 CSV 파일 (자산유형별)</li>
<li>한 파일당 수십~수백만 행, <strong>20만 행 단위 청크(chunksize)</strong> 로 나누어 읽기</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>청크 단위 처리 이유</strong></p>
<ul>
<li>메모리 효율성 확보 (전체 데이터 5GB 이상)</li>
<li>부분 전처리 후 병합 가능</li>
<li>반복 실행 시 캐시나 중간결과 재활용 용이</li>
</ul>
</blockquote>
<blockquote>
<p><strong>Parquet 포맷 사용 이유</strong></p>
<ul>
<li>용량 효율적 (CSV 대비 70% 이상 압축)</li>
<li>Streamlit 대시보드 로딩 속도 개선</li>
<li>pandas로 빠르게 재로딩 가능</li>
</ul>
</blockquote>
<h3 id="🧩-2-층화-샘플링-stratified-sampling">🧩 2. 층화 샘플링 (Stratified Sampling)</h3>
<p>전체 유형별 2만행 sampling (총 20만행으로 샘플링) → <strong>층화 sampling</strong> </p>
<ul>
<li><p>1차 층: <code>property_type</code> (아파트, 오피스텔, 연립, 단독 등)</p>
</li>
<li><p>2차 층: <strong>세부지역(<code>STRATA_COLUMN</code>)</strong> (서울 강남구 서초동, 부산 해운대구 등)</p>
<p>☞ 지역별 거래 비중을 유지하면서 일정 행 수(<code>target_rows</code>) 확보</p>
</li>
<li><p><code>stratified_sample()</code> 함수가 비율 계산 후</p>
<p>  → 그룹별 샘플링 수행, 부족한 그룹은 전량 사용</p>
</li>
</ul>
<p>목적: 전국 대표성을 유지한 샘플 확보를 위함</p>
<h3 id="📊-3-월별-요약-monthly-summary">📊 3. 월별 요약 (Monthly Summary)</h3>
<p>월별로 산출할 항목들을 저장해 놓는 별도의 parquet 파일을 만들어 streamlit을 시행할 때마다 불필요한 연산을 반복하지 않도록 함.</p>
<ul>
<li><p><code>summarise_rent_monthly()</code> / <code>summarise_sale_monthly()</code>
  → 계약년월, 자산군, 지역별로 집계 </p>
</li>
<li><p>산출 항목:</p>
<ul>
<li><strong>계약건수</strong></li>
<li><strong>평균 / 중위 거래금액</strong></li>
<li><strong>평균 / 중위 평당가</strong></li>
</ul>
</li>
<li><p>목적: 시계열 기반 Streamlit 그래프 및 KPI 카드에 활용</p>
</li>
</ul>
<h3 id="💾-4-최종-저장-build_dashboard_datapy-3159">💾 4. 최종 저장 (build_dashboard_data.py: 31–59)</h3>
<ul>
<li>전처리된 결과를 다음 두 포맷으로 저장:<ul>
<li><code>rent_sample.parquet</code>, <code>sale_sample.parquet</code> (샘플)</li>
<li><code>rent_monthly_summary.parquet</code>, <code>sale_monthly_summary.parquet</code> (월별요약)</li>
</ul>
</li>
</ul>
<hr>
<h2 id="❤︎-후기">❤︎ 후기</h2>
<blockquote>
<p><strong>좋았던 점</strong>: 
우선, 약 680만 행의 대용량 데이터를 다루뤄보면서 대용량 데이터를 다루는 데 거부감이 사라졌다는 점이 가장 좋았다. parquet 파일도 처음 이용하고, sampling도 활용하여 대용량 데이터를 큰 로딩시간 없이 streamlit으로 시각화할 수 있었다. 다음에 대용량 데이터를 처리할 때 큰 어려움을 겪지 않을 것 같다. 만족한다!
또, streamlit을 이용하여 단순 시각화 뿐만 아니라 유의미한 insight를 나타내는 대시보드를 만들어 봤다는 점에서 유익한 경험이었다.</p>
</blockquote>
<blockquote>
<p><strong>아쉬웠던 점</strong>: 
짧은 시간 내에 좋은 결과를 내려는 욕심이 있었다면 서로의 결과물 중 최적의 결과물로 제출하는 방식이 아닌 전처리,대시보드 제작까지 분업 및 협업하여 진행하면 더 좋은 결과물을 도출할 수 있지 않았을까 하는 아쉬움이 남는다. 최종적으로 내가 만든 전처리 과정 및 대시보드가 채택되어 나의 결과물을 제출할 수 있어서 기뻤지만, 분업을 했다면 더 섬세하고 만족할 만한 결과물을 낼 수 있었을 걸 하는 아쉬움이 남는다.
분업으로 진행하다보니, 야심차게 만들어 놓은 Github organization도 활용하지 못한 것이 아쉽다.</p>
</blockquote>
<blockquote>
<p><strong>느낀점</strong>:
아이디어 도출부터 데이터 처리, 대시보드 제작, 발표까지 모든 과정에 크게 기여할 수 있었다는 점에서 애정이 높은 프로젝트이다. 5일 안에 압축적으로 많은 것을 경험할 수 있어서 좋았다. 계속되는 수업 속에서 잠깐의 프로젝트 과정이 한 줄기의 빛이었다 ㅎㅎ,, 이번 프로젝트에서 아쉬웠던 점을 보완해서 2,3차 땐 피드백을 바탕으로 더 만족할 만한 결과물이 나왔으면 한다!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[week5: streamlit을 이용한 대시보드 제작]]></title>
            <link>https://velog.io/@y-hyun2/week5-streamlit%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C-%EC%A0%9C%EC%9E%91</link>
            <guid>https://velog.io/@y-hyun2/week5-streamlit%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%8C%80%EC%8B%9C%EB%B3%B4%EB%93%9C-%EC%A0%9C%EC%9E%91</guid>
            <pubDate>Wed, 01 Oct 2025 01:13:19 GMT</pubDate>
            <description><![CDATA[<p><strong>1) Streamlit 한 줄 요약과 시작하기</strong></p>
<ul>
<li><p>웹 지식 없이 데이터 앱/대시보드를 손쉽게 만들 수 있음 .</p>
</li>
<li><p><code>pip install streamlit</code> → <code>streamlit run app.py</code>로 바로 실행 .</p>
</li>
<li><p><code>.py</code> 파일만 있으면 로컬에서 곧바로 웹 UI 확인 가능.</p>
</li>
</ul>
<p><strong>2) 텍스트·표 컴포넌트 핵심</strong></p>
<ul>
<li><p>제목/헤더/서브헤더/코드블록/마크다운/텍스트로 정보 구조화.</p>
</li>
<li><p><code>st.divider()</code> 섹션 구분선 만들기 → 주제별 그룹화에 유용 .
<img src="https://velog.velcdn.com/images/y-hyun2/post/8317f42b-0671-415f-8867-5669c917c5a7/image.png" alt="">
<img src="https://velog.velcdn.com/images/y-hyun2/post/e9bed812-1705-4959-8bfa-baf09b5adbfd/image.png" alt=""></p>
</li>
</ul>
<p><strong>3) 가장 많이 쓰는 입력 위젯</strong></p>
<ul>
<li><p><code>Button</code>: 클릭 시 True 반환 → 조건문과 함께 동작 제어.</p>
<pre><code class="language-python">  def button_write():
      st.write(&#39;button activated&#39;)

  st.button(&#39;Reset&#39;, type=&#39;primary&#39;)
  st.button(&#39;activate&#39;, on_click=button_write)</code></pre>
</li>
</ul>
<ul>
<li><p><code>Checkbox/Toggle</code>: 체크/스위치 형태. on_change 콜백 지원, 상태 변화마다 실행.</p>
</li>
<li><p><code>Selectbox/Radio/Multiselect</code>: 단일/복수 선택. label, options, index=None로 비선택 초기화 가능.</p>
</li>
<li><p><code>Slider</code>: 단일 값 또는 (시작, 종료) 튜플로 범위 선택.</p>
</li>
<li><p><code>Input</code> 계열: <code>text_input(placeholder, max_chars, password)</code>, <code>number_input</code>, <code>date_input</code>, <code>ime_input</code>, <code>camera_input</code>.</p>
</li>
<li><p><code>File uploader</code>: 파일 타입 제한, 다중 업로드, on_change 콜백 지원.</p>
</li>
</ul>
<p><strong>4) 차트·이미지 붙이기</strong></p>
<ul>
<li>Matplotlib → <code>st.pyplot(fig)</code> / Plotly → <code>st.plotly_chart(fig)</code>로 렌더링.<pre><code class="language-python">import streamlit as st
import matplotlib.pyplot as plt
import seaborn as sns
</code></pre>
</li>
</ul>
<p>df = sns.load_dataset(&#39;tips&#39;)
fig, ax = plt.subplots()
sns.histplot(df, x=&#39;total_bill&#39;, ax=ax, hue=&#39;time&#39;)</p>
<p>st.pyplot(fig)</p>
<pre><code>
- Selectbox로 x/y/hue(또는 color)를 고르는 인터랙티브 박스플롯/스캐터 구성 가능.

- `st.image()`는 PIL/numpy 이미지, `width/caption` 옵션 지원.


**5) 레이아웃 제대로 쓰기**

- Sidebar: with st.sidebar: 블록에 필터·설명 배치 (p.24).

- Columns: col1, col2 = st.columns(2)로 가로 배치 (p.25).

- Tabs: 여러 뷰를 탭으로 전환 (p.26).

- Expander: 상세/부가 정보를 접어서 깔끔하게 유지 (p.27).

```python
 # --- Tabs ---
    tab_h1, tab_h2, tab_h3 = st.tabs([&quot;히트맵(AMT)&quot;, &quot;TOP 페어(AMT)&quot;, &quot;TOP 페어(AOV)&quot;])

    with tab_h1:
        st.plotly_chart(
            px.imshow(
                pivot_amt,
                aspect=&quot;auto&quot;,
                color_continuous_scale=&quot;Viridis&quot;,
                labels=dict(color=&quot;AMT&quot;)
            ),
            use_container_width=True
        )

    with tab_h2:
        top_n = st.slider(&quot;TOP N (AMT 기준)&quot;, 5, 30, 10, 1, key=&quot;amt_topn&quot;)
        top_pairs = hot_agg.sort_values(&quot;AMT&quot;, ascending=False).head(top_n)
        st.dataframe(top_pairs, use_container_width=True)
        st.plotly_chart(
            px.bar(top_pairs, x=&quot;CTY_RGN_NM&quot;, y=&quot;AMT&quot;, color=&quot;TP_GRP_NM&quot;,
                   title=f&quot;지역×업종 AMT TOP {top_n}&quot;, barmode=&quot;stack&quot;),
            use_container_width=True
        )

    with tab_h3:
        top_aov = hot_agg.sort_values(&quot;AOV&quot;, ascending=False).head(10)
        st.dataframe(top_aov, use_container_width=True)
        fig_aov = px.bar(
            top_aov,
            x=&quot;CTY_RGN_NM&quot;, y=&quot;AOV&quot;, color=&quot;TP_GRP_NM&quot;,
            title=&quot;지역 × 업종 객단가(AOV) TOP 10&quot;,
            barmode=&quot;group&quot;,
            text_auto=&quot;.0f&quot;
        )
        st.plotly_chart(fig_aov, use_container_width=True)</code></pre><p>   streamlit 패키지 이용!
   시각화하기 좋은 툴을 이제야 알았다는 것에 아수운 마음이다.
   리액트보다 훨씬 수월하고 쉽게 사용 가능 ..</p>
<h3 id="streamlit">Streamlit</h3>
<blockquote>
<p>데이터 과학자/분석가가 빠르게 프로토타입을 만들 수 있도록 설계됨.
코드 작성 방식이 일반적인 파이썬 스크립트와 거의 동일해서 진입 장벽이 낮음.
“실험용 앱/내부 툴/보고용 대시보드”에 최적.</p>
</blockquote>
<h3 id="dash-by-plotly">Dash (by Plotly)</h3>
<blockquote>
<p>웹 앱을 좀 더 체계적이고 정교하게 개발하는 데 초점.
레이아웃과 콜백 구조가 필요해 학습곡선이 Streamlit보다 다소 있음.
“엔터프라이즈 대시보드/고객-facing 앱/멀티 페이지 앱”에 더 적합.</p>
</blockquote>
<p> ༼ つ ◕_◕ ༽つ
   Dash도 파이썬 기반 웹/앱 프레임워크
   각 특징을 확인하면서 프레임워크를 적절히 골라 사용하면 좋을 거 같다.
   개인적으로는 streamlit이 기본 ui가 더 예뿌다.</p>
<h4 id="☞ﾟヮﾟ☞-한달후기"><em>(☞ﾟヮﾟ)☞ 한달후기</em></h4>
<p>파이썬, mysql, 대쉬보드 만들기까지 한 달 동안 매우 많은 것들을 배우고 실습했다.
학부 때 배운 걸 한 달 동안 후다닥 정리해볼 수 있어서 유익했다.
프로젝트가 매우매우 기대된다.
끝.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Week4: SQL]]></title>
            <link>https://velog.io/@y-hyun2/Week4-SQL</link>
            <guid>https://velog.io/@y-hyun2/Week4-SQL</guid>
            <pubDate>Fri, 26 Sep 2025 03:42:56 GMT</pubDate>
            <description><![CDATA[<p>이번 주차는 SQL의 A부터 Z는 아니고,, Q까지 정도..?
이 모든 걸 너무 후다닥 나가버린 느낌이 없지 않아 있어서 실습을 좀 더 해봐야 할 것 같다는 생각을 함.</p>
<p>근데 내가 SQL을 언제 쓸 수 있을까 ..?</p>
<h1 id="📑-목차">📑 목차</h1>
<ul>
<li><p><a href="#1-sql-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95">1. SQL 기본 문법</a>  </p>
<ul>
<li><a href="#-sql-select--from--where-%EC%8B%A4%EC%8A%B5-%EC%A0%95%EB%A6%AC">SQL SELECT ~ FROM ~ WHERE 실습 정리</a>  </li>
<li><a href="#where%EC%A0%88-vs-having--%EC%84%9C%EB%B8%8C%EC%BF%BC%EB%A6%AC-%EC%B0%A8%EC%9D%B4%EC%A0%90">WHERE절 vs HAVING / 서브쿼리 차이점</a>  </li>
<li><a href="#-order-by-limit-distinct-group-by-having">ORDER BY, LIMIT, DISTINCT, GROUP BY, HAVING</a>  </li>
</ul>
</li>
<li><p><a href="#2-sql-%EA%B3%A0%EA%B8%89-%EB%AC%B8%EB%B2%95">2. SQL 고급 문법</a>  </p>
<ul>
<li><a href="#1-mysql-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%98%95%EC%8B%9D">MySQL 데이터 형식</a>  </li>
<li><a href="#prepared-statement-%EC%A4%80%EB%B9%84%EB%90%9C-%EA%B5%AC%EB%AC%B8">Prepared Statement (준비된 구문)</a>  </li>
<li><a href="#2-join">JOIN</a>  </li>
<li><a href="#3-sql-programming">SQL Programming</a>  </li>
</ul>
</li>
<li><p><a href="#3-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EA%B0%9C%EC%B2%B4">3. 데이터베이스 개체</a>  </p>
<ul>
<li><a href="#1-%EB%B7%B0-view">뷰 (VIEW)</a>  </li>
<li><a href="#2-%EC%9D%B8%EB%8D%B1%EC%8A%A4">인덱스</a>  </li>
<li><a href="#3-stored-procedure">Stored procedure</a>  </li>
</ul>
</li>
</ul>
<hr>
<h1 id="1-sql-기본-문법">1. SQL 기본 문법</h1>
<h2 id="📌-sql-select--from--where-실습-정리">📌 SQL SELECT ~ FROM ~ WHERE 실습 정리</h2>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/c091be74-cc0b-433e-94a7-84726e66338b/image.png" alt=""><img src="https://velog.velcdn.com/images/y-hyun2/post/3086ac6e-55a5-455c-a781-888add835f29/image.png" alt=""></p>
<p><strong>- 제품 이름에 ‘지갑’이 포함된 구매 내역 조회</strong></p>
<pre><code class="language-sql">SELECT * 
FROM market_db.buy 
WHERE prod_name = &#39;지갑&#39;;

-- 어디에 지갑이 있는 지 모르니까..
SELECT * 
FROM market_db.buy 
WHERE prod_name LIKE &#39;%지갑%&#39;;</code></pre>
<p><strong>- 멤버 중 전화정보가 하나라도 비어있는(국번 또는 나머지 번호가 NULL) 사람 조회 (<code>IS NULL</code>)</strong></p>
<pre><code class="language-sql">SELECT * 
FROM market_db.member 
WHERE phone1 IS NULL OR phone2 IS NULL;</code></pre>
<blockquote>
<p>💡 <strong>NULL 값과 비교 연산자</strong></p>
</blockquote>
<ul>
<li>SQL에서 <code>NULL</code>은 <strong>알 수 없음(unknown)</strong> 을 의미하는 특별한 값  </li>
<li>숫자 <code>0</code>이나 공백(<code>&#39;&#39;</code>)과는 다르며, 어떤 값과도 같거나 같지 않다고 비교할 수 없음  </li>
<li>따라서 <code>NULL = NULL</code>, <code>NULL = &#39;특정 값&#39;</code> 같은 비교는 항상 <strong>FALSE</strong><br>👉 그래서 <code>WHERE phone1 = null</code> 은 항상 거짓(false)이므로 <code>IS NULL</code>을 사용해야 함.</li>
</ul>
<p><strong>- 멤버 이름이 두 글자인 행 조회</strong></p>
<pre><code class="language-sql">SELECT * 
FROM market_db.member 
WHERE CHAR_LENGTH(mem_name) = 2;

SELECT * 
FROM market_db.member 
WHERE mem_name LIKE &#39;__&#39;;</code></pre>
<blockquote>
<p>💡 <strong>MySQL 문자열 길이 계산</strong></p>
</blockquote>
<ul>
<li><code>LENGTH()</code> → <strong>바이트(byte)</strong> 단위 길이  </li>
<li><code>CHAR_LENGTH()</code> → <strong>문자(character)</strong> 단위 길이  </li>
<li>한글은 글자당 3바이트 → &quot;잇지&quot;(2글자) → <code>LENGTH(mem_name)=6</code><br>👉 따라서 한글은 <code>CHAR_LENGTH()</code> 또는 <code>LIKE &#39;__&#39;</code>를 사용해야 함.</li>
</ul>
<p><strong>- 디지털 또는 서적 분류에서 구매, 제품명이 ‘폰’으로 끝나는 내역 조회</strong></p>
<pre><code class="language-sql">SELECT * 
FROM market_db.buy 
WHERE (group_name = &#39;디지털&#39; OR group_name = &#39;서적&#39;) 
  AND prod_name LIKE &#39;%폰&#39;;</code></pre>
<p>❌ 잘못된 예시</p>
<pre><code class="language-sql">SELECT * 
FROM market_db.buy 
WHERE prod_name LIKE &#39;%폰&#39; 
IN (SELECT prod_name 
    FROM market_db.buy 
    WHERE group_name = &#39;디지털&#39; OR group_name = &#39;서적&#39;);</code></pre>
<blockquote>
<p>💡 <strong>오류 이유</strong></p>
</blockquote>
<ul>
<li><code>=</code> + 서브쿼리 → <code>= 연산자</code>는 단일 값과 <strong>단일 값을 비교</strong>할 때 사용됨. 다중 값 반환 시 오류 발생  </li>
<li>여러 값 비교할 땐 <code>IN</code> 사용해야 함  </li>
<li>조건은 독립적으로가 아니라 <code>AND</code>로 연결해야 논리적으로 맞음  </li>
</ul>
<h3 id="where절-vs-having--서브쿼리-차이점">WHERE절 vs HAVING / 서브쿼리 차이점</h3>
<p>💡 <strong>집계 함수 주의</strong></p>
<ul>
<li><code>MAX()</code> 같은 <strong>집계 함수</strong>는 <code>HAVING</code>이나 서브쿼리에서 사용해야 함  </li>
<li><code>WHERE MAX(height)</code> → 문법 오류 발생  </li>
</ul>
<hr>
<h2 id="📌-order-by-limit-distinct-group-by-having">📌 ORDER BY, LIMIT, DISTINCT, GROUP BY, HAVING</h2>
<h3 id="1-select절-기본-구조">1. SELECT절 기본 구조</h3>
<pre><code class="language-sql">SELECT 열_이름
FROM 테이블_이름
WHERE 조건식
GROUP BY 열_이름
HAVING 조건식
ORDER BY 열_이름
LIMIT 숫자;</code></pre>
<hr>
<h3 id="2-order-by">2. ORDER BY</h3>
<ul>
<li><code>ASC</code> (기본): 오름차순  </li>
<li><code>DESC</code>: 내림차순  </li>
</ul>
<pre><code class="language-sql">SELECT mem_id, mem_name, debut_date, height
FROM member
WHERE height &gt;= 164
ORDER BY height DESC, debut_date;</code></pre>
<hr>
<h4 id="21-limit">2.1 LIMIT</h4>
<pre><code class="language-sql">SELECT mem_name, height
FROM member
ORDER BY height DESC
LIMIT 3, 2;</code></pre>
<p>👉 3번째 행부터 2개 조회</p>
<hr>
<h4 id="22-distinct">2.2 DISTINCT</h4>
<pre><code class="language-sql">SELECT DISTINCT addr 
FROM member;</code></pre>
<p>👉 중복 제거 후 결과 반환</p>
<hr>
<h3 id="3-group-by--having">3. GROUP BY &amp; HAVING</h3>
<ul>
<li><code>GROUP BY</code> → 그룹 묶기  </li>
<li>집계 함수 (<code>SUM()</code>, <code>AVG()</code>, <code>MIN()</code>, <code>MAX()</code>, <code>COUNT()</code>)와 함께 사용  </li>
</ul>
<pre><code class="language-sql">SELECT group_name, prod_name, SUM(amount) AS total
FROM buy
WHERE group_name IS NOT NULL
GROUP BY prod_name, group_name;</code></pre>
<p>👉 <code>GROUP BY prod_name, group_name</code> → 두 컬럼 조합으로 그룹 생성. 예를 들어, &#39;디지털&#39;, &#39;아이폰&#39;은 하나의 그룹이 되고, &#39;디지털&#39;, &#39;맥북프로&#39;는 또 다른 그룹이 됨.</p>
<hr>
<h4 id="평균보다-많이-팔린-제품-조회">평균보다 많이 팔린 제품 조회</h4>
<pre><code class="language-sql">SELECT prod_name, SUM(amount) AS prod_amount
FROM buy
GROUP BY prod_name
HAVING prod_amount &gt; (
    SELECT AVG(total_amount)
    FROM (
        SELECT prod_name, SUM(amount) AS total_amount
        FROM buy
        GROUP BY prod_name
    ) AS t
);</code></pre>
<p>💡 <strong>포인트</strong>  </p>
<ul>
<li>별칭(alias)을 어디서 지정했는지에 따라 사용 가능 여부 달라짐 </li>
<li>FROM 절에선, 다중이면 무조건 별칭 사용해야함</li>
<li>첫 번째 <code>SELECT</code> → <code>prod_amount</code>  </li>
<li>두 번째 서브쿼리 → <code>total_amount</code> </li>
</ul>
<hr>
<hr>
<h1 id="2-sql-고급-문법">2. SQL 고급 문법</h1>
<h2 id="1-mysql-데이터-형식">1. MySQL 데이터 형식</h2>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/322289e5-27da-43a6-94c1-452258ab0f9b/image.png" alt="">
<strong>- 문자열로 받은 최소키(height) &#39;165&#39;를 정수로 형 변환 후, &#39;최소 키&#39; 이상인 멤버 조회</strong></p>
<pre><code class="language-sql">USE market_db;

set @min_h_str = &#39;165&#39;;
set @min_h = cast( @min_h_str as signed);

select mem_id,mem_name, height,
    date_format(debut_date,&#39;%Y - %m&#39;) as debut_ym
from member
where height &gt;= @min_h
order by height desc, mem_id;</code></pre>
<blockquote>
<p><code>DATE_FORMAT(debut_date, &#39;%Y-%m&#39;)</code>: debut_date를 YYYY-MM 형식으로 변환합니다. %Y는 4자리 연도, %m은 2자리 월을 나타냅니다.</p>
</blockquote>
<p><strong>- 구매 테이블에서 각 행의 구매 금액(price*amount)을 소수 2자리 <code>DECIMAL</code>로 변환</strong></p>
<pre><code class="language-sql">select *, cast(price * amount as decimal (10,2)) as line_amount
from market_db.buy;</code></pre>
<blockquote>
<p><strong>총 10자리</strong>를 사용하며, 그중 <strong>소수점 아래는 2자리</strong>.</p>
</blockquote>
<ul>
<li>이는 정수부가 최대 8자리(10-2=8)까지 가능하다는 것을 뜻함.</li>
<li><strong>DECIMAL(10, 2)</strong> → 총 10자리, 소수점 2자리 (정수부 8자리까지 가능)</li>
</ul>
<hr>
<h3 id="prepared-statement-준비된-구문">Prepared Statement (준비된 구문)</h3>
<ul>
<li>미리 SQL을 컴파일(준비)해두고, 동일한 쿼리를 다른 값으로 여러 번 실행 가능 → SQL Injection 방지하는 보안상 이점이 있음  </li>
<li>3단계: <strong>PREPARE → EXECUTE → DEALLOCATE</strong><ul>
<li><code>PREPARE</code> 구문:SQL 구문을 정의하고, 값이 들어갈 위치에 <code>?</code> 와 같은 자리표시자 사용</li>
<li><code>EXECUTE</code>: USING 절을 사용하여 변수들을 자리표시자에 바인딩</li>
<li><code>해제 (DEALLOCATE)</code>: 사용이 끝난 준비된 구문을 메모리에서 해제</li>
</ul>
</li>
</ul>
<pre><code class="language-sql">SET @addr = &#39;서울&#39;;
SET @min_h = 165;
SET @sql = &#39;SELECT mem_id, mem_name, addr, height FROM member WHERE addr = ? AND height &gt;= ?&#39;;

PREPARE stmt FROM @sql;
EXECUTE stmt USING @addr, @min_h;
DEALLOCATE PREPARE stmt;</code></pre>
<hr>
<h2 id="2-join">2. JOIN</h2>
<h3 id="left-join">LEFT JOIN</h3>
<ul>
<li>왼쪽 테이블의 모든 행 + 조건에 맞는 오른쪽 테이블의 행 결합  <ul>
<li><strong>조건에 맞는 행이 있는 경우</strong>: 양쪽 테이블의 데이터가 결합되어 출력</li>
<li><strong>조건에 맞는 행이 없는 경우</strong>: 왼쪽 테이블의 행은 유지하고, 오른쪽 테이블의 열은 <strong>모두 <code>NULL</code></strong> 값으로 채워짐. </li>
</ul>
</li>
<li><code>LEFT JOIN + IS NULL</code> 조합 → <strong>Anti-join (차집합 구하기)</strong></li>
</ul>
<hr>
<h2 id="3-sql-programming">3. SQL Programming</h2>
<ul>
<li>MySQL에서 프로그래밍 기능은 <strong>스토어드 프로시저</strong>에 작성  </li>
<li><code>DELIMITER $$ ... END$$</code> 안에 작성, <code>CALL</code>로 호출
<img src="https://velog.velcdn.com/images/y-hyun2/post/51cbd0f1-30c6-4d4a-89a1-14acc6cddce9/image.png" alt=""></li>
</ul>
<h3 id="1-if문">1) IF문</h3>
<pre><code class="language-sql">IF &lt;조건식&gt; THEN
    SQL 문장들
END IF;</code></pre>
<h3 id="2-case문">2) CASE문</h3>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/c359131d-bc58-4032-8c79-d9ba1ecfe462/image.png" alt=""> </p>
<ul>
<li>IF는 2중 분기 / CASE는 다중 분기</li>
</ul>
<h3 id="3-while문">3) WHILE문</h3>
<ul>
<li><code>ITERATE [레이블]</code>: 반복 계속  </li>
<li><code>LEAVE [레이블]</code>: 반복 종료</li>
</ul>
<hr>
<hr>
<h1 id="3-데이터베이스-개체">3. 데이터베이스 개체</h1>
<h2 id="1-뷰-view">1. 뷰 (VIEW)</h2>
<ul>
<li>뷰는 <strong>데이터 저장하지 않음</strong> → SELECT 실행 결과를 가상 테이블처럼 보여줌  </li>
<li>종류: 단순 뷰(1개 테이블), 복합 뷰(2개 이상 테이블)</li>
<li>복합 뷰로는 테이블의 데이터 수정 불가<pre><code class="language-sql">CREATE VIEW 뷰_이름
AS
  SELECT문;</code></pre>
</li>
</ul>
<h3 id="뷰의-장점">뷰의 장점</h3>
<ol>
<li>보안(SECURITY)  </li>
<li>복잡한 SQL 단순화</li>
</ol>
<h3 id="뷰의-작동">뷰의 작동</h3>
<ul>
<li>사용자는 뷰를 테이블이라고 생각하고 접근</li>
<li>MySQL이 뷰 안에 있는 SELECT를 실행해서 그 결과를 사용자에게 보냄</li>
<li>뷰는 기본적으로 &#39;읽기 전용&#39;이지만, 원본 테이블의 데이터를 수정할 수도 있음</li>
</ul>
<h3 id="뷰-관련-명령">뷰 관련 명령</h3>
<ul>
<li>생성: <code>CREATE VIEW 뷰이름 AS SELECT ...</code></li>
<li>수정: <code>ALTER VIEW ...</code></li>
<li>삭제: <code>DROP VIEW ...</code></li>
</ul>
<p>뷰에 접근 → 일반 테이블처럼 <code>SELECT</code> 사용</p>
<pre><code class="language-SQL">SELECT 열이름 FROM 뷰이름
    [where 조건];</code></pre>
<hr>
<h2 id="2-인덱스">2. 인덱스</h2>
<p>데이터를 빠르게 찾을 수 있도록 도와주는 도구</p>
<ul>
<li>Clustered Index<ul>
<li><strong>기본 키로 지정하면 자동 생성</strong>되며 테이블에 1개만 만들 수 있음</li>
<li>기본 키로 지정한 열을 기준으로 <strong>자동 정렬</strong>됨</li>
</ul>
</li>
<li>Secondary Index<ul>
<li><strong>고유 키로 지정하면 자동 생성</strong>되며 여러 개를 만들 수 있음</li>
<li>자동 정렬되지는 않음</li>
<li>고유 인덱스는 값이 중복되지 않는 인덱스 → 기본 키나 고유 키로 지정하면 고유 인덱스가 자동 생성됨</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>인덱스의 문제점</strong></p>
</blockquote>
<ul>
<li>필요 없는 인덱스를 만드는 바람에 데이터베이스가 차지하는 공간만 더 늘어남</li>
<li>인덱스를 이용해서 데이터를 찾는 것이 전체 테이블을 찾는 것보다 느려짐</li>
</ul>
<blockquote>
<p><strong>인덱스의 장점</strong></p>
</blockquote>
<ul>
<li>select 문으로 검색하는 속도가 매우 빨라짐</li>
<li>그 결과 컴퓨터의 부담이 줄어서 결국 전체 시스템의 성능이 향상됨</li>
</ul>
<h3 id="1-인덱스의-내부-작동-원리">1. 인덱스의 내부 작동 원리</h3>
<ul>
<li><p>Clusterd Index와 Secondary Index는 모두 내부적으로 균형 트리(B-tree)로 만들어짐</p>
</li>
<li><p><strong>Balanced tree, B-tree</strong>는 자료 구조에서 범용적으로 사용되는 데이터 구조
<img src="https://velog.velcdn.com/images/y-hyun2/post/25becc94-863c-452f-8b98-8a30aa81d3bb/image.png" alt="">
B-tree 구조에서 데이터가 저장되는 공간을 node라고 함</p>
<p>  → Root node, Internal node, Leaf node로 구성
  → MySQL에서는 node를 page라고 부름
  → 페이지는 최소한의 저장 단위로, 16kbyte 크기를 가짐</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/21ce228a-c51e-40be-8c2c-abb52a70b64e/image.png" alt="">
<strong>균형 트리의 페이지 분할</strong></p>
<ul>
<li>인덱스를 구성하면 데이터 변경 작업( INSERT, UPDATE, DELETE) 시 성능이 나빠짐</li>
<li>특히 INSERT 작업이 일어날 때 더 느리게 입력될 수 있음 → “페이지 분할” 작업 때문</li>
</ul>
<h4 id="1-클러스터형-인덱스-구성">1. <strong>클러스터형 인덱스 구성</strong></h4>
<p>→ 실제 데이터는 다음과 같이 데이터 페이지가 정렬되고 균형 트리 형태의 인덱스가 형성됨</p>
<pre><code class="language-sql"> ALTER TABLE cluster
     ADD CONSTRAINT
     PRIMARY KEY(mem_id);</code></pre>
<h4 id="2-보조-인덱스-구성"><strong>2. 보조 인덱스 구성</strong></h4>
<pre><code class="language-sql">
ALTER TABLE second
        ADD CONSTRAINT
        UNIQUE (mem_id);

    SELECT* FROM second;</code></pre>
<ul>
<li>보조 인덱스가 생성되었는데도 입력한 것과 순서가 동일</li>
<li>데이터 페이지를 건드리지 않음</li>
</ul>
<p><strong>3. 인덱스에서 데이터 검색하기</strong></p>
<p>클러스터형 vs 보조 인덱스</p>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/fa869fb2-f6e1-435d-a22c-5598db7ba8cc/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/7bc0500b-35c8-49f7-88c3-f6dd4b179d60/image.png" alt=""></p>
<blockquote>
<p>💡 FULL SCAN: <strong>전체 테이블 검색</strong>은 데이터를 처음부터 끝까지 검색하는 것. 인덱스가 없으면 전체 페이지를 검색하는 방법밖에 없음
<strong>페이지 분할</strong>은 데이터를 입력할 때, 입력할 페이지에 공간이 없어서 2개 페이지로 데이터가 나눠지는 것을 말함
<strong>인덱스 검색</strong>은 클러스터형 또는 보조 인덱스를 이용해서 데이터를 검색하는 것. 속도는 인덱스를 사용하지 않았을 때보다 빠름</p>
</blockquote>
<h3 id="2-인덱스-생성-제거">2. 인덱스 생성 제거</h3>
<p><strong>인덱스 생성 문법</strong></p>
<pre><code class="language-sql">CREATE (UNIQUE) INDEX 인덱스_이름
    ON 테이블_이름(열_이름) (ASC or DESC)</code></pre>
<p>→ UNIQUE를 사용하면 고유 인덱스 생성, 생략하면 중복 허용 보조 인덱스 생성</p>
<p><strong>인덱스 제거 문법</strong></p>
<pre><code class="language-sql">DROP INDEX 인덱스_이름
    ON 테이블_이름</code></pre>
<p>→ 기본 키, 고유 키로 자동 생성된 인덱스는 <code>DROP INDEX</code>로 제거하지 못함
→ <code>ALTER TABLE 문</code>으로 자동 생성된 인덱스 제거 가능</p>
<ul>
<li><strong>인덱스 생성 실습</strong></li>
</ul>
<pre><code class="language-sql">CREATE INDEX idx_member_addr
    ON member(addr)

ANALYZE TABLE member;</code></pre>
<p>생성한 인덱스를 실제로 적용시키려면 <code>ANALYZE TABLE 문</code>으로 먼저 테이블을 분석/처리해줘야 함</p>
<hr>
<h2 id="3-stored-procedure">3. Stored procedure</h2>
<ul>
<li><p>SQL에 프로그래밍 기능을 추가해서 일반 프로그래밍 언어와 비슷한 효과를 낼 수 있음
: SQL + 프로그래밍 기능 -&gt; 스토어드 프로시저
<img src="https://velog.velcdn.com/images/y-hyun2/post/0da2cf6a-a623-479b-ac4d-e48c58a8ed5c/image.png" alt=""></p>
</li>
<li><p>특징:</p>
<ul>
<li><code>CREATE PROCEDURE</code>로 정의, <code>CALL</code>로 실행.</li>
<li>매개변수 3종: 입력(IN), 출력(OUT), 입출력(INOUT).</li>
<li>조건문(IF), 반복문(WHILE), 동적 SQL 등 프로그래밍 로직 작성 가능.</li>
</ul>
</li>
<li><p>활용 예시:
  회원 검색, 계산 처리, 반복 작업 자동화 등.
  복잡한 쿼리를 재사용할 때 효율적.</p>
</li>
<li><p><code>CREATE PROCEDURE</code>는 스토어드 프로시저를 만든 것뿐이며, 아직 실행한 것은 아님</p>
</li>
<li><p><code>CALL 스토어드_프로시저_이름();</code> 로 호출함</p>
</li>
<li><p><code>DROP PROCUDURE</code></p>
</li>
</ul>
<h3 id="📌-실습-예제">📌 실습 예제</h3>
<p>1) 입력 매개변수</p>
<pre><code class="language-sql">DELIMITER $$
CREATE PROCEDURE user_proc1(IN username VARCHAR(20))
BEGIN
    SELECT * FROM member WHERE mem_name = username;
END $$
DELIMITER ;

CALL user_proc1(&#39;APINK&#39;);</code></pre>
<p>2) 출력 매개변수</p>
<pre><code class="language-sql">DELIMITER $$
CREATE PROCEDURE user_proc2(OUT cnt INT)
BEGIN
    SELECT COUNT(*) INTO cnt FROM member;
END $$
DELIMITER ;

CALL user_proc2(@total);
SELECT @total;  -- 출력 값 확인</code></pre>
<p>3) 조건문 활용</p>
<pre><code class="language-sql">DELIMITER $$
CREATE PROCEDURE checkAgeProc(IN age INT)
BEGIN
    IF age &gt;= 20 THEN
        SELECT &#39;성인입니다.&#39;;
    ELSE
        SELECT &#39;미성년자입니다.&#39;;
    END IF;
END $$
DELIMITER ;

CALL checkAgeProc(25);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Week3: 📝 Data Preprocessing(Pandas& Numpy) + MLP 기초]]></title>
            <link>https://velog.io/@y-hyun2/Week3-Data-PreprocessingPandas-Numpy-MLP-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@y-hyun2/Week3-Data-PreprocessingPandas-Numpy-MLP-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Sun, 14 Sep 2025 15:12:38 GMT</pubDate>
            <description><![CDATA[<p>이번 주 학습 정리</p>
<p>이번 주에는 <strong>Titanic 데이터셋</strong>과 <strong>MNIST 데이터셋</strong>을 통해<br><strong>데이터 전처리(Pandas &amp; Numpy)</strong>와 <strong>MLP(다층 퍼셉트론)</strong> 기본기를 익힘</p>
<hr>
<h2 id="📚-목차">📚 목차</h2>
<ul>
<li><a href="#1-pandas-%EC%A1%B0%EA%B1%B4-%EA%B2%80%EC%83%89">1. Pandas 조건 검색</a></li>
<li><a href="#2-%EA%B2%B0%EC%B8%A1%EC%B9%98-%EC%B2%98%EB%A6%AC--map-vs-apply">2. 결측치 처리 &amp; map vs apply</a></li>
<li><a href="#3-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B3%80%ED%99%98--%ED%86%B5%EA%B3%84-%ED%95%A8%EC%88%98">3. 데이터 변환 &amp; 통계 함수</a></li>
<li><a href="#4-numpy-%EB%B0%B0%EC%97%B4-%EA%B8%B0%EC%B4%88--%EC%A1%B0%EC%9E%91">4. NumPy 배열 기초 &amp; 조작</a></li>
<li><a href="#5-%EC%8B%A0%EA%B2%BD%EB%A7%9D-%EA%B8%B0%EC%B4%88-feedforward-neural-network">5. 신경망 기초 (Feedforward Neural Network)</a></li>
<li><a href="#6-mlpclassifier-%EC%8B%A4%EC%8A%B5-iris--mnist">6. MLPClassifier 실습 (Iris &amp; MNIST)</a></li>
<li><a href="#7-%EB%A1%9C%EC%A7%80%EC%8A%A4%ED%8B%B1-%ED%9A%8C%EA%B7%80-vs-%EB%9E%9C%EB%8D%A4%ED%8F%AC%EB%A0%88%EC%8A%A4%ED%8A%B8-%EB%B9%84%EA%B5%90">7. 로지스틱 회귀 vs 랜덤포레스트 비교</a></li>
<li><a href="#8-%EC%9D%B4%EB%B2%88-%EC%A3%BC-%ED%95%99%EC%8A%B5-%ED%8F%AC%EC%9D%B8%ED%8A%B8-%EC%B4%9D%EC%A0%95%EB%A6%AC">8. 이번 주 학습 포인트 총정리</a></li>
</ul>
<hr>
<h2 id="1-pandas-조건-검색">1. Pandas 조건 검색</h2>
<table>
<thead>
<tr>
<th>방법</th>
<th>예시 코드</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Boolean Index</strong></td>
<td><code>df[df[&#39;Age&#39;]&gt;30]</code></td>
<td>조건 True/False로 필터링</td>
</tr>
<tr>
<td><strong>loc</strong></td>
<td><code>df.loc[df[&#39;Age&#39;]&gt;30, [&#39;Name&#39;,&#39;Age&#39;]]</code></td>
<td>조건 + 특정 열만 선택</td>
</tr>
<tr>
<td><strong>isin</strong></td>
<td><code>df[df[&#39;Name&#39;].isin([&#39;John&#39;,&#39;Mary&#39;])]</code></td>
<td>리스트 값 필터링</td>
</tr>
<tr>
<td><strong>isin+loc</strong></td>
<td><code>df.loc[df[&#39;Name&#39;].isin(my_condition), &#39;Age&#39;]</code></td>
<td>조건 + 특정 열</td>
</tr>
</tbody></table>
<hr>
<h2 id="2-결측치-처리--map-vs-apply">2. 결측치 처리 &amp; map vs apply</h2>
<h3 id="🟡-결측치-확인">🟡 결측치 확인</h3>
<pre><code class="language-python">df[&#39;Age&#39;].isna()           # True/False
df[&#39;Age&#39;].isnull().sum()   # NaN 개수
df[&#39;Age&#39;].notnull()        # 결측 아닌 값</code></pre>
<h3 id="🟡-결측치-채우기">🟡 결측치 채우기</h3>
<p><code>df[&#39;Cabin&#39;] = df[&#39;Cabin&#39;].fillna(&#39;U&#39;)</code></p>
<h3 id="🔵-map-vs-apply-차이">🔵 map vs apply 차이</h3>
<table>
<thead>
<tr>
<th>항목</th>
<th><code>map()</code></th>
<th><code>apply()</code></th>
</tr>
</thead>
<tbody><tr>
<td>대상</td>
<td>iterable 전체</td>
<td>Series/DataFrame</td>
</tr>
<tr>
<td>반환</td>
<td>map 객체</td>
<td>Series/DataFrame</td>
</tr>
<tr>
<td>입력으로 허용</td>
<td>함수, dict, Series(매핑 가능 객체)</td>
<td>함수만 (dict나 Series 매핑 X)</td>
</tr>
</tbody></table>
<hr>
<h2 id="3-데이터-변환--통계-함수">3. 데이터 변환 &amp; 통계 함수</h2>
<ul>
<li><strong>숫자 변환</strong>: <code>pd.to_numeric(errors=&#39;coerce&#39;)</code> → 변환 불가 시 NaN<ul>
<li>errors = ‘ignore’ : 숫자형으로 변경할 수 없는 데이터라면 원본 데이터 그대로 반환</li>
<li>errors = ‘coerce’ : 숫자형으로 변경할 수 없는 데이터라면 기존 데이터는 지우고 NaN으로 설정하여 반환</li>
<li>erros= ‘ raise’ : 숫자형으로 변경할 수 없는 데이터라면 오류가 발생하며 코드가 중단</li>
</ul>
</li>
<li><strong>데이터 타입 변경</strong>: <code>astype()</code></li>
<li><strong>구간별 카테고리화</strong>: <code>pd.cut()</code></li>
<li><strong>통계</strong>: <code>df.describe()</code>, <code>df[&#39;col&#39;].mean()</code> 등</li>
</ul>
<hr>
<h2 id="4-numpy-배열-기초--조작">4. NumPy 배열 기초 &amp; 조작</h2>
<h3 id="1-numpy와-pandas-비교">1. NumPy와 Pandas 비교</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>NumPy 배열 (ndarray)</th>
<th>Pandas 데이터프레임 (DataFrame)</th>
</tr>
</thead>
<tbody><tr>
<td>구조</td>
<td>다차원 배열 (벡터·행렬·텐서)</td>
<td>2차원 테이블 구조</td>
</tr>
<tr>
<td>자료형</td>
<td>동일한 자료형(int, float)만</td>
<td>열마다 서로 다른 자료형 가능</td>
</tr>
<tr>
<td>인덱싱</td>
<td>정수 기반</td>
<td>레이블 기반(행/열)</td>
</tr>
<tr>
<td>특징</td>
<td>빠른 수치 연산, 브로드캐스팅</td>
<td>groupby, merge, join, pivot 등 고급 기능</td>
</tr>
</tbody></table>
<h3 id="2-numpy-배열-생성">2. NumPy 배열 생성</h3>
<h4 id="①-arange--reshape">① <code>arange</code> + <code>reshape</code></h4>
<pre><code class="language-python">import numpy as np

d = np.arange(12).reshape(3,4)
print(d, d.shape)</code></pre>
<pre><code>[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]] (3, 4)</code></pre><ul>
<li>arange(): 특정 수열을 만들어 배열 생성</li>
<li>reshape(): 배열의 차원/형태를 변경</li>
</ul>
<h4 id="②-배열-속성">② 배열 속성</h4>
<ul>
<li>dtype : 데이터형</li>
<li>ndim : 배열 차원</li>
<li>T : 행/열 전치 (Transpose)</li>
<li>size : 총 원소 수</li>
<li>nbytes : 총 바이트 수</li>
<li>flat : 모든 요소 일괄 변경 (d.flat = 1)</li>
</ul>
<h4 id="③-nparray로-직접-생성">③ np.array()로 직접 생성</h4>
<p><strong>1차원</strong></p>
<pre><code class="language-python">a = np.arange(0,5,2)
print(a, a.shape)</code></pre>
<p><strong>2차원</strong></p>
<pre><code class="language-python">m = np.array([np.arange(0,4,3),
              np.arange(1,5,3),
              np.arange(2,6,3)])
print(m, m.shape)

# [[0 3]
#  [1 4]
#  [2 5]] (3,2)</code></pre>
<p><strong>3차원</strong></p>
<pre><code class="language-python">m = np.array([[[0,1,2],
               [3,4,5]],
              [[0,1,2],
               [3,4,5]]])
print(m.shape)

# (2,2,3)</code></pre>
<p><strong>💡 Python range() vs NumPy arange()</strong>
→ arange()는 실수 간격도 가능, NumPy 배열 반환.</p>
<h3 id="3-배열-다루기-reshape-flatten-방향-변경">3. 배열 다루기 (reshape, flatten, 방향 변경)</h3>
<h4 id="①-reshape로-형태-변경">① reshape()로 형태 변경</h4>
<pre><code class="language-python">m1 = np.arange(6)
m2 = m1.reshape(6,1)   # 6행 1열
m3 = m1.reshape(2,3)   # 2행 3열
m4 = m1.reshape(2,2,3) # 2면 2행 3열</code></pre>
<p>행 수를 -1로 주면 자동 계산:</p>
<pre><code class="language-python">m2 = m1.reshape(-1,2)  # 2열, 행은 자동</code></pre>
<h4 id="②-flatten--다차원-→-1차원">② flatten() : 다차원 → 1차원</h4>
<pre><code class="language-python">flat = m4.flatten()</code></pre>
<h4 id="③-배열-방향-뒤집기">③ 배열 방향 뒤집기</h4>
<pre><code class="language-python">arr[::-1]  # 행 방향 뒤집기
arr[:, ::-1]  # 열 방향 뒤집기</code></pre>
<h3 id="4-배열-통합과-분할">4. 배열 통합과 분할</h3>
<h4 id="①-합치기">① 합치기</h4>
<table>
<thead>
<tr>
<th>행 방향</th>
<th>열 방향</th>
</tr>
</thead>
<tbody><tr>
<td><code>vstack()</code>, <code>row_stack()</code>, <code>concatenate(..., axis=0)</code></td>
<td><code>hstack()</code>, <code>column_stack()</code>, <code>concatenate(..., axis=1)</code></td>
</tr>
<tr>
<td>#### ② 분할하기</td>
<td></td>
</tr>
<tr>
<td>행 단위 분할</td>
<td>열 단위 분할</td>
</tr>
<tr>
<td>-----------------------</td>
<td>-----------------------</td>
</tr>
<tr>
<td><code>vsplit(arr, n)</code></td>
<td><code>hsplit(arr, n)</code></td>
</tr>
<tr>
<td><code>split(arr, n, axis=0)</code></td>
<td><code>split(arr, n, axis=1)</code></td>
</tr>
</tbody></table>
<h3 id="5-numpy-배열의-연산">5. Numpy 배열의 연산</h3>
<p><strong>브로드캐스팅</strong>: 차원의 크기가 다른 배열끼리 산술연산이 가능하도록 하는 것.</p>
<pre><code class="language-python">A = np.array([[1,2,3],
              [4,5,6]])
B = np.array([[2],
              [4]])
print(A+B)

[[ 3  4  5]
 [ 8  9 10]]</code></pre>
<hr>
<h2 id="5-신경망-기초-neural-network">5. 신경망 기초 (Neural Network)</h2>
<h3 id="📌-순전파-신경망feedforward-neural-network-로직">📌 순전파 신경망(Feedforward Neural Network) 로직</h3>
<ol>
<li><p><strong>입력층 (Input Layer)</strong></p>
<ul>
<li>데이터 x가 들어옵니다. 예를 들어, 특징(feature) 벡터 [x1,x2,...,xn][x_1, x_2, ..., x_n][x1,x2,...,xn].</li>
</ul>
</li>
<li><p><strong>가중치 및 편향 (Weights, Bias)</strong></p>
<ul>
<li>각 층에는 가중치 행렬 <em>W</em>와 편향 벡터 <em>b</em>가 있습니다.</li>
<li>수식:z=W⋅x+b</li>
</ul>
</li>
<li><p><strong>활성화 함수 (Activation Function)</strong></p>
<ul>
<li><p>비선형성을 추가하기 위해 <em>z</em>를 활성화 함수 <em>f</em> 에 통과시킵니다.</p>
</li>
<li><p>예: ReLU, Sigmoid, Tanh</p>
<p>  a=f(z)</p>
</li>
</ul>
</li>
<li><p><strong>다음 층으로 전달 (Forward Propagation)</strong></p>
<ul>
<li>계산된 <em>a</em>는 다음 층의 입력이 됩니다. [다중 Hidden Layer]</li>
<li>이를 반복해서 출력층까지 진행.</li>
</ul>
</li>
<li><p><strong>출력층 (Output Layer)</strong></p>
<ul>
<li>회귀 문제라면 보통 활성화 없이 그대로 출력.</li>
<li>분류 문제라면 <strong><code>Softmax</code></strong>를 써서 확률 분포로 변환.</li>
<li>이진 분류 문제라면 <strong><code>Sigmoid</code></strong> 를 사용하여 0~1 확률로 변환</li>
</ul>
</li>
</ol>
<p><strong><em>순전파(Forward)로 입력→출력, 역전파(Backpropagation)로 가중치 업데이트</em></strong></p>
<hr>
<h2 id="6-mlpclassifier-실습-iris--mnist">6. MLPClassifier 실습 (Iris &amp; MNIST)</h2>
<p><strong>🔹 Iris 데이터</strong></p>
<pre><code class="language-python">from sklearn.neural_network import MLPClassifier

mlp = MLPClassifier(hidden_layer_sizes=(10,),
                    activation=&#39;logistic&#39;,
                    solver=&#39;lbfgs&#39;)
mlp.fit(X_train, y_train) # 학습
# 작은 데이터셋(150개) → 작은 은닉층으로도 높은 정확도</code></pre>
<p><strong>🔹 MNIST 데이터</strong></p>
<pre><code class="language-python">from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier

mnist = fetch_openml(&#39;mnist_784&#39;, version=1, as_frame=False)
X, y = mnist.data / 255.0, mnist.target.astype(int)

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

mlp = MLPClassifier(hidden_layer_sizes=(128,64),
                    activation=&#39;relu&#39;,
                    solver=&#39;adam&#39;,
                    max_iter=100)
mlp.fit(X_train, y_train)</code></pre>
<ul>
<li><p><code>fetch_openml(&#39;mnist_784&#39;)</code> : 28×28 픽셀 → 784 벡터</p>
</li>
<li><p>정규화: <code>/255.0</code> → 0~1 스케일링(scaling).</p>
<ul>
<li>원래 픽셀 값은 0=검정, 255=흰색.</li>
<li>신경망 학습 시 입력 값이 크면 기울기 폭발(gradient explosion) 문제 생김.</li>
<li><strong>스케일링</strong>을 통해 학습 안정성과 속도를 개선.</li>
</ul>
</li>
<li><p>라벨 변환: <code>.astype(int)</code></p>
</li>
<li><p>은닉층: 고차원 데이터 → 큰 네트워크(128→64) 설정
  <code>hidden_layer_sizes</code> 에 전달하는 <strong>튜플(tuple)</strong> 의 각 원소는 <strong>각 은닉층의 뉴런(유닛) 개수</strong>를 의미.</p>
<p>  <code>(100, 50)</code> 은</p>
<ul>
<li><p>첫 번째 은닉층: 100개의 뉴런</p>
</li>
<li><p>두 번째 은닉층: 50개의 뉴런</p>
<p>  → 즉 <strong>2개의 은닉층</strong>을 가진 구조입니다.</p>
</li>
</ul>
<p><code>(3,)</code> 은 은닉층 1개, 뉴런 3개. <code>(5, 3, 2)</code> 는 은닉층 3개(5→3→2).</p>
<hr>
<h2 id="7-로지스틱-회귀-vs-랜덤포레스트-비교">7. 로지스틱 회귀 vs 랜덤포레스트 비교</h2>
</li>
<li><p><strong><code>로지스틱 회귀</code></strong> → &quot;성별이 생존에 미치는 영향이 얼마나 큰가?&quot; (계수 해석, 오즈비 Odds Ratio, AUC/Recall 중점): <code>선형 분류 모델, 예측 확률을 직접 제공</code></p>
<p>  👉 <strong>중요한 평가지표</strong></p>
<ol>
<li><strong>정확도(Accuracy)</strong><ul>
<li>전체 예측 중 맞춘 비율</li>
<li>클래스 불균형(예: 생존자보다 사망자가 많음)이 심할 때는 맹점이 있음</li>
</ul>
</li>
<li><strong>정밀도(Precision) / 재현율(Recall) / F1-score</strong><ul>
<li>생존자 예측 문제처럼 &quot;양성 클래스(1=생존)&quot;가 중요한 경우, Accuracy만 보면 안 되고 <strong>재현율(Recall)</strong> 이 중요해요.</li>
<li><strong>정밀도</strong>: 모델이 &quot;생존&quot;이라고 한 사람 중 실제 생존한 비율</li>
<li><strong>재현율</strong>: 실제 생존한 사람 중 모델이 맞게 &quot;생존&quot;이라 한 비율</li>
<li><strong>F1-score</strong>: Precision과 Recall의 조화평균</li>
</ul>
</li>
</ol>
</li>
<li><p><strong><code>랜덤 포레스트</code></strong> → &quot;성별, 요금, 나이, 가족 수 중 어떤 변수가 가장 중요한가?&quot; (Feature Importance, Accuracy 중점): <code>앙상블 트리 기반 모델, 변수 중요도를 산출</code></p>
<p>  👉 <strong>중요한 평가지표</strong></p>
<ol>
<li><strong>정확도(Accuracy)</strong><ul>
<li>랜덤 포레스트는 기본적으로 정확도를 높이기 위한 모델이라 많이 씀</li>
</ul>
</li>
</ol>
</li>
</ul>
<p>👉 따라서,</p>
<ul>
<li><strong>설명력 중시 (변수가 생존 확률에 미치는 영향 해석)</strong> → 로지스틱 회귀 + Precision/Recall/AUC</li>
<li><strong>예측력 중시 (변수 중요도와 분류 정확도)</strong> → 랜덤 포레스트 + Accuracy/AUC/Feature Importance</li>
</ul>
<hr>
<h2 id="8-이번-주-학습-포인트-총정리">8. 이번 주 학습 포인트 총정리</h2>
<p>✔︎ 데이터 전처리: </p>
<ul>
<li><code>[Pandas]</code> 조건 검색, 결측치 처리, 데이터형 변환 </li>
<li><code>[Numpy]</code> 배열 조작, 배열 연산(브로드캐스팅)</li>
</ul>
<p>✔︎ 신경망 기초: <code>[입력층]</code>입력→ <code>[은닉층]</code> 가중치→활성화 → <code>[출력층]</code> 출력 순서</p>
<ul>
<li>활성화함수: 시그모이드 함수,ReLU, Tanh</li>
</ul>
<p>✔︎ 사이킷런을 통한 신경망 구현: </p>
<ul>
<li>MLPClassifier: 작은 데이터는 작은 네트워크, 큰 데이터는 큰 네트워크 + 정규화 필수<pre><code class="language-python">mlp = MLPClassifier(hidden_layer_sizes=(128, 64),  # 은닉층 2개 (128 → 64)
                  activation=&#39;relu&#39;,
                  solver=&#39;adam&#39;, #모델 학습 방법
                  max_iter=100,   # 반복 횟수 (20 → 100 실험 가능)
                  random_state=42, #초기 가중치 값 고정
                  verbose=True)
</code></pre>
</li>
</ul>
<p>```
✔︎ 로지스틱 회귀 vs 랜덤포레스트: 해석력 vs 예측력</p>
<p>☁️ <strong>총평</strong>: 실습해보면서 계속 자주 쓰이는 함수/패키지들을 익히고 모델들의 특성을 익혀서 어떨 때 사용하면 좋을지 바로 아는 능력을 기르는 게 중요할 듯. 다음주도 화이팅~</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[HDC LABS NOVA 1기 - week1 후기]]></title>
            <link>https://velog.io/@y-hyun2/HDC-LABS-NOVA-1%EA%B8%B0-week1-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@y-hyun2/HDC-LABS-NOVA-1%EA%B8%B0-week1-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Sun, 07 Sep 2025 05:13:54 GMT</pubDate>
            <description><![CDATA[<h2 id="☺︎-why">☺︎ Why?</h2>
<p>처음에는 학부 연구생을 하면서 2025 하반기를 보낼 생각이었다.
7월은 체코에서 돌아와 일상에 적응하면서 가고 싶은 연구실을 찾고 하고 싶은 것들 다 하면서 방학을 보내던 중 우연히 HDC LABS NOVA 지원링크를 전달받게 되었다.</p>
<p>2차 모집 마감 d-2,
HDC LABS가 무슨 회사인지도 몰랐던 내가 끌렸던 이유는 딱 두 가지였다.</p>
<p>❶ <strong>HDC랩스 데이터(IoT, 영상, 음성 등)를 이용한 프로젝트 가능</strong>
    학교 다닐 때 했던 프로젝트들에서는 이 데이터를 찾는 게 정말 고역이었다. 손수 크롤링을 하거나 공공 데이터, AI hub 데이터를 이용할 수 밖에 없어, 데이터를 못 구해 프로젝트 방향을 아예 바꾼 적도 있었다.
    이 부트캠프를는 실무 데이터를 활용하여 프로젝트를 진행할 수 있다는 점이 정말 큰 메리트라고 생각했다. 그 중에서도 <strong>부동산 데이터 기반 AIoT 통합 서비스 개발</strong> 주제로 프로젝트를 진행한다면 재밌을 것 같다고 생각했다.</p>
<p>❷ ** 현직자 강의 &amp; 멘토링 **
    실제 현업에서는 어떤 식으로 프로젝트를 진행하고 관리하는 지가 항상 궁금했다.
    우리끼리 매일 학교에서 &quot;진짜 회사에서도 이런식으로 데이터를 처리한다고??&quot;하면서 의문을 가졌다. 현직자가 직접 강의 및 멘토링을 해주시면서 이런 궁금증이 좀 더 해소되고 실제 취업에 조금 더 가깝게 도움을 받을 수 있지 않을까하는 생각이었다.</p>
<ul>
<li>그 외에도 우리 학교에서는 인도네시아 교수님이 데이터 수업을 전적으로 맡아 강의하시다보니.. 수업 때 100% 이해한 적이 많지 않고, 제대로 배워보고 싶다는 생각을 많이 하긴했다. 
파이썬부터 SQL, 머신 러닝~딥러닝까지 체계적으로 전문 강사님께 배워보고, 컴공에서 다루지만 항상 배워보고 싶었던 CV, LLM까지 배우는 커리큘럼이다보니 나에게 굉장히 fit해보였다. </li>
<li>한학기동안 제대로된 프로젝트로 포폴 쌓기</li>
<li>우수 수료생은 HDC LABS 서류 면제</li>
</ul>
<p>그렇지만 주변에서 들어본 SAFFY, Naver 등 유명한 부트캠프도 아니었고 뭐가 뭔지 하나도 몰라 고민을 했지만..
일단 시간과 기회가 있으니 일단 GO . 유명한 부트캠프들은 코딩테스트 준비한다고 고민만 하다가 지원도 못했을 것 같다. 어차피 해야하는 휴학. 시간을 그냥 흘려보내기보단 하길 잘 한 것 같다.</p>
<p><img src="https://velog.velcdn.com/images/y-hyun2/post/bfb80b21-054f-427d-b04d-1ba9f2ab29cc/image.jpg" alt="">
power  개발자를 꿈꾸며 ..</p>
<hr>
<h2 id="☺︎-week1--현직자-특강">☺︎ week1 : 현직자 특강</h2>
<p>25.08.26 Tue - 부트캠프 시작
week1은 무려 5일동안 현직자 특강으로 진행되었다.
HDC LABS AI LAB의 NLP, CV, DS 파트의 현직자 분들이 오셔서 각 분야에 대해 강의를 해주셨다.</p>
<h3 id="✔︎-nlp-aiot-음성-챗봇-만들기">✔︎ NLP [AIoT 음성 챗봇 만들기]</h3>
<p>🌐 <strong>실습도구</strong></p>
<ul>
<li>STT : <code>Whisper model</code> 다운받아 실행 [edge Layer]</li>
<li>LLM: <code>Groq</code> 클라우드 서비스 (API 사용) [Cloud Layer]</li>
<li>TTS: <code>Edge-TTS</code> [Cloud Layer]</li>
</ul>
<p>🌐 <strong>Edge-Cloud 분산 아키텍처</strong></p>
<pre><code>- Edge Layer: 데이터 발생지점에서 처리
    → 빅스비/시리 같은 Wake Word감지 (항상 대기: 전력 소모가 심함.. )
    → 장점: 빠른 응답, 네트워크 독립
- Cloud Layer:  중앙서버/데이터 센터를 이용
    → 클라우드에서 처리된 결과를 다시 edge로 전달
    → 장점: 강력한 AI, 최신 정보, 복잡한 추론  </code></pre><p>🔄 <strong>음성챗봇 처리 파이프라인</strong></p>
<p><code>👤 사용자 음성 → 🎤 STT → 🧠 LLM → 🔊 TTS → 🔈 AI 음성</code></p>
<hr>
<h4 id="1-sst-기술-심화-whisper-중심">1. SST 기술 심화 [Whisper 중심]</h4>
<p><code>STT</code></p>
<ul>
<li>기술: Transformer</li>
<li>특징: 다국어 지원</li>
<li>대표 사례: Whisper, Wav2Vec</li>
</ul>
<p>🏗️ 모델 구조</p>
<pre><code>📊 Audio Input (16kHz)
    ⬇️
🔄 Mel-Spectrogram 변환
    ⬇️  
🧠 Encoder (음성 특징 추출)
    ⬇️
🧠 Decoder (텍스트 생성)
    ⬇️
📝 Text Output (UTF-8)</code></pre><p>📊 모델 크기별 특성</p>
<table>
<thead>
<tr>
<th>모델</th>
<th>크기</th>
<th>처리속도</th>
<th>정확도</th>
<th>💡 <strong>용도</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>tiny</strong></td>
<td>39MB</td>
<td>⚡⚡⚡</td>
<td>80%</td>
<td>실시간 서비스</td>
</tr>
<tr>
<td><strong>base</strong></td>
<td>74MB</td>
<td>⚡⚡</td>
<td>85%</td>
<td>🎓 <strong>교육용 적합</strong></td>
</tr>
<tr>
<td><strong>small</strong></td>
<td>244MB</td>
<td>⚡</td>
<td>90%</td>
<td>일반 앱</td>
</tr>
<tr>
<td><strong>large</strong></td>
<td>1.55GB</td>
<td>🐌</td>
<td>95%</td>
<td>고정밀 서비스</td>
</tr>
</tbody></table>
<p>🆚 주요 STT 기술 비교</p>
<table>
<thead>
<tr>
<th>기술</th>
<th>장점</th>
<th>단점</th>
<th>비용</th>
</tr>
</thead>
<tbody><tr>
<td>🚀 Whisper</td>
<td>✅ 99개 언어<br/>✅ 오픈소스<br/>✅ 노이즈 강건성</td>
<td>❌ 실시간 제한<br/>❌ GPU 필요</td>
<td>🆓 무료</td>
</tr>
<tr>
<td>🌐 Google Cloud STT</td>
<td>✅ 실시간 스트리밍<br/>✅ 높은 정확도<br/>✅ 한국어 우수</td>
<td>❌ 인터넷 필수<br/>❌ 벤더 종속</td>
<td>💰 $0.006/분</td>
</tr>
<tr>
<td>🇰🇷 네이버 클로바</td>
<td>✅ 한국어 특화<br/>✅ 방언 지원<br/>✅ 데이터 주권</td>
<td>❌ 다국어 제한<br/>❌ 글로벌 확장성</td>
<td>💰 유료</td>
</tr>
<tr>
<td>🔒 Mozilla DeepSpeech</td>
<td>✅ 완전 오픈소스<br/>✅ 프라이버시<br/>✅ 로컬 처리</td>
<td>❌ 낮은 정확도<br/>❌ 한국어 제한</td>
<td>🆓 무료</td>
</tr>
</tbody></table>
<p>→ 무료로 사용: Whisper
→ 한국어로 높은 정확도: 네이버 클로바 
사용하는 게 좋을 듯하죠?</p>
<h4 id="2-llm-기술-심화---groq-중심">2. LLM 기술 심화 - Groq 중심</h4>
<table>
<thead>
<tr>
<th>플랫폼</th>
<th>처리속도</th>
<th>토큰/초</th>
<th>지연시간</th>
<th>🎯 <strong>특징</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>⚡ Groq</strong></td>
<td>최고속</td>
<td>500-1000</td>
<td>0.1초</td>
<td><strong>실시간 대화 최적</strong></td>
</tr>
<tr>
<td>🤖 OpenAI</td>
<td>보통</td>
<td>50-100</td>
<td>1-2초</td>
<td>높은 성능</td>
</tr>
<tr>
<td>🎭 Anthropic</td>
<td>느림</td>
<td>30-80</td>
<td>2-3초</td>
<td>안전성 우수</td>
</tr>
<tr>
<td>🌐 Google Gemini</td>
<td>보통</td>
<td>100-200</td>
<td>1초</td>
<td>멀티모달</td>
</tr>
</tbody></table>
<p><strong>Groq</strong> = 클라우드 서비스, AI 모델 추론에서 초고속 연산을 지원하는 하드웨어 및 소프트웨어 솔루션을 제공하는 기업과 그 기술을 가르킴. GPU 대안으로 주목받고 있음. (LPU라는 자체 아키텍처를 사용, GPU 대신 낮은 전력 소모로 에너지 효율이 높음)</p>
<pre><code>→ GPU 없이 사용 가능, 로컬 환경(또는 Colab CPU 런타임)에서 API 호출만 하면 됨. 
모델 연산은 Groq 서버에서 수행하므로 컴퓨터 성능과는 무관</code></pre><p><strong>🏗️ LPU 기술</strong></p>
<blockquote>
<p>LPU (Language Processing Unit)</p>
<p>GPU 대비 <strong>10배 빠른</strong> 토큰 생성 속도</p>
<p>초당 500-1000 토큰 생성 가능</p>
</blockquote>
<h4 id="3-tts-기술-심화---edge-tts-중심">3. TTS 기술 심화 - Edge TTS 중심</h4>
<p><code>TTS</code></p>
<ul>
<li>기술: Neural TTS</li>
<li>특징: 기존 통계 기반에 비해 사람과 구별이 어려운 목소리</li>
<li>대표 사례: Edge-TTS, ElevenLabs</li>
</ul>
<p>🆚 주요 TTS 기술 비교</p>
<table>
<thead>
<tr>
<th>TTS 서비스</th>
<th>🎵 자연도</th>
<th>🇰🇷 한국어</th>
<th>💰 비용</th>
<th>⚡ 속도</th>
<th>🎯 <strong>특화 분야</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>🔥 Edge-TTS</strong></td>
<td>⭐⭐⭐⭐</td>
<td>⭐⭐⭐⭐</td>
<td>⭐⭐⭐⭐⭐</td>
<td>⭐⭐⭐⭐</td>
<td><strong>교육/프로토타입</strong></td>
</tr>
<tr>
<td>🎭 <strong>ElevenLabs</strong></td>
<td>⭐⭐⭐⭐⭐</td>
<td>⭐⭐</td>
<td>⭐⭐</td>
<td>⭐⭐⭐</td>
<td><strong>음성 복제, 콘텐츠</strong></td>
</tr>
<tr>
<td>🌐 <strong>Google Cloud TTS</strong></td>
<td>⭐⭐⭐⭐</td>
<td>⭐⭐⭐⭐</td>
<td>⭐⭐⭐</td>
<td>⭐⭐⭐⭐</td>
<td><strong>기업 서비스</strong></td>
</tr>
<tr>
<td>📦 <strong>AWS Polly</strong></td>
<td>⭐⭐⭐⭐</td>
<td>⭐⭐⭐</td>
<td>⭐⭐⭐</td>
<td>⭐⭐⭐⭐</td>
<td><strong>뉴스, 비즈니스</strong></td>
</tr>
<tr>
<td>🇰🇷 <strong>클로바 Voice</strong></td>
<td>⭐⭐⭐⭐</td>
<td>⭐⭐⭐⭐⭐</td>
<td>⭐⭐⭐</td>
<td>⭐⭐⭐</td>
<td><strong>한국어 전용</strong></td>
</tr>
<tr>
<td>🎬 <strong>TYPECAST</strong></td>
<td>⭐⭐⭐⭐⭐</td>
<td>⭐⭐⭐⭐</td>
<td>⭐⭐</td>
<td>⭐⭐⭐</td>
<td><strong>더빙, 콘텐츠 제작</strong></td>
</tr>
</tbody></table>
<p>→ ElevenLabs가 가장 자연스럽지만 비용문제로, 상업적 품질을 무료로 제공하는 Edge-TTS를 많이 사용</p>
<hr>
<p>** 🚀 지연시간 최소화**</p>
<table>
<thead>
<tr>
<th>방식</th>
<th>순차 처리 (기본)</th>
<th>병렬 처리 (최적화)</th>
</tr>
</thead>
<tbody><tr>
<td><strong>처리 방식</strong></td>
<td>STT → LLM → TTS</td>
<td>STT + LLM 동시 시작</td>
</tr>
<tr>
<td><strong>총 시간</strong></td>
<td>6초 (3+2+1)</td>
<td><strong>3-4초</strong></td>
</tr>
<tr>
<td><strong>개선율</strong></td>
<td>기준</td>
<td><strong>40% 단축</strong></td>
</tr>
</tbody></table>
<p><strong>🎯 (실제 구현시) 비용 절감 전략</strong></p>
<blockquote>
<p>📦 캐싱 활용</p>
<p>자주 묻는 질문 → 미리 생성된 응답 사용</p>
</blockquote>
<blockquote>
<p>🎚️ 모델 선택</p>
<p>간단한 질문 → 작은 모델</p>
<p>복잡한 질문 → 큰 모델</p>
</blockquote>
<hr>
<h3 id="✔︎-aiml-기본-지식">✔︎ AI/ML 기본 지식</h3>
<h4 id="📌-ai--머신러닝--딥러닝">📌 AI &gt; 머신러닝 &gt; 딥러닝</h4>
<ul>
<li><strong>머신러닝 (ML)</strong>  <ul>
<li>정형 데이터 기반, 패턴 탐색 (예: 온습도 센서, 서버 로그 등)  </li>
</ul>
</li>
<li><strong>딥러닝 (DL)</strong>  <ul>
<li>비정형 데이터(이미지, 텍스트) 처리  </li>
<li>GPU 필요, 학습 시간 길다  </li>
</ul>
</li>
<li>머신러닝은 <strong>블랙박스</strong> 성격 → 전적으로 맡기기엔 위험  </li>
</ul>
<h4 id="⚙️-모델링-프로세스">⚙️ 모델링 프로세스</h4>
<ol>
<li>문제 정의  </li>
<li>데이터 수집  </li>
<li>데이터 탐색  <ul>
<li>분포 확인  </li>
<li>이상치/결측치 처리  </li>
<li>변수 간 상관성 확인  </li>
</ul>
</li>
<li>데이터 전처리  <ul>
<li>결측값 처리, 데이터 통합  </li>
<li>원핫인코딩  </li>
<li>비정형 데이터 행렬 변환 등  </li>
</ul>
</li>
<li>모델링  <ul>
<li>모델 선택, 하이퍼파라미터 설정, 학습  </li>
</ul>
</li>
<li>모델 평가  <ul>
<li>Precision, Recall, Accuracy, F1 Score 등  </li>
</ul>
</li>
</ol>
<p>🔄 <strong>피드백 루프</strong>: 평가 → 전처리 → 모델링 반복  </p>
<h4 id="💡-주요-개념">💡 주요 개념</h4>
<ul>
<li><strong>Chain of Thought</strong>: 모델이 추론 과정을 단계적으로 설명하도록 유도  </li>
<li><strong>Few-shot Learning</strong>: 예시 기반 학습  </li>
<li><strong>Prompt Engineering</strong>: 프롬프트 설계 중요  </li>
<li><strong>Fine-tuning</strong>: LORA 등 경량화 방식 활용  </li>
<li><strong>RAG (Retrieval-Augmented Generation)</strong>: 벡터 검색 기반 지식 활용  </li>
</ul>
<hr>
<h3 id="☁️-느낀점">☁️ 느낀점</h3>
<p>NLP, CV, LLM, DS .. 그냥 뭉뚱그려 <code>데이터</code> 라고만 알고 있던 내게 세분화하여 정리될 수 있는 아주 유익한 시간이었다.</p>
<p>학부 때 주변에서 사용하라고 권해서 뭔지도 제대로 모르고 써봤던 Hugging Face, Kaggle, Dacon 등 데이터 공유 플랫폼이나 RAG, LoRA 등의 기법들에 대해 거시적인 개념들을 잡을 수 있어서 좋았다.
그리고 바이브 코딩의 도구들 Cursor, claude code. 처음들어보는데 점점 IT 지식이 늘어가는 것 같아 즐거웠음~..
특히, DAY3에 NLP 파트에서 오신 현직자 분의 특강이 가장 유익했다. 작년에 데이콘 AI 경진대회에서 뭔지도 모르고 사용했던 STT, TTS 모델들의 종류들도 명확히 알게 되었고, 프로젝트 진행 시 주요 모델들의 선택 기준(?)을 정리해서 알려주셔서 재밌었다.
(뭐가 뭔지도 모르고 일단 GPT가 쓰라는 대로 사용하다가, 모델들의 개념, 장단점 및 활용 방안을 알게 되어서 좋았달까..)</p>
]]></description>
        </item>
    </channel>
</rss>