<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>rokmc1257_lse.log</title>
        <link>https://velog.io/</link>
        <description>이상억</description>
        <lastBuildDate>Tue, 18 Mar 2025 08:49:10 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. rokmc1257_lse.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/rokmc1257_lse" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[LoRa 이론]]></title>
            <link>https://velog.io/@rokmc1257_lse/LoRA-%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-AI-%ED%8C%8C%EC%9D%B8%ED%8A%9C%EB%8B%9D%EC%9D%98-%ED%98%81%EC%8B%A0</link>
            <guid>https://velog.io/@rokmc1257_lse/LoRA-%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-AI-%ED%8C%8C%EC%9D%B8%ED%8A%9C%EB%8B%9D%EC%9D%98-%ED%98%81%EC%8B%A0</guid>
            <pubDate>Tue, 18 Mar 2025 08:49:10 GMT</pubDate>
            <description><![CDATA[<h2 id="1-lora의-기본-개념과-원리">1. LoRA의 기본 개념과 원리</h2>
<h3 id="기본-개념">기본 개념</h3>
<ul>
<li>Low-Rank Adaptation: LoRA는 이름 그대로 기존 모델의 가중치를 수정하지 않고, 그 업데이트 분을 저차원(저랭크) 행렬 두 개의 곱으로 표현.</li>
<li>가중치 고정: 사전학습된 거대 모델의 파라미터 대부분을 동결(freeze)해 두고, 필요한 부분에만 추가적인 학습 가능한 파라미터(저랭크 행렬)를 도입.</li>
</ul>
<h3 id="동작-원리">동작 원리</h3>
<ul>
<li>기존 모델의 특정 레이어 가중치 $W$ 대신,
$$
W&#39; = W + \Delta W , \Delta W = W_A \times W_B
$$</li>
</ul>
<p>와 같이 표현.</p>
<ul>
<li><p>$W_A$와 $W_B$는 출력 차원x랭크, 랭크x입력 차원의 행렬</p>
</li>
<li><p>학습 과정에서 $W$는 고정하고 $W_A$와 $W_B$만 업데이트 함</p>
</li>
<li><p>이를 통해 전체 파라미터 대비 매우 적은 수의 파라미터만 학습하게 되어, 메모리 사용량과 계산 비용을 크게 줄일 수 있음.</p>
</li>
</ul>
<hr>
<h2 id="2-기존-파인튜닝-기법과의-비교">2. 기존 파인튜닝 기법과의 비교</h2>
<h3 id="기존-파인튜닝-기법">기존 파인튜닝 기법</h3>
<ul>
<li><p>전체 파인튜닝 (Full Fine-Tuning): 모델의 모든 가중치를 업데이트하여 작업별로 최적화.</p>
<ul>
<li>장점: 모델 전반에 걸친 섬세한 조정 가능.</li>
<li>단점: 매개변수 수가 많아 메모리와 연산 비용이 크게 소모됨.</li>
</ul>
</li>
<li><p>어댑터(Adapters) 기반 미세조정: 각 레이어에 소규모 모듈을 추가해 파인튜닝.</p>
<ul>
<li>장점: 전체 파라미터 업데이트보다 효율적.</li>
<li>단점: 추론 시 추가 모듈을 통과해야 하므로 약간의 지연 발생.</li>
</ul>
</li>
</ul>
<h3 id="lora의-장점">LoRA의 장점</h3>
<ul>
<li><p><strong>매우 적은 추가 파라미터</strong></p>
<ul>
<li>전체 모델에 비해 0.1%~2% 수준의 파라미터만 업데이트하면 되므로 메모리와 연산 비용이 대폭 줄어듦</li>
</ul>
</li>
<li><p><strong>빠른 학습 속도</strong></p>
<ul>
<li>대부분의 가중치는 고정된 상태로, gradient 계산 부담이 줄어들어 학습 속도가 향상 됨</li>
</ul>
</li>
<li><p><strong>성능 유지 및 개선</strong></p>
<ul>
<li>불필요한 가중치 변경을 줄여 사전학습된 지식을 보존하며, 일부 작업에서는 전체 파인튜닝과 동등하거나 더 나은 성능을 보임</li>
</ul>
</li>
<li><p><strong>추론 오버헤드 최소화</strong></p>
<ul>
<li>학습 완료 후 추가 모듈을 모델 가중치에 병합(merge)할 수 있어, 추론 시 별도의 추가 연산 없이 기존 모델과 동일하게 동작</li>
</ul>
</li>
<li><p><strong>유연한 확장성</strong></p>
<ul>
<li>여러 작업에 대해 동일한 기반 모델을 공유하며, 작업별로 저장된 LoRA 모듈만 교체하여 쉽게 전환할 수 있음</li>
</ul>
</li>
</ul>
<hr>
<h2 id="3-실제-적용-사례-및-성능-비교">3. 실제 적용 사례 및 성능 비교</h2>
<h3 id="대규모-언어-모델-파인튜닝">대규모 언어 모델 파인튜닝</h3>
<p><strong>Stanford Alpaca</strong> </p>
<ul>
<li>Meta의 LLaMA 7B 모델을 기반으로 사용자 지시문에 따라 응답을 생성하는 Alpaca 모델은, LoRA를 활용해 단 하나의 GPU로 몇 시간 내에 미세조정되었음. 결과적으로, 오리지널 Alpaca와 유사한 출력 품질을 보임.</li>
</ul>
<p><strong>GPT-3 175B 실험</strong> </p>
<ul>
<li>전체 파인튜닝에 비해 LoRA를 적용한 모델은 학습 파라미터가 약 0.3% 수준에 머무르면서도 WikiSQL, 자연어추론(NLI), 대화 요약 등 여러 벤치마크에서 동등하거나 소폭 개선된 성능을 기록.</li>
</ul>
<p><strong>이미지 생성 모델</strong></p>
<ul>
<li>Stable Diffusion: 텍스트-이미지 모델인 Stable Diffusion에도 LoRA가 적용되어, 특정 화풍이나 캐릭터를 소수의 데이터만으로 빠르게 학습시킬 수 있음. 전체 모델을 부분 미세조정하는 방식에 비해, 훨씬 빠르고 가벼운 파인튜닝이 가능해짐.</li>
<li>커뮤니티에서는 다양한 스타일이나 도메인에 특화된 LoRA 모듈이 공유되고 있으며, 기존 모델에 손쉽게 병합하여 새로운 이미지 생성 능력을 부여하는 사례가 늘어나고 있음.</li>
</ul>
<h3 id="성능-비교-요약">성능 비교 요약</h3>
<ul>
<li><p>파라미터 효율성</p>
<ul>
<li>LoRA는 전체 파인튜닝 대비 극소수의 파라미터만 업데이트하면서도, 모델 성능에서 큰 손실 없이 동등하거나 오히려 개선된 결과를 도출.</li>
</ul>
</li>
<li><p>학습 및 추론 속도</p>
<ul>
<li>적은 학습 파라미터 덕분에 학습 속도가 빠르고, 추론 시 추가 연산 부담 없이 기존 모델과 동일한 처리 속도를 유지할 수 있음.</li>
</ul>
</li>
<li><p>실제 활용도 </p>
<ul>
<li>대규모 언어 모델, 이미지 생성 모델 등 다양한 분야에서 실제 적용되며, 비용 효율성과 운영상의 편리함을 입증받고 있음.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Docker 3편] - 포트 매핑부터 컨테이너 관리까지]]></title>
            <link>https://velog.io/@rokmc1257_lse/Docker-3%ED%8E%B8-%ED%8F%AC%ED%8A%B8-%EB%A7%A4%ED%95%91%EB%B6%80%ED%84%B0-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EA%B4%80%EB%A6%AC%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@rokmc1257_lse/Docker-3%ED%8E%B8-%ED%8F%AC%ED%8A%B8-%EB%A7%A4%ED%95%91%EB%B6%80%ED%84%B0-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EA%B4%80%EB%A6%AC%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Tue, 18 Mar 2025 06:46:56 GMT</pubDate>
            <description><![CDATA[<h2 id="1-포트-매핑과-옵션-차이--p-vs--p">1. 포트 매핑과 옵션 차이 (-p vs -P)</h2>
<ul>
<li><p>Docker 컨테이너는 기본적으로 외부 네트워크와 격리되어 실행되지만, 포트 매핑을 통해 호스트와 통신할 수 있음.</p>
</li>
<li><p>두 가지 옵션이 있는데, 그 차이는 다음과 같음.</p>
</li>
</ul>
<h4 id="-p-옵션">-p 옵션</h4>
<ul>
<li>형식: -p 호스트포트:컨테이너포트</li>
<li>특징: 원하는 포트를 직접 지정해서 매핑할 수 있음</li>
<li><em>예시:*</em><pre><code class="language-bash"># nginx 컨테이너의 기본 포트(80)를 호스트의 8080 포트에 매핑하여 실행
docker run --rm -d -p 8080:80 --name mynginx nginx</code></pre>
</li>
<li>이제 브라우저에서 <a href="http://localhost:8080%EC%9C%BC%EB%A1%9C">http://localhost:8080으로</a> 접근하면 nginx 서비스에 연결됨.</li>
</ul>
<h4 id="-p-옵션-1">-P 옵션</h4>
<ul>
<li>설명: 컨테이너 내에서 노출된 모든 포트를 Docker가 임의의 호스트 포트에 자동으로 매핑함</li>
<li><em>예시:*</em><pre><code class="language-bash"></code></pre>
</li>
</ul>
<h1 id="모든-노출된-포트를-임의의-포트로-매핑하여-실행">모든 노출된 포트를 임의의 포트로 매핑하여 실행</h1>
<p>docker run --rm -d -P --name auto_nginx nginx</p>
<pre><code>- 실행 후 docker ps 명령어로 실제 매핑된 호스트 포트를 확인할 수 있음.
- 포인트: 외부에서 컨테이너 서비스(예: 웹서버)에 접근하려면 반드시 포트 매핑을 설정해야 함

-----

## 2. 컨테이너 정보 확인 (docker inspect)
- docker inspect 명령어를 사용하면 컨테이너의 상세 정보를 JSON 형식으로 확인할 수 있음.
- 여기엔 컨테이너 ID, 이름, 네트워크 설정(예: IP 주소, 포트 매핑), 바인드 마운트 정보, 환경 변수 등 다양한 정보가 포함.

**사용법**
```bash
docker run --rm -d --name mynginx nginx
docker inspect mynginx  # 전체 정보 출력</code></pre><ul>
<li>특정 정보(예: IP 주소)만 보고 싶을 땐 grep 또는 --format 옵션을 활용할 수 있음.</li>
</ul>
<pre><code class="language-bash">docker inspect mynginx | grep &#39;&quot;IPAddress&quot;&#39;</code></pre>
<hr>
<h2 id="3-컨테이너-간-통신">3. 컨테이너 간 통신</h2>
<ul>
<li><p>기본적으로 Docker 컨테이너들은 같은 브릿지 네트워크에 연결되어 있어 서로 제약 없이 통신할 수 있음.</p>
</li>
<li><p>각 컨테이너는 고유한 IP 주소를 할당받으며, 컨테이너 이름이나 IP 주소를 통해 통신할 수 있음.</p>
</li>
<li><p>보안이 필요한 경우에는 사용자 정의 네트워크를 생성하여 컨테이너들을 격리할 수 있음.</p>
</li>
</ul>
<p><strong>실습 예시</strong></p>
<h4 id="1-my-nginx-1-컨테이너-띄우기">1. my-nginx-1 컨테이너 띄우기</h4>
<pre><code class="language-bash">docker run --rm -d --name my-nginx-1 nginx
docker inspect my-nginx-1 | grep &#39;&quot;IPAddress&quot;&#39;</code></pre>
<ul>
<li>보통 172.17.0.2 정도의 IP가 할당됨.</li>
</ul>
<h4 id="2-nginx-2-컨테이너에서-my-nginx-1에-접속하기">2. nginx-2 컨테이너에서 my-nginx-1에 접속하기</h4>
<pre><code class="language-bash">docker run --rm -it --name nginx-2 nginx bash
# 컨테이너 내부에서
apt update &amp;&amp; apt install -y wget
wget http://172.17.0.2/index.html
cat index.html</code></pre>
<hr>
<h2 id="4-docker-exec로-컨테이너-내부-작업">4. docker exec로 컨테이너 내부 작업</h2>
<ul>
<li>실행 중인 컨테이너에 추가 명령어를 실행하고 싶을 때 docker exec를 사용.</li>
<li>예를 들어, nginx 컨테이너의 웹루트 디렉토리를 확인하거나 파일을 찾아볼 때 유용함.</li>
</ul>
<pre><code>bash
# my-nginx-1 컨테이너 띄우기
docker run --rm -d --name my-nginx-1 nginx

# 컨테이너 내부에 bash 접속
docker exec -it my-nginx-1 bash

# nginx 웹루트 디렉토리(일반적으로 /usr/share/nginx/html) 내 index.html 찾기
find / -name index.html 2&gt;/dev/null</code></pre><ul>
<li>또한, locate 명령어를 사용하려면 패키지 설치와 데이터베이스 업데이트가 필요.</li>
</ul>
<pre><code class="language-bash">apt update &amp;&amp; apt install -y mlocate
updatedb
locate index.html</code></pre>
<hr>
<h2 id="5-웹루트-디렉토리에-파일-추가하기-docker-exec-활용">5. 웹루트 디렉토리에 파일 추가하기 (docker exec 활용)</h2>
<ul>
<li>nginx의 기본 웹루트 디렉토리는 /usr/share/nginx/html.</li>
<li>여기에 파일을 추가하면 외부에서 바로 접근할 수 있음.</li>
</ul>
<p>*<em>예시
*</em></p>
<pre><code class="language-bash">
# my-nginx-1 컨테이너 띄우기 (포트 매핑 포함)
docker run --rm -d -p 8080:80 --name my-nginx-1 nginx

# 컨테이너 내부로 들어가기
docker exec -it my-nginx-1 bash

# 웹루트 디렉토리 확인
locate index.html   # 보통 /usr/share/nginx/html 경로가 나옴

# sub.html 파일 추가
echo &quot;&lt;h1&gt;Hello Devs&lt;/h1&gt;&quot; &gt; /usr/share/nginx/html/sub.html</code></pre>
<ul>
<li>브라우저에서 <a href="http://localhost:8080/sub.html%EB%A1%9C">http://localhost:8080/sub.html로</a> 확인하면 추가한 파일이 보일 것 임.</li>
</ul>
<hr>
<h2 id="6-docker-cp로-호스트와-컨테이너-간-파일-복사">6. docker cp로 호스트와 컨테이너 간 파일 복사</h2>
<ul>
<li>docker cp 명령어를 사용하면 컨테이너 내부에 직접 접속하지 않고도 파일을 전송할 수 있음.</li>
</ul>
<p><strong>명령어 형식</strong></p>
<ul>
<li>호스트 → 컨테이너<pre><code class="language-bash">docker cp 호스트경로 컨테이너명:컨테이너경로</code></pre>
</li>
<li>컨테이너 → 호스트<pre><code class="language-bash">docker cp 컨테이너명:컨테이너경로 호스트경로</code></pre>
</li>
</ul>
<p><strong>실습 예시</strong></p>
<pre><code class="language-bash">
# my-nginx-1 컨테이너 띄우기
docker run --rm -d -p 8080:80 --name my-nginx-1 nginx

# 호스트에서 파일 생성
echo &quot;&lt;h1&gt;Hello from docker cp&lt;/h1&gt;&quot; &gt; sub.html

# 호스트에서 컨테이너로 파일 복사
docker cp sub.html my-nginx-1:/usr/share/nginx/html/

# 파일 복사가 완료되면 호스트에서 파일 삭제 (원본 정리)
rm sub.html

# 컨테이너 내부에서 파일 존재 확인
docker exec -it my-nginx-1 bash -c &quot;ls /usr/share/nginx/html&quot;</code></pre>
<hr>
<h2 id="7-바인드-마운트를-이용한-html-파일-관리">7. 바인드 마운트를 이용한 HTML 파일 관리</h2>
<ul>
<li>개발 시 호스트의 파일을 컨테이너에 바로 반영하고 싶다면, 바인드 마운트가 아주 유용함.</li>
<li>컨테이너를 삭제해도 호스트의 파일은 유지되며, 실시간으로 변경 사항이 반영 됨.</li>
</ul>
<p>*<em>예시
*</em></p>
<pre><code class="language-bash">cd ~  # 홈 디렉토리로 이동

# 바인드 마운트를 이용해 컨테이너 실행
docker run \
  --rm \
  -d \
  -p 8080:80 \
  --name my-nginx-1 \
  -v /${PWD}/testDockerProjects/exam27/my-nginx-1/volumes/usr/share/nginx/html:/usr/share/nginx/html \
  nginx</code></pre>
<ul>
<li>호스트의 /testDockerProjects/exam27/my-nginx-1/volumes/usr/share/nginx/html 경로에 HTML 파일을 생성하거나 수정하면, 컨테이너의 /usr/share/nginx/html에 바로 반영 됨.</li>
</ul>
<p>예를 들어,</p>
<pre><code class="language-bash">
echo &quot;&lt;h1&gt;Hello Devs&lt;/h1&gt;&quot; &gt; ${PWD}/testDockerProjects/exam27/my-nginx-1/volumes/usr/share/nginx/html/sub.html</code></pre>
<ul>
<li>이후 브라우저에서 <a href="http://localhost:8080/sub.html%EB%A1%9C">http://localhost:8080/sub.html로</a> 접속하면 변경된 내용을 확인할 수 있음.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Docker 2편] - 엔트리포인트, 컨테이너 실행 & 관리, 로그, 종료/삭제]]></title>
            <link>https://velog.io/@rokmc1257_lse/Docker-2%ED%8E%B8-%EC%97%94%ED%8A%B8%EB%A6%AC%ED%8F%AC%EC%9D%B8%ED%8A%B8-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EC%8B%A4%ED%96%89-%EA%B4%80%EB%A6%AC-%EB%A1%9C%EA%B7%B8-%EC%A2%85%EB%A3%8C%EC%82%AD%EC%A0%9C</link>
            <guid>https://velog.io/@rokmc1257_lse/Docker-2%ED%8E%B8-%EC%97%94%ED%8A%B8%EB%A6%AC%ED%8F%AC%EC%9D%B8%ED%8A%B8-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%EC%8B%A4%ED%96%89-%EA%B4%80%EB%A6%AC-%EB%A1%9C%EA%B7%B8-%EC%A2%85%EB%A3%8C%EC%82%AD%EC%A0%9C</guid>
            <pubDate>Mon, 17 Mar 2025 06:44:22 GMT</pubDate>
            <description><![CDATA[<h2 id="1-엔트리포인트entrypoint-재지정">1. 엔트리포인트(Entrypoint) 재지정</h2>
<ul>
<li>엔트리포인트: 컨테이너가 실행될 때 맨 처음 실행되는 스크립트/프로그램</li>
<li>Nginx 등의 공식 이미지는 docker-entrypoint.sh 같은 스크립트가 엔트리포인트로 등록되어 있음</li>
<li>재지정하기<pre><code class="language-bash"></code></pre>
</li>
</ul>
<h1 id="ls-명령어로-엔트리포인트-교체">ls 명령어로 엔트리포인트 교체</h1>
<p>docker run --entrypoint ls nginx</p>
<pre><code>- 복잡한 명령어를 전달할 때
```bash

# entrypoint로 bash를 지정 후, 그 뒤에 -c &quot;ls -al&quot; 전달
docker run --entrypoint bash nginx -c &quot;ls -al&quot;</code></pre><hr>
<h2 id="2-인터랙티브-옵션-it">2. 인터랙티브 옵션(-it)</h2>
<ul>
<li>-it → -i(표준 입력 연결) + -t(TTY 할당)<pre><code class="language-bash">docker run -it --entrypoint bash nginx
컨테이너 내부 쉘에서 작업 후 exit로 빠져나올 수 있음.</code></pre>
</li>
</ul>
<hr>
<h2 id="3-도커-이미지-정보-확인">3. 도커 이미지 정보 확인</h2>
<pre><code class="language-bash">
docker inspect nginx
docker inspect nginx | grep -A 1 &#39;&quot;Entrypoint&quot;&#39;
docker inspect nginx | grep -A 4 &#39;&quot;Cmd&quot;&#39;</code></pre>
<ul>
<li>도커 엔트리포인트와 명령어(Cmd)가 어떻게 설정되어 있는지 확인 가능</li>
</ul>
<hr>
<h2 id="4-docker-entrypointsh-의-동작-방식">4. docker-entrypoint.sh 의 동작 방식</h2>
<ul>
<li>컨테이너 실행 전 docker-entrypoint.d 폴더 내 .envsh, .sh 등을 실행해주는 스크립트</li>
<li>결국 exec &quot;$@&quot; 구문으로 최종 명령어(예: nginx -g &quot;daemon off;&quot;)를 실행</li>
<li>이를 통해 컨테이너 초기화 작업(환경변수 로드, 설정 파일 수정 등)을 수행할 수 있음</li>
</ul>
<hr>
<h2 id="5-컨테이너-실행-시-최종적으로-어떤-명령어가-실행되는가">5. 컨테이너 실행 시 최종적으로 어떤 명령어가 실행되는가?</h2>
<ul>
<li>예) docker run nginx → 실제로 내부에서는 ./docker-entrypoint.sh &quot;nginx&quot; &quot;-g&quot; &quot;daemon off;&quot; 가 동작</li>
<li>docker run nginx ls -al → 내부적으로는 ./docker-entrypoint.sh &quot;ls&quot; &quot;-al&quot;이 실행되어 결과를 출력 후 종료</li>
</ul>
<hr>
<h2 id="6-컨테이너-실행-후-자동-삭제--rm">6. 컨테이너 실행 후 자동 삭제(--rm)</h2>
<ul>
<li>컨테이너가 종료되면 컨테이너 정보가 자동 제거됨<pre><code class="language-bash"></code></pre>
</li>
</ul>
<p>docker run --rm hello-world</p>
<pre><code>- 단, 디버깅을 위해 종료 후 상태를 살펴봐야 한다면 --rm 없이 실행하는 편이 좋음

----


## 7. Detach 모드(-d 옵션)와 컨테이너 중지(docker stop)
- -d 옵션으로 백그라운드(Detach) 실행
```bash

docker run -d nginx
docker ps    # 컨테이너 동작 중
docker logs [컨테이너 ID or 이름]</code></pre><ul>
<li>컨테이너 중지<pre><code class="language-bash"></code></pre>
</li>
</ul>
<p>docker stop [컨테이너 ID or 이름]</p>
<pre><code>
---
## 8. docker logs와 --name 옵션
- 컨테이너에 이름을 부여하고 싶다면 --name 사용
```bash

docker run --rm -d --name mynginx nginx</code></pre><ul>
<li>로그 확인<pre><code class="language-bash"></code></pre>
</li>
</ul>
<p>docker logs mynginx       # 실행된 로그 조회
docker logs -f mynginx    # 실시간 모니터링
docker logs --timestamps mynginx</p>
<pre><code>
--- 

## 9. 중지된 컨테이너 재시작(docker start)와 -a 옵션
- 기본 재시작 (출력이 바로 붙지 않음)
```bash

docker start [컨테이너 이름 or ID]</code></pre><ul>
<li>a 옵션으로 재시작 시, 바로 attach 모드로 실행<pre><code class="language-bash"></code></pre>
</li>
</ul>
<p>docker start -a [컨테이너 이름 or ID]</p>
<pre><code>- hello-world 같이 실행 후 종료되는 컨테이너는 재시작 시 -a를 붙이면 메시지를 확인할 수 있음

---- 
## 10. 컨테이너 종료(docker stop/kill)와 삭제(rm -f)
- docker stop: SIGTERM → 정상 종료, 일정 시간 후 SIGKILL
- docker kill: 즉시 SIGKILL → 강제 종료
- docker rm -f: 실행 중인 컨테이너도 즉시 종료 + 삭제
```bash

docker stop mycontainer
docker kill mycontainer
docker rm -f mycontainer</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Docker 1편] - 설치, 필요성, 기본 개념 및 이미지/컨테이너 기초]]></title>
            <link>https://velog.io/@rokmc1257_lse/Docker</link>
            <guid>https://velog.io/@rokmc1257_lse/Docker</guid>
            <pubDate>Mon, 17 Mar 2025 06:19:30 GMT</pubDate>
            <description><![CDATA[<h2 id="1-도커-설치">1. 도커 설치</h2>
<h3 id="도커-가입-및-docker-desktop-설치">도커 가입 및 Docker Desktop 설치</h3>
<ul>
<li>도커 공식 홈페이지에서 가입 후 Docker Desktop 다운로드</li>
<li>Mac 사용자는 인텔칩(amd64)과 애플칩(ARM) 구분해서 다운로드<h3 id="bios-가상화-관련-참고">BIOS 가상화 관련 참고</h3>
</li>
<li>CPU 모델(AMD/Intel)에 따라 BIOS에서 가상화 설정을 켜야 할 수 있음</li>
</ul>
<h3 id="설치-확인-명령어">설치 확인 명령어</h3>
<pre><code class="language-bash">docker run hello-world</code></pre>
<ul>
<li>정상이라면 “Hello from Docker!”가 출력됩니다.</li>
</ul>
<hr>
<h2 id="2-도커를-사용하는-이유-의존성-충돌-해결">2. 도커를 사용하는 이유 (의존성 충돌 해결)</h2>
<p>도커 컨테이너를 사용하면, 프로젝트마다 격리된 환경을 제공하여 의존성 충돌 문제를 효율적으로 해결할 수 있음.</p>
<ul>
<li>예) Python 2.7과 3.x를 동시에 사용하거나, 프로젝트별로 서로 다른 라이브러리 버전이 필요한 경우</li>
<li>도커는 호스트 OS의 커널을 공유하면서도, 컨테이너라는 독립된 실행 환경을 제공하므로 충돌이 거의 발생하지 않음</li>
</ul>
<hr>
<h2 id="3-가상머신vm과-도커-컨테이너의-차이">3. 가상머신(VM)과 도커 컨테이너의 차이</h2>
<ul>
<li><p>가상머신(VM)</p>
<ul>
<li>호스트 OS 위에 게스트 OS 전체를 올리는 방식 → 무겁고, 성능 저하가 있음</li>
</ul>
</li>
<li><p>도커 컨테이너 </p>
<ul>
<li>호스트 OS 커널을 공유하며 필요한 부분만 가볍게 격리 → 성능저하가 거의 없음</li>
</ul>
</li>
</ul>
<p>즉, 도커 컨테이너는 “가상머신처럼 OS 전체를 올리는 대신 <strong>프로세스 단위로 격리</strong>”하기 때문에 속도도 빠르고 자원도 적게 듦.</p>
<h3 id="4-도커-환경-전체-초기화-방법">4. 도커 환경 전체 초기화 방법</h3>
<p>실습을 통째로 다시 하고 싶을 때, 아래와 같은 명령어로 도커 관련 리소스를 전부 정리할 수 있음</p>
<pre><code class="language-bash"># 1) 실습에 사용했던 외부 폴더 삭제 (예: ~/testDockerProjects)
rm -rf ~/testDockerProjects/*

# 2) 실행/중지된 모든 컨테이너 삭제
docker rm -f $(docker ps -qa)

# 3) 모든 이미지 삭제
docker rmi -f $(docker images -qa)

# 4) 사용되지 않는 네트워크 삭제
docker network prune -f

# 5) 사용되지 않는 볼륨 삭제
docker volume prune -f</code></pre>
<hr>
<h2 id="5-도커-이미지--컨테이너의-기초-개념">5. 도커 이미지 &amp; 컨테이너의 기초 개념</h2>
<ul>
<li>도커 이미지: 일종의 “프로그램 설치 파일”</li>
<li>도커 컨테이너: 이미지를 실행한 “프로세스”에 가까움</li>
</ul>
<h4 id="일반-pc-환경과의-비교표">일반 PC 환경과의 비교표:</h4>
<table>
<thead>
<tr>
<th>도커 개념</th>
<th>일반 프로그램 비교</th>
</tr>
</thead>
<tbody><tr>
<td>도커 이미지</td>
<td>프로그램(설치 파일)</td>
</tr>
<tr>
<td>도커 이미지 다운로드</td>
<td>프로그램 설치</td>
</tr>
<tr>
<td>도커 이미지 실행 → 컨테이너 생성</td>
<td>프로그램 실행 → 프로세스 생성</td>
</tr>
<tr>
<td>도커 이미지 1개</td>
<td>여러 개의 컨테이너 가능</td>
</tr>
<tr>
<td>프로그램 1개</td>
<td>여러 개의 프로세스 가능</td>
</tr>
</tbody></table>
<hr>
<h2 id="6-도커-이미지-다운로드-및-관리">6. 도커 이미지 다운로드 및 관리</h2>
<h4 id="이미지-다운로드pull">이미지 다운로드(pull)</h4>
<pre><code class="language-bash">
docker pull nginx         # 최신 버전 다운로드
docker pull nginx:1.25    # 특정 버전 다운로드</code></pre>
<h4 id="이미지-목록-확인">이미지 목록 확인</h4>
<pre><code class="language-bash">
docker images</code></pre>
<h4 id="이미지-삭제">이미지 삭제</h4>
<pre><code class="language-bash">
docker rmi nginx:1.25</code></pre>
<hr>
<h2 id="7-기본-도커-컨테이너-실행-hello-world">7. 기본 도커 컨테이너 실행 (Hello World)</h2>
<h4 id="컨테이너-실행">컨테이너 실행</h4>
<pre><code class="language-bash">docker run hello-world</code></pre>
<ul>
<li>이미지가 없다면 자동으로 pull 후 실행</li>
<li>메시지 출력 후 프로세스가 종료 → 컨테이너도 종료</li>
</ul>
<h4 id="컨테이너-목록-확인">컨테이너 목록 확인</h4>
<pre><code class="language-bash">
docker ps -a</code></pre>
<h4 id="종료된-컨테이너-삭제">종료된 컨테이너 삭제</h4>
<pre><code class="language-bash">
docker rm [컨테이너_ID]</code></pre>
<h4 id="이미지-삭제-1">이미지 삭제</h4>
<pre><code class="language-bash">
docker rmi hello-world</code></pre>
<hr>
<h2 id="8-컨테이너와-주-프로세스-개념">8. 컨테이너와 주 프로세스 개념</h2>
<ul>
<li><p>도커 컨테이너 내부에서 실행되는 “주 프로세스”가 종료되면 컨테이너도 종료 됨.</p>
<ul>
<li>docker run hello-world → Hello 출력 후 즉시 종료</li>
<li>docker run ubuntu → 주 프로세스 없이 실행되므로 바로 종료(-it 없이)</li>
<li>docker run -it ubuntu bash → bash 프로세스가 살아있는 동안 유지</li>
<li>docker run nginx → nginx 서버 프로세스는 계속 동작하므로 자동 종료 안 됨</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Elastic Search]]></title>
            <link>https://velog.io/@rokmc1257_lse/Elastic-Search</link>
            <guid>https://velog.io/@rokmc1257_lse/Elastic-Search</guid>
            <pubDate>Wed, 26 Feb 2025 05:56:54 GMT</pubDate>
            <description><![CDATA[<h2 id="엘라스틱-서치의-동작-원리-개요">엘라스틱 서치의 동작 원리 개요</h2>
<p>엘라스틱 서치는 방대한 양의 문서들 중 사용자가 입력한 검색어에 대해 빠르고 정확한 검색 결과를 제공하기 위해 두 가지 주요 단계를 지남. 이 두 단계는 검색의 성능과 정확도를 결정짓는 핵심 요소</p>
<ul>
<li>문서를 기반으로 인덱스 생성 (Indexing)</li>
<li>생성된 인덱스를 바탕으로 검색 처리 (Searching)</li>
</ul>
<hr>
<h2 id="인덱스-생성-indexing">인덱스 생성 (Indexing)</h2>
<p>인덱스는 단순히 문서의 내용을 빠르게 찾기 위한 검색용 테이블. 단순 테이블 생성이 아니라 여러 복잡한 전처리 과정을 거쳐 효율적인 검색 구조를 만드는 것을 의미.</p>
<h3 id="전처리-pre-processing">전처리 (Pre-processing)</h3>
<ul>
<li>문서 정제<ul>
<li>문서 내 불필요한 기호, HTML 태그, 특수문자 등을 제거.</li>
</ul>
</li>
</ul>
<ul>
<li><p>정규화</p>
<ul>
<li>예를 들어, 영어의 경우 대문자를 소문자로 변환하여 “Apple”과 “apple”을 동일하게 인식하게 함.</li>
</ul>
</li>
<li><p>불용어 제거:</p>
<ul>
<li>검색 시 의미 없는 단어(예: “the”, “is” 등)를 제거하여 분석 효율 향상.</li>
</ul>
</li>
</ul>
<h3 id="형태소-분석-tokenization--morphological-analysis">형태소 분석 (Tokenization &amp; Morphological Analysis)</h3>
<ul>
<li><p>토큰화</p>
<ul>
<li>문장을 단어 혹은 의미 단위(토큰)로 분리.</li>
<li>예를 들어, “운동화”가 “운”과 “동화”로 분리될 수 있는 경우, 이를 올바르게 분석하기 위한 커스텀 분석기가 필요.</li>
</ul>
</li>
<li><p>어간 추출 및 표제어 추출</p>
<ul>
<li>단어의 어미, 접미사를 제거하여 기본 형태로 변환.</li>
<li>이 과정은 검색 시 다양한 형태의 단어를 하나의 토큰으로 매칭하게 함.</li>
</ul>
</li>
</ul>
<h3 id="후처리-post-processing">후처리 (Post-processing)</h3>
<ul>
<li><p>표준화</p>
<ul>
<li>대소문자 변환 외에도, 숫자나 특수문자 등 특정 패턴을 표준화하여 검색 결과의 일관성을 유지.</li>
</ul>
</li>
<li><p>동의어 처리</p>
<ul>
<li>“노트북”과 “랩탑” 같이 의미가 동일한 단어를 동일하게 인식할 수 있도록 설정.</li>
</ul>
</li>
<li><p>필터링</p>
<ul>
<li>불필요한 토큰을 제거하거나 중요도를 조정하여 검색 시 가중치를 부여할 수 있음.</li>
</ul>
</li>
</ul>
<h3 id="주요-포인트">주요 포인트</h3>
<p><strong>동일한 문서라도 “전처리 → 형태소 분석 → 후처리” 과정을 어떻게 커스텀하느냐에 따라, 최종 생성된 인덱스의 내용이 달라지고 이는 검색 결과에 큰 영향을 미침.</strong></p>
<hr>
<h2 id="검색-처리-searching">검색 처리 (Searching)</h2>
<h3 id="인덱스-기반-검색">인덱스 기반 검색</h3>
<ul>
<li><p>빠른 조회</p>
<ul>
<li>생성된 인덱스를 기반으로 검색어가 포함된 토큰들을 빠르게 찾아냄. 이 때, 역인덱스(Inverted Index) 구조가 사용되는데, 이는 각 토큰이 포함된 문서들의 목록을 저장하여 빠른 검색이 가능하게  함.</li>
</ul>
</li>
<li><p>정확한 매칭</p>
<ul>
<li>검색어에 대해 전처리 및 형태소 분석이 동일하게 적용되어야, 사용자가 입력한 검색어와 인덱스가 동일한 규칙으로 변환되어 정확한 매칭이 이루어짐.</li>
</ul>
</li>
</ul>
<h3 id="검색-결과-가중치와-순위">검색 결과 가중치와 순위</h3>
<ul>
<li>TF-IDF 및 BM25:<ul>
<li>단순히 검색어의 포함 여부만 확인하는 것이 아니라, 문서 내 검색어의 빈도수와 전체 문서 집합에서의 중요도를 고려해 점수를 산출.</li>
</ul>
</li>
</ul>
<ul>
<li>커스텀 스코어링<ul>
<li>사용자가 정의한 비즈니스 로직에 따라 검색 결과의 우선순위를 조정할 수 있음.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="엘라스틱-서치-vs-기존-db의-fts">엘라스틱 서치 vs. 기존 DB의 FTS</h2>
<p>일반적인 데이터베이스(MongoDB, MySQL 등)도 기본적인 전체 텍스트 검색(FTS) 기능을 제공하지만,
엘라스틱 서치는 전처리, 형태소 분석, 후처리의 과정을 세밀하게 커스터마이징할 수 있다는 점에서 차별화.</p>
<ul>
<li>유연한 분석 체인:<ul>
<li>각 단계별 설정을 통해, 도메인 특화 검색어 처리 및 정확도 향상이 가능.</li>
</ul>
</li>
<li>확장성 및 분산처리<ul>
<li>대량의 데이터를 실시간으로 처리하고 검색할 수 있도록 분산 클러스터 환경을 제공.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JWT 저장 위치 ]]></title>
            <link>https://velog.io/@rokmc1257_lse/JWT-%EC%A0%80%EC%9E%A5-%EC%9C%84%EC%B9%98</link>
            <guid>https://velog.io/@rokmc1257_lse/JWT-%EC%A0%80%EC%9E%A5-%EC%9C%84%EC%B9%98</guid>
            <pubDate>Wed, 19 Feb 2025 05:57:54 GMT</pubDate>
            <description><![CDATA[<h2 id="xss-공격과-csrf-공격">XSS 공격과 CSRF 공격</h2>
<h3 id="xss-cross-site-scripting-공격">XSS (Cross Site Scripting) 공격</h3>
<h4 id="정의">정의</h4>
<ul>
<li><p>공격자가 악의적인 JavaScript 코드를 피해자의 웹 페이지에 삽입하여, 피해자의 브라우저에서 실행되도록 만드는 공격</p>
</li>
<li><p>흔히 code injection attack이라고도 함</p>
<h4 id="공격-방식">공격 방식</h4>
</li>
<li><p>예를 들어, 입력값에 대한 충분한 검증 없이 HTML에 그대로 출력할 경우, 공격자가 스크립트를 삽입할 수 있음</p>
</li>
<li><p>삽입된 스크립트는 사용자 세션, 쿠키, 로컬스토리지에 저장된 데이터(예: JWT) 등에 접근하여 탈취할 수 있음</p>
<h4 id="방어-대책">방어 대책</h4>
</li>
<li><p>입력값 검증 및 출력 인코딩: 사용자 입력을 반드시 검증하고, 출력 시 HTML 이스케이프 처리를 적용</p>
</li>
<li><p>Content Security Policy (CSP) 적용: 스크립트 실행을 제한하여, 신뢰할 수 없는 코드의 실행을 방지</p>
</li>
<li><p>정기적인 보안 점검: XSS 취약점을 지속적으로 확인하고 패치</p>
</li>
</ul>
<p>**
XSS 공격은 JWT뿐만 아니라 페이지 내의 모든 중요한 정보가 노출될 수 있으므로, 위와 같은 기본적인 보안 대책은 반드시 필요
**</p>
<hr>
<h3 id="csrf-cross-site-request-forgery-공격">CSRF (Cross Site Request Forgery) 공격</h3>
<h4 id="정의-1">정의</h4>
<ul>
<li>공격자가 사용자가 의도하지 않은 요청을 백엔드 서버에 보내게 하여, 피해자인 척 악의적인 동작(정보 수정, 정보 열람 등)을 수행하게 만드는 공격</li>
</ul>
<h4 id="공격-과정-예시">공격 과정 (예시)</h4>
<ul>
<li>공격자는 사용자가 이미지나 링크를 클릭하도록 유도</li>
<li>이 클릭 액션은 사용자의 의지와 무관하게 HTTP request를 발생</li>
<li>사용자가 이미 로그인되어 있다면, 브라우저는 자동으로 인증 쿠키를 함께 전송하여 서버는 정상적인 요청으로 인식</li>
</ul>
<h4 id="방어-대책-1">방어 대책</h4>
<ul>
<li>CSRF 토큰 적용: 요청마다 서버에서 발급한 토큰을 포함시켜, 유효하지 않은 요청을 차단</li>
<li>쿠키의 SameSite 옵션 설정: SameSite=Lax 또는 SameSite=Strict를 적용하여, 외부 요청에 쿠키가 포함되지 않도록 제한</li>
</ul>
<p><strong>CSRF 공격은 단순히 HTML 태그(img, link 등)만으로도 발생할 수 있기 때문에, 위와 같은 추가 방어 조치는 필수.</strong></p>
<hr>
<h2 id="jwt-저장-위치-local-storage-vs-cookie-vs-메모리">JWT 저장 위치: Local Storage vs. Cookie vs. 메모리</h2>
<h3 id="local-storage에-저장">Local Storage에 저장</h3>
<h4 id="장점">장점</h4>
<ul>
<li><p>CSRF 공격에 안전</p>
<ul>
<li>Local Storage에 저장된 토큰은 브라우저의 자동 요청에 포함되지 않으므로, CSRF 공격에 취약하지 않음</li>
</ul>
</li>
<li><p>개발자 제어</p>
<ul>
<li>필요 시 JavaScript를 통해 직접 헤더에 토큰을 담아 전송 가능<h4 id="단점">단점</h4>
</li>
</ul>
</li>
<li><p>XSS 공격에 취약</p>
<ul>
<li>악의적인 스크립트가 주입되면 Local Storage에 접근해 토큰을 탈취할 수 있음</li>
</ul>
</li>
<li><p>지속성</p>
<ul>
<li>브라우저에 영구 저장되어, 탈취 시 장기간 위험에 노출될 수 있음</li>
</ul>
</li>
</ul>
<hr>
<h3 id="cookie에-저장-httponly-옵션-활용">Cookie에 저장 (HttpOnly 옵션 활용)</h3>
<h4 id="장점-1">장점</h4>
<ul>
<li>XSS 공격에 강함:<ul>
<li>HttpOnly 옵션이 적용되면 JavaScript에서 쿠키에 접근할 수 없어, XSS 공격에 의한 토큰 탈취 위험이 줄어듦</li>
</ul>
</li>
<li>자동 포함<ul>
<li>브라우저가 HTTP 요청 시 자동으로 쿠키를 포함시켜 편리함</li>
</ul>
</li>
</ul>
<h4 id="단점-1">단점</h4>
<ul>
<li>CSRF 공격에 취약<ul>
<li>쿠키는 모든 요청에 자동 포함되므로, 공격자가 CSRF 기법으로 피해자의 인증 정보를 도용할 수 있음</li>
</ul>
</li>
<li>추가 보안 설정 필요<ul>
<li>CSRF 방어를 위해 SameSite 옵션이나 별도의 CSRF 토큰 적용이 필요하며, 서버와의 협의가 요구됨</li>
</ul>
</li>
</ul>
<hr>
<h3 id="메모리javascript-변수에-저장">메모리(JavaScript 변수)에 저장</h3>
<h4 id="장점-2">장점</h4>
<ul>
<li>XSS 공격 위험 최소화<ul>
<li>토큰이 브라우저 메모리에만 존재하므로, 페이지를 새로고침하거나 브라우저를 닫으면 사라져 장기간 노출 위험이 없음</li>
</ul>
</li>
<li>CSRF에 안전<ul>
<li>메모리에 저장된 토큰은 자동으로 HTTP 요청에 포함되지 않음</li>
</ul>
</li>
</ul>
<h4 id="단점-2">단점</h4>
<ul>
<li><p>휘발성</p>
<ul>
<li>페이지 리프레시나 브라우저 종료 시 토큰이 소실되어, 재인증이나 Refresh Token을 통한 토큰 재발급이 필요함</li>
</ul>
</li>
<li><p>사용자 경험:</p>
<ul>
<li>지속적 인증 상태 유지를 위해 별도의 처리 로직이 필요</li>
</ul>
</li>
</ul>
<hr>
<h2 id="access-token과-refresh-token-분리-관리-권장-방식">Access Token과 Refresh Token 분리 관리 권장 방식</h2>
<p>보안성과 사용자 경험을 모두 고려할 때, 가장 권장되는 방식은 Access Token과 Refresh Token을 분리하여 관리하는 것.</p>
<h3 id="access-token">Access Token</h3>
<ul>
<li>특징: 짧은 유효기간을 가지며, 민감 정보임</li>
<li>저장 위치: 메모리(예: JavaScript 변수)에 저장하여, XSS 위험을 최소화</li>
<li>보호: 유출되더라도 유효기간이 짧아 피해를 제한할 수 있음</li>
</ul>
<h3 id="refresh-token">Refresh Token</h3>
<ul>
<li>특징: 비교적 긴 유효기간을 가지며, 새로운 Access Token 발급에 사용</li>
<li>저장 위치: HttpOnly Cookie에 저장하여, JavaScript에서 접근할 수 없게 함</li>
<li>보호: XSS 공격에 대한 보호가 강화되며, CSRF 방어(SameSite 옵션 등) 추가 적용</li>
</ul>
<hr>
<p><strong>XSS 공격은 입력값 검증, 출력 인코딩, CSP 적용 등을 통해 방어해야 하며, JWT가 저장된 위치에 따라 보안 위협이 달라짐.</strong></p>
<p><strong>CSRF 공격은 CSRF 토큰 및 SameSite 쿠키 옵션을 활용하여 방어할 수 있음.</strong></p>
<p><strong>JWT 저장 방식에서는 Access Token은 메모리에 저장하여 XSS 위험을 줄이고, Refresh Token은 HttpOnly 쿠키를 통해 CSRF와 XSS 모두에 대한 보안을 강화하는 방식이 보편적이고 안전.</strong></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[세션(Session) vs 쿠키(Cookie) vs 토큰(Token)]]></title>
            <link>https://velog.io/@rokmc1257_lse/%EC%84%B8%EC%85%98Session-vs-%EC%BF%A0%ED%82%A4Cookie-vs-%ED%86%A0%ED%81%B0Token</link>
            <guid>https://velog.io/@rokmc1257_lse/%EC%84%B8%EC%85%98Session-vs-%EC%BF%A0%ED%82%A4Cookie-vs-%ED%86%A0%ED%81%B0Token</guid>
            <pubDate>Wed, 19 Feb 2025 02:17:00 GMT</pubDate>
            <description><![CDATA[<h2 id="세션session">세션(Session)</h2>
<h3 id="특징">특징</h3>
<ul>
<li><p>서버 저장 방식</p>
<ul>
<li>사용자의 상태 정보(예: 로그인 정보, 장바구니 등)를 서버의 메모리나 데이터베이스에 저장.</li>
</ul>
</li>
<li><p>세션 ID</p>
<ul>
<li>각 사용자마다 고유의 세션 ID를 발급하고, 이 ID를 통해 서버에서 해당 사용자의 데이터를 조회.</li>
</ul>
</li>
<li><p>Stateful:</p>
<ul>
<li>서버가 상태 정보를 유지하므로, 클라이언트가 별도의 상태 정보를 관리할 필요가 없음.</li>
</ul>
</li>
<li><p>보안성:</p>
<ul>
<li>서버에 저장되므로 비교적 안전. 다만, 세션 하이재킹(Session Hijacking) 등의 공격에 대한 대비가 필요.<h3 id="장단점">장단점</h3>
</li>
</ul>
</li>
</ul>
<table>
<thead>
<tr>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>민감한 사용자 데이터를 서버에 안전하게 저장 가능</td>
<td>서버 자원을 많이 사용하여 대규모 분산 시스템에서는확장성이 떨어짐</td>
</tr>
<tr>
<td>사용자 상태 관리를 위한 구현이 비교적 직관적</td>
<td>세션 스토리지에 대한 관리 및 클러스터링 처리가 필요함</td>
</tr>
</tbody></table>
<h3 id="활용-사례">활용 사례</h3>
<ul>
<li>로그인 인증, 쇼핑몰과 같이 사용자의 상태를 철저하게 관리해야 하는 경우</li>
</ul>
<hr>
<h2 id="쿠키cookie">쿠키(Cookie)</h2>
<h3 id="특징-1">특징</h3>
<ul>
<li><p>클라이언트 저장 방식:</p>
<ul>
<li>사용자의 브라우저에 데이터를 저장하여, 이후 요청 시 서버에 함께 전송.</li>
</ul>
</li>
<li><p>데이터 크기 제한:</p>
<ul>
<li>일반적으로 4KB 내외의 데이터를 저장할 수 있음.</li>
</ul>
</li>
<li><p>유형</p>
</li>
</ul>
<pre><code>- 세션 쿠키: 브라우저 종료 시 삭제되어 상대적으로 보안성이 높음.

- 영속 쿠키: 만료 날짜를 지정하여 장기간 저장 가능하지만, 탈취 위험이 존재.</code></pre><ul>
<li><p>보안 이슈:</p>
<ul>
<li>XSS(교차 스크립팅 공격)나 CSRF(사이트 간 요청 위조) 등의 공격에 취약할 수 있으므로, 보안 대책이 필수.</li>
</ul>
</li>
</ul>
<h3 id="장단점-1">장단점</h3>
<table>
<thead>
<tr>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>사용자 기기에 저장되어 서버 자원을 덜 사용</td>
<td>보안에 민감한 데이터 저장에는 부적합 (노출 위험)</td>
</tr>
<tr>
<td>간단한 사용자 설정이나 기본 상태 정보를 저장하는 데 적합</td>
<td>데이터 크기 제한으로 인해 대용량 정보 저장 불가</td>
</tr>
</tbody></table>
<h3 id="활용-사례-1">활용 사례</h3>
<ul>
<li>사용자 선호도, 테마 설정 등 비교적 민감하지 않은 정보를 저장할 때
로그인 유지 기능(예: &quot;Remember Me&quot;) 구현 시</li>
</ul>
<hr>
<h2 id="토큰token">토큰(Token)</h2>
<h3 id="특징-2">특징</h3>
<ul>
<li><p>자체 인증 방식:</p>
<ul>
<li>토큰(예: JWT – JSON Web Token)은 자체적으로 필요한 사용자 정보를 포함하고 있으며, 서버는 상태를 저장하지 않음(stateless).</li>
</ul>
</li>
<li><p>클라이언트 저장:</p>
<ul>
<li>사용자는 로컬 스토리지나 메모리에 토큰을 저장하고, API 요청 시 이를 서버에 첨부함.</li>
</ul>
</li>
<li><p>확장성:</p>
<ul>
<li>서버에서 별도의 세션 스토리지 없이 토큰만 검증하면 되므로, 분산 시스템이나 RESTful API에 적합.</li>
</ul>
</li>
<li><p>보안 고려사항:</p>
<ul>
<li>토큰 탈취 시 보안 위험이 크므로, 짧은 만료 시간 및 리프레시 토큰 등의 기법을 사용하여 보안을 강화해야 함.</li>
</ul>
</li>
</ul>
<h3 id="장단점-2">장단점</h3>
<table>
<thead>
<tr>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>서버 상태 유지가 필요 없으므로 확장성이 뛰어남</td>
<td>토큰 탈취 시 즉각적인 보안 위협이 발생할 수 있음</td>
</tr>
<tr>
<td>클라이언트와 서버 간의 통신이 간편해짐</td>
<td>토큰 자체가 정보를 담고 있기 때문에, 민감한 정보는 암호화하여 사용해야 함</td>
</tr>
</tbody></table>
<h3 id="활용-사례-2">활용 사례</h3>
<ul>
<li>RESTful API 및 마이크로서비스 아키텍처에서 사용자 인증</li>
<li>분산 시스템에서의 세션 관리 대체</li>
<li>모바일 및 싱글 페이지 애플리케이션(SPA)에서 주로 사용</li>
</ul>
<hr>
<table>
<thead>
<tr>
<th>항목</th>
<th>세션(Session)</th>
<th>쿠키(Cookie)</th>
<th>토큰(Token)</th>
</tr>
</thead>
<tbody><tr>
<td>저장 위치</td>
<td>서버</td>
<td>클라이언트(브라우저)</td>
<td>클라이언트 (로컬 스토리지, 메모리 등)</td>
</tr>
<tr>
<td>상태 관리</td>
<td>서버가 상태 유지 (Stateful)</td>
<td>클라이언트가 상태 유지</td>
<td>서버가 상태를 저장하지 않음 (Stateless)</td>
</tr>
<tr>
<td>보안</td>
<td>상대적으로 안전하나 서버 부하 큼</td>
<td>노출 위험 존재 (특히 영속 쿠키)</td>
<td>탈취 위험 있으나, 짧은 만료 시간 및 암호화로 대응</td>
</tr>
<tr>
<td>확장성</td>
<td>서버 자원 소모, 확장성 낮음</td>
<td>상대적으로 가볍지만, 보안에 주의 필요</td>
<td>서버 부하 적고 확장성 우수</td>
</tr>
<tr>
<td>사용 예시</td>
<td>로그인, 쇼핑몰 사용자 상태 관리</td>
<td>사용자 설정, &quot;Remember Me&quot; 기능</td>
<td>RESTful API, 분산 시스템, SPA 인증</td>
</tr>
</tbody></table>
<ul>
<li>사용자 상태 관리와 보안이 중요한 경우: <code>세션 기반</code> 인증이 유리.</li>
<li>경량화된 사용자 설정이나 간단한 상태 정보 관리: <code>쿠키</code>가 적합.</li>
<li>확장성과 분산 시스템 환경: <code>토큰 기반 인증(JWT 등)</code>이 효과적.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Security 인증 흐름]]></title>
            <link>https://velog.io/@rokmc1257_lse/Spring-Security-%EC%9D%B8%EC%A6%9D-%ED%9D%90%EB%A6%84</link>
            <guid>https://velog.io/@rokmc1257_lse/Spring-Security-%EC%9D%B8%EC%A6%9D-%ED%9D%90%EB%A6%84</guid>
            <pubDate>Tue, 18 Feb 2025 08:19:06 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/7afcc4b7-a501-4b0d-807a-b197439cf56e/image.png" alt=""></p>
<h2 id="인증-흐름">인증 흐름</h2>
<h4 id="1-사용자의-인증-요청-http-request">1. 사용자의 인증 요청 (Http Request)</h4>
<ul>
<li>사용자가 로그인 폼에서 <code>username</code>과 <code>password</code>를 입력한 뒤, 서버로 요청을 보냄.</li>
<li>이때, <code>AuthenticationFilter</code> (예: <code>UsernamePasswordAuthenticationFilter</code>)가 이 요청을 처리할 준비를 함.</li>
</ul>
<h4 id="2-authenticationfilter에서-usernamepasswordauthenticationtoken-생성">2. AuthenticationFilter에서 UsernamePasswordAuthenticationToken 생성</h4>
<ul>
<li>Spring Security는 필터 체인을 통해 가장 먼저 인증 관련 요청을 가로채서 처리함.</li>
<li>해당 요청에서 <code>username</code>과 <code>password</code>를 추출하여, <strong>인증 전</strong> 상태의 <code>UsernamePasswordAuthenticationToken</code> 객체를 생성함.</li>
<li>이 토큰에는 <code>principal</code>과 <code>credentials</code>만 포함되며, 아직 인증은 이루어지지 않음.</li>
</ul>
<h4 id="3-authenticationmanagerprovidermanager에게-token-전달">3. AuthenticationManager(ProviderManager)에게 Token 전달</h4>
<ul>
<li>생성된 <code>UsernamePasswordAuthenticationToken</code>은 <code>AuthenticationManager</code>의 구현체인 <code>ProviderManager</code>에게 전달됨.</li>
<li>Spring Security 설정에 따라 여러 <code>AuthenticationProvider</code>들이 등록될 수 있음.</li>
</ul>
<h4 id="4-authenticationprovider들을-순회하며-인증-시도">4. AuthenticationProvider(들)을 순회하며 인증 시도</h4>
<ul>
<li><code>ProviderManager</code>는 내부에 등록된 여러 <code>AuthenticationProvider</code> 중, 현재 요청을 처리할 수 있는 Provider를 찾아 인증을 위임함.</li>
<li>기본적으로 <code>DaoAuthenticationProvider</code>가 많이 사용되며, 이 단계에서 실제 사용자 정보를 확인함.</li>
</ul>
<h4 id="5-userdetailsservice를-통해-db-혹은-외부-리소스에서-사용자-정보-조회">5. UserDetailsService를 통해 DB 혹은 외부 리소스에서 사용자 정보 조회</h4>
<ul>
<li><code>DaoAuthenticationProvider</code>는 <code>UserDetailsService</code>를 사용해 DB(또는 다른 저장소)에서 사용자 정보를 가져옴.</li>
<li>일반적으로 <code>UserDetailsService</code> 인터페이스를 구현한 <code>CustomUserDetailsService</code> 같은 클래스를 만들어 원하는 DB 쿼리 로직을 작성함.</li>
</ul>
<h4 id="6-userdetails-객체-생성">6. UserDetails 객체 생성</h4>
<ul>
<li><code>UserDetailsService</code>는 DB 조회 결과를 바탕으로 <code>UserDetails</code> 객체(대부분 <code>User</code> 클래스를 상속한 객체)를 반환함.</li>
<li>이 객체에는 <code>username</code>, <code>password</code>, <code>enabled</code>, <code>authorities</code> (권한 정보) 등이 포함됨.</li>
</ul>
<h4 id="7-authenticationprovider가-userdetails와-입력받은-정보-비교">7. AuthenticationProvider가 UserDetails와 입력받은 정보 비교</h4>
<ul>
<li>Provider는 전달받은 <code>UserDetails</code>와 사용자가 입력한 비밀번호를 비교하여 일치 여부, 계정 잠금 상태 등을 검사함.</li>
<li>내부적으로 <code>BCryptPasswordEncoder</code> 등 암호화 기법을 사용해 비교하며, 반드시 동일한 인코더를 사용해야 함.</li>
</ul>
<h4 id="8-인증-성공-시-authentication-객체-반환">8. 인증 성공 시 Authentication 객체 반환</h4>
<ul>
<li>인증에 성공하면, <code>ProviderManager</code>를 통해 최종적으로 인증된 <code>Authentication</code> 객체를 반환함.</li>
<li>이 객체에는 사용자의 권한 정보, 인증 방식, 그리고 기타 세부 정보가 포함됨.</li>
</ul>
<h4 id="9-authenticationfilter로-다시-authentication-객체-반환">9. AuthenticationFilter로 다시 Authentication 객체 반환</h4>
<ul>
<li>필터 체인 상에서 최초에 생성된 <code>AuthenticationFilter</code> (예: <code>UsernamePasswordAuthenticationFilter</code>)로 인증 결과가 반환됨.<ul>
<li><strong>인증 성공 시</strong>: 반환된 <code>Authentication</code> 객체를 <code>SecurityContext</code>에 저장하고, 성공 핸들러(<code>AuthenticationSuccessHandler</code>)가 동작하거나 지정된 URL로 리다이렉트함.</li>
<li><strong>인증 실패 시</strong>: 실패 핸들러(<code>AuthenticationFailureHandler</code>)가 동작하거나 에러 페이지로 리다이렉트함.</li>
</ul>
</li>
</ul>
<h4 id="10-securitycontext에-authentication-저장">10. SecurityContext에 Authentication 저장</h4>
<ul>
<li>성공적으로 인증된 <code>Authentication</code> 객체는 <code>SecurityContextHolder.getContext().setAuthentication(...)</code>를 통해 <code>SecurityContext</code>에 저장됨.</li>
<li>이후 애플리케이션의 Controller, Service 등에서 <code>SecurityContextHolder.getContext().getAuthentication()</code>을 통해 현재 사용자 정보를 조회할 수 있음.</li>
</ul>
<hr>
<h2 id="내부-구성-요소-설명">내부 구성 요소 설명</h2>
<h3 id="authentication">Authentication</h3>
<ul>
<li><strong>역할</strong>: 현재 접근하는 주체의 정보와 권한(Authorities)을 담는 인터페이스로, 인증 여부 등 보안 정보를 포함함.</li>
<li><strong>주요 메서드</strong>:<ul>
<li><code>getAuthorities()</code>: 사용자 권한 목록 반환.</li>
<li><code>getCredentials()</code>: 주로 비밀번호나 인증 토큰 반환.</li>
<li><code>getDetails()</code>: 추가 인증 관련 정보 반환.</li>
<li><code>getPrincipal()</code>: 사용자 정보 반환.</li>
<li><code>isAuthenticated()</code>: 인증 여부 확인.</li>
<li><code>setAuthenticated(boolean)</code>: 인증 상태 설정.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="usernamepasswordauthenticationtoken">UsernamePasswordAuthenticationToken</h3>
<ul>
<li><code>Authentication</code> 인터페이스를 구현한 클래스로, 폼 기반 인증 시 사용됨.</li>
<li><strong>구분</strong>:<ul>
<li><strong>인증 전</strong>: 사용자 ID(주로 <code>username</code>)와 비밀번호만 포함하며, <code>isAuthenticated()</code>는 <code>false</code>로 설정됨.</li>
<li><strong>인증 후</strong>: 인증 성공 후 권한 정보가 추가되어 <code>isAuthenticated()</code>가 <code>true</code>로 변경됨.</li>
</ul>
</li>
</ul>
<pre><code class="language-java">public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
    private final Object principal;
    private Object credentials;

    // 인증 전: 사용자 ID와 비밀번호만 보유
    public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {
        super(null);
        this.principal = principal;
        this.credentials = credentials;
        setAuthenticated(false);
    }

    // 인증 후: 권한 정보 포함, 인증된 상태로 생성
    public UsernamePasswordAuthenticationToken(Object principal, Object credentials,
            Collection&lt;? extends GrantedAuthority&gt; authorities) {
        super(authorities);
        this.principal = principal;
        this.credentials = credentials;
        super.setAuthenticated(true);
    }
}</code></pre>
<hr>
<h3 id="authenticationmanager--providermanager">AuthenticationManager &amp; ProviderManager</h3>
<p><strong>AuthenticationManager</strong>:  </p>
<ul>
<li>인증 처리를 위한 인터페이스로, <code>authenticate(Authentication)</code> 메서드를 통해 인증을 시도함.</li>
</ul>
<pre><code class="language-java">public interface AuthenticationManager {
    Authentication authenticate(Authentication authentication) throws AuthenticationException;
}</code></pre>
<p><strong>ProviderManager:</strong></p>
<ul>
<li>AuthenticationManager의 기본 구현체로, 내부에 여러 AuthenticationProvider를 보유하고 순차적으로 호출하여 인증을 수행함.</li>
</ul>
<pre><code class="language-java">
public class ProviderManager implements AuthenticationManager {
    private List&lt;AuthenticationProvider&gt; providers;

    public List&lt;AuthenticationProvider&gt; getProviders() {
        return this.providers;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        for (AuthenticationProvider provider : getProviders()) {
            if (provider.supports(authentication.getClass())) {
                Authentication result = provider.authenticate(authentication);
                if (result != null) {
                    return result;
                }
            }
        }
        throw new AuthenticationException(&quot;Authentication failed&quot;);
    }
}</code></pre>
<hr>
<h3 id="authenticationprovider">AuthenticationProvider</h3>
<ul>
<li>실제 인증 로직을 수행하는 컴포넌트로, 전달받은 Authentication 객체를 기반으로 인증을 수행한 후, 인증된 Authentication 객체를 반환함.</li>
</ul>
<pre><code class="language-java">
public interface AuthenticationProvider {
    Authentication authenticate(Authentication authentication) throws AuthenticationException;
    boolean supports(Class&lt;?&gt; authentication);
}</code></pre>
<hr>
<h3 id="userdetailsservice--userdetails">UserDetailsService &amp; UserDetails</h3>
<p><strong>UserDetailsService</strong></p>
<ul>
<li>사용자 이름을 기반으로 사용자 정보를 조회하여 UserDetails 객체를 반환하는 인터페이스.</li>
</ul>
<pre><code class="language-java">
public interface UserDetailsService {
    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}</code></pre>
<p><strong>UserDetails</strong></p>
<ul>
<li>사용자 정보를 담는 인터페이스로, AuthenticationProvider가 인증 성공 시 이를 활용하여 인증된 토큰을 생성함.</li>
</ul>
<pre><code class="language-java">
public interface UserDetails extends Serializable {
    Collection&lt;? extends GrantedAuthority&gt; getAuthorities();
    String getPassword();
    String getUsername();
    boolean isAccountNonExpired();
    boolean isAccountNonLocked();
    boolean isCredentialsNonExpired();
    boolean isEnabled();
}</code></pre>
<hr>
<h3 id="securitycontextholder-및-securitycontext">SecurityContextHolder 및 SecurityContext</h3>
<p>*<em>SecurityContext:
*</em></p>
<ul>
<li>현재 요청의 인증 정보를 보관하는 컨테이너.</li>
</ul>
<p><strong>SecurityContextHolder</strong>:</p>
<ul>
<li>ThreadLocal을 사용하여 각 요청마다 별도의 SecurityContext를 유지하며, 애플리케이션 전반에서 현재 사용자 정보를 조회할 수 있도록 함.</li>
</ul>
<pre><code class="language-java">
SecurityContextHolder.getContext().setAuthentication(authentication);
SecurityContextHolder.getContext().getAuthentication();</code></pre>
<hr>
<h3 id="grantedauthority">GrantedAuthority</h3>
<ul>
<li>현재 사용자가 가진 권한(예: ROLE_ADMIN, ROLE_USER)을 나타냄.</li>
<li><code>UserDetailsService</code>에서 로드된 권한 정보를 기반으로 접근 제어나 권한 검증을 수행함.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Security 내부 구조]]></title>
            <link>https://velog.io/@rokmc1257_lse/Spring-Security-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@rokmc1257_lse/Spring-Security-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Tue, 18 Feb 2025 05:49:28 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/3133e7b8-f570-441f-baed-e53c776e00e2/image.png" alt=""></p>
<hr>
<h2 id="1-was-필터-단계--delegatingfilterproxy">1. WAS 필터 단계 – DelegatingFilterProxy</h2>
<h3 id="delegatingfilterproxy-역할">DelegatingFilterProxy 역할</h3>
<ul>
<li><p>WAS(Web Application Server)에 등록된 서블릿 필터로, 클라이언트의 요청을 애플리케이션 진입 시점에서 가장 먼저 가로 챔.</p>
</li>
<li><p>주요 기능: 실제 보안 처리는 스프링 컨테이너 내부에 정의된 빈(보통 springSecurityFilterChain 이름)을 위임하여 수행.</p>
</li>
<li><p>자동 구성: 스프링 시큐리티 의존성을 추가하면, 스프링 부트의 자동 구성 기능 또는 수동 설정을 통해 자동으로 등록.</p>
</li>
</ul>
<hr>
<h2 id="2-스프링-컨테이너와-filterchainproxy">2. 스프링 컨테이너와 FilterChainProxy</h2>
<h3 id="a-filterchainproxy">a. FilterChainProxy</h3>
<p><strong>역할</strong></p>
<ul>
<li>DelegatingFilterProxy로부터 요청을 전달받아 내부에 등록된 여러 보안 필터 체인(SecurityFilterChain) 중 하나를 선택하여 실행.</li>
</ul>
<p><strong>동작 방식</strong></p>
<ul>
<li>여러 SecurityFilterChain 존재: 애플리케이션에 여러 보안 설정(예: /admin/** 등) 을 적용할 수 있으며, 요청 URL 및 조건에 따라 가장 먼저 매칭되는 SecurityFilterChain을 선택.</li>
<li>순차 실행: 선택된 SecurityFilterChain에 등록된 필터들을 순서대로 실행.<h3 id="b-securityfilterchain">b. SecurityFilterChain</h3>
</li>
<li><em>구성*</em></li>
<li>여러 보안 필터(예: 인증, 인가, CSRF 방어, 세션 관리, 로그인/로그아웃 처리 등)가 하나의 체인으로 묶여 있음.</li>
</ul>
<p>** 설정 방법 **</p>
<ul>
<li>주로 HttpSecurity 객체를 사용하여 구성하며, 개발자가 세밀하게 설정할 수 있음.</li>
<li>예시: /admin/** 경로에는 관리자 전용 보안 체인을, /user/** 경로에는 일반 사용자 체인을 적용하는 식으로 URL별 맞춤 구성이 가능.</li>
</ul>
<p><strong>필터 종류</strong></p>
<ul>
<li>인증 필터: 로그인 요청을 처리하고, 사용자의 자격 증명을 검증.</li>
<li>인가 필터: 사용자의 역할과 권한을 확인하여 접근 제어를 수행.</li>
<li>CSRF 방어 필터: CSRF 공격을 방지하기 위해 토큰 검증을 수행.</li>
<li>기타: 세션 관리, Remember-me 기능 등 추가적인 보안 기능을 제공하는 필터들이 포함.</li>
</ul>
<hr>
<h2 id="3-보안-정보-저장과-관리">3. 보안 정보 저장과 관리</h2>
<p>스프링 시큐리티는 인증된 사용자와 그 권한 정보를 효과적으로 관리하기 위해 <strong>SecurityContextHolder와</strong> <strong>Authentication</strong> 객체를 사용.</p>
<h3 id="a-securitycontextholder">a. SecurityContextHolder</h3>
<p><strong>역할</strong></p>
<ul>
<li>현재 요청 또는 사용자의 보안 정보를 저장하는 컨테이너 역할 수행.</li>
<li>어디서든 쉽게 접근하여 현재 사용자의 인증 정보를 확인 가능.</li>
</ul>
<p>** 구현 방식 **</p>
<ul>
<li>기본적으로 <strong>ThreadLocal</strong> 방식을 사용하여, 각 요청마다 별도의 보안 정보를 유지.</li>
<li><strong>멀티스레드 환경 고려</strong>: 요청이 별도의 스레드에서 처리되어도 보안 정보가 올바르게 분리되어 저장.</li>
</ul>
<h3 id="b-authentication">b. Authentication</h3>
<p>** 역할 **</p>
<ul>
<li>사용자의 인증(로그인) 정보를 담는 객체.</li>
<li>Authentication 객체는 SecurityContext에 포함되어 관리되며 SecurityContext는 0개 이상 존재할 수 있다. 그리고 이 N개의 SecurityContext는 하나의 SecurityContextHolder에 의해서 관리</li>
</ul>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/b45dc7a2-f3a3-4696-ac58-0c67749072ef/image.png" alt=""></p>
<p>** 구성 요소 ** </p>
<ul>
<li>Principal: 사용자의 기본 정보(예: 사용자 이름, 상세 정보 등).</li>
<li>Credentials: 비밀번호, 인증 토큰 등 실제 인증을 위해 사용되는 자료.</li>
<li>Authorities: 사용자의 역할과 권한 목록 (예: ROLE_ADMIN, ROLE_USER 등).</li>
</ul>
<p>** 활용 방법 **</p>
<ul>
<li>인증 성공 후: 인증 처리 필터(예: UsernamePasswordAuthenticationFilter)는 로그인 성공 시 Authentication 객체를 생성하여 SecurityContextHolder에 저장.</li>
<li>애플리케이션 전반: 이후 다른 필터나 서비스, 컨트롤러 등에서 SecurityContextHolder.getContext().getAuthentication()을 통해 현재 사용자의 정보를 쉽게 조회할 수 있음. </li>
<li>인증 정보 활용: 접근 제어나 권한 체크를 위해 스프링 시큐리티는 이 Authentication 객체에 저장된 Authorities 정보를 사용.</li>
</ul>
<h3 id="c-securitycontext의-생명-주기">c. SecurityContext의 생명 주기</h3>
<ul>
<li>Authentication 객체를 관리하는 SecurityContext는 사용자의 요청이 서버로 들어오면 생성되고, 처리가 끝난 후 응답되는 순간에 초기화 됨</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JDBC(Java DataBase Connectivity)]]></title>
            <link>https://velog.io/@rokmc1257_lse/JDBCJava-DataBase-Connectivity</link>
            <guid>https://velog.io/@rokmc1257_lse/JDBCJava-DataBase-Connectivity</guid>
            <pubDate>Thu, 05 Dec 2024 07:42:05 GMT</pubDate>
            <description><![CDATA[<h2 id="jdbcjava-database-connectivity-란-">JDBC(Java DataBase Connectivity) 란 ?</h2>
<ul>
<li><p>JAVA Program에서 데이터베이스를 표준화된 방법으로 접속할 수 있도록 만든 API 규격</p>
<ul>
<li>개발자는 DB 종류에 무관하게 표준화된 API를 이용해 프로그램 개발 가능</li>
<li>DB 종류 변경시 프로글매 수정 최소화 </li>
</ul>
</li>
</ul>
<p><img src="blob:https://velog.io/fc6a39a2-306d-458e-bec5-88d4619ad293
" alt="이미지 설명" style="width: 70%; height: auto;"></p>
<hr>
<h2 id="jdbc의-주요-클래스와-인터페이스">JDBC의 주요 클래스와 인터페이스</h2>
<h3 id="drivermanager">DriverManager</h3>
<ul>
<li>데이터베이스 드라이버를 관리하고 연결을 생성하는 데 사용.</li>
</ul>
<h3 id="connection">Connection</h3>
<ul>
<li>데이터베이스와의 연결을 나타내며, 쿼리 실행에 필요한 객체를 생성.</li>
</ul>
<h3 id="statement">Statement</h3>
<ul>
<li>SQL 쿼리를 실행하는 객체.</li>
</ul>
<h3 id="preparedstatement">PreparedStatement</h3>
<ul>
<li>파라미터화된 쿼리를 실행하며, SQL Injection 방지와 성능 향상 가능.</li>
</ul>
<h3 id="resultset">ResultSet</h3>
<ul>
<li>SELECT 쿼리 결과를 처리하기 위한 객체.</li>
</ul>
<hr>
<h2 id="jdbc-프로그램-개요">JDBC 프로그램 개요</h2>
<img src="https://velog.velcdn.com/images/rokmc1257_lse/post/9fa26a4d-bf8a-4682-b9c9-22e2bc5c0695/image.png" alt="이미지 설명" style="width: 70%; height: auto;">



<h3 id="1-jdbc-드라이버-로드">1. JDBC 드라이버 로드</h3>
<ul>
<li><p>설명</p>
<ul>
<li>JDBC 드라이버를 로드하여 애플리케이션이 데이터베이스와 통신할 수 있도록 설정</li>
</ul>
</li>
</ul>
<ul>
<li><p>역할</p>
<ul>
<li>데이터베이스와 애플리케이션 간의 연결을 위한 통로를 설정</li>
</ul>
</li>
</ul>
<h3 id="2-데이터베이스-연결">2. 데이터베이스 연결</h3>
<ul>
<li><p>설명</p>
<ul>
<li>데이터베이스 URL, 사용자 이름, 비밀번호를 사용해 데이터베이스와 연결을 생성</li>
</ul>
</li>
<li><p>역할</p>
<ul>
<li>데이터베이스와 실제 연결을 열어 쿼리 실행이 가능하도록 준비</li>
</ul>
</li>
</ul>
<h3 id="3-statement-생성">3. Statement 생성</h3>
<ul>
<li><p>설명</p>
<ul>
<li><p>SQL 쿼리를 실행하기 위한 객체를 생성</p>
</li>
<li><p>Statement는 데이터베이스와 상호 작용할 때 SQL 명령을 전달하는 데 사용</p>
</li>
</ul>
</li>
</ul>
<h3 id="4-sql문-전송">4. SQL문 전송</h3>
<ul>
<li><p>설명</p>
<ul>
<li><p>SQL 문장을 데이터베이스로 전송하여 실행</p>
</li>
<li><p>쿼리 종류에 따라 결과를 조회하거나 데이터를 삽입/수정/삭제</p>
</li>
</ul>
</li>
</ul>
<h3 id="5-결과-받기">5. 결과 받기</h3>
<ul>
<li><p>설명:</p>
<ul>
<li><p>데이터베이스에서 반환된 결과를 처리</p>
</li>
<li><p>SELECT 쿼리 실행 후 반환되는 ResultSet 객체를 통해 데이터를 읽음</p>
</li>
</ul>
</li>
</ul>
<h3 id="6-연결-해제">6. 연결 해제</h3>
<ul>
<li><p>설명:</p>
<ul>
<li><p>사용이 끝난 데이터베이스 연결 및 Statement, ResultSet 객체를 닫아 자원을 반환</p>
</li>
<li><p>연결 해제는 메모리 누수를 방지하고 데이터베이스 성능을 유지하기 위해 필수</p>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="jdbc의-한계와-대안">JDBC의 한계와 대안</h2>
<h3 id="한계">한계</h3>
<ul>
<li>SQL 문 작성을 직접 해야 하므로 코드가 장황해짐.</li>
<li>예외 처리와 자원 관리가 복잡.</li>
<li>대규모 프로젝트에서는 코드 관리가 어려움.<h3 id="대안">대안</h3>
</li>
<li>ORM(Object-Relational Mapping) 프레임워크: Hibernate, JPA 등.</li>
<li>Spring JDBC: 스프링 프레임워크가 제공하는 JDBC 간소화 도구.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[TDD(Test-Driven Development)]]></title>
            <link>https://velog.io/@rokmc1257_lse/TDDTest-Driven-Development</link>
            <guid>https://velog.io/@rokmc1257_lse/TDDTest-Driven-Development</guid>
            <pubDate>Tue, 26 Nov 2024 07:43:09 GMT</pubDate>
            <description><![CDATA[<h2 id="tdd-test-driven-development-란-">TDD (Test-Driven Development) 란 ?</h2>
<ul>
<li>SW 개발 방법론 중 하나로, 테스트를 먼저 작성하고 이를 통과시키기 위해 코드를 작성하는 과정을 반복하는 개발 방식</li>
<li>개발 과정에서의 오류를 사전에 방지하고, 코드의 품질과 유지 보수성을 향상시키는데 큰 도움.</li>
</ul>
<hr>
<h2 id="tdd의-핵심-사이클--red-green-refactor">TDD의 핵심 사이클 : Red-Green-Refactor</h2>
<ul>
<li>Red-Green-Refactor 라는 3단계를 반복하면서 개발을 진행</li>
</ul>
<h3 id="red--실패하는-테스트-작성-">Red ( 실패하는 테스트 작성 )</h3>
<ul>
<li>구현할 기능에 대한 테스트 케이스를 먼저 작성.</li>
<li>이 단계에서 테스트는 실패해야 함 ( 아직 기능이 구현되지 않았기 때문 )</li>
</ul>
<h3 id="green--테스트-통과를-위한-최소한의-코드-작성-">Green ( 테스트 통과를 위한 최소한의 코드 작성 )</h3>
<ul>
<li>테스트를 통과시키기 위해 필요한 최소한의 코드를 작성</li>
<li>이 단계에서 코드의 최적화나 리팩터링보다는 테스트 통과에 집중</li>
</ul>
<h3 id="refactor--코드-리팩터링-">Refactor ( 코드 리팩터링 )</h3>
<ul>
<li>테스트를 통과하면 , 코드를 정리하고 개선.</li>
<li>리팩터링 후에도 모든 테스트가 통과해야 함</li>
</ul>
<hr>
<h2 id="tdd의-장점">TDD의 장점</h2>
<h3 id="1-높은-코드-품질">1. 높은 코드 품질</h3>
<ul>
<li>테스트를 먼저 작성함으로써 코드의 요구사항이 명확해지고, 코드가 보다 깔끔하고 유지보수하기 쉬워짐.<h3 id="2-버그-감소">2. 버그 감소</h3>
</li>
<li>모든 기능에 대해 테스트를 작성하기 때문에, 버그를 조기에 발견하고 수정할 수 있다.<h3 id="3리팩터링-용이">3.리팩터링 용이</h3>
</li>
<li>테스트가 이미 존재하므로,코드를 리팩터링할 때 기존 기능이 올바르게 동작하는지 즉시 확인할 수 있음.</li>
</ul>
<h3 id="4-요구사항-충족-보장">4. 요구사항 충족 보장</h3>
<ul>
<li>테스트는 요구사항을 기반으로 작성되므로, 요구사항을 누락하지 않고 구현할 수 있음.</li>
</ul>
<hr>
<h2 id="tdd의-단점">TDD의 단점</h2>
<h3 id="1-시간-소모">1. 시간 소모</h3>
<ul>
<li>초기에는 테스트 작성에 추가적인 시간이 필요할 수 있음.<h3 id="2-학습-곡선">2. 학습 곡선</h3>
</li>
<li>TDD 방식에 익숙하지 않은 개발자에게는 초기 학습이 필요할 수 있다.<h3 id="3-복잡한-테스트-관리">3. 복잡한 테스트 관리</h3>
</li>
<li>프로젝트가 커질수록 많은 테스트 케이스를 관리해야 하므로, 테스트 관리가 복잡해질 수 있음.</li>
</ul>
<hr>
<h2 id="tdd-예제-콜라츠-추측-구현하기">TDD 예제: 콜라츠 추측 구현하기</h2>
<h3 id="요구사항">요구사항</h3>
<ul>
<li>solution(int num) 함수는 콜라츠 추측에 따라 num이 1이 될 때까지의 연산 횟수를 반환해야 함. 단, 500번 이상의 반복이 발생하면 -1을 반환해야 함.</li>
</ul>
<h3 id="1단계-실패하는-테스트-작성-red">1단계: 실패하는 테스트 작성 (Red)</h3>
<ul>
<li>아직 solution 함수가 구현되지 않았기 때문에, 테스트를 먼저 작성하고 이 테스트가 실패하는 것을 확인</li>
</ul>
<pre><code class="language-import">import static org.assertj.core.api.Assertions.assertThat;

class SolutionTest {
    @Test
    void testCollatzBasicCase() {
        Solution solution = new Solution();
        assertThat(solution.solution(6)).isEqualTo(8); // 예제 6은 8번 반복
        assertThat(solution.solution(1)).isEqualTo(0); // 1은 반복 없이 바로 0 반환
        assertThat(solution.solution(626331)).isEqualTo(-1); // 500번 초과시 -1
    }
}</code></pre>
<p>*<em>실행 결과:
*</em></p>
<ul>
<li>solution 함수가 아직 구현되지 않았기 때문에, 모든 테스트가 실패</li>
</ul>
<h3 id="2단계-최소한의-코드-작성-green">2단계: 최소한의 코드 작성 (Green)</h3>
<ul>
<li>테스트를 통과시키기 위해, 간단히 solution 함수를 구현</li>
</ul>
<pre><code class="language-class">    public int solution(int num) {
        long n = num; // int 대신 long으로 오버플로우 방지
        int count = 0;

        while (n != 1) {
            if (count &gt;= 500) return -1; // 500번 이상 반복 시 종료
            n = (n % 2 == 0) ? n / 2 : n * 3 + 1;
            count++;
        }

        return count;
    }
}</code></pre>
<ul>
<li>테스트를 실행하면 모든 테스트가 통과</li>
</ul>
<h3 id="3단계-리팩터링-refactor">3단계: 리팩터링 (Refactor)</h3>
<ul>
<li><p>코드를 가독성 좋게 리팩터링</p>
<pre><code>class Solution {
  public int solution(int num) {
      long n = num; // int 대신 long으로 오버플로우 방지
      int count = 0;

      while (n != 1 &amp;&amp; count &lt; 500) { // 두 조건을 결합
          n = (n % 2 == 0) ? n / 2 : n * 3 + 1;
          count++;
      }

      return (count == 500) ? -1 : count;
  }
}</code></pre></li>
<li><p>리팩터링 후에도 테스트를 실행하여 모든 테스트가 통과함을 확인합니다</p>
</li>
</ul>
<hr>
<h2 id="tdd와-일반-개발의-차이점">TDD와 일반 개발의 차이점</h2>
<table>
<thead>
<tr>
<th>일반 개발</th>
<th>TDD</th>
</tr>
</thead>
<tbody><tr>
<td>코드 작성 후 테스트 작성</td>
<td>테스트 작성 후 코드를 작성</td>
</tr>
<tr>
<td>테스트는 추가 작업처럼 여겨짐</td>
<td>테스트가 개발 과정의 일부</td>
</tr>
<tr>
<td>예상 외 동작 발견이 느림</td>
<td>테스트가 예상 외 동작을 조기에 발견</td>
</tr>
<tr>
<td>요구사항에서 세부 구현으로 진행</td>
<td>테스트를 작성하며 요구사항을 점진적으로 세분화</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spark Memory Allocation & Memory Management]]></title>
            <link>https://velog.io/@rokmc1257_lse/Spark-Memory-Allocation-Memory-Management</link>
            <guid>https://velog.io/@rokmc1257_lse/Spark-Memory-Allocation-Memory-Management</guid>
            <pubDate>Wed, 04 Sep 2024 11:14:52 GMT</pubDate>
            <description><![CDATA[<ul>
<li>Spark는 JVM(Java Virtual Machine) 위에서 동작</li>
<li>Spark의 메모리 관리 구조는 주로 Spark Memory, Memory inside of JVM 및 Memory outside JVM 으로 나눌 수 있음 </li>
</ul>
<hr>
<hr>
<h2 id="memory-inside-of-jvm">Memory inside of JVM</h2>
<ul>
<li>JVM 내부 메모리는 Spark application에서 대부분의 연산이 이루어지는 공간<h3 id="reserved-memory">Reserved memory</h3>
</li>
<li>Spark의 JVM process가 시작될 때, 일정한 메모리 영역은 시스템을 위해 예약, Spark에서 사용 불가</li>
<li>JVM 자체 오버헤드(EX:메타데이터 관리,힙 오브젝트, 코드 실행)에 사용</li>
<li>default Value = 300MB, <strong>spark.memory.offHeap.size</strong> 로 조정 불가능</li>
<li><strong>spark.memory.reserved</strong>로 예약 메모리 크기 설장 할 수 있음</li>
</ul>
<hr>
<h3 id="spark-memory">Spark Memory</h3>
<ul>
<li><p>JVM 내부에서 Spark가 사용하는 memory</p>
<ul>
<li>주로 두 가지 용도로 사용 </li>
<li>1.Execution Memory</li>
<li>2.Storage Memory</li>
</ul>
</li>
<li><p>Spark는 Unified Memory Management라는 메모리 관리 모델을 사용, 두 영역을 동적으로 메모리 공유 할 수 있음.</p>
</li>
</ul>
<h4 id="execution-memoryoperations">Execution memory(operations)</h4>
<ul>
<li>연산잔업 ( EX: shuffle, sort, join 등) 을 처리할 때 사용하는 memory</li>
<li>Spark 내부 연산에서 일시적으로 필요한 memory로 작업이 완료되면 메모리 해제</li>
<li>Spark의 중간 데이터 처리에 필요하며, 주로 RDD, DataFrame을 처리할 때 사용</li>
<li>Spark에서 큰 연산 작업이 이루어질 때, Execution Memory가 충분하지 않으면 disk에 데이터를 기록하고 연산 성능이 저하될 수 있음</li>
</ul>
<h4 id="storage-memorycaching">Storage memory(caching)</h4>
<ul>
<li>caching 및 데이터 저장을 위해 사용. RDD, DataFrame을 메모리에 캐시할 때 이 영역을 사용</li>
<li>caching 된 데이터는 나중에 다시 사용할 수 있도록 메모리에 저장, 필요한 경우 디스크에 저장할 수 있음</li>
<li><strong>spark.storage.memoryFraction</strong> 으로 설정되는 비율에 따라, Storage Memory가 Execution Memory와 메모리를 공유할 수 있음</li>
<li>캐시된 데이터는 주로 중복 계산을 피하기 위해 사용, 저장할 공간이 부족할 경우 오래된 캐시된 데이터가 지워질 수 있음 (LRU 방식)</li>
</ul>
<h4 id="unified-memory-model통합-메모리-모델">Unified Memory Model(통합 메모리 모델)</h4>
<ul>
<li>Execution Memory와 Storage Memory가 동적으로 메모리를 공유할 수 있도록 허용</li>
<li>Storage 메모리가 부족할 때 Execution 메모리에서 사용하지 않는 메모리를 빌려올 수 있고, 그 반대도 가능</li>
</ul>
<hr>
<h3 id="user-memory">User memory</h3>
<ul>
<li>Spark가 아닌 사용자 정의 애플리케이션 코드에서 사용하는 memory</li>
<li>사용자가 사용자 정의 함수(UDF)를 작성하거나, 사용자 정의 데이터 구조를 관리 할 때 필요한 memory</li>
<li>Spark는 JVM Heap에서 일정 비율을 사용자 메모리로 예약해 두며, 나머지는 시스템 메모리로 할당</li>
</ul>
<hr>
<hr>
<h2 id="memory-outside-of-jvm-overheadmemory">Memory outside of JVM (overheadMemory)</h2>
<ul>
<li>Saprk는 JVM 외부에서도 메모리 사용 가능</li>
<li>JVM Heap Memory 만으로 모든 데이터를 처리하기에는 한계가 있을 수 있기 때문에 외부 메모리에서 추가적으로 작업을 처리하거나 오버헤드를 관리</li>
</ul>
<h3 id="overhead-memory">overhead memory</h3>
<ul>
<li>Spark가 실제 작업을 처리하는 데 필요한 추가 메모리. 주로 셔플, 데이터 직렬화 및 네트워크 통신 같은 부가적인 작업에서 사용</li>
<li>Spark 작업을 관리하는 Driver와 Executor에서 필요한 자원이 포함 됨</li>
<li>이 메모리는 JVM 외부에서 사용 될 수 있으며 , 특히 자원 관리(YARN, Kubernetes)와 연계된 환경에서는 중요</li>
</ul>
<h3 id="offheap-memory">OffHeap memory</h3>
<ul>
<li>JVM 힙 외부에서 관리되는 메모리, 주로 대규모 데이터를 효율적으로 처리하기 위해 사용</li>
<li>Spark에서 Off-Heap 메모리를 사용하려면 <strong>spark.memory.offHeap.enabled</strong> 설정을 활성화해야하며, <strong>spark.memory.offHeap.size</strong>로 크기를 설정 가능</li>
<li>OffHeap 메모리는 주로 메모리 관리 효율성을 높이고, 가비지 컬렉션의 영향을 줄이기 위해 사용</li>
</ul>
<h3 id="external-process-memory">External process memory</h3>
<ul>
<li>Spark는 외부 프로세스를 실행하여 작업을 수행하는 경우도 있음, 이때 JVM 외부의 외부 프로세스에서 사용하는 메모리도 포함</li>
<li>EX : Hadoop의 HDFS 작업이나 다른 분산 파일 시스템과 통신할 때 외부 프로세스에서 메모리를 사용</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ Apache Spark SQL 엔진의 쿼리 처리 과정]]></title>
            <link>https://velog.io/@rokmc1257_lse/Logical-plan-Physical-plan</link>
            <guid>https://velog.io/@rokmc1257_lse/Logical-plan-Physical-plan</guid>
            <pubDate>Wed, 04 Sep 2024 08:27:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/46f37c8c-10e4-4b9c-9710-3b96f1cadadd/image.png" alt=""></p>
<h2 id="apache-spark-sql-엔진의-쿼리-처리-과정">Apache Spark SQL 엔진의 쿼리 처리 과정</h2>
<h3 id="unresolved-logical-plan">Unresolved Logical Plan</h3>
<ul>
<li>Schema Information, table name 등이 확정 되지 않았기 때문에 참조하는 Data Structure, Column name 등이 제대로 확인 되지 않은 상태</li>
</ul>
<hr>
<h3 id="catalog">Catalog</h3>
<ul>
<li>Spark는 Catalog를 사용하여 Database, Table, View, function 등 Meta Data 확인</li>
<li>Unresolved Logical Plan 의 각 부분이 실제 테이블과 컬럼 정보와 매칭되며, 이 과정 오류 발생 시 query 실행 되지 않음</li>
</ul>
<hr>
<h3 id="logical-plan">Logical Plan</h3>
<ul>
<li>Meta Data 확인되면, Logical Plan 생성</li>
<li>Query나 DataFrame의 구조가 명확</li>
<li>Query의 순서와 수행해야 할 작업들이 논리적으로 배치</li>
<li>But, 아직 최적화되지 않은 상태</li>
</ul>
<hr>
<h3 id="optimized-logical-plan">Optimized Logical Plan</h3>
<p>Query의 성능을 크게 개선할 수 있는 여러 최적화 작업이 수행</p>
<h4 id="projection-pushdown">Projection Pushdown</h4>
<ul>
<li>Query에서 실제 필요한 컬럼만 최대한 빨리 선택하는 최적화</li>
<li>예를 들어, 특정 컬럼만 필요한데도 쿼리에서 전체 테이블을 읽고 있다면, Spark는 프로젝션 푸시다운을 통해 불필요한 컬럼들을 제외하고 처리</li>
</ul>
<h4 id="filter-pushdown">Filter Pushdown</h4>
<ul>
<li>WHERE, HAVING 과 같은 필터 조건을 가능한 한 빨리 적용하여, Query 실행 중 불필요한 데이터를 미리 걸러내는 최적화</li>
<li>필터가 데이터 소스 가까이에서 실행되면 Spark는 그 이후의 연산에서 처리할 데이터 양을 줄일 수 있다. 큰 데이터셋을 처리할 때 중요한 최적화</li>
</ul>
<h4 id="stage-optimization">Stage Optimization</h4>
<ul>
<li><p>Spark는 작업을 stage 로 나누어 실행. 각 stage는 cluster 에서 병렬로 실행 될 수 있는 최소 단위의 작업 세트를 의미</p>
</li>
<li><p>Spark는 여러 작업이 하나의 stage에서 처리 될 수 있는지, 아니면 데이터를 suffle 해야 하므로 stage를 나눠야 하는지를 분석</p>
<ul>
<li>데이터가 이미 같은 파티션으로 나누어져 있으면 추가적인 suffle 없이 같은 stage에서 처리 할 수 있음</li>
<li>반면, 데이터가 suffle 되어야 한다면 Spark는 새로운 stage를 만들고, suffle 작업을 최적화 함</li>
</ul>
</li>
</ul>
<h4 id="predicate-pushdown">Predicate Pushdown</h4>
<ul>
<li>필터링 조건을 데이터 소스에서 최대한 빨리 적용하는 또 다른 최적화 전략</li>
<li>Spark는 물리적 데이터 소스가 지원하는 경우, 데이터베이스 수준에서 조건을 푸시다운하여 데이터를 더 적게 읽어옴</li>
</ul>
<h4 id="elimination-of-redundant-operations--cache-optimization">Elimination of Redundant Operations &amp; Cache Optimization</h4>
<ul>
<li>Spark 는 Query Plan 에서 중복된 연산을 찾아 제거</li>
<li>데이터가 반복적으로 사용된다면 Cache를 이용해 재사용할 수 있도록 최적화 함<h4 id="predicate-and-expression-simplification">Predicate and Expression Simplification</h4>
</li>
<li>Spark는 논리적 최적화 단계에서 수식을 단순화하거나 논리적으로 일관되지 않는 조건을 제거합</li>
</ul>
<hr>
<h3 id="physical-plans">Physical Plans</h3>
<ul>
<li><p>Logical Plan을 Cluster 가 알아 들을 수 있게 바꿔 줌</p>
</li>
<li><p>여러 개의 물리 계획이 생성 될 수 있는데, Cost Model을 사용하여 각 물리 계획의 비용을 계산</p>
<ul>
<li>비용이란 CPU 사용량, 네트워크 셔플, 메모리 사용량 등 실행 시 소모될 자원에 대한 평가<ul>
<li>Spark는 여러 물리 계획 중에서 가장 효율적인 계획을 선택</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="selected-physical-plan">Selected Physical Plan</h3>
<ul>
<li>비용 모델을 기반으로 최종적으로 선택된 물리 계획이 결정</li>
<li>이 계획에 따라 실행이 이루어지며, 최종적으로 코드를 생성</li>
</ul>
<hr>
<h3 id="code-generation">Code Generation</h3>
<ul>
<li>선택된 물리 계획이 완료되면, Spark는 실행할 코드를 생성</li>
<li>주로 Tungsten 엔진을 통해 JIT(Just-In-Time) 컴파일을 수행하여 효율적인 바이트코드로 변환</li>
<li>실제로 RDD로 변환되어 클러스터 상에서 작업이 실행</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[메타러너]]></title>
            <link>https://velog.io/@rokmc1257_lse/%EB%A9%94%ED%83%80%EB%9F%AC%EB%84%88</link>
            <guid>https://velog.io/@rokmc1257_lse/%EB%A9%94%ED%83%80%EB%9F%AC%EB%84%88</guid>
            <pubDate>Mon, 05 Aug 2024 09:29:42 GMT</pubDate>
            <description><![CDATA[<h2 id="메타러너">메타러너</h2>
<ul>
<li>ML Algorithm 활용하여 처치 효과를 추정하는 간단하면서도 강력한 방법론</li>
<li>조건부 평균 처치 효과(CATE, Conditional Average Treatment Effect)를 추정하는 데 주로 사용</li>
<li>실험 대상이 어떻게 처치에 따라 다르게 반응하는지를 식별하는 데 중점</li>
</ul>
<h3 id="기본-개념">기본 개념</h3>
<ul>
<li><p>기존 예측 ML Algorithm 활용해 처치효과를 추정하는 간단한 방법</p>
</li>
<li><p>ATE 추정에 사용할 수 있지만, 일반적으로 고차원 데이터를 잘 처리 하기 때문에 CATE 추정에 사용</p>
</li>
<li><p>예측 모델을 인과추론에 재활용하는 역할</p>
</li>
<li><p>메타러너는 다양한 머신러닝 알고리즘과 결합하여 사용할 수 있음.</p>
<ul>
<li>선형 회귀(Linear Regression): 간단한 예측 모델로, 해석이 용이.</li>
<li>부스트 의사결정 트리(Boosted Decision Trees): 고차원 데이터를 잘 처리하며, 강력한 예측 성능을 보임.</li>
<li>신경망(Neural Networks): 복잡한 비선형 관계를 잘 학습 함.</li>
<li>가우스 과정(Gaussian Processes): 확률적 모델로, 예측의 불확실성을 평가할 수 있음.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="이산형-처치-메타러너">이산형 처치 메타러너</h2>
<p>온라인 소매업체의 마케팅 팀에서 일한다고 가정하고, 목표는 어떤 고객이 마케팅 이메일에 긍정적으로 반응하는지 파악하는 것. 마케팅 이메일은 고객의 소비를 늘릴 잠재력이 있지만, 일부 고객은 이를 선호하지 않을 수 있다. 이를 해결하기 위해, 이메일이 고객의 미래 구매량에 미치는 조건부 평균 처치 효과(CATE)를 추정. 이를 통해 효율적인 이메일 발송 전략을 수립.</p>
<blockquote>
<p>import pandas as pd<br>import numpy as np<br>data_biased = pd.read_csv(&quot;./data/email_obs_data.csv&quot;)<br>data_rnd = pd.read_csv(&quot;./data/email_rnd_data.csv&quot;)<br>print(len(data_biased), len(data_rnd))        data_rnd.head()</p>
</blockquote>
<table>
<thead>
<tr>
<th></th>
<th>mkt_email</th>
<th>next_mnth_pv</th>
<th>age</th>
<th>tenure</th>
<th>...</th>
<th>jewel</th>
<th>books</th>
<th>music_books_movies</th>
<th>health</th>
</tr>
</thead>
<tbody><tr>
<td>0</td>
<td>0</td>
<td>24426</td>
<td>61.0</td>
<td>1.0</td>
<td>...</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>2</td>
</tr>
<tr>
<td>1</td>
<td>0</td>
<td>2967</td>
<td>36.0</td>
<td>1.0</td>
<td>...</td>
<td>1</td>
<td>0</td>
<td>2</td>
<td>2</td>
</tr>
<tr>
<td>2</td>
<td>0</td>
<td>1173</td>
<td>64.0</td>
<td>0.0</td>
<td>...</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<td>3</td>
<td>0</td>
<td>4141</td>
<td>74.0</td>
<td>0.0</td>
<td>...</td>
<td>0</td>
<td>4</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
<td>4</td>
<td>0</td>
<td>44789</td>
<td>59.0</td>
<td>0.0</td>
<td>...</td>
<td>1</td>
<td>1</td>
<td>2</td>
<td>1</td>
</tr>
</tbody></table>
<ul>
<li>실험 데이터와 관측 데이터에는 동일한 열</li>
<li>여기서 이메일 발송 여부인 처치변수 mkt_email가 이메일을 받고 한 달 후의 구매 금액인 next_mnth_pv에 미치는 영향을 알아보겠음</li>
<li>이 열 외에도 데이터에는 나이, 첫 구매 이후의 기간, 각 카테고리에서 구매한 금액과 같은 다양한 공변량이 포함</li>
<li>이러한 공변량에 따라 적합시키려는 이질적 처치가 결정</li>
</ul>
<p>CATE 모델 개발을 간소화하기 위해 처치, 결과, 공변량, 훈련 및 테스트 셋을 저장하는 변수를 생성 할 수 있음, 이를 다 갖추면 대부분의 메타러너를 구성하는 일이 간단해짐</p>
<blockquote>
<p> y = &quot;next_mnth_pv&quot;<br>T = &quot;mkt_email&quot;<br>X = list(data_rnd.drop(columns=[y, T]).columns)<br>train, test = data_biased, data_rnd</p>
</blockquote>
<h3 id="t-러너">T 러너</h3>
<ul>
<li>범주형 처치를 다룰 때 첫 번째 시도해 볼 메타러너는 T 러너</li>
<li>T 러너는 매우 간단, 잠재적 결과 $Y_i$를 추정하기 위해 모든 처치에 대한 하나의 결과 모델 $u_t(x)$를 적합</li>
<li>이진 처치에서는 추정해야 할 모델이 두 개뿐이므로 T 러너라고 불림</li>
</ul>
<p>$u_0(x)=E[ Y|T=0,  X]$
$u_1(x)=E[ Y|T=1,  X]$</p>
<p>이러한 모델을 만들면 각 처치에 대한 반사실 예측을 하고 다음가 같이 CATE를 추정할 수 있다.</p>
<p>$\hat{\tau}(x)_i=\hat{u}(X_i)-\hat{u_0}(X_i)$</p>
<ul>
<li>$\hat{\tau}(x)$ 는 특성 $𝑋=𝑥$ 를 가진 고객의 조건부 평균 처치 효과(CATE)</li>
<li>$\hat{u}(X_i)$는 마케팅 이메일을 받은 경우의 예상 구매량</li>
<li>$\hat{u_0}(X_i)$ 는 마케팅 이메일을 받지 않은 경우의 예상 구매량</li>
</ul>
<p>T러너 다이어그램
<img src="https://velog.velcdn.com/images/rokmc1257_lse/post/586277ee-cefb-46f5-a6a6-6c497a304e6f/image.png" alt=""></p>
<ul>
<li>러너가 각자 T = 1 그리고 T = 0에서 머신러닝 모델을 학습. 예측 시점에 두 모델을 모두 사용해서 실험군과 대조군의 차이를 추정함</li>
</ul>
<p>결과 모델로 boosted regression tree 사용해서 구현
회귀 모델인 LGBMRegressor를 적용</p>
<blockquote>
<p>from lightgbm import LGBMRegressor        np.random.seed(123)<br>m0 = LGBMRegressor()<br>m1 = LGBMRegressor()<br>m0.fit(train.query(f&quot;{T}==0&quot;)[X], train.query(f&quot;{T}==0&quot;)[y])<br>m1.fit(train.query(f&quot;{T}==1&quot;)[X], train.query(f&quot;{T}==1&quot;)[y]);</p>
</blockquote>
<p>두 개의 모델이 있으므로 test set 에서 CATE 예츠갛기 매우 쉬움</p>
<blockquote>
<p>t_learner_cate_test = test.assign(            cate=m1.predict(test[X]) - m0.predict(test[X])        </p>
</blockquote>
<p>이 평가 방법은 처치효과가 가장 높은 고객부터 가장 낮은 고객까지 올바르게 정렬했는지에만 관심
<img src="https://velog.velcdn.com/images/rokmc1257_lse/post/ac559bab-a56d-48bf-b8c0-a4877d126a2c/image.png" alt=""></p>
<p>T 러너는 이 데이터셋에서 잘 작동</p>
<ul>
<li>T 러너는 단순한 모델이므로 처치가 이산형으로 주어진 상황일 때 처음 시도하기 좋음</li>
<li>상황에 따라 정규화 편향이 발생하기 쉬움</li>
</ul>
<p>대조군은 많고 실험군의 데이터는 매우 적은 상황을 생각 -&gt; 이는 처치에 큰 비용이 들어가는 적용 사례에서 매우 흔한 상황
결과 Y에 약간의 비선형성이 있지만, 처치효과는 일정하다고 가정
<img src="https://velog.velcdn.com/images/rokmc1257_lse/post/d8d2ab2d-f9aa-4caa-8a9c-266331b25457/image.png" alt=""></p>
<blockquote>
</blockquote>
<ul>
<li>데이터에서 처치를 받은 관측값이 적고 처치를 받지 않은 관측값이 많은 경우, 과적합을 피하기 위해 모델이 과적합되지 않도록 주의</li>
<li>처치를 받은 그룹의 모델 $\hat{u_1}$ 모델은 단순해질 가능성이 크고, 처치를 받지 않은 그룹의 모델 $\hat{u_0}$ 모델은 더 복잡할 수 있지만, 데이터가 풍부하므로 과적합 방지</li>
<li>동일한 하이퍼파라미터를 사용하더라도, 각 그룹의 데이터 크기에 따라 모델의 복잡도와 정규화 정도가 달라짐</li>
</ul>
<ul>
<li>LightGBM Regressor 모델을 사용하여 min_child_samples=25로 설정했을 때, 데이터가 적으면 트리가 더 작아지고 단순해지는 경향이 있습니다. 이는 모델의 자기 정규화(self-regularization) 효과로 설명할 수 있다.</li>
<li>실제 예시에서 $\hat{u_1}$ 모델은 선형성을 띠고  $\hat{u_0}$  모델은 비선형성을 포착할 수 있다. 이는 두 모델 간의 차이로 인해 비선형 CATE가 계산될 수 있다.</li>
<li>그러나 실제 CATE는 일정하게 1이므로, 이는 잘못된 결과를 초래할 수 있다.</li>
</ul>
<p>X-러너(X-learner)는 이러한 문제를 해결하는 방법으로 등장. X-러너는 각 그룹의 데이터를 더욱 효과적으로 활용하여 처치 효과를 추정할 수 있도록 도와줌</p>
<hr>
<h3 id="x-러너">X 러너</h3>
<ul>
<li>X-러너는 데이터 크기에 따른 모델의 차이와 비선형성 문제를 해결하기 위해 고안된 방법.</li>
<li>처치를 받은 그룹과 처치를 받지 않은 그룹의 모델을 각각 학습한 후, 이들을 결합하여 보다 정확한 CATE를 추정.</li>
<li>이를 통해 데이터가 적은 그룹에서도 비선형성을 잘 포착할 수 있다.</li>
</ul>
<p>더 복잡하지만 보다 정확한 처치 효과를 추정</p>
<p>*<em>단계 1: T-러너와 동일한 과정:
*</em></p>
<ul>
<li>먼저, 고객을 두 그룹으로 나눔: 이메일을 받은 그룹과 받지 않은 그룹.</li>
<li>각 그룹에 대해 모델을 적합시킴:<ul>
<li>$\hat{u_1}$: 이메일을 받은 그룹의 구매 예측</li>
<li>$\hat{u_2}$: 이메일을 받지 않은 그룹의 구매 예측</li>
</ul>
</li>
</ul>
<p>*<em>단계 2: 누락된 잠재적 결과 추정:
*</em></p>
<ul>
<li>각 그룹의 모델을 사용해 누락된 결과를 예측:<ul>
<li>이메일을 받지 않은 그룹의 데이터로 이메일을 받은 경우의 결과를 예측</li>
<li>이메일을 받은 그룹의 데이터로 이메일을 받지 않은 경우의 결과를 예측</li>
</ul>
</li>
</ul>
<p>*<em>단계 3: CATE 계산:
*</em>
각각의 그룹에서 CATE를 계산:</p>
<ul>
<li>$\hat{\tau_1}(x)=\hat{u_1}(X)-\hat{u_0}(X)$</li>
<li>$\hat{\tau_0}(x)=\hat{u_1}(X)-\hat{u_0}(X)$</li>
</ul>
<p>*<em>단계 4: 두 모델 결합:
*</em></p>
<ul>
<li>두 모델을 결합할 때, 더 정확한 모델에 더 많은 가중치를 부여. 이는 성향점수(propensity score)를 사용해 가중치를 설정:<ul>
<li>$\hat{\tau_1}(X)=e(X)\hat{\tau_1}(X)-(1-e(X))\hat{\tau_0}(X)$</li>
<li>여기서 e(X)는 성향점수로, 특정 고객이 이메일을 받을 확률을 나타냄.</li>
</ul>
</li>
</ul>
<h3 id="왜-x-러너가-더-나은가-">왜 X-러너가 더 나은가 ?</h3>
<ul>
<li>정확한 가중치 부여: X-러너는 더 정확한 모델에 더 많은 가중치를 부여하여 잘못된 결과를 최소화합니다.</li>
<li>데이터 활용: 이메일을 받지 않은 그룹의 많은 데이터를 잘 활용하면서, 적은 데이터를 가진 이메일 받은 그룹의 모델도 적절히 활용합니다.</li>
<li>비선형성 보정: 데이터 불균형으로 인한 비선형성을 보정하여 더 정확한 CATE를 추정</li>
</ul>
<hr>
<h2 id="연속형-처치-메타러너">연속형 처치 메타러너</h2>
<ul>
<li>레스토랑 체인은 데이터를 분석하여 고객의 할인 민감도를 파악하고, 이를 바탕으로 최적의 할인 시기를 결정할 수 있다.</li>
<li>CATE를 정확히 추정하면, 고객 반응을 극대화할 수 있는 할인 정책을 설계할 수 있다.</li>
</ul>
<table>
<thead>
<tr>
<th></th>
<th>rest_id</th>
<th>day</th>
<th>month</th>
<th>weekday</th>
<th>...</th>
<th>is_nov</th>
<th>competitors_price</th>
<th>discounts</th>
<th>sales</th>
</tr>
</thead>
<tbody><tr>
<td>0</td>
<td>0</td>
<td>2016-01-01</td>
<td>1</td>
<td>4</td>
<td>...</td>
<td>False</td>
<td>2.88</td>
<td>0</td>
<td>79.0</td>
</tr>
<tr>
<td>1</td>
<td>0</td>
<td>2016-01-02</td>
<td>1</td>
<td>5</td>
<td>...</td>
<td>False</td>
<td>2.64</td>
<td>0</td>
<td>57.0</td>
</tr>
<tr>
<td>2</td>
<td>0</td>
<td>2016-01-03</td>
<td>1</td>
<td>6</td>
<td>...</td>
<td>False</td>
<td>2.08</td>
<td>5</td>
<td>294.0</td>
</tr>
<tr>
<td>3</td>
<td>0</td>
<td>2016-01-04</td>
<td>1</td>
<td>0</td>
<td>...</td>
<td>False</td>
<td>3.37</td>
<td>15</td>
<td>676.5</td>
</tr>
<tr>
<td>4</td>
<td>0</td>
<td>2016-01-05</td>
<td>1</td>
<td>1</td>
<td>...</td>
<td>False</td>
<td>3.79</td>
<td>0</td>
<td>66.0</td>
</tr>
</tbody></table>
<ul>
<li>할인이 처치이고 매출이 결과</li>
<li>일련의 날짜 관련 특성들(월, 요일, 휴일 여부 등)도 포함</li>
<li>목표는 CATE 예측이므로 데이터셋을 학습 및 테스트 데이터셋으로 분할하는 것이 가장 좋음</li>
<li>이 경우, 시간 차원을 활용하여 이러한 데이터셋을 구성 할 수 있음</li>
</ul>
<blockquote>
<p>tain = data_cont.query(&quot;day&lt;&#39;2018-01-01&#39;&quot;)<br>test = data_cont.query(&quot;day&gt;=&#39;2018-01-01&#39;&quot;)</p>
</blockquote>
<p>가장 먼저 S 러너 시도</p>
<h3 id="s-러너">S 러너</h3>
<ul>
<li>가장 기본적인 방식</li>
<li>단일 머신러닝 모델 $\hat{u_1}$ 를 사용하여 추정</li>
</ul>
<h4 id="s-러너의-기본-개념">S 러너의 기본 개념</h4>
<ul>
<li>단일 모델 사용: S 러너는 단일 머신러닝 모델을 사용하여 처치 변수와 결과 변수를 함께 학습</li>
<li>모델 적합: 처치 변수(T)와 다른 모든 특징(X)을 사용하여 결과(Y)를 예측</li>
<li>CATE 계산: 모델의 예측값을 이용해 조건부 평균 처치 효과를 추정</li>
</ul>
<h4 id="수식">수식</h4>
<p>$\hat{u_s}(x,t) = E[Y|X =x ,T=t$]
<strong>1.모델 학습:</strong></p>
<ul>
<li>단일 모델 $\hat{u_s}$를 학습시켜 𝑌를 X와 𝑇에 대해 예측.</li>
<li>예를 들어, $\hat{u_s}(x,1)$은 특정 고객이 할인을 받았을 때의 예측 매출, $\hat{u_s}(x,0)$은 할인을 받지 않았을 때의 예측 매출을 의미.</li>
</ul>
<p><strong>2.CATE 계산:</strong></p>
<ul>
<li><p>특정 고객의 CATE는 다음과 같이 계산: </p>
<ul>
<li>$\hat{\tau}(x) = \hat{u_s}(x,1)-\hat{u_s}(x,0)$</li>
</ul>
</li>
</ul>
<h4 id="ex">EX</h4>
<p>CATE를 추정하려면 결과 Y를 예측하려는 모델에 처치변수를 특성으로 포함하면 됨</p>
<blockquote>
<p>X = [&quot;month&quot;, &quot;weekday&quot;, &quot;is_holiday&quot;, &quot;competitors_price&quot;]<br>T = &quot;discounts&quot;
y = &quot;sales&quot;<br>np.random.seed(123)<br>s_learner = LGBMRegressor()<br>s_learner.fit(train[X+[T]], train[y]);</p>
</blockquote>
<ul>
<li>이 모델은 처치효과를 직접 출력하지 않고, 오히려 반사실 예측값을 구함</li>
<li>즉 다양한 처치에서의 예측 가능</li>
<li>처치가 이산형인 경우에도 이 모델은 여전히 작동할 것</li>
<li>실험군과 대조군의 예측값 차이가 CATE 추정값이 됨</li>
</ul>
<p>연속형 처치는 약간의 추가작업이 필요</p>
<ul>
<li>처치의 그리드를 정의</li>
<li>예시에서는 할인율이 0부터 40%까지 변하므로 [ 0,10,20,30,40 ] 그리드 사용 가능</li>
<li>예측하고자 하는 데이터를 확장하여 각 행이 그리드의 각 처칫값을 한번씩 복사해야 함</li>
<li>이를 수행하는 가장 쉬운 방법은 그리드의 값이 있는 데이터 프레임을 예측하려는 데이터에 교차조인 하는 것<blockquote>
<p>t_grid = pd.DataFrame(dict(key=1, discounts=np.array([0, 10, 20, 30, 40])))<br>  test_cf = (test                    .drop(columns=[&quot;discounts&quot;])                    .assign(key=1)                    .merge(t_grid)          # 확장된 데이터에서 예측하기                         .assign(sales_hat = lambda d: s_learner.predict(d[X+[T]])))<br>  test_cf.head(8)</p>
</blockquote>
</li>
</ul>
<table>
<thead>
<tr>
<th></th>
<th>rest_id</th>
<th>day</th>
<th>month</th>
<th>weekday</th>
<th>...</th>
<th>sales</th>
<th>key</th>
<th>discounts</th>
<th>sales_hat</th>
</tr>
</thead>
<tbody><tr>
<td>0</td>
<td>0</td>
<td>2018-01-01</td>
<td>1</td>
<td>0</td>
<td>...</td>
<td>251.5</td>
<td>1</td>
<td>0</td>
<td>67.957972</td>
</tr>
<tr>
<td>1</td>
<td>0</td>
<td>2018-01-01</td>
<td>1</td>
<td>0</td>
<td>...</td>
<td>251.5</td>
<td>1</td>
<td>10</td>
<td>444.245941</td>
</tr>
<tr>
<td>2</td>
<td>0</td>
<td>2018-01-01</td>
<td>1</td>
<td>0</td>
<td>...</td>
<td>251.5</td>
<td>1</td>
<td>20</td>
<td>793.045769</td>
</tr>
<tr>
<td>3</td>
<td>0</td>
<td>2018-01-01</td>
<td>1</td>
<td>0</td>
<td>...</td>
<td>251.5</td>
<td>1</td>
<td>30</td>
<td>1279.640793</td>
</tr>
<tr>
<td>4</td>
<td>0</td>
<td>2018-01-01</td>
<td>1</td>
<td>0</td>
<td>...</td>
<td>251.5</td>
<td>1</td>
<td>40</td>
<td>1512.630767</td>
</tr>
<tr>
<td>5</td>
<td>0</td>
<td>2018-01-02</td>
<td>1</td>
<td>1</td>
<td>...</td>
<td>541.0</td>
<td>1</td>
<td>0</td>
<td>65.672080</td>
</tr>
<tr>
<td>6</td>
<td>0</td>
<td>2018-01-02</td>
<td>1</td>
<td>1</td>
<td>...</td>
<td>541.0</td>
<td>1</td>
<td>10</td>
<td>495.669220</td>
</tr>
<tr>
<td>7</td>
<td>0</td>
<td>2018-01-02</td>
<td>1</td>
<td>1</td>
<td>...</td>
<td>541.0</td>
<td>1</td>
<td>20</td>
<td>1015.401471</td>
</tr>
</tbody></table>
<p>앞 단계에서 각 실험 대상(이 경우 날짜 ) 에 대해 처치 반응 함수 Y(t)의 대략적인 버전을 추정했음
몇몇 실험 대상(일) 에 대한 곡선을 그려서 어떤 모습인지 확인해보겠음
다음 그래프에서 크리스마스인 2018년 12월 25일에 추정된 반응 함수가 2018년 6월 18일보다 더 가파른 모습을 볼 수 있다. 이는 고객이 6월의 특정 날보다 크리스마스에 할인에 더 민감함을 모델이 학습했음을 의미</p>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/d833990c-973c-4a02-a679-78e0b4e17175/image.png" alt=""></p>
<p>각 날짜와 할인율에 대한 반사실 예측을 수행했지만 CATE 예측을 하지 않아 배운 평가방법을 사용할 수 없음</p>
<ul>
<li>실험 대상 수준의 곡선을 단일 숫자로 요약하여 처치효과를 나타내는 CATE 추정값을 얻어야 함.</li>
<li>방법: 선형회귀를 사용하여 각 실험 대상에 대해 회귀분석을 수행하고, 처치의 기울기 매개변수를 추출하여 CATE 추정값으로 활용.</li>
</ul>
<p>단순선형회귀 계수를 사용하여 기울기 매개변수를 추출</p>
<blockquote>
<p><strong>$\hat{\beta}=Cov(t,y)/Var(t)$</strong></p>
</blockquote>
<p>*<em>1.기울기 매개변수 요약 함수 정의:
*</em></p>
<ul>
<li>각 실험 대상의 곡선을 기울기 매개변수로 요약하는 함수를 정의.</li>
</ul>
<p>*<em>2. 데이터 그룹화 및 함수 적용:
*</em></p>
<ul>
<li>확장된 테스트 데이터를 rest_id와 day별로 그룹화하고, 각 그룹에 기울기 함수를 적용.</li>
<li>결과는 인덱스가 rest_id와 day인 판다스 시리즈가 되며, 이 시리즈의 이름을 cate로 지정.</li>
</ul>
<p>*<em>3. CATE 예측값 조인:
*</em></p>
<ul>
<li>생성된 시리즈를 원래 테스트 셋에 조인하여 각 날짜 및 레스토랑의 CATE 예측값을 얻음.</li>
</ul>
<blockquote>
<p>from toolz import curry<br>@curry<br>def linear_effect(df, y, t):             return np.cov(df[y], df[t])[0, 1]/df[t].var()
    cate = (test_cf                 .groupby([&quot;rest_id&quot;, &quot;day&quot;])                 .apply(linear_effect(t=&quot;discounts&quot;, y=&quot;sales_hat&quot;))                 .rename(&quot;cate&quot;))         test_s_learner_pred = test.set_index([&quot;rest_id&quot;, &quot;day&quot;]).join(cate)<br>    test_s_learner_pred.head()</p>
</blockquote>
<p>이제 CATE 예측값이 있으므로 모델을 평가 할 수 있음</p>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/bc77d5fc-617f-4b13-be85-8d4dcece2a57/image.png" alt="">
누적 이득 곡선에서 볼 수 있듯이 S 러너는 간단하지만 이 데이터셋에서 괜찮은 성능을 보임</p>
<ul>
<li>랜덤화된 데이터가 많고 상대적으로 쉬운 해당 데이터셋에 특화된 성능</li>
<li>실제로 S 러너는 그 단순함 때문에 어떤 인과 문제에도 처음 시도하기 좋은 선택</li>
<li>첫째, S 러너는 랜덤화된 데이터가 없어도 괜찮은 성능을 보이는 경향</li>
<li>둘째, S 러너는 이진 및 연속형 처치 모두 활용</li>
</ul>
<h4 id="s-러너의-단점과-해결책-요약">S 러너의 단점과 해결책 요약</h4>
<p>*<em>문제점: S 러너의 편향
*</em></p>
<ul>
<li>정규화 문제: S 러너는 일반적으로 정규화된 머신러닝 모델을 사용하기 때문에, 추정된 처치효과(ATE)가 0으로 편향되는 경향.</li>
<li>실제 사례: 빅터 체르노주코프 등이 작성한 논문에서 시뮬레이션 데이터를 사용하여 S 러너의 ATE 추정을 분석한 결과, 추정된 ATE가 실제 ATE보다 왼쪽으로 편향되어 0에 가까운 경향을 보임.</li>
<li>추정된 ATE의 분포: 시뮬레이션과 추정을 500회 반복한 결과, 추정된 ATE가 실제 ATE보다 작게 나타나는 경우가 많음.</li>
<li>처치변수의 영향력: 처치변수가 다른 공변량보다 결과를 설명하는 데 영향력이 작을 경우, S 러너는 처치변수를 완전히 무시할 수 있다. 이는 선택한 머신러닝 모델과 정규화 정도에 따라 문제가 더 심해질 수 있다.</li>
</ul>
<p>** 해결책: 이중/편향 제거 머신러닝 (R 러너)**</p>
<ul>
<li>R 러너 소개: 체르노주코프 등이 제안한 방법으로, S 러너의 편향 문제를 해결하기 위해 고안된 방법</li>
<li>방법: 이중/편향 제거 머신러닝을 통해 처치효과 추정에서 발생하는 편향을 줄이고, 보다 정확한 ATE 추정을 가능하게 함.</li>
</ul>
<pre><code>----
### 이중/편향 제거 머신러닝 (Double/Debiased Machine Learning)</code></pre><h4 id="개념">개념</h4>
<ul>
<li>이중/편향 제거 머신러닝(또는 R 러너)은 FWL 정리의 정제된 버전 </li>
<li>결과와 처치의 잔차를 구성할 때 머신러닝 모델을 사용하는 간단하면서도 강력한 방법. </li>
<li>이 접근법은 복잡한 상호작용과 비선형성을 잘 포착하며, 다음과 같은 단계로 이루어짐:</li>
</ul>
<p>** 1. 결과 Y 추정**</p>
<ul>
<li>머신 러닝 회귀 모델 $u_y$를 사용하여 특성 X로 결과 Y를 추정</li>
<li>$\hat{u_y}(X)=E[Y|X]$</li>
</ul>
<p><strong>2. 처치 T 추정</strong></p>
<ul>
<li>머신 러닝 회귀 모델 $u_t$를 사용하여 특성 X로 처치 T를 추정<ul>
<li>$\hat{u_t}(X)=E[T|X]$</li>
</ul>
</li>
</ul>
<p><strong>3. 잔차 계산</strong></p>
<ul>
<li>결과의 잔차 : $$\tilde{Y} = Y - \hat{\mu}_y(X)$$</li>
<li>처치의 잔차 : $$\tilde{T} = Y - \hat{\mu}_t(X)$$</li>
</ul>
<p>*<em>4. 잔차 회귀 : *</em></p>
<ul>
<li><p>결과의 잔차를 처치 잔차에 대해 회귀하여 인과 매개변수(ATE)를 추정
$$
\tilde{Y} = \tau \tilde{T} + \alpha
$$</p>
</li>
<li><p>여기서 $(\tau)$는 OLS를 사용하여 추정된 인과 매개변수입니다.</p>
</li>
</ul>
<p>이중/편향 제거 머신러닝(R 러너)은 복잡한 상호작용과 비선형성을 잘 포착하여 정확한 인과 추정을 가능하게 한다. R 러너는 잔차를 사용하여 처치 효과를 추정하는 방법이다.
하지만 </p>
<ul>
<li>동일한 데이터에서 모델을 적합하고 잔차를 구하면 과적합이 발생할 수 있다.</li>
<li>교차 예측(cross prediction)과 아웃 오브 폴드(out-of-fold) 잔차를 사용. 데이터를 K개의 폴드로 분할하고, K-1개의 폴드에서 모델을 학습한 후 남겨진 폴드에서 잔차를 계산</li>
</ul>
<h3 id="이중-머신러닝으로-cate-추정">이중 머신러닝으로 CATE 추정</h3>
<h4 id="cate-추정">CATE 추정</h4>
<p>$$
\hat{\tau}(X) = \frac{\text{Cov}(T, Y)}{\text{Var}(T)}
$$</p>
<h4 id="손실-함수">손실 함수</h4>
<p>R 러너는 다음의 손실 함수를 최소화합니다.
$$
L(\tau) = \frac{1}{n} \sum_{i=1}^{n} \left( \tilde{Y}_i - \tau \tilde{T}_i \right)^2
$$</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[인과추론-그래프 인과모델]]></title>
            <link>https://velog.io/@rokmc1257_lse/%EC%9D%B8%EA%B3%BC%EC%B6%94%EB%A1%A0-%EA%B7%B8%EB%9E%98%ED%94%84-%EC%9D%B8%EA%B3%BC%EB%AA%A8</link>
            <guid>https://velog.io/@rokmc1257_lse/%EC%9D%B8%EA%B3%BC%EC%B6%94%EB%A1%A0-%EA%B7%B8%EB%9E%98%ED%94%84-%EC%9D%B8%EA%B3%BC%EB%AA%A8</guid>
            <pubDate>Mon, 29 Jul 2024 11:18:40 GMT</pubDate>
            <description><![CDATA[<h3 id="사슬구조">사슬구조</h3>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/6698143a-af4e-4d05-8987-78ff9a098d10/image.png" alt=""></p>
<ul>
<li>T는 M의 원인</li>
<li>M은 Y의 원인</li>
<li>중간 노드는 T와 Y 사이의 관계를 연결하므로 매개체 </li>
</ul>
<h3 id="인과관계">인과관계</h3>
<ul>
<li>인과관계는 화살표 방향으로만 흐릅니다.</li>
<li>예: 인과추론 지식 → 문제 해결력 향상 → 승진 가능성 증가<h4 id="연관관계">연관관계</h4>
</li>
<li>연관관계는 양방향으로 흐를 수 있습니다.</li>
<li>예: 인과추론 지식 ↔ 승진 가능성</li>
</ul>
<h4 id="예시-설명">예시 설명</h4>
<ol>
<li>인과관계:</li>
</ol>
<ul>
<li>인과추론 지식이 문제 해결력을 향상시킵니다.</li>
<li>문제 해결력이 향상되면 승진 가능성이 높아집니다.</li>
<li>따라서, 인과추론 지식이 승진의 원인이 됩니다.</li>
</ul>
<ol start="2">
<li>연관관계:</li>
</ol>
<ul>
<li>인과추론 전문성이 높을수록 승진할 가능성이 높아집니다.</li>
<li>승진 가능성이 높을수록 인과추론 지식이 많을 확률도 높습니다.</li>
<li>두 변수는 서로 영향을 주고받으며, 독립적이지 않습니다.</li>
</ul>
<p><strong>T⊥Y</strong>는 독립성을 나타내는 기호. 이는 두 변수 T와Y가 서로 독립적이라는 의미</p>
<h3 id="매개자-고정에-따른-인과관계-차단">매개자 고정에 따른 인과관계 차단</h3>
<p>매개자(M)를 고정한다는 것은 특정 변수의 값을 일정하게 유지하면서 다른 변수들 간의 관계를 관찰하는 것. 이를 통해 고정 변수의 영향을 통제하고, 다른 변수들 간의 관계를 명확하게 이해할 수 있다.</p>
<h4 id="매개자-고정의-효과">매개자 고정의 효과</h4>
<ul>
<li><p><strong>M (문제 해결력)</strong>을 고정하면, T (인과추론 지식)와 Y (승진 가능성) 간의 직접적인 연관성이 차단</p>
</li>
<li><p>공식적으로, M에 대한 조건부는 다음과 같이 표현:
T$\perp$Y$\vert$M</p>
</li>
<li><p>이는 M이 주어졌을 때, T와 Y는 독립임을 의미</p>
</li>
</ul>
<p>조건부 독립성</p>
<ul>
<li><p>수학적 표현</p>
<ul>
<li><p>$E[승진\vert 문제해결력, 인과추론 지식]= E[승진\vert문제해결력]$</p>
</li>
<li><p>문제 해결력이 동일한 사람들 사이에서는 인과추론 지식(T)이 승진 가능성(Y)에 대한 추가 정보를 제공하지 않는다.</p>
</li>
</ul>
</li>
<li><p>반대의 경우 </p>
</li>
</ul>
<pre><code>- $E[인과추론 지식\vert 문제해결력, 승진]= E[인과추론 지식\vert문제해결력]$
- 문제 해결력을 알면, 승진 상태가 인과추론 지식에 대한 추가 정보를 제공하지 않는다.</code></pre><hr>
<h2 id="분기구조">분기구조</h2>
<ul>
<li>분기 구조는 공통 원인이 두 변수에 영향을 미치는 구조</li>
<li>그래프에서 공통 원인이 화살표를 통해 두 변수에 연결.</li>
<li>이 구조에서는 두 변수가 직접적인 인과관계가 없더라도 공통 원인 때문에 연관성을 가질 수 있다.</li>
<li>인과추론에서 처치와 결과 사이에 공통원인이 있을 때 공통 원인을 <strong>교란 요인</strong>이라 함</li>
</ul>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/105be656-d2d7-45e4-8912-c944f141cfa3/image.png" alt=""></p>
<p>예시: 인과추론, 머신러닝, 통계학</p>
<ul>
<li>통계 지식이 높으면 인과추론과 머신러닝 지식 모두 높을 가능성이 있다.</li>
<li>통계 지식이 없는 경우, 인과추론 지식이 머신러닝 지식에 대한 추가 정보를 제공할 수 있다.</li>
</ul>
<p><strong>조건부 독립성</strong></p>
<ul>
<li>공통 원인(X)가 주어지면 두 변수는 독립적이게 됨</li>
</ul>
<p><strong>수식</strong></p>
<ul>
<li><p>조건이 없느 경우 $T \not\perp Y$</p>
</li>
<li><p>X가 주어진 경우 T$\perp$Y$\vert$X</p>
</li>
</ul>
<hr>
<h2 id="충돌부-구조">충돌부 구조</h2>
<ul>
<li>충돌부 구조는 두 변수가 하나의 공통 결과 변수(자식)를 공유하지만, 두 변수 간에는 직접적인 관계가 없는 구조.</li>
<li>두 변수는 공통의 효과를 공유하며, 이 공통 효과는 두 화살표가 충돌하는 지점이므로 충돌부.</li>
<li>두 부모 노드는 서로 독립적.</li>
<li>공통 효과(자식 변수)를 조건부로 두면 부모 노드들은 종속적으로 변함.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/86c2228b-c982-4c0e-8950-1090bdfe0b3e/image.png" alt=""></p>
<p>통계를 잘 알거나 상사에게 아부하는 사람이 승진할 수 있다.
승진(X)을 조건부로 하지 않으면 통계 지식(Y)과 아부(T)는 독립적.
승진(X)을 조건부로 하면 통계 지식(Y)과 아부(T)는 종속적으로 변함.</p>
<p><strong>조건부 독립성과 종속성</strong>
*<em>조건부가 없는 경우:
*</em>통계 지식(Y)과 아부(T)는 독립적.
 $T \not\perp Y$</p>
<p><strong>조건부가 있는 경우:</strong>
승진 여부(X)를 조건부로 두면, 통계 지식(Y)과 아부(T)는 종속적이다.
 $T \not\perp Y\vert X$</p>
<p><strong>예시 설명
독립성:</strong></p>
<ul>
<li><p>승진 여부를 모른다면, 통계 지식이 상사에게 아부하는 정도에 대해 아무 정보도 제공하지 않는다.</p>
</li>
<li><p><em>종속성:*</em></p>
</li>
<li><p>승진(X)을 조건부로 두면, 통계 지식(Y)과 아부(T)는 종속적이 됩니다.</p>
</li>
<li><p>ex) 승진(X)했다면, 통계 지식(Y)이 낮은 사람은 상사에게 아부(T)하는 정도가 높을 가능성이 있다. 통계 지식(Y)이 높은 사람은 상사에게 아부(T)할 필요가 적어진다.</p>
</li>
</ul>
<p>중요한 것은, 충돌부에 대한 조건부 대신 (직접적이든 아니든) 충돌부의 효과에 조건부를 두어도 동일한 종속 경로dependence path를 열 수 있다는 점
예제에 승진이 연봉을 크게 올린다는 가정을 추가해보자
<img src="https://velog.velcdn.com/images/rokmc1257_lse/post/8690f989-3062-42ec-b405-476e40e9ece6/image.png" alt=""></p>
<p>*<em>조건부의 효과
*</em>
충돌부(X1) 대신 효과(X1)에 조건부:</p>
<ul>
<li>승진(X1)을 직접 조건부로 하지 않고, 승진(X1)의 효과인 높은 연봉(X2)을 조건부로 해도 부모 노드(Y와 T)는 종속적으로 변함.</li>
<li>즉, 승진(X1) 정보를 몰라도 높은 연봉(X2) 정보를 안다면, 통계 지식(Y)과 아부(T)는 종속적이 됨.</li>
</ul>
<p>*<em>조건부가 없는 경우:
*</em></p>
<ul>
<li>$Y \perp T$</li>
<li>통계 지식(Y)과 상사에게 아부하는 정도(T)는 독립적.</li>
</ul>
<p><strong>승진(X1)에 조건부인 경우:</strong></p>
<ul>
<li><p>$Y \not\perp T \vert X1$</p>
</li>
<li><p>승진 여부(X1)를 조건부로 하면, 통계 지식(Y)과 아부(T)는 종속적이 됨.</p>
</li>
</ul>
<p><strong>연봉(X2)에 조건부인 경우:</strong> </p>
<ul>
<li><p>$Y \not\perp T\vert X2$</p>
</li>
<li><p>승진 여부(X1)를 모르지만 연봉(X2)을 조건부로 하면, 통계 지식(Y)과 아부(T)는 종속적이 된다.</p>
</li>
</ul>
<hr>
<h2 id="연관성-흐름-치트-시트">연관성 흐름 치트 시트</h2>
<p>차단 경로의 필요충분조건
*<em>1. 조건으로 주어진 비충돌부(non-collider) 구조 포함
*</em></p>
<ul>
<li>사슬(chain) 또는 분기(fork) 구조에서 조건부로 주어진 비충돌부가 포함되면 경로가 차단된다.</li>
</ul>
<p>*<em>2. 조건부로 주어지지 않고 자식(descendant)이 없는 충돌부(collider) 포함
*</em>충돌부가 조건부로 주어지지 않고, 그 자식도 조건부로 주어지지 않으면 경로가 차단된다.</p>
<p><strong>치트 시트 요약</strong>
<strong>사슬 구조:</strong></p>
<ul>
<li>A→B→C 또는 A←B←C</li>
<li>B가 조건부로 주어지면 A와 C는 독립적</li>
<li><em>분기 구조:*</em></li>
<li>A←B→C</li>
<li>B가 조건부로 주어지면 A와 C는 독립적</li>
<li><em>충돌부 구조:*</em></li>
<li>A→B←C</li>
<li>B가 조건부로 주어지지 않으면 A와 C는 독립적</li>
<li>B가 조건부로 주어지면 A와 C는 종속적</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[인과추론-1]]></title>
            <link>https://velog.io/@rokmc1257_lse/%EC%9D%B8%EA%B3%BC%EC%B6%94%EB%A1%A0-%EA%B8%B0%EC%B4%88-%EC%9D%B8%EA%B3%BC%EC%B6%94%EB%A1%A0-%EC%86%8C%EA%B0%9C</link>
            <guid>https://velog.io/@rokmc1257_lse/%EC%9D%B8%EA%B3%BC%EC%B6%94%EB%A1%A0-%EA%B8%B0%EC%B4%88-%EC%9D%B8%EA%B3%BC%EC%B6%94%EB%A1%A0-%EC%86%8C%EA%B0%9C</guid>
            <pubDate>Sat, 27 Jul 2024 16:34:25 GMT</pubDate>
            <description><![CDATA[<h2 id="인과추론-소개">인과추론 소개</h2>
<ul>
<li><p>연관관계</p>
<ul>
<li>두 개의 수치나 확률변수가 같이 움직이는 것</li>
</ul>
</li>
<li><p>인과관계</p>
<ul>
<li>한 변수의 변화가 다른 변수의 변화를 일으키는 것</li>
</ul>
</li>
</ul>
<p>즉, 인과추론은 연관관계로부터 인과관계를 추론하고 언제, 그리고 왜 서로 다른지 이해하는 것</p>
<hr>
<h2 id="인과추론의-목적">인과추론의 목적</h2>
<ul>
<li><p>현실을 이해하는 것</p>
</li>
<li><p>일반적으로 원인과 결과의 관계를 알아야만 원인에 개입하여 원하는 결과를 가져 올 수 있음</p>
<ul>
<li>ex : 회사에서 인과추론 소개서 마케팅 비용이 매출 증가로 이어지는지 알고 싶어 하는 이유는, 만약 그렇다면 이를 지렛대 삼아 수익을 늘릴 수 있기 때문</li>
</ul>
</li>
</ul>
<hr>
<h2 id="연관관계와-인과관계">연관관계와 인과관계</h2>
<p>해당 기간에 가격을 할인하면 판매량이 어떻게 증가하는지를 살펴보고, 여러 어린이 장난감 기업의 데이터를 활용해서 할인이 좋은 생각인지 판단해보겠다.</p>
<table>
<thead>
<tr>
<th></th>
<th>store</th>
<th>weeks_to_xmas</th>
<th>avg_week_sales</th>
<th>is_on_sale</th>
<th>weekly_amount_sold</th>
</tr>
</thead>
<tbody><tr>
<td>0</td>
<td>1</td>
<td>3</td>
<td>12.98</td>
<td>1</td>
<td>21960</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>2</td>
<td>12.98</td>
<td>1</td>
<td>18470</td>
</tr>
<tr>
<td>2</td>
<td>1</td>
<td>1</td>
<td>12.98</td>
<td>1</td>
<td>14575</td>
</tr>
<tr>
<td>3</td>
<td>1</td>
<td>0</td>
<td>12.98</td>
<td>0</td>
<td>10245</td>
</tr>
<tr>
<td>4</td>
<td>2</td>
<td>3</td>
<td>19.92</td>
<td>0</td>
<td>10322</td>
</tr>
<tr>
<td>5</td>
<td>2</td>
<td>2</td>
<td>19.92</td>
<td>0</td>
<td>5373</td>
</tr>
</tbody></table>
<ul>
<li>store: 상점의 고유 식별자(ID)</li>
<li>weeks_to_xmas: 크리스마스까지 남은 기간(주)</li>
<li>avg_week_sales: 12월 각 상점의 주간 판매량 </li>
<li>is_on_sale: 해당 주간, 기업의 가격할인 진행 여부(진행 = 1, 미진행 = 0)</li>
<li>weekly_amount_sold: 해당 연도의 상점 주간 평균 판매</li>
</ul>
<blockquote>
<p><strong>분석단위</strong></p>
</blockquote>
<ul>
<li>인과추론 연구에서 분석단위는 일반적으로 개인(처치하려는 대상)</li>
<li>새로운 제품이 유저 잔존에 미치는 영향을 분석할 때 처럼, 분석단위는 대부분 사람</li>
<li>다른 유형의 분석단위를 사용하기도 함</li>
</ul>
<h3 id="처치와-결과">처치와 결과</h3>
<p> 장난감 할인 데이터와 함께 첫 번째 기술적인 내용을 살펴보겠다.</p>
<p> $$T_i$$는 실험 대상 i의 처치 여부를 나타냄</p>
<p> $T_i=
\begin{cases}
1,;실험대상 i \ 가  \ 처치받은\  경우\
0,;실험대상 i \ 가  \ 처치받지\ 않은 \  경우\
\end{cases}$</p>
<ul>
<li>여기서의 처치는 구하려는 효과에 대한 개입을 나타낼때 사용하는 용어</li>
<li>해당 예시에서 처치는 is_on_sale 을 말함</li>
</ul>
<p> 영향을 주려는 변수인 주간 판매량(weekly_amount_sold)를 결과라 칭하겠음
 또한, 실험 대상 i의 결과는 $$Y_i$$로 표기
 &#39;처치&#39;와 &#39;결과&#39;라는 두 개념을 사용하여 인과추론의 목표를 재정의 하자면</p>
<ul>
<li>T가 Y에 미치는 영향을 학습하는 과정</li>
</ul>
<hr>
<h3 id="인과추론의-근본적인-문제">인과추론의 근본적인 문제</h3>
<ul>
<li><p>문제 </p>
<ul>
<li>동일한 실험 대상이 &#39;처치&#39;를 받은 상태와 받지 않은 상태를 동시에 관측할 수 없다는 점</li>
</ul>
</li>
</ul>
<p>좀 더 문제를 직관적으로 알아보자
처치 (is on sale) 에 따른 결과 ( weekly_amount_sold) 그래프를 그려본다.
<img src="https://velog.velcdn.com/images/rokmc1257_lse/post/6ebb2960-a08e-4533-8be0-1b0e8d06c987/image.png" alt=""></p>
<p>그래프를 보면 상품 가격을 낮춘 상품들의 판매량이 더 많음을 알 수 있다.</p>
<p>*<em>할인과 판매량의 관계 
*</em></p>
<ul>
<li>가격이 낮아지면 구매량이 증가하는 경향이 있으며, 이는 우리의 직관과도 일치합니다.</li>
</ul>
<p>*<em>인과추론과 도메인 지식 
*</em></p>
<ul>
<li>상품 할인과 광고 노출은 판매량 증가로 이어질 수 있지만, 이를 단순한 인과관계로 간주하기엔 위험합니다.</li>
</ul>
<p>*<em>데이터 분석 
*</em></p>
<ul>
<li>그래프를 통해 할인 시 판매량이 평균 약 150 단위 더 높아지는 것을 관찰할 수 있습니다. 하지만 이는 의심스러울 정도로 높은 수치입니다.</li>
</ul>
<p>*<em>연관관계와 인과관계 구분
*</em></p>
<ul>
<li>판매량 증가가 단순히 할인의 결과가 아닐 수 있으며, 대기업의 공격적 가격 정책이나 크리스마스 시즌 등의 다른 요인이 영향을 미쳤을 가능성이 있습니다.</li>
</ul>
<p>*<em>반사실 비교의 필요성 
*</em></p>
<ul>
<li>동일한 실험 대상이 할인된 상황과 그렇지 않은 상황을 동시에 관측해야만 할인의 실제 효과를 확신할 수 있습니다. 이는 <strong>인과추론의 근본적인 문제로, 반사실 상황을 통해 해결</strong>할 수 있습니다. 앞서 설명했듯이 인과추론의 근본적인 문제는 동일 대상의 두 상황을 동시에 관측할 수 없다는 점 대신 다른 방법을 찾아야 함.</li>
</ul>
<hr>
<h3 id="인과모델">인과모델</h3>
<p>모든 문제를 직관적으로 추론할 수 있지만 단순한 직관을 넘어서려면 공식적인 표기법이 필요</p>
<ul>
<li>화살표 ($\larr$) 로 표시하는 일련의 할당 메커니즘</li>
</ul>
<p>다음 인과모델을 예로 들어보겠다
u를 사용해 모델 외부의 변수를 나타내며, 변수 u가 어떻게 생성되었는지 따로 설명하지 않을 것
$$T \larr f_t(u_t)$$
$$Y \larr f_y(T,u_y)$$</p>
<ul>
<li>첫 번째 식에서, 모델링하지 않는 변수 집합 $$u_t(외부변수)^2$$가 함수$$f_t$$롤 통해 처치변수 T를 유발하는 원인</li>
<li>두 번째 식에서 처치변수 T는 다른 변수 집합 $u_y$(또한, 모델링하지 않을 변수) 와 함께 함수$f_y$를 통해 결과 Y를 유발</li>
<li>해당 수식에서 $u_y$는 결과가 단순히 처치변수만으로 결정되지 않음을 나타냄</li>
<li>즉 모델링하지 않기로 선택한 변수라 하더라도 결과에 영향을 미침</li>
</ul>
<p>EX ) 가격할인 예시에 적용</p>
<ul>
<li>weekly_amount_sold( 결과변수 Y ) 는 처치에 해당하는 할인 is_on_sale ( 처치변수 T ) 및 특정되지 않은 요인들인 u (외부 변수 )  때문에 발생</li>
<li>변수 u의 목적은 모델에 포함된 변수로는 설명되지 않은 변수의 모든 변동을 설명하는 것 -&gt; 이를 내생변수</li>
<li>해당 예시에서는 가격할인이 모델 내에 없는 요인들( 기업 규모 등 ) 때문에 유발</li>
</ul>
<p>IsOnSales $\larr f_t(u_t)$
AmountSold $\larr f_y(IsOnSales, u_y)$</p>
<p>*<em>인과관계 비가역성
*</em></p>
<ul>
<li>$\larr$ 대신 (=) 를 사용하면 Y = T + X 와 T = Y - X 가 같아진다. T가 Y의 원인인 것과 그 반대인 Y가 T의 원인이지 않다. 이를 구분하기 위해 화살표 사용</li>
</ul>
<p>*<em>외부 변수 (u)
*</em></p>
<ul>
<li>모델에서 설명되지 않는 변동을 설명. 예를 들면 기업들이 더 공격적으로 할인을 진행할 수 있는 요인은 모델에 포함되지 않는 변수 u로 설명 가능</li>
</ul>
<p>*<em>내생변수
*</em></p>
<ul>
<li>관측되지 않은 요인 (u)에 의해 영향을 받는 변수 예시에서는 is_on_sale이 모델 내에 없는 BusinessSize 때문에 유발</li>
</ul>
<p>모델을 더 정밀하게 만들기 위해 외부 변수(u)를 모델에 포함시킬 수 있다. 예를 들어, 대기업들의 할인 전략이 판매량에 미치는 영향을 더 잘 이해하기 위해 BusinessSize를 모델에 포함시킬 수 있다.</p>
<hr>
<h4 id="인과추론-모델링-쉽게-설명하기">인과추론 모델링 쉽게 설명하기</h4>
<p>인과추론 모델링은 변수들 간의 인과관계를 명확히 하기 위해 사용하는 방법. 이번에는 &quot;BusinessSize&quot;라는 변수를 추가해서 좀 더 정교하게 모델링하는 방법을 알아보겠다.</p>
<p>*<em>기존 모델
*</em></p>
<ul>
<li>IsOnSales (처치변수 T) $\larr f_t(u_t)$</li>
<li>AmountSold (결과변수 Y) $\larr f_y(IsOnSales, u_y)$</li>
<li>외부변수 (u) : 모델에 포함되지 않은 기타 요인들</li>
</ul>
<p>*<em>새로운 변수 추가 : BusinessSize
*</em></p>
<p>BusinessSize $\larr f_s(u_s)$
IsOnSales $\larr f_t(BusinessSize, u_t)$
AmountSold $\larr f_y(IsOnSales, BusinessSize, u_y)$</p>
<ul>
<li>&quot;BusinessSize&quot;라는 추가 내생변수를 모델에 추가하려고 함. </li>
<li>해당 변수가 어떻게 생성되었는지 수식을 추가 BusinessSize를 모델 외부변수에서 다루지 않도록 $u_t$에서 제외ㅗ</li>
<li>두 번째 수식은 isonsale의 원인이 businesssSize와 u ( 모델링하지 않기로 선택한 다른 외부 변수들) 임을 의미. 즉, 대기업이 가격을 할인할 가능성이 높다는 믿음을 수식 표현</li>
<li>BusinessSize는 isonSale(처치)와 amountsold(결과)의 모두의 공통 원인 즉, 대기업들이 더 많이 판매한다는 생각을 표현한 식</li>
</ul>
<p>선형 모델 표현
$AmountSold_i = a + β_1IsOnSales_i + β_2BusinessSize_i +e_i$</p>
<ul>
<li>a는 상수항으로 모델이 기본적으로 갖는 기준점. 독립 변수들이 모두 0인 상태에서 종속 변수( 판매량 )가 어떤 값을 가지는지를 나타냄</li>
<li>β₁과 β₂는 변수들의 영향력을 나타내는 계수.</li>
<li>$e_i$는 모델에 포함되지 않은 외부 요인.</li>
</ul>
<hr>
<h3 id="개입">개입</h3>
<p>인과모델을 통해 어떤 일이 왜 일어나는지 이해하고, 이를 개선할 수 있는 방법을 찾을 수 있다. 특히, 우리가 특정 변수를 조작했을 때 어떤 결과가 나올지를 예측할 수 있다. 이를 <strong>개입(intervention)</strong>이라고 함.</p>
<ul>
<li>수학적으로 개입을 do(.)연산자를 활용해 나타낼 수 있음</li>
<li>T에 개입해 어떤 일이 일어날지를 추론하고 싶다면 do(T=$t_0)로 표현 가능</li>
</ul>
<blockquote>
<p>기댓값</p>
</blockquote>
<ul>
<li>평균이 추정하려는 모집단값</li>
<li>기댓값은 평균이 추정하려는 모집단의 값</li>
<li>E[X]는 확률 변수 X의 기댓값</li>
<li>E[$Y\vert X = x$]는 X=x가 주어졌을 때 Y에 대한 기댓값을 나타냄, 이는 X=x일 때 Y의 평균으로 근사될 수 있음</li>
</ul>
<p>*<em>연관관계와 인과관계의 차이
*</em> do 연산자를 통해 다른 이유를 한눈에 알 수 있음</p>
<p>앞서 <strong>가격을 할인한 회사의 판매량 기댓값  E[AmountSold|IsOnSales = 1]</strong> 이 높으면, <strong>가격을 할인하도록 개입한 경우의 판매량 기댓값 E[AmountSold|do(IsOnSales = 1)]</strong> 이 과대 추정될 수 있다고 주장한 바 있다.
이때 첫번째 경우처럼 가격을 할인하기로 결정한 회사는 대기업일 확률이 높다.
반면 <strong>E[AmountSold|do(IsOnSales = 1)]</strong> 은 모든 회사가 가격을 할인 통재 했을 때 어떤 일이 발생했을지를 나타낸다.
일반적으로 <strong>가격을 할인한 회사의 판매량에 대한 조건부 기댓값과 할인하도록 통제한 회사의 판매량에 대한 조건부 기댓값은 다르다는 점</strong> </p>
<p>*<em>선택(selection)과 개입(intervention)의 차이
*</em> </p>
<ul>
<li>선택(selection): 할인 여부에 따라 실제로 할인한 회사들의 판매량을 측정.</li>
<li>개입(intervention): 모든 회사가 할인하도록 한 후 전체 회사들의 판매량을 측정.</li>
</ul>
<p>do(.) 연산자는 관측된 데이터에서 직접 얻을 수 없는 인과 추정량(causal quantity)을 정의하는 데 사용. 예를 들어, 실제로 모든 회사가 할인하지 않았기 때문에 do(IsOnSales = 1) 상황을 관측할 수 없다. 따라서, do(.) 연산자는 이론적 개념으로 사용되어 우리가 구하려는 인과 추정량을 명확히 표현다.</p>
<p>식별(Identification)
인과추론은 직접 관측할 수 없는 인과 추정량을 이론적으로 표현하고, 이를 식별하는 과정. 이는 우리가 실제로 개입하지 않고도 인과관계를 이해할 수 있도록 도와줌</p>
<hr>
<h3 id="개별-처치효과-individual-treatment-effectite">개별 처치효과 individual treatment effect(ITE)</h3>
<ul>
<li>do 연산자를 사용하면 개별 시험 대상 i에 처치가 결과에 미치는 영향인 ITE를 표현 할 수 있다.</li>
<li>다음 식과 같이 두 개입의 차이로 나타낼 수 있음
$\tau_i = Y_i\vert do(T=t_i)-Y_i \vert do(T=t_0)$</li>
</ul>
<p>즉, 각 실험 대상 i에 대한 처치가 $t_0$에서 $t_i$로 바뀔 떄의 효과 $\tau$는 $t_0$와 비교하여 $t_1$의 결과 차이를 나타냄</p>
<p>이를 사용하여 AmountSold에서 IsOnSales를 0에서 1로 바꿀 때의 효과도 추론할 수 있다.
$\tau_i = AmountSold_i\vert do(IsOnSales=1)-AmountSold_i \vert do(IsOnSales=0)$</p>
<p>인과추론의 근본적인 문제 때문에 앞의 식 중 한가지 항에 대해서만 관측
따라서, 이론적으로 해당 식을 표현할 수 있다해도 반드시 데이터에서 이를 찾을 수 있다는 뜻은 아님</p>
<hr>
<h3 id="잠재적-결과">잠재적 결과</h3>
<p>잠재적 결과는 인과추론에서 중요한 개념으로, 특정 처치(treatment)가 주어졌을 때 결과가 어떻게 될지를 나타낸다. 이를 통해 우리가 실제로 관측할 수 있는 결과와 관측할 수 없는 결과를 구분할 수 있다.</p>
<p>$Y_{ti} =Y_i \vert do(T_i=t)$</p>
<ul>
<li>이는 &#39;처치가 t인 상태일 때, 실험 대상의 i 결과는 Y가 될 것이다&#39;를 의미</li>
</ul>
<p>범주가 두 개인 이진 처치(처치 또는 미처치)에 관해 이야기 할 때, </p>
<ul>
<li>처치 받지 않은 실험 대상 i의 잠재적 결과 $Y_{0i}$ </li>
<li>처치 받는 동일 대상의 i의 잠재적 결과를 $Y_{1i}$로 표기</li>
<li>관측할 수 있는 한가지 잠재적 결과를 사실적 결과</li>
<li>관츨 할 수 없는 다른 한가지 결과를 반사실적 결과</li>
</ul>
<p>실험대상 i 가 처치 받은 후 어떤 일이 일어나는지 사실적 결과 확인 가능, 반대로 처치 받지 않으면 어떤 일어나는지 알 수 없음 $Y_{0i}$는 반사실적 결과이므로 관측 할 수 없음 </p>
<p> $Y_i=
\begin{cases}
Y_{1i},;실험대상 i \ 가  \ 처치받은\ 잠재적\  결과\
Y_{0i},;실험대상 i \ 가  \ 처치받지\ 않은 \ 잠재적\  결과\
\end{cases}$</p>
<p>잠재적 결과를 다음과 같이도 표현 가능
$Y_i = T_iY_{1i} +(1-T_i)Y_{0i}=Y_0i+(Y_{1i}-Y_{0i})T_i$</p>
<p>ex) </p>
<ul>
<li>$AmountSoid_0i$ 는 회사 i가 가격을 할인하지 않았을 경우 판매량</li>
<li>$AmountSoid_1i$ 는 회사 i가 가격을 할인했을  경우 판매량</li>
<li>또한 잠재적 결과에 따라 회사 i의 인과 효과를 정의 할 수 있음
$\tau = Y_{1i}-Y_{0i}$</li>
</ul>
<hr>
<h3 id="일치성-및-sutva-stable-unit-treatment-value-assumption">일치성 및 SUTVA (Stable Unit Treatment Value Assumption)</h3>
<p>인과추론에서는 두 가지 중요한 가정을 사용합니다. 이 가정들이 지켜지지 않으면 인과관계를 정확하게 추론하기 어렵습니다.</p>
<h4 id="1-일치성-가정-consistency-assumption">1. 일치성 가정 (Consistency Assumption)</h4>
<p>일치성 가정은 특정 처치가 주어졌을 때 그 처치에 대한 잠재적 결과가 실제 결과와 일치해야 한다는 것을 의미.</p>
<ul>
<li><p>일치성의 의미: $T_i=t$ 일 때, 잠재적 결과 $Y_i(t)$는 실제 결과 Y와 같아야 함</p>
</li>
<li><p>예시</p>
<ul>
<li><p>할인 쿠폰을 받았을 때 매출이 증가하는지 알고 싶다고 합시다. 여기서 처치는 쿠폰을 받았는지 여부입니다. 하지만 여러 번 할인을 시도했다면, 단순히 쿠폰을 받았는지 여부만으로는 정확한 결과를 알 수 없습니다.</p>
</li>
<li><p>또 다른 예로, 재무 설계사의 조언이 개인 자산에 미치는 영향을 알고 싶다면, 일회성 상담과 정기적인 조언을 하나로 묶으면 안 됩니다. 각각의 처치를 명확히 정의해야 일치성 가정이 지켜집니다.</p>
</li>
</ul>
</li>
</ul>
<h4 id="2-상호-간섭-없음-no-interference-또는-sutva">2. 상호 간섭 없음 (No Interference) 또는 SUTVA</h4>
<p>SUTVA는 한 실험 대상의 처치가 다른 실험 대상의 결과에 영향을 미치지 않아야 한다는 가정</p>
<ul>
<li><p>상호 간섭의 의미: 한 대상에 대한 처치가 다른 대상의 결과에 영향을 미치지 않도록 해야 합니다.</p>
</li>
<li><p>예시</p>
<ul>
<li>백신의 효과를 연구할 때, 한 사람에게 백신을 접종하면 그 주변 사람들도 질병에 걸릴 확률이 낮아질 수 있습니다. 이 경우, 한 사람의 처치가 다른 사람에게 영향을 미치는 것이므로 SUTVA가 위배됩니다.</li>
<li>만약 백신의 파급 효과가 있다면, 백신을 맞은 사람과 맞지 않은 사람 사이의 차이는 작아지므로 실제 처치효과를 과소평가하게 됩니다.</li>
</ul>
</li>
</ul>
<h4 id="가정-위배-해결-방법">가정 위배 해결 방법</h4>
<p> 가정이 위배되는 상황에서도 이를 해결할 수 있는 방법들이 있습니다.</p>
<ol>
<li>일치성 가정 위배 해결:</li>
</ol>
<ul>
<li>분석 시 처치에 대한 모든 버전을 포함하면 됩니다. 예를 들어, 여러 종류의 재무 상담을 각각 다르게 고려하는 것입니다.</li>
</ul>
<ol start="2">
<li>SUTVA 위배 해결:</li>
</ol>
<ul>
<li>파급 효과를 고려한 모델을 사용하면 됩니다. 처치효과의 정의를 확장하여 다른 대상에서 발생하는 효과를 포함시킵니다.</li>
</ul>
<hr>
<h3 id="인과-추정량">인과 추정량</h3>
<ul>
<li>인과추론의 근본적 문제, 잠재적 결과 중 하나만 관측할 수 있으므로 개별 처치효과를 알 수 없음</li>
<li>개별 효과$tau_t$를 알 수는 없지만 데이터에서 학습 할 수 있는 세 가지 인과 추정량을 알아보겠다.</li>
</ul>
<h4 id="평균-처치효과-average-treatment-effectate">평균 처치효과 average treatment effect(ATE)</h4>
<p>세 가지 방식으로 정의</p>
<ol>
<li>$ATE = E[tau_i]$ </li>
<li>$ATE = E[Y_{1i}-Y_{0i}]$ </li>
<li>$ATE = E[Y \vert do(T=1)]-E[Y \vert do(T=0)]$ </li>
</ol>
<ul>
<li>평균 처치효과는 T가 평균적으로 미치는 영향을 나타냄 실험 대상에 따라 더 많거나 더 적은 영향을 받을 수 있지만 개별 대상에 미치는 영향을 알 수 없음</li>
<li>데이터에서 ATE를 추정하고 싶다면 기댓값을 표본평균으로 대체 할 수 있음
다음과 같이 나타낼 수 있음
$\frac1N\displaystyle\sum_{i=0}^{N}{\tau_i}$
$\frac1N\displaystyle\sum_{i=0}^{N}{(Y_{1i}-Y_{0i})}$</li>
</ul>
<p>물론 인과추론의 근본적인 문제 때문에 각 실험 대상마다 잠재적 결과 중 하나만 관측되므로 실제로 이와 같이 계산 할 수 는 없음</p>
<h4 id="실험군에-대한-평균-처치효과-average-treatment-effect-on-the-treatedatt">실험군에 대한 평균 처치효과 average treatment effect on the treated(ATT)</h4>
<p>$ATT = E[Y_{1i}-Y_{0i} \vert T=1]$</p>
<ul>
<li>$Y_{1i}$ 처치 받은 대상의 결과</li>
<li>$Y_{0i}$ 처치 받지 않았을 경우의 결과</li>
<li>T = 1 처치 받은 대상들</li>
</ul>
<h4 id="조건부-평균-처치효과conditional-average-treatment-effectcate">조건부 평균 처치효과conditional average treatment effect(CATE)</h4>
<p>$CATE = E[Y_{1i}-Y_{0i} \vert X =x]$</p>
<p>예를 들어, 이메일 마케팅이 45세 이상의 고객과 45세 미만의 고객에게 미치는 영향을 알고 싶다면, CATE를 사용. 이렇게 하면 특정 연령대의 고객이 마케팅 캠페인에 어떻게 반응하는지 알 수 있다.
$CATE_{45}+ = E[Y_{1i}-Y_{0i} \vert AGE \ge 45]$
$CATE_{&lt;45} = E[Y_{1i}-Y_{0i} \vert AGE &lt; 45]$</p>
<p>연속형 처치변수의 인과 추정량
처치변수가 연속형일 때는 차이를 편도함수(partial derivative)로 대체하여 인과 추정량을 정의할 수 있다
$\frac \partial {\partial t}E[Y_i]$</p>
<ul>
<li>이는 처치가 조금 증가 할 때 $E[Y_i]$가 얼마나 변화할 것으로 기대하는지를 나타내는 방법</li>
</ul>
<hr>
<h3 id="인과-추정량-예시">인과 추정량 예시</h3>
<p>가격할인 개별 회사에 미치는 영향을 알려면 두 가지 잠재적 결과, ${AmountSold_0i},{AmountSold_1i}$를 동시에 확인해야 함
개별 효과 대신, 가격할인이 판매량에 미치는 평균 영향과 같이 추정할 수 있는 항목에 초점을 맞출 수 있다.</p>
<table>
<thead>
<tr>
<th></th>
<th>y0</th>
<th>y1</th>
<th>t</th>
<th>x</th>
<th>y</th>
<th>te01</th>
</tr>
</thead>
<tbody><tr>
<td>0</td>
<td>200</td>
<td>220</td>
<td>0</td>
<td>0</td>
<td>200</td>
<td>20</td>
</tr>
<tr>
<td>1</td>
<td>120</td>
<td>140</td>
<td>0</td>
<td>0</td>
<td>120</td>
<td>20</td>
</tr>
<tr>
<td>2</td>
<td>300</td>
<td>400</td>
<td>0</td>
<td>1</td>
<td>300</td>
<td>100</td>
</tr>
<tr>
<td>3</td>
<td>450</td>
<td>500</td>
<td>1</td>
<td>0</td>
<td>500</td>
<td>50</td>
</tr>
<tr>
<td>4</td>
<td>600</td>
<td>600</td>
<td>1</td>
<td>0</td>
<td>600</td>
<td>0</td>
</tr>
<tr>
<td>5</td>
<td>600</td>
<td>800</td>
<td>1</td>
<td>1</td>
<td>800</td>
<td>200</td>
</tr>
</tbody></table>
<ul>
<li>i는 실험 대상</li>
<li>y는 관측된 결과</li>
<li>$y_0,y_1$은 각각 실험군 및 대조군에 따른 잠재적 결과</li>
<li>t는 처치 여부</li>
<li>x는 크리스마스까지의 시간을 표시하는 공변량</li>
<li>할인여부는 처치, 판매량은 결과</li>
<li>크리스마스 일주일 전에 데이터를 수집 했으며 이는 x = 1로 표시</li>
</ul>
<ol>
<li>ATE (Average Treatment Effect)</li>
</ol>
<ul>
<li>$ATE = E[AmountSold_{1i}-AmountSold_{0i}]$</li>
<li>계산: 모든 회사의 처치 효과 평균
  $ATE = \frac{(20+20+100+50+0+200)}6=65$</li>
<li>이는 가격 할인이 평균적으로 판매량을 65개 증가시킨다는 </li>
</ul>
<ol start="2">
<li>ATT (Average Treatment Effect on the Treated)</li>
</ol>
<ul>
<li>$ATE = E[AmountSold_{1i}-AmountSold_{0i}\vert T=1]$</li>
<li>계산: 처치를 받은 회사들의 처치 효과 평균
  $ATT = \frac{(50+0+200)}3=83.33$
이는 가격 할인이 평균적으로 판매량을 83.3개 증가시킨다는 의미</li>
</ul>
<ol start="3">
<li>CATE (Conditional Average Treatment Effect)</li>
</ol>
<ul>
<li><p>정의: 특정 조건(x = 1 또는 x = 0)에서의 처치 효과</p>
</li>
<li><p>계산</p>
<ul>
<li><p>x = 1 ( 크리스마스 1 주일 전 )
$CATE_{x=1} = \frac{(100+200)}2=150$</p>
</li>
<li><p>x = 1 ( 크리스마스 주간 )
$CATE_{x=0} = \frac{(20+20+50+0)}4=22.5$</p>
</li>
</ul>
</li>
</ul>
<p>즉, 회사가 크리스마스 주간에 가격을 할인했을 때(22.5개 증가)보다 크리스마스 1주일 전에 할인했을 때(150개 증가)가 훨씬 더 많은 혜택을 누린 것으로 나타났다. 따라서 가격을 일찍 할인한 매장이 나중에 할인한 매장보다 더 많은 이득을 보았다.</p>
<p>현실 세계의 데이터 분석</p>
<ul>
<li>현실에서는 잠재적 결과 중 하나만 볼 수 있다. 따라서 개별 처치효과를 정확히 파악하기 어렵다.</li>
</ul>
<p>결측값 문제</p>
<ul>
<li>인과추론에서는 결측값이 있는 데이터를 처리하는 것이 중요. 누락된 잠재적 결과를 대체(impute)해야 함.</li>
</ul>
<p>예시 데이터</p>
<ul>
<li>다음 표는 실제로 보유한 데이터의 예시. 여기서는 잠재적 결과 중 하나만 관측할 수 있다.</li>
</ul>
<table>
<thead>
<tr>
<th></th>
<th>i</th>
<th>y0</th>
<th>y1</th>
<th>t</th>
<th>x</th>
<th>y</th>
<th>te01</th>
</tr>
</thead>
<tbody><tr>
<td>0</td>
<td>1</td>
<td>200</td>
<td>NaN</td>
<td>0</td>
<td>0</td>
<td>200</td>
<td>NaN</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>120</td>
<td>NaN</td>
<td>0</td>
<td>0</td>
<td>120</td>
<td>NaN</td>
</tr>
<tr>
<td>2</td>
<td>3</td>
<td>300</td>
<td>NaN</td>
<td>0</td>
<td>1</td>
<td>300</td>
<td>NaN</td>
</tr>
<tr>
<td>3</td>
<td>4</td>
<td>NaN</td>
<td>500</td>
<td>1</td>
<td>0</td>
<td>500</td>
<td>NaN</td>
</tr>
<tr>
<td>4</td>
<td>5</td>
<td>NaN</td>
<td>600</td>
<td>1</td>
<td>0</td>
<td>600</td>
<td>NaN</td>
</tr>
<tr>
<td>5</td>
<td>6</td>
<td>NaN</td>
<td>800</td>
<td>1</td>
<td>1</td>
<td>800</td>
<td>NaN</td>
</tr>
</tbody></table>
<p>이 수치를 보고 ‘확실히 이상적이지는 않지만, 실험군의 평균을 대조군의 평균과 비교하면 안 될까? 즉, ATE = (500 + 600 + 800) / 3 - (200 + 120 + 300) / 3 = 426.67로 하면 안 될까?’라고 생각할 수 있다. 절대로 안 된다.</p>
<p>이렇게 계산하면 인과효과가 과대평. 실제로 할인한 회사는 가격할인과 관계없이 더 많이 판매했을 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[GPT-2 논문 리뷰]]></title>
            <link>https://velog.io/@rokmc1257_lse/GPT-2</link>
            <guid>https://velog.io/@rokmc1257_lse/GPT-2</guid>
            <pubDate>Sun, 21 Jul 2024 12:00:37 GMT</pubDate>
            <description><![CDATA[<h2 id="기존-연구의-한계">기존 연구의 한계</h2>
<h3 id="domain-specific-training의-제약">Domain-Specific Training의 제약</h3>
<p>*<em>파인튜닝 의존:
*</em></p>
<ul>
<li>초기 딥러닝 모델(GPT-1, BERT 등)은 도메인별 파인튜닝 과정을 거쳐야 했습니다.</li>
<li>각 테스크에 맞게 모델의 레이어를 수정하거나, 수백~수천 개의 예제 데이터가 필요했습니다.</li>
<li>*일반화의 한계:</li>
<li>*</li>
<li>이러한 방식은 모델이 특정 도메인에 특화되도록 학습되므로, 전체적인 범용 언어 이해 및 다양한 테스크 수행 능력을 제한할 수 있습니다.</li>
</ul>
<h3 id="기존-머신러닝-모델의-데이터-한계">기존 머신러닝 모델의 데이터 한계</h3>
<p>*<em>제한된 예제 수:
*</em></p>
<ul>
<li>기존 시스템은 특정 테스크를 위해 데이터셋에서 제한된 수의 예제(수백~수천 개)에 의존했습니다.</li>
</ul>
<p>*<em>모든 테스크에 대응의 어려움:
*</em></p>
<ul>
<li>모든 도메인과 테스크에 대해 맞춤 데이터 쌍을 만드는 것은 현실적으로 매우 어렵습니다.</li>
<li>*다중 테스크 학습의 필요성:</li>
<li>*</li>
<li>이러한 한계를 극복하기 위해 다양한 테스크를 동시에 학습하는 다중 테스크 학습(Multitask Learners)이 효과적이라는 주장이 제기되었습니다.</li>
</ul>
<hr>
<h2 id="제안-방법론">제안 방법론</h2>
<h3 id="language-modeling을-통한-범용-학습">Language Modeling을 통한 범용 학습</h3>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/b0983a94-2da9-4b62-babf-ddd4a5014c72/image.png" alt=""></p>
<h3 id="단일-모델로-다양한-테스크-수행">단일 모델로 다양한 테스크 수행</h3>
<p>*<em>Language Modeling 기법:
*</em></p>
<ul>
<li>GPT-2는 GPT-1과 마찬가지로 “다음 단어 예측” 방식을 사용하여 사전학습(pretraining)을 진행합니다.</li>
<li>모델은 단순히 입력 텍스트에 기반해 p(output ∣ input)을 추정하지만, 암묵적으로 테스크 지시나 문맥 정보를 포함할 수 있어 p(output ∣ input, task)와 같은 효과를 나타냅니다.</li>
<li>*학습 전략:</li>
<li>*</li>
<li>단일 과정으로 다양한 테스크를 동시에 학습함으로써, 별도의 파인튜닝 없이도 Zero-shot, Few-shot 학습이 가능해집니다.</li>
<li>실험 결과, 큰 모델의 경우 p(output ∣ input) 방식이 p(output ∣ input, task) 방식보다 학습 속도는 다소 느리지만, 최종 성능과 범용성에서는 뛰어난 결과를 보여줍니다.<h3 id="zero-shot-학습의-가능성">Zero-shot 학습의 가능성</h3>
</li>
<li>*데이터의 다양성과 일반화:</li>
<li>*</li>
<li>대규모 텍스트 말뭉치를 활용함으로써, 모델은 다양한 도메인에서 명시적인 테스크 지시 없이도 스스로 적절한 작업을 수행하는 법을 학습합니다.</li>
<li>*범용 언어 이해:</li>
<li>*</li>
<li>충분한 데이터와 모델 크기가 확보되면, 언어 모델은 특정 도메인에 국한되지 않고 언어의 본질적인 구조와 의미를 파악할 수 있게 됩니다.</li>
</ul>
<hr>
<h2 id="training-dataset-webtext-구축">Training Dataset: WebText 구축</h2>
<h3 id="데이터-품질과-다양성-확보">데이터 품질과 다양성 확보</h3>
<p>*<em>기존 데이터셋의 한계:
*</em></p>
<ul>
<li>기존 모델들은 뉴스, 위키피디아, 소설 등 상대적으로 단일 도메인 데이터셋에 의존했습니다.</li>
<li>*WebText 데이터셋:</li>
<li>*</li>
<li>GPT-2 연구진은 웹에서 더 다양하고 풍부한 텍스트 데이터를 확보하기 위해 WebText라는 새로운 데이터셋을 구축했습니다.</li>
<li>구성 과정:<ul>
<li>Reddit에서 3 karma 이상을 받은 45M 개 이상의 글을 수집.</li>
<li>중복되거나 낮은 품질의 콘텐츠를 휴리스틱 기반으로 제거.</li>
<li>최종적으로 약 800만 개의 문서, 총 40GB 분량의 데이터를 확보.</li>
</ul>
</li>
</ul>
<p><strong>의의</strong>:</p>
<ul>
<li>다양한 출처에서 온 데이터는 모델이 여러 도메인에서 일반적인 패턴과 언어적 특징을 학습하는 데 큰 도움을 주었습니다.</li>
</ul>
<hr>
<h2 id="input-representation-효율적인-토큰화-전략">Input Representation: 효율적인 토큰화 전략</h2>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/c09f974c-c2fd-4708-8a74-a59bd74078dd/image.png" alt=""></p>
<h3 id="bpe와-vocabulary-최적화">BPE와 Vocabulary 최적화</h3>
<p>*<em>Byte Pair Encoding (BPE):
*</em></p>
<ul>
<li>GPT-2는 단어와 문자 사이의 중간 표현으로 BPE를 활용하여 텍스트를 토큰 단위로 인코딩합니다.</li>
<li>유니코드 단위에서 동작하여 약 13만 개의 Vocabulary를 생성할 수 있으나, 이는 비효율적일 수 있음.</li>
</ul>
<p>*<em>최적화 고려:
*</em></p>
<ul>
<li>만약 byte 수준에서 동작한다면 256개만의 Vocabulary가 필요하지만, 이 경우 그리디 기반 휴리스틱에 따라 불필요한 토큰이 많이 생성될 위험이 있습니다.</li>
<li>GPT-2는 문자 수준 이상의 병합을 억제하여, 제한된 Vocabulary 공간 내에서 효율적으로 언어 정보를 표현할 수 있도록 설계되었습니다.</li>
</ul>
<hr>
<h3 id="model">Model</h3>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/1ac86bb5-e5ef-4373-a5bd-b975d2a9a010/image.png" alt=""></p>
<h3 id="transformer-기반-decoder-구조">Transformer 기반 Decoder 구조</h3>
<p>*<em>모델 아키텍처:
*</em></p>
<ul>
<li>GPT-2는 Transformer의 Decoder 구조를 기본으로 하며, Masked Multi-Self Attention과 Feed Forward 네트워크로 구성됩니다.</li>
</ul>
<p>*<em>Layer Normalization 적용:
*</em></p>
<ul>
<li>각 레이어의 입력에 LayerNorm을 적용하고, 최종 디코더 블록 이후에도 추가적인 LayerNorm을 거쳐 안정적인 학습을 도모합니다.</li>
</ul>
<p>*<em>가중치 초기화:
*</em></p>
<ul>
<li>Residual layers의 수에 따라 1/√(N) (N: residual layer 수) 스케일링을 적용해, 깊은 네트워크에서도 안정적인 학습이 가능하도록 초기화합니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/f449e7b2-01c3-4ba1-961b-cf80f14edf17/image.png" alt=""></p>
<h3 id="모델-스케일과-zero-shot-성능">모델 스케일과 Zero-shot 성능</h3>
<p>*<em>모델 크기 분류:
*</em></p>
<ul>
<li>GPT-2는 small, medium, large, extra-large 등 다양한 크기로 제공되어, 모델의 규모에 따른 성능 차이를 확인할 수 있습니다.</li>
<li>*Zero-shot 학습 입증:</li>
<li>*</li>
<li>대규모 데이터(WebText)와 모델의 크기 덕분에, GPT-2는 사전학습만으로도 여러 도메인에서 Zero-shot 성능을 성공적으로 발휘합니다.</li>
<li>*BERT와의 비교:</li>
<li>*</li>
<li>논문에서는 양방향(Bidirectional) 언어 모델인 BERT와 달리, 단방향(Language Modeling) 방식이 충분한 데이터와 모델 규모에서 더 일반화된 성능을 낼 수 있음을 주장합니다.</li>
</ul>
<hr>
<h3 id="결론">결론</h3>
<p>GPT-2 논문은</p>
<p>*<em>기존의 도메인 특화 학습 방식을 극복:
*</em></p>
<ul>
<li>파인튜닝 없이 하나의 모델로 다양한 테스크를 수행할 수 있도록 제시하며, 범용 언어 이해의 가능성을 입증합니다.</li>
</ul>
<p>*<em>방대한 WebText 데이터셋 활용:
*</em></p>
<ul>
<li>다양한 도메인의 데이터를 통해 모델이 폭넓은 언어 패턴과 테스크 수행 방법을 스스로 학습하도록 설계되었습니다.</li>
</ul>
<p>*<em>효율적인 입력 표현 및 모델 구조:
*</em></p>
<ul>
<li>최적화된 BPE 토큰화와 Transformer 기반 모델 구조로, 제한된 Vocabulary 공간을 효율적으로 활용하며 안정적인 학습을 달성합니다.</li>
</ul>
<p>*<em>Zero-shot 학습 능력 증명:
*</em></p>
<ul>
<li>대규모 모델과 데이터셋이 결합되면, 명시적인 테스크 지시 없이도 모델이 여러 작업을 자동으로 수행하는 놀라운 성능을 보입니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[GPT-1 논문 리뷰]]></title>
            <link>https://velog.io/@rokmc1257_lse/GPT-1-%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0</link>
            <guid>https://velog.io/@rokmc1257_lse/GPT-1-%EB%85%BC%EB%AC%B8-%EB%A6%AC%EB%B7%B0</guid>
            <pubDate>Sun, 21 Jul 2024 11:11:20 GMT</pubDate>
            <description><![CDATA[<h2 id="0-abstract">0. Abstract</h2>
<ul>
<li>Labeled data에 비해 Unlabeled text  말뭉치의 양은 방대하여 모델 훈련과 수행에 어려움이 있음</li>
<li>따라서 Unlabeled text를 활용한 language model의 Generative Pre-Training과 각 task에 맞는 Discriminative fine-tuning을 통해 이를 해결하고자 함</li>
<li>과제 인식 입력 변환을 사용해 최소한의 모델 구조 변경으로 효과적인 전이를 달성  </li>
<li>12개 task 중에서 9개 task에서 최첨단 성능을 크게 향상</li>
</ul>
<hr>
<h2 id="1-introduction">1. Introduction</h2>
<ul>
<li><p>원시 텍스트로부터 효과적으로 학습하는 능력은 자연어 처리(NLP)에서 지도 학습에 대한 의존성을 줄이는 데 매우 중요</p>
</li>
<li><p>딥러닝 방법은 많은 수작업 라벨링 데이터를 필요로 하지만, 라벨링되지 않은 데이터로부터 학습할 수 있는 모델은 비용과 시간을 절약</p>
</li>
<li><p>충분한 지도 학습 데이터가 있을 때도 비지도 학습으로 좋은 표현을 학습하면 성능이 크게 향상될 수 있다.</p>
</li>
<li><p>사전 훈련된 단어 임베딩의 사용이 이를 뒷받침하는 주요 증거</p>
</li>
<li><p>라벨링되지 않은 텍스트에서 단어 수준 이상의 정보를 활용하는 것은 두 가지 주요 이유로 어려운 과제</p>
</li>
</ul>
<ol>
<li>어떤 유형의 최적화 목표가 전이 학습에 유용한 텍스트 표현을 학습하는 데 가장 효과적인지 명확하지 않다.</li>
<li>학습된 표현을 목표 과제에 가장 효과적으로 전이하는 방법에 대한 합의가 없다. </li>
</ol>
<ul>
<li>이 논문에서는 비지도 사전 훈련과 지도 미세 조정을 결합한 반지도 학습 접근 방식을 탐구</li>
<li>목표는 적은 적응으로 다양한 과제에 전이될 수 있는 보편적인 표현을 학습하는 것</li>
<li>라벨링되지 않은 대규모 텍스트 말뭉치와 수작업으로 주석이 달린 여러 데이터셋(목표 과제)에 접근할 수 있다고 가정</li>
</ul>
<p>2 단계의 훈련 절차를 사용</p>
<ol>
<li>라벨링되지 않은 데이터에서 언어 모델링 목표를 사용하여 신경망 모델의 초기 매개변수를 학습</li>
<li>이 매개변수를 해당하는 지도 목표를 사용하여 목표 과제에 맞추어 조정</li>
</ol>
<ul>
<li>우리의 모델 아키텍처로는 Transformer를 사용</li>
<li>텍스트의 장기 종속성을 처리하는 데 더 구조화된 메모리를 제공하여 다양한 과제에서 견고한 전이 성능을 발휘</li>
<li>전이 과정에서는 구조화된 텍스트 input을 단일 연속 token sequence로 처리하는 트리순회 방식에서 파생된 task별 입력 조정을 활용함 (task마다 text 입력 방식이 다른데 이를 바꿔준다고 보면 됨)</li>
<li>모델 아키텍처를 최소한으로 변경하면서 효과적으로 미세조정 가능</li>
</ul>
<hr>
<h2 id="2-related-work">2. Related Work</h2>
<h3 id="semi-supervised-learning-for-nlp">Semi-supervised learning for NLP</h3>
<ul>
<li>연구자들은 라벨링되지 않은 말뭉치에서 학습된 단어 임베딩을 사용하여 다양한 과제의 성능을 향상시킬 수 있음을 입증</li>
<li>이러한 접근법은 주로 단어 수준의 정보를 전이하는 데 중점, 더 높은 수준의 의미를 포착하는 것을 목표</li>
<li>라벨링되지 않은 말뭉치를 사용해 학습된 phrase-level이나 sentence-level embeddings을 시도</li>
</ul>
<h3 id="unsupervised-pre-training">Unsupervised pre-training</h3>
<ul>
<li><p>Unsupervised pre-training은 지도 학습 목표를 수정하는 대신 좋은 초기화 지점을 찾는 것을 목표로 하는 semi-supervised learning의 특별한 경우</p>
</li>
<li><p>이 접근법은 이미지 분류, 회귀 과제, 음성 인식, 기계 번역 등 다양한 분야에서 사용되며 모델의 일반화 능력을 향상</p>
</li>
<li><p>기존 방법들은 사전 훈련된 모델의 숨겨진 표현을 보조 특징으로 사용하여 각 목표 과제에 맞춰 많은 매개변수를 추가해야 함</p>
</li>
<li><p>하지만, 이 연구는 전이 과정에서 최소한의 구조 변경만으로도 효과적인 성능을 발휘</p>
</li>
</ul>
<h3 id="auxiliary-training-objectives">Auxiliary training objectives</h3>
<ul>
<li>보조 학습 목적함수를 추가하는 것은 semi-supervised learning의 대안</li>
<li>본 연구에서도 보조 학습 목표를 사용하지만, 비지도 사전 훈련이 이미 목표 과제와 관련된 여러 언어적 측면을 학습한다는 점</li>
</ul>
<hr>
<h2 id="3-framework">3. Framework</h2>
<p>2 stage 로 구성
대규모 말뭉치에서 language model 학습
labeled data를 활용하여 fine-tuning</p>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/24c3885a-71bc-45af-a016-113fcb78706a/image.png" alt=""></p>
<h3 id="31-unsupervised-pre-training">3.1 Unsupervised pre-training</h3>
<p>비지도 말뭉치 U =  𝑢1,𝑢2,…,𝑢𝑛 다음과 같은 목표를 최대화</p>
<ul>
<li>𝑘는 컨텍스트 윈도우의 크기</li>
<li>조건부 확률 P는 신경망을 사용하여 모델링</li>
<li>매개변수 θ는 SGD
ex )  I love you라는 문장이 있고 I, love가 주어졌을 때 you를 예측하는 확률값</li>
</ul>
<ul>
<li>언어 모델로 다층 Transformer 디코더를 사용</li>
<li>입력 컨텍스트 토큰에 대해 다중 헤드 자기 주의(multi-headed self-attention) 연산을 적용한 후, 위치별 피드포워드 레이어(position-wise feedforward layers)를 통해 타겟 토큰에 대한 출력 분포를 생성
<img src="https://velog.velcdn.com/images/rokmc1257_lse/post/050a74b3-3158-47bd-8ca7-c52ab793764c/image.png" alt=""></li>
</ul>
<ul>
<li>U = ( u_i-k,....u_i-1) 는 토큰의 컨텍스트 벡터</li>
<li>W_e 토큰의 임베딩 행렬</li>
<li>W_p 위치 임베딩 행렬</li>
<li></li>
<li>h0 : 임베딩(W_e) 후 position embedding matrix(W_p) 더하기</li>
<li>hl : layer개수(n=12)만큼 decoder block을 통과하고</li>
<li>P(u) : position-wise layer(W^T_e)를 거쳐 softmax로 확률값 구하기</li>
</ul>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/409e3a12-6440-40bc-b8a6-6b4cb8f9c84a/image.png" alt=""></p>
<h3 id="32-supervised-fine-tuning">3.2 Supervised fine-tuning</h3>
<ul>
<li>모델을 목표로 훈련한 후, 우리는 매개변수를 지도 학습 목표에 맞게 조정</li>
<li>labeled 데이터셋 C가 있다고 가정, C는 x^1, ... , x^m으로 이루어진 input token 시퀀스와 label인 y로 구성</li>
<li>입력은 사전 훈련된 모델을 통과하여 최종 Transformer 블록의 활성화 h^l_m를 얻고, 이를 추가된 선형 출력 레이어 W_y에 입력하여 y를 예측</li>
</ul>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/06532219-420a-43d2-ba65-945f9a4183e2/image.png" alt=""></p>
<p>이로 인해 다음과 같은 목적함수를 최대화
<img src="https://velog.velcdn.com/images/rokmc1257_lse/post/bed2adfe-3109-40b0-bfd5-75516e4b763f/image.png" alt=""></p>
<ul>
<li><p>우리는 또한 언어 모델링을 보조 목표로 추가하는 것이 지도 학습 모델의 일반화를 개선하고, 수렴 속도를 가속화하는 데 도움이 되었다고 발견</p>
</li>
<li><p>다음의 목적함수 최적화 (여기서 𝜆는 가중치):</p>
</li>
<li><p>전반적으로, 미세 조정 동안 필요한 추<img src="https://velog.velcdn.com/images/rokmc1257_lse/post/453ed331-707f-4e25-8e38-46ac6349b462/image.png" alt="">
가 매개변수는 W_y와 구분 기호 토큰에 대한 임베딩</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/rokmc1257_lse/post/b9d24699-08f1-410a-a93f-3740e7589094/image.png" alt=""></p>
<ul>
<li><p>(왼쪽) 이 연구에서 사용된 Transformer 아키텍처와 훈련 목표. </p>
</li>
<li><p>(오른쪽) 다양한 과제에 대한 미세 조정을 위한 입력 변환. 모든 구조화된 입력을 토큰 시퀀스로 변환하여 사전 훈련된 모델로 처리한 후, 선형 + 소프트맥스 레이어를 적용.</p>
<h3 id="33-task-specific-input-transformation">3.3 Task-specific input transformation</h3>
</li>
<li><p>일부 작업, 예를 들어 텍스트 분류와 같은 경우, 위에서 설명한 대로 모델을 직접 미세 조정할 수 있다</p>
</li>
<li><p>그러나 질문 응답이나 텍스트 추론과 같은 특정 작업은 정렬된 문장 쌍이나 문서, 질문, 답변의 삼중항과 같은 구조화된 입력을 필요, 이러한 작업에 적용하기 위해서는 약간의 수정</p>
</li>
<li><p>이전 연구는 전이된 표현 위에 작업 특정 아키텍처를 학습하는 방법을 제안했으나, 이는 상당한 작업 맞춤화가 필요하며 이러한 추가 아키텍처 구성 요소에 대해 전이 학습을 사용하지 않는다.</p>
</li>
<li><p>하지만 본 논문에서는 구조화된 입력 → pre-trained 모델이 처리할 수 있는 ordered sequence로 변환하는 순회 스타일(traversal-style) 접근 방식을 사용한다. 이 변환을 통해 아키텍쳐를 광범위하게 변경하는 것을 피할 수 있다.</p>
</li>
</ul>
<h4 id="텍스트-추론-textual-entailment">텍스트 추론 (Textual Entailment)</h4>
<ul>
<li>전제(p)와 가설(h) 토큰 시퀀스를 연결하고, 그 사이에 구분 기호 토큰($)을 추가</li>
</ul>
<h4 id="유사성-similarity">유사성 (Similarity)</h4>
<ul>
<li>비교하는 두 문장 간에는 본래의 순서가 없기 때문에, 입력 시퀀스를 두 문장 순서의 모든 가능한 조합을 포함하도록 수정 (구분 기호를 사이에 추가)</li>
<li>각각 독립적으로 처리하여 두 시퀀스 표현 h_m을 생성하고, 이를 요소별로 더한 후 선형 출력 레이어에 입력</li>
</ul>
<h4 id="질문-응답-및-상식-추론-question-answering-and-commonsense-reasoning">질문 응답 및 상식 추론 (Question Answering and Commonsense Reasoning)</h4>
<ul>
<li>컨텍스트 문서 z , 질문 q, 그리고 가능한 답변 집합 {a_k}이 주어짐</li>
<li>문서 컨텍스트와 질문을 각각 가능한 답변과 연결하고, 그 사이에 구분 기호 토큰을 추가하여 [z; q; $; ak] 형태로 만듬</li>
<li>이러한 시퀀스 각각을 모델을 통해 독립적으로 처리하고, 소프트맥스 레이어를 통해 가능한 답변에 대한 출력 분포를 생성</li>
</ul>
<hr>
<p>본 논문에서는 과제별로 아키텍쳐를 만드는 것이 아닌  Generative Pre-Training과 discriminative fine-tuning을 통해 단일 framework를 제안했다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spark SQL&Dataframe]]></title>
            <link>https://velog.io/@rokmc1257_lse/Spark-SQLDataframe</link>
            <guid>https://velog.io/@rokmc1257_lse/Spark-SQLDataframe</guid>
            <pubDate>Thu, 11 Jul 2024 11:17:54 GMT</pubDate>
            <description><![CDATA[<h3 id="apache-spark-sql-spark에서-구조적-데이터-처리">Apache Spark SQL: Spark에서 구조적 데이터 처리</h3>
<p>Apache Spark SQL은 Apache Spark 내에서 구조적 데이터를 처리하고 쿼리할 수 있도록 하는 모듈</p>
<h3 id="구조적-데이터란">구조적 데이터란?</h3>
<ul>
<li>구조적 데이터는 일관되고 조직적인 형식을 따르는 데이터로, 테이블에 저장할 수 있고 SQL을 사용하여 쿼리할 수 있다.</li>
<li>예를 들어, 관계형 데이터베이스, 스프레드시트, CSV 파일 등에 저장된 데이터가 이에 해당</li>
</ul>
<h3 id="데이터프레임-dataframe">데이터프레임 (DataFrame)</h3>
<ul>
<li><p>데이터프레임은 기존의 RDD에서 확장된 개념으로, 구조적 데이터를 다루는 데 사용되는 객체</p>
</li>
<li><p>데이터프레임의 주요 특징:</p>
</li>
</ul>
<ul>
<li>SQL 쿼리 사용 가능: 데이터프레임을 SQL처럼 쿼리할 수 있다</li>
<li>스키마를 가질 수 있음: 데이터프레임은 스키마를 정의하여 각 컬럼의 데이터 타입을 지정할 수 있다</li>
<li>다양한 포맷 지원: JSON, CSV, Hive, Avro, Parquet, ORC 등의 형식으로 데이터를 읽고 쓸 수 있다</li>
<li>연결성: JDBC/ODBC와 연결 가능하며, Tableau와 같은 BI 도구와도 연동이 가능</li>
</ul>
<h3 id="통합성-integrated">통합성 (Integrated)</h3>
<ul>
<li>Spark Session: Spark Session을 통해 SQL을 사용하여 데이터프레임을 생성, 관리, 쿼리할 수 있다. 이는 기존의 SparkContext를 대체하는 역할을 함</li>
<li>Spark Session은 여러 데이터 소스를 통합적으로 관리하고, 애플리케이션 전반에 걸쳐 일관된 환경을 제공함.</li>
</ul>
<h3 id="uniform-data-access">Uniform Data Access</h3>
<p>다양한 데이터 소스에 접근할 수 있습니다. 예를 들어, 파일 시스템, HDFS, S3, 데이터베이스 등 여러 소스에서 데이터를 읽고 쓸 수 있습니다.
이를 통해 다양한 데이터셋을 하나의 통합된 인터페이스로 다룰 수 있습니다.</p>
<h3 id="hive-통합-hive-integration">Hive 통합 (Hive Integration)</h3>
<ul>
<li>Hive와의 긴밀한 통합을 통해 Hive 메타스토어를 사용할 수 있다.</li>
<li>HiveQL을 그대로 사용할 수 있으며, 기존 Hive 테이블에 대해 쿼리를 실행할 수 있다.</li>
<li>Hive UDF(사용자 정의 함수)도 사용할 수 있다.</li>
</ul>
<h3 id="표준-연결성-standard-connectivity">표준 연결성 (Standard Connectivity)</h3>
<ul>
<li>다양한 BI 도구와의 연결성을 제공하여, BI 도구에서 직접 쿼리를 실행할 수 있다.</li>
<li>이를 통해 사용자는 데이터에 더 쉽게 접근하고, 분석할 수 있다.</li>
</ul>
<h3 id="산업-동향-industry-trend">산업 동향 (Industry Trend)</h3>
<ul>
<li>RDD보다는 데이터프레임이나 Spark SQL을 사용하여 데이터를 처리하는 경향이 많아졌다.</li>
<li>이는 데이터프레임이 더 높은 수준의 추상화를 제공하고, 최적화된 쿼리 실행 계획을 통해 성능을 향상시킬 수 있기 때문.</li>
<li>Spark SQL의 성능 향상과 사용 편의성 덕분에 데이터 분석과 처리에 많이 사용.</li>
</ul>
<h3 id="추가-기능-및-장점">추가 기능 및 장점</h3>
<ul>
<li>Catalyst Optimizer: Spark SQL의 핵심 컴포넌트로, 쿼리 최적화를 수행하여 성능을 극대화</li>
<li>Tungsten Execution Engine: 물리적 실행 계획을 최적화하고, CPU와 메모리 효율을 극대화</li>
<li>통합 API: SQL뿐만 아니라 DataFrame과 Dataset API를 제공하여, 다양한 언어(Python, Scala, Java, R)에서 사용 가능</li>
<li>고급 분석 기능: MLlib과 통합되어 머신 러닝 모델을 쉽게 구축하고 배포할 수 있다.
실시간 데이터 처리: Structured Streaming을 통해 실시간 데이터 스트림을 처리할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spark RDD]]></title>
            <link>https://velog.io/@rokmc1257_lse/Spark-RDD</link>
            <guid>https://velog.io/@rokmc1257_lse/Spark-RDD</guid>
            <pubDate>Wed, 10 Jul 2024 11:04:27 GMT</pubDate>
            <description><![CDATA[<h2 id="rdd-개념">RDD 개념</h2>
<p>Spark 는 in memory data 처리 HADOOP은 disk 기반의 데이터 처리</p>
<p>*<em>RDD ( Resilient Distributed Dataset) 
*</em></p>
<ul>
<li>스파크에서 사용되는 기본 데이터 구조</li>
<li>스파크에서 내부적으로 연산하는 데이터들을 모두 RDD 타입으로 처리</li>
</ul>
<p>*<em>RDD 의 다른 말 Immutable, Partitioned Collections of Record
*</em></p>
<ul>
<li>여러 분산 노드에 나누어짐</li>
<li>다수의 파티션으로 관리됨</li>
<li>변경이 불가능한 데이터 셋</li>
</ul>
<hr>
<h2 id="rdd의-생성">RDD의 생성</h2>
<ul>
<li><p>RDD를 처음 만 들 때 DISK에서 데이터를 가져옴. 모든 데이터는 DISK 에 들어 가 있음 ( HDFS )  거기서 메모리로 가져옴 그때 RDD 가 생성 , 외부(DISK)로부터 데이터를 로딩할 때</p>
</li>
<li><p>코드에서 데이터를 저장할 때 RDD를 생성할 수 있음</p>
</li>
</ul>
<h2 id="rdd의-연산">RDD의 연산</h2>
<p>*<em>RDD를 제어하는 2개의 연산 타입
*</em></p>
<ul>
<li><p>Transformation ( 변환 ) : RDD에서 새로운 RDD를 생성하는 함수</p>
<ul>
<li>filter : 특정 데이터만 산출하는 연산자</li>
<li>map : 데이터를 분산 배치하는 연산자</li>
</ul>
</li>
<li><p>Action ( 액션 ) : RDD에서 RDD가 아닌 다른 타입의 데이터로 변한하는 함수들</p>
<ul>
<li>count() : 변환 연산 후 파티션의 데이터 요소 개수</li>
<li>collect() : 변환 연산 후 파티션의 데이터 요소 집합</li>
</ul>
</li>
</ul>
<hr>
<h2 id="rdd-분산-처리-방법">RDD 분산 처리 방법</h2>
<p><strong>Immutable : 만들어진 뒤에는 변하지 않음</strong></p>
<ul>
<li>어떻게 만들었는지 알면 또 만들 수 있음</li>
</ul>
<p>** Partitioned : 데이터 셋을 잘게 잘라서 분산**</p>
<ul>
<li>가장 효율적으로 클러스터 노드에 분산시켜 볼 수 있음 </li>
</ul>
<p>** partition
**  </p>
<ul>
<li><p>하나의 RDD는 여러 개의 파티션으로 나뉘어짐</p>
<ul>
<li>성능에 유효한 영향을 줌</li>
</ul>
<ul>
<li><p>파티션의 개수, 기본 파티셔너 ( Hash, Range ) 선택 가능</p>
<ul>
<li>기본 파티셔너 외에도 사용자가 정의한 파티셔너 사용 가능</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><strong>Dependency 타입
Narrow Dependency</strong></p>
<ul>
<li>변환 후 파티션이 하나의 파티션으로 매핑되는 경우</li>
<li>하당 작업이 한 노드에서 처리 가능</li>
<li>네트워크를 사용하지 않음</li>
<li>파티션에 문제가 생겨도 복원 가능 </li>
</ul>
<p>*<em>Wide dependency 
*</em></p>
<ul>
<li>변환 후의 파티션이 여러 파티션으로 매핑되는 경우</li>
<li>파티션에 문제가 생기면 재계산 비용이 비쌈</li>
<li>셔플이 일어나야 하는 작업들</li>
<li>일반적으로 네트워크를 사용함</li>
</ul>
<hr>
<h2 id="계보-lineage">계보 (Lineage)</h2>
<p>RDD 연산의 순서를 기록 DAG로 표현</p>
<ul>
<li>DAG( Directed Acyclic Graph) : 직관적인 방향성 비순환 그래프로 표현한 것 </li>
</ul>
<p><strong>1. Fault-tolerant 확보</strong></p>
<ul>
<li>계보만 기록해두면 동일한 RDD를 생성할 수 있음</li>
<li>일부 계산 비용이 큰 RDD는 디스크에 Check Pointing 함</li>
</ul>
<p><strong>2. Lazy Execution 가능</strong></p>
<ul>
<li>변환 연산을 읽어 들일 때는 단순히 계보만 생성</li>
<li>액션 연산을 읽어 들일 때 생성된 계보를 실행함</li>
</ul>
<p><strong>3. 작업 스케줄링에 활용</strong></p>
<ul>
<li>현재 자원이 배치된 상황, 앞으로 배치될 상황, dependency 등 이런 것들을 미리 계산해서 적절한 작업을 할 수 있는 노드를 찾고 노드에게 작업을 실행 시킬 수 있음. </li>
</ul>
]]></description>
        </item>
    </channel>
</rss>