<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>cheol2.log</title>
        <link>https://velog.io/</link>
        <description>데이터 엔지니어</description>
        <lastBuildDate>Fri, 23 Jan 2026 05:26:30 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>cheol2.log</title>
            <url>https://velog.velcdn.com/images/cheol2_y/profile/481b5a98-45fb-4ac9-ba7b-ecaf9f7cd643/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. cheol2.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/cheol2_y" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[LLM의 동작 원리와 효율적인 사용법 (챗봇 설계 기술 검토)]]></title>
            <link>https://velog.io/@cheol2_y/LLM%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC%EC%99%80-%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%B1%97%EB%B4%87-%EC%84%A4%EA%B3%84-%EA%B8%B0%EC%88%A0-%EA%B2%80%ED%86%A0</link>
            <guid>https://velog.io/@cheol2_y/LLM%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC%EC%99%80-%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9D%B8-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%B1%97%EB%B4%87-%EC%84%A4%EA%B3%84-%EA%B8%B0%EC%88%A0-%EA%B2%80%ED%86%A0</guid>
            <pubDate>Fri, 23 Jan 2026 05:26:30 GMT</pubDate>
            <description><![CDATA[<h1 id="llm의-동작-원리와-효율적인-사용법">LLM의 동작 원리와 효율적인 사용법</h1>
<h2 id="서론">서론</h2>
<p>LLM(Large Language Model)을 효과적으로 사용하기 위해서는 내부 동작 원리를 이해하는 것이 중요하다.
이 글에서는 LLM의 핵심 개념들을 정리하고, 실무에서 활용할 수 있는 팁을 공유한다.</p>
<hr>
<h2 id="1-llm의-기본-특성">1. LLM의 기본 특성</h2>
<h3 id="stateless-특성">Stateless 특성</h3>
<p>LLM은 상태를 유지하지 않는다(stateless). 즉, 이전 대화를 자체적으로 &quot;기억&quot;하지 못한다.
그럼에도 multi-turn 대화가 가능한 이유는 이전 대화 내용을 매번 현재 입력에 포함시켜 전달하기 때문이다.</p>
<h3 id="대화-처리-예시">대화 처리 예시</h3>
<pre><code>Turn 1 - User: &quot;안녕&quot;
API 호출: [&quot;안녕&quot;]
Assistant: &quot;안녕하세요!&quot;

Turn 2 - User: &quot;내 이름은 철수야&quot;
API 호출: [&quot;안녕&quot;, &quot;안녕하세요!&quot;, &quot;내 이름은 철수야&quot;]  ← 이전 대화 전부 포함
Assistant: &quot;반갑습니다, 철수님!&quot;

Turn 3 - User: &quot;내 이름이 뭐라고?&quot;
API 호출: [&quot;안녕&quot;, &quot;안녕하세요!&quot;, &quot;내 이름은 철수야&quot;, &quot;반갑습니다, 철수님!&quot;, &quot;내 이름이 뭐라고?&quot;]
Assistant: &quot;철수님이라고 하셨습니다!&quot;  ← 기억하는 것처럼 보이지만, 실제로는 입력에 다 들어있음</code></pre><h3 id="웹앱-vs-api">웹앱 vs API</h3>
<p>웹앱에서 사용하는 LLM과 API로 사용하는 LLM은 동일한 모델이다.
차이점은 입력 프롬프트를 어떻게 구성하느냐에 있다.
(시스템 프롬프트, 파라미터 설정, 부가 기능 등 세부적인 차이는 존재한다.)</p>
<hr>
<h2 id="2-context-window">2. Context Window</h2>
<h3 id="context-window란">Context Window란</h3>
<p>Context window는 LLM이 한 번에 처리할 수 있는 최대 토큰의 양이다.
1M으로 되어 있으면 최대 100만 토큰까지 처리할 수 있다는 의미이다.</p>
<p>최신 모델들은 Max Input Tokens와 Max Output Tokens가 별도로 제한되어 있어서 Context Window는 Max Input Tokens를 의미한다.</p>
<table>
<thead>
<tr>
<th>모델</th>
<th>Max Input Tokens</th>
<th>Max Output Tokens</th>
</tr>
</thead>
<tbody><tr>
<td>GPT-5.2</td>
<td>400,000</td>
<td>128,000</td>
</tr>
<tr>
<td>Claude Opus 4.5</td>
<td>200,000</td>
<td>64,000</td>
</tr>
<tr>
<td>Claude Sonnet 4.5</td>
<td>200,000 (기본) / 1M (beta)</td>
<td>64,000</td>
</tr>
<tr>
<td>Gemini 3 Pro</td>
<td>1,000,000</td>
<td>64,000</td>
</tr>
<tr>
<td>Gemini 3 Flash</td>
<td>1,000,000</td>
<td>64,000</td>
</tr>
</tbody></table>
<h3 id="긴-context의-문제점">긴 Context의 문제점</h3>
<p>Context window가 크더라도, 긴 context가 입력되면 성능이 저하될 수 있다.</p>
<ul>
<li>Lost in the Middle 현상 발생 가능 (다음 섹션에서 상세 설명)</li>
<li>이전 대화를 요약하여 입력하는 과정에서 정보 손실/변형 가능</li>
<li>Attention 연산 복잡도 증가로 답변 생성 속도 저하
<img src="https://velog.velcdn.com/images/cheol2_y/post/fa4f4f8b-3460-4794-9709-6ce262d4acfb/image.png" alt=""></li>
</ul>
<h3 id="적절한-context의-이점">적절한 Context의 이점</h3>
<p>반면, 어느 수준까지는 context가 길어질수록 성능이 좋아진다.
사용자의 needs, 배경 지식, 상황, 조건이 충분히 제공되면 더 정확한 답변이 가능하기 때문이다.</p>
<h3 id="권장-사항">권장 사항</h3>
<ul>
<li>초기에 사용자의 needs를 명확하게 프롬프트에 포함</li>
<li>배경 지식, 상황, 조건 등을 잘 정리하여 입력</li>
<li>실질적인 입력 토큰은 API에서 50K, 웹앱에서는 100K 미만으로 유지하는 것이 안정적</li>
<li>답변 속도가 느려지거나 퀄리티가 낮아지면, 대화를 요약하여 새 채팅 시작 권장</li>
</ul>
<h3 id="참고-모델별-context-window">참고: 모델별 Context Window</h3>
<table>
<thead>
<tr>
<th>모델</th>
<th>Context Window</th>
</tr>
</thead>
<tbody><tr>
<td>Claude 4.5 series</td>
<td>200K</td>
</tr>
<tr>
<td>GPT 5.2 series</td>
<td>400K</td>
</tr>
<tr>
<td>Gemini 3.0 series</td>
<td>1M</td>
</tr>
</tbody></table>
<hr>
<h2 id="3-causal-decoder와-attention">3. Causal Decoder와 Attention</h2>
<h3 id="causal-decoder의-동작-원리">Causal Decoder의 동작 원리</h3>
<p>Causal decoder는 답변을 생성할 때 앞에 있는 token들을 참조하여 다음에 올 단어를 하나씩 예측한다.
이때 사용되는 것이 attention이다.
Attention은 말 그대로 &quot;어디에 주목할 것인가&quot;를 수치적으로 계산하는 메커니즘이다.
여기서 causal masking이 적용되어 현재 위치 이후의 토큰은 참조하지 못하도록 제한된다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/f3c0ab06-e26b-4970-bac5-b6668ae83ac1/image.png" alt=""></p>
<h3 id="primacy-effect---앞부분-중요도-상승">Primacy Effect - 앞부분 중요도 상승</h3>
<p>첫 번째 토큰은 모든 연산에서 항상 참조 대상에 포함된다.
또한 모델이 특별히 attention을 줄 곳이 없을 때, 첫 번째 토큰에 attention을 몰아주는 경향이 있다.
이를 <strong>Attention Sink</strong> 현상이라고 한다.
이로 인해 앞부분의 중요도가 높아진다.</p>
<h3 id="recency-effect---뒷부분-중요도-상승">Recency Effect - 뒷부분 중요도 상승</h3>
<p>질문(쿼리)과 가까이 위치한 뒷부분 토큰들은 거리상 가깝기 때문에 높은 attention 값을 받는다.
이로 인해 뒷부분의 중요도 역시 높아진다.</p>
<h3 id="lost-in-the-middle---중간부분-중요도-하락">Lost in the Middle - 중간부분 중요도 하락</h3>
<p>앞부분(Primacy)과 뒷부분(Recency) 사이에 끼인 중간 부분은 상대적으로 attention을 적게 받는다.
이 현상을 <strong>U-shaped Attention</strong> 또는 <strong>&quot;Lost in the Middle&quot;</strong>이라고 부른다.
이것은 causal decoder의 구조적인 특성에서 비롯된 문제로, 완전한 해결은 어렵지만 완화는 가능하다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/915a3b1f-8479-44fa-b693-a05e018a2dde/image.png" alt=""></p>
<h3 id="실제-적용-사례">실제 적용 사례</h3>
<p>문서 1, 문서 2, 문서 3과 쿼리(질문)가 주어진 상황을 가정하자.
모델이 쿼리에 대한 답변을 생성할 때, 문서 1과 문서 3의 내용은 잘 참조하여 답변한다.
하지만 문서 2에 있는 내용은 상대적으로 누락될 가능성이 높다.</p>
<hr>
<h2 id="4-system-prompt">4. System Prompt</h2>
<h3 id="system-prompt의-역할">System Prompt의 역할</h3>
<p>System prompt는 모델의 행동 방식, 페르소나, 제약 조건을 정의하는 특별한 입력이다.
모든 대화에서 최상단에 위치하며, Primacy Effect로 인해 강한 영향력을 가진다.</p>
<h3 id="구성-요소">구성 요소</h3>
<ul>
<li>역할/페르소나 정의</li>
<li>출력 형식 지정</li>
<li>제약 조건 및 금지 사항</li>
<li>배경 지식 및 컨텍스트</li>
</ul>
<h3 id="활용-예시">활용 예시</h3>
<ul>
<li><strong>역할 부여</strong>: &quot;너는 10년차 백엔드 개발자야. 코드 리뷰를 해줘.&quot;</li>
<li><strong>출력 형식</strong>: &quot;답변은 반드시 JSON 형식으로만 해.&quot;</li>
<li><strong>제약 조건</strong>: &quot;확실하지 않은 내용은 추측하지 말고 모른다고 답변해.&quot;</li>
<li><strong>언어 지정</strong>: &quot;모든 답변은 한국어로 해.&quot;</li>
</ul>
<p>System prompt는 매 요청마다 전송되므로, 토큰 효율성을 위해 간결하게 작성하는 것이 좋다.</p>
<hr>
<h2 id="5-생성-파라미터">5. 생성 파라미터</h2>
<h3 id="temperature">Temperature</h3>
<p>Temperature는 답변의 무작위성을 조절하는 파라미터이다.
0에 가까울수록 일관적이고 예측 가능한 답변을 생성하고, 높을수록 다양하고 창의적인 답변을 생성한다.</p>
<p><strong>원리:</strong></p>
<ul>
<li>다음 토큰 예측 시 각 토큰의 확률 분포가 계산됨</li>
<li>Temperature가 낮으면 확률 높은 토큰에 집중 (sharp distribution)</li>
<li>Temperature가 높으면 확률 분포가 평탄해짐 (flat distribution)</li>
</ul>
<p><strong>권장 설정:</strong></p>
<table>
<thead>
<tr>
<th>용도</th>
<th>Temperature</th>
</tr>
</thead>
<tbody><tr>
<td>코드 생성, 팩트 기반 답변</td>
<td>0 ~ 0.3</td>
</tr>
<tr>
<td>일반 대화, 설명</td>
<td>0.5 ~ 0.7</td>
</tr>
<tr>
<td>창작, 브레인스토밍</td>
<td>0.8 ~ 1.0</td>
</tr>
</tbody></table>
<h3 id="top-p--top-k">Top-p / Top-k</h3>
<ul>
<li><strong>Top-p (nucleus sampling)</strong>: 누적 확률이 p에 도달할 때까지의 토큰만 후보로 사용</li>
<li><strong>Top-k</strong>: 확률 상위 k개 토큰만 후보로 사용</li>
</ul>
<p><strong>예시 (Top-p = 0.9):</strong></p>
<ul>
<li>&quot;the&quot; (0.5) + &quot;a&quot; (0.3) + &quot;an&quot; (0.15) = 0.95 → 이 세 개만 후보</li>
<li>나머지 토큰은 후보에서 제외</li>
</ul>
<p>Temperature와 함께 사용하여 답변의 다양성과 품질을 조절할 수 있다.</p>
<hr>
<h2 id="6-언어별-효율성">6. 언어별 효율성</h2>
<h3 id="토큰-효율성">토큰 효율성</h3>
<p>한글로 입력했을 때와 영어로 입력했을 때는 토큰 소모량에 차이가 있다.
대부분의 LLM tokenizer가 영어 중심으로 학습되었기 때문에, 한글은 같은 의미를 표현하더라도 더 많은 토큰을 사용한다.</p>
<p><strong>예시:</strong></p>
<ul>
<li>&quot;hello&quot; → 1 token / &quot;안녕하세요&quot; → 3~5 tokens</li>
<li>&quot;the&quot; → 1 token / &quot;그&quot; → 1~2 tokens</li>
</ul>
<h3 id="답변-품질">답변 품질</h3>
<p>LLM의 학습 데이터에서 영어가 차지하는 비중이 압도적으로 높다.
따라서 영어로 질문했을 때 모델이 학습한 지식이 더 잘 활성화될 가능성이 있다.</p>
<p>같은 의미라도 한글 입력과 영어 입력은 내부적으로 다른 경로로 처리된다.
영어로 학습된 지식이 많기 때문에, 영어 입력이 해당 지식과 더 직접적으로 연결될 수 있다.</p>
<h3 id="결론">결론</h3>
<p>한국에 특화된 정보를 질문하는 것이 아니라면, 영어로 질문하는 것이 효율적일 수 있다.
체감할 정도로 큰 차이는 아닐 수 있지만, 성능 최적화를 위해 시도해볼 가치는 있다.</p>
<hr>
<h2 id="결론-1">결론</h2>
<p>LLM을 효과적으로 사용하기 위한 핵심 포인트:</p>
<ol>
<li>LLM은 stateless하므로 필요한 정보는 매번 입력에 포함해야 한다. (API에 해당하는 내용)</li>
<li>Context window의 한계를 인식하고, 적정 수준의 입력 토큰을 유지한다.</li>
<li>Lost in the Middle 현상을 고려하여 중요한 정보는 앞이나 뒤에 배치한다.</li>
<li>System prompt를 활용하여 모델의 행동을 제어한다.</li>
<li>용도에 맞게 Temperature와 Top-p를 조절한다.</li>
<li>가능하다면 영어로 질문하여 토큰 효율성과 답변 품질을 높인다.</li>
</ol>
<p>이러한 원리를 이해하고 적용하면 LLM을 더욱 효율적으로 활용할 수 있다.</p>
<hr>
<h2 id="참고-문헌">참고 문헌</h2>
<p>[1] Liu et al., &quot;Lost in the Middle: How Language Models Use Long Contexts&quot;, arXiv:2307.03172, 2023<br><a href="https://arxiv.org/abs/2307.03172">https://arxiv.org/abs/2307.03172</a></p>
<p>[2] Zhang et al., &quot;Found in the Middle: How Language Models Use Long Contexts Better via Plug-and-Play Positional Encoding&quot;, arXiv:2403.04797, 2024<br><a href="https://arxiv.org/abs/2403.04797">https://arxiv.org/abs/2403.04797</a></p>
<p>[3] Qiang et al., &quot;Uncovering the Role of Initial Saliency in U-Shaped Attention Bias&quot;, arXiv:2512.13109, 2025<br><a href="https://arxiv.org/abs/2512.13109">https://arxiv.org/abs/2512.13109</a></p>
<p>[4] Chen et al., &quot;A Survey on Recent Advances in LLM-Based Multi-turn Dialogue Systems&quot;, arXiv:2402.18013, 2024<br><a href="https://arxiv.org/abs/2402.18013">https://arxiv.org/abs/2402.18013</a></p>
<p>[5] Databricks, &quot;Long Context RAG Performance of LLMs&quot;, 2024<br><a href="https://www.databricks.com/blog/long-context-rag-performance-llms">https://www.databricks.com/blog/long-context-rag-performance-llms</a></p>
<p>[6] 3Blue1Brown, &quot;트랜스포머, ChatGPT가 트랜스포머로 만들어졌죠. - DL5&quot;
<a href="https://www.youtube.com/watch?v=g38aoGttLhI">https://www.youtube.com/watch?v=g38aoGttLhI</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS EC2 k8s]]></title>
            <link>https://velog.io/@cheol2_y/AWS-EC2-k8s</link>
            <guid>https://velog.io/@cheol2_y/AWS-EC2-k8s</guid>
            <pubDate>Mon, 05 Feb 2024 06:49:04 GMT</pubDate>
            <description><![CDATA[<img src="https://velog.velcdn.com/images/cheol2_y/post/f2597a01-15db-4ec4-82ff-a623e47a97ca/image.png" width="200">

<br>

<h3 id="1-ec2-인스턴스-생성-및-접속">1. EC2 인스턴스 생성 및 접속</h3>
<pre><code class="language-bash"># 인스턴스 생성 (t2.small, 20GB 스토리지)
# 인스턴스에 접속</code></pre>
<h3 id="2-aws-cli-설치-및-구성">2. AWS CLI 설치 및 구성</h3>
<pre><code class="language-bash">sudo apt-get install -y unzip
curl &quot;https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip&quot; -o &quot;awscliv2.zip&quot;
unzip awscliv2.zip
sudo ./aws/install
aws --version

# AWS 구성
aws configure
# Access Key, Secret Access Key, region 입력
aws sts get-caller-identity</code></pre>
<h3 id="3-eksctl-및-kubectl-설치">3. eksctl 및 kubectl 설치</h3>
<pre><code class="language-bash"># eksctl 설치
ARCH=amd64
PLATFORM=$(uname -s)_$ARCH
curl -sLO &quot;https://github.com/eksctl-io/eksctl/releases/latest/download/eksctl_$PLATFORM.tar.gz&quot;
tar -xzf eksctl_$PLATFORM.tar.gz -C /tmp &amp;&amp; rm eksctl_$PLATFORM.tar.gz
sudo mv /tmp/eksctl /usr/local/bin

# kubectl 설치
curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.27.7/2023-11-14/bin/linux/amd64/kubectl
chmod +x ./kubectl
mkdir -p $HOME/bin &amp;&amp; cp ./kubectl $HOME/bin/kubectl &amp;&amp; export PATH=$HOME/bin:$PATH
echo &#39;export PATH=$HOME/bin:$PATH&#39; &gt;&gt; ~/.bashrc
kubectl version --short --client</code></pre>
<h3 id="4-eks-클러스터-생성">4. EKS 클러스터 생성</h3>
<pre><code class="language-bash">eksctl create cluster \
    --name k8s-scw \
    --region ap-northeast-2 \
    --with-oidc \
    --ssh-access \
    --ssh-public-key encore_17_key \
    --nodes 3 \
    --node-type t3.medium \
    --node-volume-size=20 \
    --managed</code></pre>
<h3 id="5-kubectl-자동완성-설정">5. kubectl 자동완성 설정</h3>
<pre><code class="language-bash"># kubectl 자동완성 사용하기
source &lt;(kubectl completion bash)
echo &quot;source &lt;(kubectl completion bash)&quot; &gt;&gt; ~/.bashrc</code></pre>
<h3 id="6-k9s-설치">6. k9s 설치</h3>
<pre><code class="language-bash">wget https://github.com/derailed/k9s/releases/download/v0.13.7/k9s_0.13.7_Linux_i386.tar.gz
tar xvzf k9s_0.13.7_Linux_i386.tar.gz
sudo mv k9s /usr/local/bin</code></pre>
<h3 id="7-kubernetes-용어-및-명령어">7. Kubernetes 용어 및 명령어</h3>
<pre><code class="language-bash"># Kubernetes 용어 및 명령어
kubectl get pods --all-namespaces
kubectl create deployment webtest --image=nginx:1.14 --port=80 --replicas=1
kubectl get pods -o wide</code></pre>
<h3 id="8-애플리케이션-배포-및-관리">8. 애플리케이션 배포 및 관리</h3>
<pre><code class="language-bash"># 애플리케이션 배포 및 관리
kubectl create deployment dpy-nginx --image=nginx
kubectl get pods --all-namespace
kubectl exec -it pod-name -- /bin/bash
kubectl delete deployment dpy-nginx</code></pre>
<h3 id="9-애플리케이션-롤아웃">9. 애플리케이션 롤아웃</h3>
<pre><code class="language-bash"># 애플리케이션 롤아웃
kubectl apply -f echo-hname.yaml
kubectl scale deployment echo-hname --replicas=3
kubectl rollout history deployment echo-hname
kubectl set image deployment echo-hname nginx=nginx:1.17.23 --record
kubectl rollout status deployment echo-hname
kubectl rollout undo deployment echo-hname</code></pre>
<h3 id="10-노드-조작">10. 노드 조작</h3>
<pre><code class="language-bash"># 노드 조작
kubectl cordon node-name
kubectl uncordon node-name
kubectl drain node-name --ignore-daemonsets --delete-emptydir-data</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Docker 명령어 정리]]></title>
            <link>https://velog.io/@cheol2_y/Docker-%EB%AA%85%EB%A0%B9%EC%96%B4-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@cheol2_y/Docker-%EB%AA%85%EB%A0%B9%EC%96%B4-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Wed, 31 Jan 2024 07:27:36 GMT</pubDate>
            <description><![CDATA[<bv>


<h2 id="docker-설치">Docker 설치</h2>
<pre><code class="language-bash"># Docker 설치
sudo curl -sSL get.docker.com | sh</code></pre>
<h2 id="기본-docker-명령어">기본 Docker 명령어</h2>
<pre><code class="language-bash"># 컨테이너 생성 및 시작
docker run -it --name test ubuntu:14.04

# 현재 사용자를 Docker 그룹에 추가하여 권한 부여
sudo usermod -aG docker $USER

# 컨테이너 종료하지 않고 나가기
# (Ctrl + P, Q로 나가기)
# exit로 나가면 컨테이너 종료

# 종료된 컨테이너 다시 시작
docker start test

# Docker 이미지 확인
docker images

# 컨테이너 중복 이름 불가능
docker run -it --name test2 ubuntu:18.04

# 컨테이너 삭제
docker rm test
docker rm test2

# 모든 컨테이너 삭제
docker rm $(docker ps -a -q)

# 포트 매핑
docker run -it --name webserver -p 90:80 ubuntu:14.04</code></pre>
<h2 id="mysql-컨테이너">MySQL 컨테이너</h2>
<pre><code class="language-bash"># MySQL 컨테이너 생성
docker run -d --name wordpressdb -e MYSQL_ROOT_PASSWORD=encore -e MYSQL_DATABASE=wordpress mysql:5.7

# WordPress 컨테이너와 연결
docker run -d -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_PASSWORD=encore -e WORDPRESS_DB_NAME=wordpress --name wordpress --link wordpressdb:mysql -p 90:80 wordpress

# MySQL 컨테이너 생성 (포트포워딩, 환경변수 설정, 볼륨 마운트)
docker run -d --name encoredb -e MYSQL_ROOT_PASSWORD=encore -e MYSQL_DATABASE=encore -p 3306:3306 -v /home/ubuntu/data:/var/lib/mysql mysql:5.7</code></pre>
<h2 id="컨테이너-조작">컨테이너 조작</h2>
<pre><code class="language-bash"># 백그라운드에서 실행 중인 컨테이너에 접속
docker exec -it encoredb bash

# 컨테이너에 attach (백그라운드에서 실행 중이면 사용 불가)
docker attach test

# 파일 복사 (로컬 -&gt; 컨테이너)
docker cp encore_backup.sql encoredb:/root/</code></pre>
<h2 id="데이터베이스-관련">데이터베이스 관련</h2>
<pre><code class="language-bash"># MySQL 복원
docker exec -it encoredb bash 
cd ~
mysql -uroot -pencore encore &lt; encore_backup.sql </code></pre>
<h2 id="docker-volume">Docker Volume</h2>
<pre><code class="language-bash"># 볼륨 생성
docker volume create --name myvol

# 볼륨 확인
docker volume ls

# 볼륨 삭제
docker volume rm myvol

# 볼륨 마운트
docker run -it --name myvol_1 -v myvol:/root ubuntu:14.04</code></pre>
<h2 id="docker-네트워크">Docker 네트워크</h2>
<pre><code class="language-bash"># 네트워크 생성
docker network create --driver bridge mybridge

# 컨테이너에 네트워크 적용
docker run -it --name mynetwork_cont --net mybridge ubuntu:14.04</code></pre>
<h2 id="apache-airflow">Apache Airflow</h2>
<pre><code class="language-bash"># Airflow 설치
pip install apache-airflow==2.8.1 --constraint https://raw.githubusercontent.com/apache/airflow/constraints-2.8.1/constraints-3.10.txt

# Airflow standalone 실행
airflow standalone

# Airflow 컨테이너 실행
docker run -it -p 8080:8080 -v /home/ubuntu/airflow:/opt/airflow/dags/ --entrypoint=/bin/bash --name airflow2 apache/airflow:2.0.0-python3.8</code></pre>
<h2 id="dockerfile">Dockerfile</h2>
<pre><code class="language-dockerfile"># 예시 Dockerfile
FROM ubuntu:14.04
LABEL &quot;purpose&quot;=&quot;practice&quot;
RUN apt-get update
RUN apt-get install apache2 -y
ADD test.html /var/www/html
WORKDIR /var/www/html
RUN [&quot;/bin/bash&quot;, &quot;-c&quot;, &quot;echo hello &gt;&gt; test2.html&quot;]
EXPOSE 80
CMD apachectl -DFOREGROUND</code></pre>
<h2 id="docker-compose">Docker Compose</h2>
<h3 id="docker-compose-설치">Docker Compose 설치</h3>
<pre><code class="language-bash"># 실행 권한 부여
sudo chmod +x /usr/local/bin/docker-compose</code></pre>
<h3 id="docker-compose-명령어">Docker Compose 명령어</h3>
<pre><code class="language-bash"># Docker Compose 빌드
docker-compose build

# Docker Compose로 컨테이너 실행
docker-compose up

# Docker Compose로 컨테이너를 백그라운드에서 실행
docker-compose up -d

# Docker Compose로 실행 중인 컨테이너 종료
docker-compose down</code></pre>
<p><a href="https://tyoon9781.tistory.com/entry/aws-ec2-vscode-setting-2023">vscode에서 aws ec2연결하는 방법 사이트</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로젝트]]></title>
            <link>https://velog.io/@cheol2_y/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</link>
            <guid>https://velog.io/@cheol2_y/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</guid>
            <pubDate>Fri, 26 Jan 2024 08:39:08 GMT</pubDate>
            <description><![CDATA[<h1 id="대용량-data-etl-및-분석-프로젝트">대용량 DATA ETL 및 분석 프로젝트</h1>
<h2 id="프로젝트-개요">프로젝트 개요</h2>
<p>이 프로젝트는 대용량 데이터 ETL(Extract, Transform, Load) 및 분석을 목표로 합니다. 주어진 데이터는 아마존 리뷰 데이터로, 총 187GB로 replication을 3으로 설정하여 총 561GB의 저장 용량을 차지하고 있습니다. 데이터는 리뷰와 메타데이터로 구성되어 있으며, 전체 리뷰 수는 약 2억 건에 해당합니다.</p>
<h2 id="프로젝트-진행과정">프로젝트 진행과정</h2>
<ol>
<li><p><strong>데이터 다운로드와 저장 구조</strong></p>
<p>데이터는 카테고리별로 나눠서 다운로드한 후 Hadoop에 put하는 과정을 거쳤습니다. 이로써 데이터의 내고장성이 확보되었습니다.</p>
<ul>
<li>총 리뷰 수: 228,764,070</li>
<li>총 제품 수: 11,867,792
<img src="https://velog.velcdn.com/images/cheol2_y/post/6f49c54d-10fb-42c9-ab09-67f63d1ef601/image.png" alt="review data"></li>
</ul>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/fb8f3e5d-50b3-4912-b4bf-d7b779fa758d/image.png" alt="meta data"></p>
<p>   <img src="https://velog.velcdn.com/images/cheol2_y/post/595460b2-92d7-47a3-b35a-98687f31d8e2/image.png" alt="Hadoop Datanodes"></p>
<ol start="2">
<li><p><strong>데이터 병합과 처리</strong></p>
<p>데이터를 Spark를 사용하여 처리하였습니다. Datanode를 6개 사용하며 각각의 Executor를 최대한 활용하기 위해 리소스를 튜닝했습니다. 데이터는 Parquet 파일로 저장되었습니다.</p>
<pre><code class="language-python"># Spark 설정 예시
from pyspark.sql import SparkSession

spark = (SparkSession.builder
    .appName(&quot;myAppName&quot;)
    .config(&quot;spark.executor.instances&quot;, &quot;6&quot;)
    .config(&quot;spark.executor.cores&quot;, &quot;2&quot;) 
    .config(&quot;spark.executor.memory&quot;, &quot;4g&quot;) 
    .config(&quot;spark.driver.memory&quot;, &quot;4g&quot;) 
    .config(&quot;spark.yarn.executor.memoryOverhead&quot;, &quot;1g&quot;) 
    .config(&quot;spark.yarn.driver.memoryOverhead&quot;, &quot;1g&quot;) 
    .config(&quot;spark.master&quot;, &quot;yarn&quot;)
    .getOrCreate())</code></pre>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/3ef23294-d81b-4da6-a0e6-471e9fdd0093/image.png" alt="Spark Configuration"></p>
</li>
</ol>
<ol start="3">
<li><p><strong>데이터 분석</strong></p>
<p>데이터를 Parquet 파일로 저장한 후, Spark를 사용하여 리뷰 데이터와 메타데이터를 각각의 테이블로 분리하였습니다.</p>
<ul>
<li>Review 데이터: df_reviewer_id, df_review</li>
<li>Meta 데이터: df_product, df_also_view, df_also_buy</li>
</ul>
<p>최종적으로 Hadoop에 저장된 데이터는 아래와 같은 구조를 갖추게 되었습니다.</p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/10a0a510-3218-4e93-abb7-fff3a4d22f28/image.png" alt="Hadoop Directory Structure"></p>
</li>
</ol>
<h2 id="프로젝트에서-발생한-이슈와-해결과정">프로젝트에서 발생한 이슈와 해결과정</h2>
<ol>
<li><p><strong>네트워크 문제와 DHCP 고정</strong></p>
<p>초기에는 공유기를 통한 네트워크 문제가 발생하였습니다. DHCP 고정을 통해 IP를 설정하여 이를 해결하였습니다.</p>
</li>
<li><p><strong>데이터 다운로드 용량 문제</strong></p>
<p>데이터 다운로드 과정에서 용량 문제가 발생하였습니다. 카테고리별로 나눠 다운로드하고 Hadoop에 put하여 이를 극복하였습니다.</p>
</li>
<li><p><strong>Spark Executor 설정과 메모리 문제</strong></p>
<p>Spark Executor를 높게 설정했을 때 초기화 과정에서 시간이 오래 걸렸습니다. 메모리 문제로 인해 여러 번 실패하였으나, 조정을 통해 해결하였습니다.</p>
</li>
<li><p><strong>Datanode 추가 및 환경 설정</strong></p>
<p>Datanode를 추가하는 과정에서 몇몇 사람이 중간에 작업하다보니 오차가 발생하였습니다. 이를 해결하기 위해 세심한 조정이 필요했습니다.</p>
</li>
</ol>
<h2 id="데이터-분석-결과">데이터 분석 결과</h2>
<p>최종적으로 Hadoop에 저장된 데이터를 기반으로 리뷰에 대한 Wordcloud를 생성하여 아래와 같은 시각화를 얻었습니다.</p>
<ul>
<li><p>별점 5점에 대한 Wordcloud</p>
<p> ![Wordcloud for 5-Star Reviews]<img src="https://velog.velcdn.com/images/cheol2_y/post/4b9c7ca0-bde3-40bc-b619-ad0ea9a43197/image.png" alt=""></p>
</li>
</ul>
<ul>
<li><p>별점 1점에 대한 Wordcloud</p>
<p> ![Wordcloud for 1-Star Reviews]<img src="https://velog.velcdn.com/images/cheol2_y/post/ca776587-9357-4983-875b-efe46ab1082e/image.png" alt=""></p>
</li>
</ul>
<h2 id="아쉬운-점-및-향후-계획">아쉬운 점 및 향후 계획</h2>
<p>프로젝트를 진행하면서 외부 데이터 활용, 데이터 전처리, 자동화 등 여러 측면에서 더 발전할 수 있는 부분이 있었습니다. 향후에는 이러한 아쉬운 점들을 보완하고 추가적인 분석 및 기능 개선을 계획하고 있습니다.</p>
<h2 id="스파크-작업">스파크 작업</h2>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/f3145b3d-a71f-4d19-9c11-e80875e0a921/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/e9955bff-7172-4fa7-9aef-261380af9f47/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/c2a1e541-67fa-48e7-82c4-a8032e4667ed/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/e04dd2c3-865e-43de-9165-50a04bbff926/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/e34dc584-b5f1-41a4-999f-532a78f10c51/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS]]></title>
            <link>https://velog.io/@cheol2_y/aws</link>
            <guid>https://velog.io/@cheol2_y/aws</guid>
            <pubDate>Mon, 22 Jan 2024 08:50:10 GMT</pubDate>
            <description><![CDATA[<h1 id="인스턴스-생성하는-방법">인스턴스 생성하는 방법</h1>
<ol>
<li>Quick Start에서 사용할 운영체제 선택</li>
<li>아키텍처는 윈도우 -&gt; x86, 맥 -&gt; arm으로 선택</li>
<li>다음으로는 인스턴스 유형을 선택 (예: t2.medium 사용)</li>
<li>키페어(Key Pair) 생성: Windows라면 ppk, 맥이라면 pem을 생성</li>
<li>Putty를 사용하여 접속: Putty에 인스턴스의 public IP를 입력하고, Connection -&gt; SSH -&gt; Auth -&gt; Credentials에 ppk 파일을 등록<ul>
<li>사용자 이름은 ubuntu (운영체제에 따라 다를 수 있음)</li>
</ul>
</li>
</ol>
<h1 id="git-web-was-만들기">Git, Web, WAS 만들기</h1>
<ol>
<li>인스턴스를 총 3개 생성</li>
<li>생성할 때 키페어(Key Pair)는 기존에 있는 것을 선택</li>
<li>보안 그룹(Security Group)은 한 개만 생성하고, 나머지 2개는 첫 번째에서 생성한 보안 그룹을 선택</li>
<li>보안 그룹에서 ICMP를 허용하고, authorized_keys를 통합하고, /etc/hosts에서 IP 설정<ul>
<li>서로간의 통신이 원활하게 이루어지도록 설정</li>
</ul>
</li>
</ol>
<h2 id="git-설정">Git 설정</h2>
<ol>
<li><code>mkdir ~/repos</code>: Git 저장소 폴더 생성</li>
<li><code>cd ~/repos</code>: 저장소 위치로 이동</li>
<li><code>git init --bare .</code>: Bare 저장소 생성 (--bare 옵션은 순수한 Git 저장소를 생성)</li>
<li>로컬 개발용 컴퓨터(Windows)에서 Git을 이용해 저장소에 코드를 올림:</li>
</ol>
<pre><code class="language-bash">git init
git remote add origin ssh://ubuntu@&lt;인스턴스IP&gt;:/home/ubuntu/repos
git add .
git commit -m &#39;first&#39;
git push origin master</code></pre>
<h2 id="web-was-서버에서-git-설정">Web, WAS 서버에서 Git 설정</h2>
<ol>
<li><code>git clone ssh://ubuntu@&lt;인스턴스IP&gt;:/home/ubuntu/repos</code>: Git 저장소 복제</li>
<li>개발용 PC에서 작업 후:<ul>
<li><code>git add .</code></li>
<li><code>git commit -m &#39;any&#39;</code></li>
<li><code>git push origin master</code> </li>
</ul>
</li>
<li>Web, WAS 서버에서는 <code>git pull origin master</code>로 업데이트</li>
</ol>
<h2 id="nginx-설정">nginx 설정</h2>
<h1 id="이론">이론</h1>
<h2 id="web과-was">WEB과 WAS</h2>
<h2 id="nginx">NGINX</h2>
<p><strong>Nginx 개요:</strong></p>
<p>Nginx (엔진엑스라고 발음)는 강력하고 널리 사용되는 오픈 소스 웹 서버 소프트웨어입니다. 또한 역방향 프록시 서버, 로드 밸런서 및 HTTP 캐시로 작동합니다. 원래 C10k 문제(10,000개 이상의 동시 연결 처리)를 해결하기 위해 만들어진 Nginx는 높은 성능, 효율성 및 낮은 자원 소비로 알려져 있습니다.</p>
<p><strong>주요 기능 및 사용 사례:</strong></p>
<ol>
<li><p><strong>웹 서버:</strong></p>
<ul>
<li>Nginx는 주로 HTML, CSS 및 이미지와 같은 정적 콘텐츠를 제공하는 데 사용되는 웹 서버로 사용됩니다.</li>
<li>이름 기반 및 IP 기반 가상 서버를 지원하여 단일 서버에서 여러 도메인을 호스팅할 수 있습니다.</li>
</ul>
</li>
<li><p><strong>역방향 프록시:</strong></p>
<ul>
<li>역방향 프록시로 Nginx는 클라이언트 요청을 백엔드 서버로 전송하여 로드 밸런싱, SSL 종료 및 캐싱과 같은 추가 기능을 제공합니다.</li>
<li>클라이언트와 응용 프로그램 서버 간의 중개자로 작동하여 보안을 강화합니다.</li>
</ul>
</li>
<li><p><strong>로드 밸런서:</strong></p>
<ul>
<li>Nginx는 들어오는 트래픽을 여러 백엔드 서버에 분산하여 최적의 리소스 활용 및 단일 서버에 대한 과부하를 방지할 수 있습니다.</li>
<li>다양한 로드 밸런싱 알고리즘을 지원합니다.</li>
</ul>
</li>
<li><p><strong>HTTP 캐시:</strong></p>
<ul>
<li>Nginx에는 메모리에서 직접 정적 콘텐츠를 저장하고 제공하는 내장 캐싱 메커니즘이 포함되어 있습니다. 이는 백엔드 서버의 부하를 줄이고 성능과 응답 시간을 향상시킵니다.</li>
</ul>
</li>
<li><p><strong>SSL/TLS 종료:</strong></p>
<ul>
<li>Nginx는 SSL/TLS 종료를 처리하여 백엔드 서버에서 암호화 및 해독 프로세스를 오프로드하고 전반적인 성능을 향상시킬 수 있습니다.</li>
<li>현대적인 암호화 프로토콜을 지원합니다.</li>
</ul>
</li>
<li><p><strong>응용 프로그램 서버를 위한 역방향 프록시:</strong></p>
<ul>
<li>Nginx는 역방향 프록시로 사용되어 응용 프로그램 서버 (예: Node.js, Django, Flask) 앞에서 로드 밸런싱, 캐싱 및 정적 파일 제공과 같은 작업을 처리합니다.</li>
</ul>
</li>
</ol>
<p><strong>구성:</strong></p>
<ul>
<li><p>Nginx는 구성 파일에서 선언적 구성 구문을 사용합니다. 주요 구성 파일에는 <code>nginx.conf</code> 및 다양한 사이트별 구성 파일이 포함됩니다.</p>
</li>
<li><p>구성에는 서버 블록, 위치 지시문, SSL 인증서 등이 포함됩니다.</p>
</li>
</ul>
<p><strong>장점:</strong></p>
<ul>
<li><p><strong>성능:</strong> Nginx는 뛰어난 성능과 낮은 메모리 사용량으로 알려져 있어 대규모 동시 연결을 처리하기에 적합합니다.</p>
</li>
<li><p><strong>확장성:</strong> 높은 확장성을 가지고 있으며 분산 및 마이크로서비스 아키텍처에서 잘 수행됩니다.</p>
</li>
<li><p><strong>다용도:</strong> Nginx의 다양성은 정적 콘텐츠 제공, 응용 프로그램 서버에 프록시, 로드 밸런싱 등에 적합합니다.</p>
</li>
<li><p><strong>구성의 용이성:</strong> 구성 구문은 간단하며 유연한 설정을 가능하게 합니다.</p>
</li>
</ul>
<p><strong>커뮤니티 및 지원:</strong></p>
<ul>
<li><p>Nginx에는 방대하고 활발한 커뮤니티가 있어 포괄적인 문서, 자습서 및 모듈을 제공합니다.</p>
</li>
<li><p>Nginx, Inc., Nginx 뒤의 기업은 상업적인 지원과 고급 기능이 포함된 Nginx Plus를 제공합니다.</p>
</li>
</ul>
<p>요약하면 Nginx는 웹 서버 및 역방향 프록시 서버로서 높은 성능, 보안 및 확장성을 갖춘 프로덕션 환경에서 널리 사용되는 소프트웨어입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spark]]></title>
            <link>https://velog.io/@cheol2_y/Spark</link>
            <guid>https://velog.io/@cheol2_y/Spark</guid>
            <pubDate>Mon, 15 Jan 2024 01:13:49 GMT</pubDate>
            <description><![CDATA[<h1 id="하둡의-전반적인-eco-system">하둡의 전반적인 eco-system</h1>
<h3 id="1-하둡-분산-파일-시스템-hdfs">1. <strong>하둡 분산 파일 시스템 (HDFS):</strong></h3>
<ul>
<li><p><strong>목적:</strong> 분산 클러스터에서 대량의 데이터를 저장하고 관리합니다.</p>
</li>
<li><p><strong>운영 위치:</strong> 일반적으로 여러 대의 머신으로 구성된 클러스터에서 동작합니다.</p>
</li>
<li><p><strong>사용된 조합:</strong> Hadoop 생태계의 다양한 구성 요소에서 입력 및 출력 데이터를 저장하는 데 사용됩니다.</p>
</li>
<li><p><em>예제 코드:*</em></p>
<pre><code class="language-bash"># HDFS에 디렉터리 생성
hdfs dfs -mkdir /user/username

# 로컬 파일을 HDFS로 복사
hdfs dfs -copyFromLocal localfile.txt /user/username/hdfsfile.txt</code></pre>
</li>
</ul>
<h3 id="2-mapreduce">2. <strong>MapReduce:</strong></h3>
<ul>
<li><p><strong>목적:</strong> 대규모 데이터 세트의 분산 처리를 위한 프로그래밍 모델 및 처리 엔진입니다.</p>
</li>
<li><p><strong>운영 위치:</strong> Hadoop 클러스터에서 동작하며 데이터 저장을 위해 HDFS를 활용합니다.</p>
</li>
<li><p><strong>사용된 조합:</strong> 주로 HDFS 및 YARN과 함께 사용됩니다.</p>
</li>
<li><p><em>예제 코드:*</em> Java에서의 WordCount 예제입니다.</p>
<pre><code class="language-java">// Mapper
public class WordMapper extends Mapper&lt;LongWritable, Text, Text, IntWritable&gt; {
   // 구현

// Reducer
public class WordReducer extends Reducer&lt;Text, IntWritable, Text, IntWritable&gt; {
   // 구현
}</code></pre>
</li>
</ul>
<h3 id="3-yarn-yet-another-resource-negotiator">3. <strong>YARN (Yet Another Resource Negotiator):</strong></h3>
<ul>
<li><strong>목적:</strong> Hadoop 클러스터에서 리소스를 관리하고 작업을 스케줄링합니다. 동일한 클러스터에서 여러 데이터 처리 엔진이 실행되도록 합니다.</li>
<li><strong>운영 위치:</strong> HDFS 및 MapReduce와 함께 Hadoop 클러스터에서 동작합니다.</li>
<li><strong>사용된 조합:</strong> HDFS, MapReduce 및 기타 데이터 처리 엔진과 함께 사용됩니다.</li>
</ul>
<h3 id="4-hadoop-공통-모듈">4. <strong>Hadoop 공통 모듈:</strong></h3>
<ul>
<li><strong>목적:</strong> 다른 Hadoop 모듈을 지원하는 공통 유틸리티, 라이브러리 및 API의 모음입니다.</li>
<li><strong>운영 위치:</strong> Hadoop 생태계 전체에서 동작합니다.</li>
<li><strong>사용된 조합:</strong> 다른 Hadoop 구성 요소에서 사용됩니다.</li>
</ul>
<h3 id="5-apache-hive">5. <strong>Apache Hive:</strong></h3>
<ul>
<li><p><strong>목적:</strong> Hadoop 위에 구축된 데이터 웨어하우징 및 SQL 유사 쿼링 인프라입니다.</p>
</li>
<li><p><strong>운영 위치:</strong> 일반적으로 HDFS를 사용하여 Hadoop 클러스터에서 동작합니다.</p>
</li>
<li><p><strong>사용된 조합:</strong> 주로 HDFS, MapReduce 및 YARN과 함께 사용됩니다.</p>
</li>
<li><p><em>예제 코드:*</em> HiveQL을 사용한 WordCount 쿼리입니다.</p>
<pre><code class="language-sql">CREATE TABLE wordcount AS
SELECT word, COUNT(*) AS count
FROM input
GROUP BY word;</code></pre>
</li>
</ul>
<h3 id="6-apache-pig">6. <strong>Apache Pig:</strong></h3>
<ul>
<li><p><strong>목적:</strong> MapReduce 프로그램을 작성하기 위한 고수준 스크립팅 언어입니다.</p>
</li>
<li><p><strong>운영 위치:</strong> Hadoop 클러스터에서 동작하며 저장소로 HDFS를 활용합니다.</p>
</li>
<li><p><strong>사용된 조합:</strong> 주로 HDFS, MapReduce 및 기타 Hadoop 구성 요소와 함께 사용됩니다.</p>
</li>
<li><p><em>예제 코드:*</em> Pig Latin을 사용한 WordCount 예제입니다.</p>
<pre><code class="language-pig">input_data = LOAD &#39;input.txt&#39; AS (line:chararray);
words = FOREACH input_data GENERATE FLATTEN(TOKENIZE(line)) AS word;
word_count = GROUP words BY word;
result = FOREACH word_count GENERATE group, COUNT(words);
STORE result INTO &#39;output&#39;;</code></pre>
</li>
</ul>
<h3 id="7-apache-hbase">7. <strong>Apache HBase:</strong></h3>
<ul>
<li><p><strong>목적:</strong> 대규모 데이터 세트에 대한 실시간 읽기/쓰기 액세스를 위해 설계된 분산, 확장 가능하고 NoSQL 데이터베이스입니다.</p>
</li>
<li><p><strong>운영 위치:</strong> 일반적으로 Hadoop 클러스터에서 동작합니다.</p>
</li>
<li><p><strong>사용된 조합:</strong> HDFS 및 기타 Hadoop 구성 요소와 함께 사용됩니다.</p>
</li>
<li><p><em>예제 코드:*</em> Java API를 사용한 HBase에서의 CRUD 작업입니다.</p>
</li>
</ul>
<h3 id="8-apache-spark">8. <strong>Apache Spark:</strong></h3>
<ul>
<li><p><strong>목적:</strong> 빠르고 범용적인 클러스터 컴퓨팅 시스템으로, 인메모리 처리를 지원합니다. 분산 데이터 처리 및 머신러닝을 위한 고수준 API를 제공합니다.</p>
</li>
<li><p><strong>운영 위치:</strong> Hadoop 클러스터 또는 스탠드얼론 모드에서 HDFS 또는 다른 데이터 소스를 활용합니다.</p>
</li>
<li><p><strong>사용된 조합:</strong> HDFS, MapReduce, YARN 및 기타 Hadoop 구성 요소와 함께 사용될 수 있습니다.</p>
</li>
<li><p><em>예제 코드:*</em> Scala를 사용한 Spark에서의 WordCount 예제입니다.</p>
<pre><code class="language-scala">val textFile = sc.textFile(&quot;hdfs://...&quot;)
val wordCounts = textFile.flatMap(line =&gt; line.split(&quot; &quot;))
                       .map(word =&gt; (word, 1))
                       .reduceByKey(_ + _)</code></pre>
</li>
</ul>
<h3 id="9-apache-mahout">9. <strong>Apache Mahout:</strong></h3>
<ul>
<li><strong>목적:</strong> 확장 가능하고 분산 알고리즘을 위한 Hadoop 기반의 머신러닝 라이브러리입니다.</li>
<li><strong>운영 위치:</strong> 일반적으로 Hadoop 클러스터에서 동작합니다.</li>
</ul>
<ul>
<li><strong>사용된 조합:</strong> HDFS 및 MapReduce와 함께 사용됩니다.</li>
</ul>
<h3 id="10-apache-zookeeper">10. <strong>Apache ZooKeeper:</strong></h3>
<pre><code>- **목적:** 분산 시스템을 관리하고 동기화하기 위한 분산 조정 서비스입니다.
- **운영 위치:** 일반적으로 Hadoop 클러스터에서 동작합니다.
- **사용된 조합:** Hadoop에서 분산 작업 및 구성을 조정하는 데 사용됩니다.</code></pre><h3 id="11-apache-sqoop">11. <strong>Apache Sqoop:</strong></h3>
<pre><code>- **목적:** Hadoop과 관계형 데이터베이스 사이에서 대량 데이터를 효율적으로 전송하기 위한 도구입니다.
- **운영 위치:** 일반적으로 Hadoop 클러스터에서 동작합니다.
- **사용된 조합:** Hadoop과 관계형 데이터베이스 간의 데이터 가져오기 및 내보내기에 사용됩니다.</code></pre><br>
<br>

<h1 id="spark-이론">Spark 이론</h1>
<p><strong>Spark이 하는 일:</strong></p>
<p>Apache Spark은 고성능 및 범용적인 클러스터 컴퓨팅 프레임워크로 대규모 데이터 처리를 위한 오픈 소스 분산 컴퓨팅 시스템입니다. Spark은 배치 처리, 대화형 쿼리, 스트리밍 및 머신러닝을 포함한 다양한 워크로드를 지원하도록 설계되었습니다. Spark의 주요 기능은 다음과 같습니다:</p>
<ol>
<li><p><strong>인메모리 처리:</strong> Spark은 중간 데이터를 메모리에 유지하여 디스크로의 쓰기 필요성을 줄이고 처리 속도를 크게 향상시킵니다.</p>
</li>
<li><p><strong>사용 편의성:</strong> Spark은 Java, Scala, Python 및 R에서 높은 수준의 API를 제공하여 다양한 개발자에게 접근성을 제공합니다.</p>
</li>
<li><p><strong>통합된 프레임워크:</strong> Spark은 MapReduce를 사용한 배치 처리, Spark SQL을 사용한 SQL과 유사한 쿼리, Spark Shell을 사용한 대화형 쿼리, Spark Streaming을 사용한 스트리밍 분석, 그리고 MLlib를 사용한 머신러닝을 포함한 다양한 데이터 처리 작업을 위한 통합 플랫폼을 제공합니다.</p>
</li>
<li><p><strong>고장 허용성:</strong> Spark은 라인지 정보를 통해 고장 허용성을 달성합니다. 만약 RDD의 파티션이 손실되면 해당 라인지 정보를 사용하여 다시 계산할 수 있습니다.</p>
</li>
<li><p><strong>호환성:</strong> Spark은 Apache Mesos, Hadoop YARN 및 자체 내장된 스탠드얼론 관리자와 같은 다양한 클러스터 관리자에서 실행될 수 있습니다.</p>
</li>
</ol>
<p><strong>Spark이 작동하는 곳:</strong></p>
<p>Spark은 다양한 환경 및 데이터 저장 시스템에서 작동할 수 있습니다. 몇 가지 일반적인 사용 사례 및 환경은 다음과 같습니다:</p>
<ol>
<li><p><strong>하둡 분산 파일 시스템 (HDFS):</strong> Spark은 HDFS에서 데이터를 읽고 쓸 수 있어 Hadoop 클러스터와 호환됩니다.</p>
</li>
<li><p><strong>클라우드 플랫폼:</strong> Spark은 AWS, Azure 및 Google Cloud와 같은 클라우드 플랫폼과 통합됩니다. 이를 통해 사용자는 클라우드 리소스의 확장성과 유연성을 활용할 수 있습니다.</p>
</li>
<li><p><strong>로컬 머신:</strong> 개발자는 로컬 머신에서 테스트 및 개발 목적으로 Spark을 스탠드얼론 모드로 실행할 수 있습니다.</p>
</li>
<li><p><strong>데이터 레이크:</strong> Spark은 데이터 레이크에서 데이터를 처리할 수 있으며, 데이터 레이크는 원시 데이터의 대형 저장소입니다.</p>
</li>
</ol>
<p><strong>Spark에서의 작업 순서:</strong></p>
<p>Spark 응용 프로그램을 제출하면 다음과 같은 일반적인 작업 순서가 따릅니다:</p>
<ol>
<li><p><strong>드라이버 프로그램 초기화:</strong></p>
<ul>
<li>드라이버 프로그램은 RDD에 대한 변환 및 액션을 정의하는 주 프로그램입니다. SparkContext를 초기화하여 Spark 기능의 진입점을 설정합니다.</li>
</ul>
</li>
<li><p><strong>SparkContext 연결:</strong></p>
<ul>
<li>SparkContext는 클러스터 관리자(예: Apache Mesos, Hadoop YARN 또는 Spark의 스탠드얼론 관리자)에 연결합니다.</li>
</ul>
</li>
<li><p><strong>작업 실행:</strong></p>
<ul>
<li>드라이버 프로그램은 높은 수준의 Spark 작업을 단계라고 하는 더 작은 작업으로 분할합니다. 스테이지에는 RDD에 대한 변환 및 액션이 포함됩니다. 이러한 작업은 클러스터의 워커 노드에서 실행되는 실행자 프로세스로 전송됩니다.</li>
</ul>
</li>
<li><p><strong>실행자 실행:</strong></p>
<ul>
<li>실행자는 할당된 작업을 실행하고 가능한 경우 중간 결과를 메모리에 저장합니다.</li>
</ul>
</li>
<li><p><strong>결과 수집:</strong></p>
<ul>
<li>액션이 트리거될 경우(<code>collect</code> 또는 <code>count</code> 등), 드라이버 프로그램은 실행자 프로세스에서 결과를 수집하고 사용자에게 반환하거나 외부 저장소에 기록합니다.</li>
</ul>
</li>
<li><p><strong>작업 완료:</strong></p>
<ul>
<li>Spark 응용 프로그램은 실행이 완료되고 드라이버 프로그램이 SparkContext를 중지합니다.</li>
</ul>
</li>
</ol>
<pre><code class="language-bash"># spark는 병렬 처리로 작업하기에 yarn에게 요청한다.
pyspark --master yarn --num-executors 3 </code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Crawling]]></title>
            <link>https://velog.io/@cheol2_y/Crawling</link>
            <guid>https://velog.io/@cheol2_y/Crawling</guid>
            <pubDate>Tue, 09 Jan 2024 07:18:35 GMT</pubDate>
            <description><![CDATA[<h1 id="crawling">Crawling</h1>
<h2 id="requests">Requests</h2>
<p>requests는 url주소, 필요하다면 payload와 header를 추가로 사용하여 웹사이트의 주소를 가져오는 방법이다.</p>
<p>url 주소와 payload를 가져오는 방법은 해당 crawling을 할 웹 페이지에 들어간 후 f12를 눌러 개발자 도구를 키고 네트워크 탭에서 요청되는 정보들 중에서 유효한 정보를 가져오면 된다.
header는 user-agent를 가져오면 된다.</p>
<p>payload와 header는 언제 가져오는 거고, 유효한 정보는 어디서 판단하는 건지는 아직 잘 모르겠다.</p>
<p>아래는 starbucks 크롤링 예시이다.</p>
<pre><code class="language-python">url_cd = &quot;https://www.starbucks.co.kr/store/getSidoList.do&quot;
url_place = &quot;https://www.starbucks.co.kr/store/getStore.do?r=YKWS2U9PS5&quot;
r = requests.post(url_cd)
total = []
for x in tqdm(r.json()[&#39;list&#39;]):
    #print(x[&#39;sido_nm&#39;], x[&#39;sido_cd&#39;])
    payload[&#39;p_sido_cd&#39;] = x[&#39;sido_cd&#39;]
    r = requests.post(url_place, data=payload)
    total.append(pd.DataFrame(r.json()[&#39;list&#39;]))
starbuck_df = pd.concat(total)</code></pre>
<p>krx_stock, cu, gs25에서 크롤링할 수 있다.</p>
<h2 id="selenium">Selenium</h2>
<p>셀레니움은 메크로로도 사용할 수 있는 좋은 도구이다. 크롬 창을 하나 생성하고 거기서 python 코드로 자동으로 동작 할 수 있게끔 조종할 수 있다. 메크로처럼 사용 할 수 있기에 자동화 도구로 사용된다.</p>
<p>Selenium과 Requests는 웹 데이터를 가져오는 데에 사용되는 두 가지 주요 도구입니다. 그러나 두 도구는 목적과 사용 시나리오에 따라 선택되어야 하는 차이점이 있습니다.</p>
<ol>
<li><p><strong>JavaScript 렌더링:</strong></p>
<ul>
<li>Selenium은 웹 페이지 내의 JavaScript를 실행하고, 동적으로 렌더링되는 콘텐츠를 가져올 수 있습니다. 반면에 Requests는 JavaScript를 실행하지 않으며, 정적인 HTML만 가져옵니다. 만약 웹 페이지가 JavaScript를 통해 데이터를 로드하거나 변경한다면, Selenium이 더 나은 선택일 수 있습니다.</li>
</ul>
</li>
<li><p><strong>브라우저 시뮬레이션:</strong></p>
<ul>
<li>Selenium은 실제 웹 브라우저를 제어하여 사용자와 유사한 상호 작용을 시뮬레이션할 수 있습니다. 이는 로그인, 폼 작성, 클릭 등과 같은 사용자 행동을 자동화하는 데 유용합니다.</li>
</ul>
</li>
<li><p><strong>페이지 이동 및 대기:</strong></p>
<ul>
<li>Selenium은 특정 페이지로 이동하거나, 요소가 로드되기를 대기하는 등의 동작을 편리하게 수행할 수 있는 메서드들을 제공합니다. 이는 웹 페이지의 로딩이나 동적 콘텐츠 로딩을 기다릴 때 유용합니다.</li>
</ul>
</li>
<li><p><strong>웹 애플리케이션 테스트:</strong></p>
<ul>
<li>Selenium은 웹 애플리케이션의 테스트를 위해 설계되었습니다. 웹 페이지의 동작을 시뮬레이션하고 테스트하는 데 강력한 기능을 제공합니다.</li>
</ul>
</li>
</ol>
<p>그러나 속도 측면에서는 Requests가 보다 경량이며 빠릅니다. 만약 간단한 웹 페이지에서 데이터를 가져오거나, JavaScript를 사용하지 않는 경우라면 Requests가 더 빠를 수 있습니다. 선택은 사용하려는 시나리오, 요구 사항, 그리고 어떤 데이터를 얻으려는지에 따라 달라집니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[15주차]]></title>
            <link>https://velog.io/@cheol2_y/15%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@cheol2_y/15%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Tue, 02 Jan 2024 02:01:21 GMT</pubDate>
            <description><![CDATA[<p><strong>1. 정형데이터 (Structured Data):</strong></p>
<ul>
<li><strong>특징:</strong> 고정된 스키마 또는 구조를 가지며, 표 형태의 데이터베이스에 저장 가능.</li>
<li><strong>예시:</strong><ul>
<li>관계형 데이터베이스의 테이블 (MySQL, PostgreSQL, Oracle 등).</li>
<li>엑셀 스프레드시트.</li>
<li>CSV 파일.</li>
<li>주문 데이터베이스의 주문 테이블 (주문번호, 날짜, 고객ID, 상품ID, 수량 등).</li>
</ul>
</li>
</ul>
<p><strong>2. 비정형데이터 (Unstructured Data):</strong></p>
<ul>
<li><strong>특징:</strong> 고정된 구조가 없고, 텍스트, 이미지, 오디오, 비디오 등의 형태를 가짐.</li>
<li><strong>예시:</strong><ul>
<li>텍스트 문서 (워드 문서, PDF).</li>
<li>이미지 파일.</li>
<li>동영상 파일.</li>
<li>웹 페이지.</li>
<li>소셜 미디어 콘텐츠 (트위터 트윗, 페이스북 게시물).</li>
</ul>
</li>
</ul>
<p><strong>3. 반정형데이터 (Semi-Structured Data):</strong></p>
<ul>
<li><strong>특징:</strong> 일정한 구조를 갖추지만 완전한 정형데이터가 아닌 데이터 형태.</li>
<li><strong>예시:</strong><ul>
<li>XML 데이터 (확장 가능한 마크업 언어).</li>
<li>JSON 데이터 (JavaScript Object Notation).</li>
<li>HTML 문서.</li>
<li>로그 파일 (서버 로그, 이벤트 로그).</li>
</ul>
</li>
</ul>
<p>이러한 분류는 데이터의 특성과 구조에 따라서 이루어진 것이며, 각각의 데이터 유형은 다양한 응용 분야에서 활용됩니다.</p>
<h1 id="crontab--e-사용법">crontab -e 사용법</h1>
<p>crontab은 날짜와 시간에 맞춰서 자동으로 파일을 실행시키는 명령을 내리는 작업이다.
이걸 사용해서 py파일이나 sh파일을 특정 시간에 자동으로 실행시키게 만들 수 있다.</p>
<p>hadoop 설치가 끝났으면 다음 작업은 hive를 사용하여 쿼리문을 실행시키는 것이다.
hadoop은 원래 sql이 아닌 java 언어를 사용하여 데이터를 동작시키는데 hive라는 프로그램이 sql언어를 java로 바꿔주어 sql 문으로도 hadoop이 동작하게 만들 수 있다.</p>
<p>hive를 통해 이전에 만들어 두었던 stock csv 파일들을 넣을 수 있다. 먼저 csv의 column명들에 맞게 table을 생성해준다. 생성된 table에 data를 넣어주면 된다. location을 csv 파일들이 있는 폴더로 설정하면 알아서 table에 입력이 된다.</p>
<p>table이 만들어 졌으니 이것을 sql로 조작하면 된다. 이것을 다시 hadoop dir에 넣을 수도 있다. 이렇게 넣은 data를 python에서 사용할 수 있다.
from hdfs import InsecureClient
client = InsecureClient(&#39;<a href="http://namenode:50070&#39;">http://namenode:50070&#39;</a>, user=&#39;hadoop&#39;)</p>
<h1 id="hive">hive</h1>
<p>원래 하둡은 java문으로만 쿼리를 조작할 수 있었다. 근데 java 코드는 불편하다. sql문을 입력하면 java문으로 변경하여 hadoop이 동작하게 만들어 주는 것이 hive이다.</p>
<p>DB(MySQL) 백업하기
DB를 자동으로 백업 가능
CLI 창에 아래의 명령어를 입력한다.
mysqldump -uroot -p123 hivedb &gt; ~/workspace/hivedb.sql</p>
<p>이걸 저번에 배운 crontab -e 를 사용하면 자동으로 특정 시간에 백업할 수 있다.</p>
<pre><code class="language-python">from datetime import date
import os 
today = str(date.today()).replace(&quot;-&quot;, &quot;&quot;)
os.system(f&quot;mysqldump -uroot -p123 hivedb &gt; ~/workspace/{today}.sql&quot;)</code></pre>
<p>이렇게 생긴 py파일을 만들고 sh으로 변경후 실행권한을 준 후 crontab에서 자동으로 실행시키게 하면 된다.</p>
<p>문제 발생
schematool -initSchema -dbType mysql
사용하니까 failed라고 실패가 발생함 이것은 mariadb가 외부 사용자 ip에대하여 사용 허용을 안해두었기 때문이다.
cd /etc/mysql/mariadb.conf.d/
sudo vim 50-server.cnf
여기서 bind-address = 0.0.0.0 으로 설정해주면 된다.
sudo service mysql restart
여기까지 하고 다시 실행하면 정상 작동할것이다.</p>
<h1 id="sqoop">SQOOP</h1>
<p>SQOOP은 1과 2가 있는데
1은 단일 기능을 하고 2는 다양한 기능을 할 수 있다.</p>
<p>2는 설정하는게 어렵기때문에 간단하게 sqoop1을 사용하였다. data를 migration할 때 사용한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[14주차 리눅스 환경 설치]]></title>
            <link>https://velog.io/@cheol2_y/14%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@cheol2_y/14%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Thu, 28 Dec 2023 04:59:54 GMT</pubDate>
            <description><![CDATA[<br>

<h1 id="virtualbox에서-linux-사용하기">Virtualbox에서 Linux 사용하기</h1>
<p><a href="https://www.virtualbox.org/wiki/Downloads">Virtual Box 설치</a></p>
<p>만약 visual C++ 설치하라고 한다면</p>
<p><a href="https://learn.microsoft.com/ko-kr/cpp/windows/latest-supported-vc-redist?view=msvc-170">여기서 설치</a></p>
<p><a href="https://learn.microsoft.com/ko-kr/cpp/windows/latest-supported-vc-redist?view=msvc-170">우분투 설치</a></p>
<br>

<h1 id="virtual-box에서-우분투-환경-설치하기">virtual box에서 우분투 환경 설치하기</h1>
<p> <img src="https://velog.velcdn.com/images/cheol2_y/post/64682104-e0ed-43e2-aef4-c91ac2b804eb/image.png" alt=""></p>
<p>기본메모리는 pc 메모리의 절반정도를 넣으면 되고
cpu도 절반정도 할당하면 괜찮습니다.</p>
<p>입력 -&gt; 키보드설정에서 host 키는 컨트롤 알트로 하면 됩니다.</p>
<br>
# Linux Window 연결
이제 terminators 설치해서 terminal 작업을 하면됩니다.
여기서 sudo 권한이 없다면 새로운 계정을 만들면 되고, 만들때 관리자 권한을 주면 된다.

<p>terminal 에서 
sudo apt-get install openssh-server 
sudo service ssh status
여기까지 준비하면 된다.</p>
<p>이후에는 다시 virtual box에서 설정-&gt; 네트워크 -&gt; 어댑터 2에서 호스트 전용 어댑터를 추가해주고 ubuntu 다시 실행한다.</p>
<p>terminal에서 ip addr을 쳐보면 3번에 ip가 하나 보일거다. window용 ip를 확인했다면 그걸 virtual box 밖에있는 기존 window에서 cmd 창을 키고 
ssh play@[serverip] 
이걸 입력하면 된다.
그러면 ubuntu와 window가 연결성공이다.</p>
<h1 id="기타">기타</h1>
<pre><code>play@ubuntu:~$ ls -al
합계 84
drwxr-x--- 16 play play 4096 12월 22 16:37 .
drwxr-xr-x  4 root root 4096 12월 22 15:41 ..
-rw-------  1 play play  306 12월 22 16:19 .bash_history
-rw-r--r--  1 play play  220 12월 22 15:41 .bash_logout
-rw-r--r--  1 play play 3771 12월 22 15:41 .bashrc
drwx------ 10 play play 4096 12월 22 16:23 .cache
drwx------  3 play play 4096 12월 22 16:14 .local
-rw-r--r--  1 play play  807 12월 22 15:41 .profile
-rw-------  1 play play    7 12월 22 16:37 .python_history
drwx------  2 play play 4096 12월 22 16:15 .ssh
-rw-r--r--  1 play play    0 12월 22 15:44 .sudo_as_admin_successful
drwx------  3 play play 4096 12월 22 16:14 snap
drwxr-xr-x  2 play play 4096 12월 22 16:14 비디오
drwxr-xr-x  2 play play 4096 12월 22 16:14 사진
drwxr-xr-x  2 play play 4096 12월 22 16:14 음악
drwxr-xr-x  2 play play 4096 12월 22 16:14 템플릿</code></pre><p>rwx(소유자) , r-x(그룹), r-x(others)
r: read , w: write, x: excute
rwx는 2^2+ 2^1+ 2^0 = 7
r-x는 5
rw-는 6을 의미한다.</p>
<p>컴퓨터 이름 변경하기
sudo hostnamectl set-hostname client</p>
<p>file 전송 프로그램 scp 
scp ./dog_model_service.7z <a href="mailto:play@192.123.45.678">play@192.123.45.678</a>:/home/play/
scp  [대상파일]&amp;nbsp[계정]@[ip]:[경로]</p>
<br>

<h1 id="miniconda-설치">Miniconda 설치</h1>
<p>wget <a href="https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh">https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh</a></p>
<p>권한 변경 
chmod 700 ./Miniconda3-latest-Linux-x86_64.sh</p>
<p>실행
./Miniconda3-latest-Linux-x86_64.sh</p>
<p>source ~/.bashrc </p>
<p>pip install jupyter </p>
<p>ls -al ~/ | grep bash</p>
<p>hash 구조: key value가 있는것 dict도 hash 구조를 갖음
hash 구조를 갖으면 속도가 빠르다</p>
<h1 id="운영체제">운영체제</h1>
<ol>
<li>데스크탑 - 윈도우, 맥OS</li>
<li>서버 - 유닉스 - Linux - 안드로이드, 서버용(RedHat-CentOS, Ubuntu)
 유닉스 - iOS</li>
<li>서버 - CLI(Command Line Interface), GUI(Graphic User Interface)</li>
<li>서버 - 편집기 - vi(vim), emacs, nano</li>
</ol>
<h1 id="네트워크">네트워크</h1>
<ol>
<li>Private IP</li>
<li>Public IP</li>
<li>IPv4 (32bit(8bit(A class).8bit(B).8bit(C).8bit(D)(255.255.255.255))) -</li>
<li>IPv6(64bit)</li>
</ol>
<br>

<h1 id="vim편집기-사용기">vim(편집기) 사용기</h1>
<p>Vim(Vi Improved)이란 Unix, Linux 환경에서 사용되는 텍스트 편집기(editor)인 Vi의 업그레이드 버전이다.</p>
<p>vim /home/play/.jupyter/jupyter_notebook_config.py
i나 insert키 눌러서 편집모드 실행
esc 누르면 다시 일반모드 실행
나가기 하는법
esc -&gt; :q! -&gt; 엔터 누르면 됨
저장후 나가기 :wq 하면됩니다.</p>
<p>pwd는 현재 위치를 알려줌</p>
<p>ip=0.0.0.0으로 두면 모든 ip를 의미한다.
그래서 server 터미널에서 주피터 노트북을 열고 이것을 모든 ip에서 허용하려고 한다면 다음과 같이 치면 된다.
jupyter lab --ip=0.0.0.0
근데 이렇게 하면 터미널이 프롬프트가 계속 실행중이게 되어서 그 터미널을 사용할 수가 없다. 그래서 백그라운드에서 작동하도록 하기위해 아래와 같은 코드를 사용하는 것이 좋다.
nohup jupyter lab --ip=0.0.0.0 &amp;</p>
<p>사용중인 포트 확인
netstat -nao | grep 8888</p>
<p>netstat -lntp | grep 8888</p>
<p>실행중인 프로세스 목록 확인 
ps -ef | grep vim</p>
<p>kill -&gt; 프로세스 죽이기 
kill -9 &lt; pid &gt;</p>
<p>rm 삭제 명령어 
폴더 삭제 
rm -rf   </p>
<h1 id="데이터-크롤링">데이터 크롤링</h1>
<h2 id="스벅-데이터">스벅 데이터</h2>
<p>스타벅스 데이터 중에서도 이번에는 매장의 정보를 가져오려고 한다. 스타벅스 홈페이지에 들어가서 매장찾기에 들어간다. 그곳에서 dev tools를 켜서 네트워크 -&gt; dev tools 검색창에 get을 친다. 아무것도 나오지 않는다면 화면을 움직여서 새로운 정보를 요청하면 나올것이다. /getStore.do?r=YKWS2U9PS5 이러한 url 요청사항이 있을텐데 여기서 헤더에 가서 요청 url 정보를 복사한다. 그리고 payload에 있는 json타입의 data를 가져온다.
가져온 url 정보와 payload 정보가 있으면 이제 크롤링을 할 수 있다.</p>
<pre><code class="language-python">url_cd = &quot;https://www.starbucks.co.kr/store/getSidoList.do&quot;
url_place = &quot;https://www.starbucks.co.kr/store/getStore.do?r=YKWS2U9PS5&quot;
r = requests.post(url_cd)
total = []
for x in tqdm(r.json()[&#39;list&#39;]):
    #print(x[&#39;sido_nm&#39;], x[&#39;sido_cd&#39;])
    payload[&#39;p_sido_cd&#39;] = x[&#39;sido_cd&#39;]
    r = requests.post(url_place, data=payload)
    total.append(pd.DataFrame(r.json()[&#39;list&#39;]))
starbuck_df = pd.concat(total)
</code></pre>
<p>이런 식으로 가져오면 국내 스타벅스 갯수는 1887개이다.
이제 이렇게 수집한 데이터를 분석하고 그래프로 시각화도 하고 하면 된다.</p>
<br>

<h1 id="filezilla">Filezilla</h1>
<p>이건 내 컴퓨터에서 server 컴퓨터로 보내는 방법이다.
다운은 알아서 잘하면 되고 설치할 때 광고 파일도 다운받아지려고 하는게 있으니 decline 잘 하면된다.
파일을 설치한 이후에는 filezilla를 실행하여 파일 아래에 있는 아이콘(사이트 관리자 열기)에 들어가서 server pc의 ip주소를 입력하고 유저 아이디와 비밀번호를 입력하면 연결이 된다. 이렇게 연결이 되면 두 컴퓨터간에 파일 전송이 손쉽게 가능해진다.</p>
<br>

<h1 id="mariadb">MariaDB</h1>
<p>sudo apt install mariadb-server 
sudo service mysql status
(active 상태인거 확인한 후 나가고 싶을땐 q를 누르면 된다.)
sudo mysql_secure_installation
이렇게 설치하면 된다.</p>
<p>아래 두개는 하면 좋은 것들인 것같은데 정확히 무엇인지는 모른다.
sudo apt update
sudo apt install net-tools</p>
<p>MariaDB를 사용할 도구는 heidisql나 DBeaver를 사용하면 된다.
DBeaver에서 연결하다 보면 서버 컴퓨터에서 사용하는 것이기때문에 IP 권한이 없다고 나온다. 이것은 아래에 들어가서 변경해주면 된다.
sudo vim /etc/mysql/mariadb.conf.d/50-server.cnf</p>
<p>vim 편집기에서 명령어 모드로 :/bind 를 쳐서 나온 곳에서 IP를 0.0.0.0으로 해서 모든 IP에서 접근 가능하게 설정해준다. 이러면 보안적인 면에서 취약하긴 하다. 해커조심!</p>
<p>이렇게 하면 IP권한은 획득했지만 계정권한이 아직 없어서 막힐 것이다.
계정권한은</p>
<p>mysql -uroot -p 으로 접속해서 아래와 같은 코드 두줄을 입력해주면 된다.</p>
<p>CREATE USER &#39;설정할 계정이름&#39;@&#39;%&#39; IDENTIFIED BY &#39;설정할 pwd&#39;;
GRANT ALL PRIVILEGES ON <em>.</em> TO &#39;설정한 계정이름&#39;@&#39;%&#39;;
이 과정을 완료하면 IP 권한, 계정 권한 모두를 받았기에 실행이 될 것이다.</p>
<p>이제 이렇게 설정을 완료했다면, python에서 DB에 작업을 넣을 수 있게끔 설정해주면 된다.</p>
<pre><code class="language-python">import pymysql
con = pymysql.connect(host = &quot;192.168.56.102&quot;, user=&quot;설정한 이름&quot;, password=&#39;설정한 비번&#39;, db=&#39;만든 DB이름&#39;)
cur= con.cursor()</code></pre>
<p>이렇게 연결이 되었다면 cur를 이용해 쿼리문을 실행시키고, 마지막에 con.commit()하면 된다.</p>
<p>다른 방법으로는 sqlalchemy로도 가능하다. 이건 pypi.org에 들어가서 해당 모듈을 검색해서 설치하는 방법을 보면 된다. 설치후 import해서 아래와 같은 코드 짜면 된다.</p>
<pre><code class="language-python">user = &quot;설정한 유저 이름&quot;
password = &quot;설정한 비밀번호&quot;
host = &quot;호스트 주소&quot;
port = &quot;3306&quot;
database = &quot;설정한 DB이름&quot;

engine = sqlalchemy.create_engine(f&quot;mysql://{user}:{password}@{host}:{port}/{database}&quot;)

star_df.to_sql(name=&quot;star2&quot;, if_exists=&quot;replace&quot;, con=engine)</code></pre>
<p>ORM은 관계 객체 매핑이다.
Demon은 백그라운드에서 실행되고 있는 것을 의미한다.</p>
<br>

<h1 id="ip">IP</h1>
<p>IP는 일반적으로 public 공용 IP는 유니크해야한다.
private은 내가 사용하는 네트워크 내에서만 사용가능한 IP 주소이다. 이건 192또는 172로 시작하는 경향이 있다.
IP 주소와 넷마스크, 서브넷마스크가 있는데 이건 기본 IP주소와 넷마스크를 2진수로 표현한 후 and 연산을 하면 네트워크 주소를 얻을 수 있다.
IP주소 뒤에 /20 이런 것을 써서 넷마스크의 1의 갯수를 알려준다.</p>
<p>ex) IP 주소가 192.168.72.162/20 이라면
netmask가 255.255.240.0 -&gt; 11111111.11111111.11110000.00000000 으로 나온다.</p>
<p>gateway 는 IP주소와 똑같은데 D클래스만 1로 설정된다. (192.168.72.1)
<br></p>
<h1 id="hadoop">Hadoop</h1>
<p>새로운 계정(hadoop)을 만들고
sudo adduser hadoop 
+) sudo passwd [계정]</p>
<p>su hadoop 계정을 이동한다. 근데 아직 hadoop에게 권한이 부여되어 있지 않기때문에 다시 메인 계정으로 돌아와서 권한을 부여해줘야한다.</p>
<p>sudo visudo 을 실행한다. 그러면 nano창이 나오는데 여기서 root아래에 hadoop을 만들고 위와 똑같이 쓰면 된다. (ALL:ALL) ALL</p>
<p>이제 sudo 권한이 생겼으니 새로 만든 계정에 java를 설치해주면 된다.</p>
<p>sudo apt update 
sudo apt install openjdk-8-jdk</p>
<p>java를 설치했으면 java home을 지정해줘야한다. 기존에는 환경변수 설정에서 설정했지만 linux 터미널에서 진행하려면 아래와 같이 진행하면 된다.</p>
<p>vim ~/.bashrc으로 들어가서 export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64를 넣어주면 된다. </p>
<p>근데 이 위치는 아무곳에나 해도 되는건지 아니면 특정한 위치에 해줘야하는지 잘 모르겠다. 일단 나같은 경우에는 4번째 줄에 작성해주었다. (for example 써있는 아래줄) 그리고 잘 설정되었는지 확인하려면 echo $JAVA_HOME 이걸 사용해서 있나 확인하면 된다.</p>
<p>이제 hadoop을 설치한다.
cd ~ 
wget <a href="https://dlcdn.apache.org/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz">https://dlcdn.apache.org/hadoop/common/hadoop-3.3.6/hadoop-3.3.6.tar.gz</a>
이걸 하면 되는데 주소정보는 hadoop 홈페이지에서 확인하는걸 추천한다.</p>
<p>hadoop에서 map reduce를 알아야한다.
병렬처리와 직렬처리도 알아야할듯
sql문을 공부하는게 중요하다.
분석: 코딩 통계 도메인. 이 3개가 중요하다
<br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[


10주차]]></title>
            <link>https://velog.io/@cheol2_y/10%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@cheol2_y/10%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Thu, 30 Nov 2023 09:48:01 GMT</pubDate>
            <description><![CDATA[<h1 id="spring-boot">Spring Boot</h1>
<p>Spring Boot는 웹 프레임워크로 웹페이지를 만드는데 매우 편리한 도구이다. VScode에서 설치를 하고 구현을 한다. 처음에 프로젝트를 만들때는 빈 폴더에 Spring Boot Project를 만들어야한다. 다른 파일이 있다면 오류가 날 수 있다. Spring Boot 버전과 JAVA 버전도 맞춰서 잘 설정해야한다. 또한 기본적으로 Lombok이랑 Spring Boot web web은 추가해주는 것이 좋다. 외부 라이브러리도 추가할 수 있지만, 처음 프로젝트를 만들 때 넣어주는 것이 좋다. 추가로 넣으려고 한다면 build.gradle이나 pom.xml파일에서 dependencies 부분에 추가해주면 될 것이다.<br></p>
<h2 id="controller">Controller</h2>
<p>\basic\src\main\java\com\example\basic
basic은 아마 프로젝트 만들 때 설정한 이름일 것이다. 마지막 baisc 폴더 안에 controller 폴더를 만들고 그 안에 BasicController.java라는 파일을 만들어 java 코드를 짜면 된다. java 파일을 만들었으면 어노테이션(annotation)을 추가하여 주면된다. 이 어노테이션은 import와 비슷한데 자동으로 코드도 넣어주는 것으로 보인다. 코드를 자동으로 추가해주지만 화면에는 안보이기에 더 깔끔하다. 우선 우리는 Controller를 사용할 것이기 때문에 @RestController를 public class BasicController 위에 넣어주면 기능이 추가된다. 
<br></p>
<p>다음으로는 http 링크에 들어가면 함수가 실행되게 만드는 코드이다. 함수를 선언하는 부분위에 @GetMapping(&quot;/something&quot;)을 설정하면 주소에 들어가면 바로 함수가 진행된다. 기본적으로 코드를 실행하면 생기는 주소는 <a href="http://localhost:8080%EC%9D%B4%EB%8B%A4">http://localhost:8080이다</a>. 우리는 mapping을 /something으로 해주었기 때문에 <a href="http://localhost:8080/something%EC%9C%BC%EB%A1%9C">http://localhost:8080/something으로</a> 들어가게 되면 지정해준 함수가 자동으로 실행된다.</p>
<pre><code class="language-java">@Slf4j
@RestController
public class BasicController {

  @GetMapping(&quot;/hello&quot;)
  public String getHello(){

    String msg = &quot;Hello Wrold&quot;;

    System.out.println(&quot;msg: &quot; + msg);
    log.info(&quot;msg: &quot; +msg);
    return msg;
  }}</code></pre>
<p>코드에서는 hello로 설정했기 때문에 localhost:8080/hello로 들어가게 되면 화면에 return되는 값인 msg가 출력된다. println과 log.info를 사용했기 때문에 터미널에는 &quot;msg: &quot;+ msg가 출력된다. log.info와 println은 같은 역할을 하지만 log.info가 자원을 덜 먹기때문에 이것을 사용하면된다. 사용하는 방법은 @Slf4j라는 어노테이션을 추가해주면된다.
<br>
<br></p>
<p>@GetMapping을 사용하여 주소를 통해 변수를 받아 올 수 있다. 아래와 같이 {param1}/{param2} 처럼 {}을 사용하여 변수를 받는다. 받은 변수는 @PathVariable이라는 어노테이션을 사용하여 함수 내부에서 변수로 사용 할 수 있다. localhost:8080/variabl2/hi/hello 라고 입력을 해준다면 터미널에서는 hi가 출력되고 web페이지에서는 hello가 출력될 것이다.</p>
<pre><code class="language-java">  @GetMapping(&quot;variable2/{param1}/{param2}&quot;)
  public String getHeollo3(@PathVariable String param1,@PathVariable String param2){

    log.info(&quot;url로부터 받은&quot;+param1);
    return param2;
  }</code></pre>
<br>
<br>

<p>이것을 활용하여 쿼리문을 작성 할 수 있다. 쿼리는 질문하다라는 뜻으로 사용되고 주소에서 질문을 하고 값을 받을 수 있다. 예를들어 아래와 같은 코드가 있다면 key라는 질문을 받고 그것에 해당하는 value값을 반환한다. web 주소는 다음과 같다. 
localhost:8080/query?key=value 로 설정할 수 있다. key=까지는 고정이고 뒤에 value값에 원하는 변수를 입력 할 수 있다. @RequestParam이라는 어노테이션을 사용하는데 key대신 다른 값을 사용할 수 있다. query?name=cheol2라고 입력한다면 key대신 name이라고 코드에 입력해줘야하고 출력값은 cheol2가 될 것이다.</p>
<p>localhost:8080/query?key=value</p>
<pre><code class="language-java">  @GetMapping(&quot;/query&quot;)
  public String getQuery1(@RequestParam String key){

    log.info(&quot;쿼리는 질의문입니다!&quot;);
    return key;
  }</code></pre>
<br>
<br>


<p>DTO도 설정해줄 수 있다. DTO는 data transfer object 데이터를 변환해준다. 이것은 getter와 setter를 사용하여 아래와 같이 구현할 수 있다. @ModelAttribute를 통해 BasicDto의 함수를 가져온다. BasicDto는 basic폴더에 model이라는 폴더를 만들고 그안에 BasicDto.java 파일을 만들었다. 아래와 같이 @getter를 쓰면 getter함수가 만들어지고 @setter를 치면 setter함수가 만들어진다. constructor는 생성자이고 Tostring은 string으로 바꿔주는 함수이다. 말했다싶이 어노테이션은 코드가 보이지는 않지만 내부적으로 전부 처리됐다.</p>
<p>//localhost:8080/dto1?name=name1&amp;email=email1</p>
<pre><code class="language-java">  @GetMapping(&quot;/dto1&quot;)

  public String getDto1(@ModelAttribute BasicDto dto){

    return dto.toString();
  }</code></pre>
<pre><code class="language-java">package com.example.basic.model;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class BasicDto {

  private String name;
  private String email;

}
</code></pre>
<br>


<p>혹시 잘 실행이 안된다면 파일 위치를 잘 설정했는지를 확인해보자
<img src="https://velog.velcdn.com/images/cheol2_y/post/65904abf-dc56-40dd-b63e-324018a02344/image.png" alt=""></p>
<p>최상단에 폴더명이 1.2.Springgradle/basic로 되어있는데 원래는 basic만 나오게끔 폴더를 열어줘야한다. 프로젝트 하나만 나오게 해야한다고 들었다. 지금은 블로그 정리를 위해 모든 폴더를 띄워뒀기때문에 저렇게 나온다.
<br></p>
<h2 id="filter--interceptor">Filter &amp; Interceptor</h2>
<p>Dispatcher-Servlet처리 과정이다
<img src="blob:https://velog.io/51a69ff7-4c57-4a11-9602-55cc3311f45f" alt="업로드중.."></p>
<p>우선 Filter는 Client에서 입력을 하면 모든 data가 Filter를 거쳐가기때문에 모든 입력에대해 반응을한다. Interceptor는 이것과 달리 특정한 데이터 입력에 대해서만 반응하게 만들 수 있다.</p>
<p>Filter보다 Interceptor를 많이 쓴다고는 하지만 두가지 모두 구현해보려한다.</p>
<p>위에서 했던 것 처럼 프로젝트를 새로 만든 다음 main에 있는 basic폴더에서 config라는 폴더를 새로 하나 만든다. 그리고 그안에 filter와 interceptor라는 폴더를 각각 생성한다. filter폴더 안에는 BasicFilter.java라는 파일을 만들고 interceptor에는 BasicInterceptor.java라는 파일을 만든다.</p>
<p>우선 BasicFilter.java 파일이다. 상단에 있는 import들은 따로 쳐줄 필요가 없다. 안쪽에 있는 class를 형성하고 어노테이션을 설정하다보면 자동으로 생성된다. 우선 @Component를 사용하여 bean을 만들어 준다. Spring bean은 객체라고 보면되는데 자세한 내용은 차차 알게 될 것으로 보인다. 상속을 받아야하니 implements Filter를 치면 알아서 Filter에 대한 코드가 형성이 된다. 우리는 이번에 Filter가 어디서 작용하는지만 확인할 것이기 때문에 filter를 지날때마다 터미널에 &quot;filter 실행완료&quot;라는 출력이 실행되게 한다.</p>
<pre><code class="language-java">package com.example.basic.config.filter;

import java.io.IOException;

import org.springframework.stereotype.Component;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class BasicFilter implements Filter {

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    // TODO Auto-generated method stub

    log.info(&quot;filter 실행완료&quot;);

    chain.doFilter(request, response);
  }

}</code></pre>
<br>

<p>다음으로는 BasicInterceptor.java파일이다. 위에서 했으니까 간단하게 진행하겠다. 아래와 같은 코드만 쳐도 알아서 상속을 받아 Interceptor를 만들어준다. 3개의 interceptor class가 생성될 것이다. afterCompletion, postHandle, preHandle 세가지가 형성된다. 각각 의미하는 바는 해석한 의미와 같다.</p>
<pre><code class="language-java">
@Component
public class BasicInterceptor implements HandlerInterceptor
</code></pre>
<br>

<p>Interceptor는 이렇게만 진행하면 안되고 config 폴더안에 WebMvcConfig.java라는 파일을 만들어야한다. MVC는 Model-View-Controller로 그냥 역할을 나누는 것이라고 생각하면 될 것같다. 여기도 똑같이 implements로 상속을 받으면 알아서 코드가 생성된다. 그리고 아래에 add와 exclude를 사용하여 interceptor를 할 부분과 안할 부분을 지정해주면 된다. admin이라는 path가 있는데 AdminController를 하나 만들어서 또 @GetMapping을 해주면된다. 그리고 AdminController class가 선언되는 부분위에 @RequestMapping(&quot;/admin&quot;)을 해주면 알아서 localhost:8080/admin이 작성된다.</p>
<pre><code class="language-java">public class WebMvcConfig implements WebMvcConfigurer{

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    // TODO Auto-generated method stub
    // WebMvcConfigurer.super.addInterceptors(registry);

    registry.addInterceptor(new BasicInterceptor())
      .addPathPatterns(&quot;/**&quot;)
      .excludePathPatterns(&quot;/admin/**&quot;);
  }</code></pre>
<br>
<br>


<h2 id="mybatis">MyBatis</h2>
<p>MyBatis는 Java에서 사용가능한 객체 관계 매핑 프레임워크이다. 객체들을 서로 연결해주는 역할을 한다고 보면 된다. MySQL이랑 비슷하다. 이것을 처음에 사용하려면 Spring Boot 프로젝트를 만들때 추가 라이브러리를 넣어줘야한다. 위에서 사용한 2개의 라이브러리 외에 추가로 MySQL과 MyBatis를 추가해주면 된다. 그리고 아래는 우리 챗박사님이 알려주신 MyBatis에 대한 정보이다. 전체적인 개요를 이해하기에 아주 좋고 깔끔해 보여서 가져왔다.
<br></p>
<p>MyBatis와 Spring Boot를 함께 사용할 때, 전형적인 구조는 다음과 같습니다. 이 구조는 MVC(Model-View-Controller) 아키텍처를 기반으로 하며, MyBatis를 데이터베이스와 연동하는 부분을 포함합니다.</p>
<ol>
<li><p><strong>Controller (컨트롤러):</strong></p>
<ul>
<li>Spring Boot에서의 Controller는 클라이언트의 요청을 받아 적절한 비즈니스 로직을 호출하고, 그 결과를 사용자에게 반환합니다.</li>
<li>클라이언트에서의 HTTP 요청을 처리하고, 비즈니스 로직을 실행하기 위해 Service 계층을 호출합니다.</li>
<li>MyBatis와 직접 상호 작용하지 않으며, Service 계층에게 데이터베이스 처리를 위임합니다.</li>
</ul>
</li>
<li><p><strong>Service (서비스):</strong></p>
<ul>
<li>비즈니스 로직을 담당하는 계층으로, Controller에서 받은 요청을 처리합니다.</li>
<li>MyBatis의 Mapper를 사용하여 데이터베이스와 상호 작용합니다.</li>
<li>하나 이상의 DAO(Data Access Object)나 Repository를 호출하여 데이터베이스 조작을 수행하고, 그 결과를 반환합니다.</li>
</ul>
</li>
<li><p><strong>Model (모델):</strong></p>
<ul>
<li>데이터를 나타내는 객체로, MyBatis와 연동되어 데이터베이스의 특정 테이블과 매핑됩니다.</li>
<li>주로 JavaBeans 규약을 따르며, 데이터베이스의 레코드를 표현하는 역할을 합니다.</li>
</ul>
</li>
<li><p><strong>DAO (데이터 액세스 객체) 또는 Repository:</strong></p>
<ul>
<li>MyBatis의 Mapper 인터페이스를 구현한 객체로, 실제로 데이터베이스에 접근하여 쿼리를 수행합니다.</li>
<li>MyBatis의 XML 매핑 파일을 사용하거나, 어노테이션을 활용하여 SQL 쿼리를 정의하고 실행합니다.</li>
</ul>
</li>
<li><p><strong>MyBatis 설정:</strong></p>
<ul>
<li>MyBatis의 설정 파일 및 Spring Boot에서의 설정 클래스를 통해 MyBatis와 Spring Boot를 통합합니다.</li>
<li>DataSource, SqlSessionFactory, Mapper 등의 빈을 설정하여 MyBatis의 기능을 Spring Boot와 함께 사용할 수 있습니다.</li>
</ul>
</li>
<li><p><strong>Spring Boot 프로젝트 구조 예시:</strong></p>
<pre><code>src
├── main
│   ├── java
│   │   ├── com.example.demo
│   │   │   ├── controller
│   │   │   │   ├── MyController.java
│   │   │   ├── service
│   │   │   │   ├── MyService.java
│   │   │   ├── model
│   │   │   │   ├── MyModel.java
│   │   │   ├── dao
│   │   │   │   ├── MyMapper.java
│   │   ├── resources
│   │   │   ├── mapper
│   │   │   │   ├── MyMapper.xml
│   │   ├── DemoApplication.java
├── resources
│   ├── application.properties
│   ├── mybatis-config.xml</code></pre><p>위의 예시에서 <code>MyController</code>가 클라이언트의 요청을 받고, <code>MyService</code>에서 MyBatis의 <code>MyMapper</code>를 호출하여 데이터베이스 조작을 수행합니다. <code>MyModel</code>은 데이터를 표현하는 Java 객체로 MyBatis와 연동되어 데이터베이스와 매핑됩니다. <code>MyMapper.xml</code>은 MyBatis의 XML 매핑 파일로 SQL 쿼리를 정의합니다.</p>
</li>
</ol>
<p>이러한 구조를 통해 Spring Boot와 MyBatis를 함께 사용하여 데이터베이스와의 효율적인 상호 작용을 달성할 수 있습니다.</p>
<p>from. Chat GPT</p>
<br>

<p>위에서 본 구조처럼 정말 다양한 것들을 설계해야 MyBatis가 동작한다. 내부 코드내용은 블로그에 올리지 않도록 하겠다. 코드를 올린다면 너무 복잡해질 것으로 예상되기 때문이다.
<br></p>
<p>간단하게 작업 순서만 적어두려고 한다. 프로젝트 폴더 이름은 demo가 아닌 basic으로 설정했고 구현하려는 것은 Product라는 table을 변경하는 controller다.</p>
<blockquote>
<ol>
<li>resources폴더에 application.yml 파일을 만들고 내부에 코드를 작성하여 Spring Boot 설정, DataBase(MySQL) 설정, MyBatis를 설정한다.<br>
1-1 (선택사항) build.gradle이나 pom.xml에서 추가 할 라이브러리가 있다면 추가한다. resources폴더에 추가로 받은 파일 2개를 추가<br></li>
<li>resources폴더에 mapper폴더를 만들고 그 안에 ProductMapper.xml를 만들고 사용할 MyBatis 코드를 설계한다.<br></li>
<li>basic폴더에 model폴더를 만들고 그 안에 dto폴더를 만든 후 ProductDto.java 파일을 만든다. 내부에는 table의 coulumn들과 이름을 private 변수로 지정해주고 getter, setter를 구현해준다.<br></li>
<li>model폴더에 repository폴더를 만들고 ProductMapper.java를 만들고 설계한다.       <br></li>
<li>basic폴더에 service라는 폴더를 만들고 ProductService.java를 만들고 설계한다.<br></li>
<li>basic폴더에 controller라는 폴더를 만들고 ProductController.java를 만들고 설계한다.</li>
</ol>
</blockquote>
<p>결과에서 오류가 발생한다면 모두 복사해서 GPT에게 물어보면 된다.
<br></p>
<p>Mapper.xml으로부터 파생되어 모든 설계가 진행되기 때문에 잘 설계하고 이해하는 것이 중요하다. 만드는 순서를 다시 한번 말하면 
Mapper.xml -&gt;  Dto.java -&gt; Mapper.java -&gt; Service.java -&gt; Controller.java
이다.</p>
<p>아래는 사용한 xml코드이다.</p>
<pre><code class="language-mybatis">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
&lt;!DOCTYPE mapper PUBLIC &quot;-//mybatis.org//DTO Mapper 3.0//EN&quot; &quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;

&lt;mapper namespace=&quot;com.example.basic.model.repository.ProductMapper&quot;&gt;

    &lt;!-- 조회할때는 select --&gt;
    &lt;select id=&quot;selectAll&quot; resultType=&quot;ProductDto&quot;&gt;
        select 
            product_id 
            , product_name 
            , product_price 
        from product
        where 1=1
        ;
    &lt;/select&gt;
&lt;!-- resultType은 return하는 값이 있을때 사용한다. parameterType은 parameter가 있을때 사용한다.
          보면 ProductDto에서 입력해주는 값이나 출력하는 값의 형태를 변형 시켜준다고 생각 --&gt;
    &lt;select id=&quot;selectProduct&quot; resultType=&quot;ProductDto&quot; parameterType=&quot;ProductDto&quot;&gt;
        select 
            product_id 
            , product_name 
            , product_price 
        from product
        where 1=1
        &lt;if test=&#39;productName != null and productName != &quot;&quot;&#39;&gt;
            and product_name = #{productName}
        &lt;/if&gt;
        &lt;if test=&#39;productPrice != null and productPrice &gt; 0&#39;&gt;
            and product_price = #{productPrice}
        &lt;/if&gt;
        ;
    &lt;/select&gt;

    &lt;!-- 데이터를 저장할 때는 insert  --&gt;
    &lt;insert id=&quot;insertProduct&quot; parameterType=&quot;ProductDto&quot;&gt;
      insert into product(product_name, product_price)
      values (#{productName}, #{productPrice});
    &lt;/insert&gt;

    &lt;update id=&quot;updateProduct&quot; parameterType=&quot;ProductDto&quot;&gt;
        update product
        &lt;set&gt;
            &lt;if test=&#39;productName != null and productName != &quot;&quot;&#39;&gt;
                product_name = #{productName}
            &lt;/if&gt;
            &lt;if test=&#39;productPrice != null and productPrice &gt; 0&#39;&gt;
                product_price = #{productPrice}
            &lt;/if&gt;
        &lt;/set&gt;
        where 1=1
            and product_id = #{productId}
    &lt;/update&gt;

    &lt;delete id=&quot;deleteProduct&quot;&gt;
        delete from product 
        where 1=1
            and product_id = #{productId}
        ;
    &lt;/delete&gt;
&lt;/mapper&gt;</code></pre>
<h1 id="jsp">JSP</h1>
<p>JSP(Java Server Pages)는 최근에는 많이 사용하지 않아 간단하게 공부하고 넘어갔다. JSP는 HTML 웹 코드에 java 코드를 삽입하여 사용할 수 있게 만드는 것이다. &lt;% java 코드  %&gt; 라는 코드를 삽입하여 사용할 수 있다. java 코드를 import 하는 과정에서는 &lt;%@   %&gt; 을 사용하면 된다. class를 불러오는 코드는 &lt;%!  %&gt; 을 사용한다.
<br></p>
<pre><code class="language-html">&lt;%@ page import=&quot;java.sql.*&quot;%&gt;

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;%
    String url = &quot;jdbc:mysql://localhost:3306/examplesdb&quot;;
    String user = &quot;urstory&quot;;
    String password = &quot;&quot;;

    Connection conn=null;
    PreparedStatement pstmt=null;
    ResultSet rs = null;

    try {

        Class.forName(&quot;com.mysql.jdbc.Driver&quot;);
        conn = DriverManager.getConnection(url, user, password);

        System.out.println(&quot;MySQL 연결 성공 &quot;);

        String sql = &quot;show tables;&quot;;
        pstmt = conn.prepareStatement(sql);
        rs = pstmt.executeQuery();

        while(rs.next()) {

            System.out.println(&quot;결과: &quot;+rs.getString(&quot;Tables_in_examplesdb&quot;));
        }

    } catch (Exception e) {

        System.out.println(&quot;MySQL 연결 오류: &quot;+e.getMessage());
    } finally {

        if(pstmt != null) 
             try{pstmt.close();}catch(SQLException sqle){}
         if(conn != null) 
             try{conn.close();}catch(SQLException sqle){}
    }
%&gt;

&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>위 코드는 mysql을 java에 불러와서 사용하고 그 코드를 HTML에 사용하는 JSP file의 코드이다.
<br></p>
<p>Java코드에서 사용한 변수를 가져오려면 &lt;%= 변수명 %&gt;을 사용하면 된다. JSP를 사용하여 할일 목록을 만드는 코드를 만들 수 있다. MySQL에서 Database를 만들고 그것을 Java에 연결할 수 있다. 이렇게 연결된 데이터를 JSP에서 사용하여 바로 웹페이지에 구현하게 할 수있다. 내가 만든 것은 ToDO List(할일 목록)를 만드는 프로젝트를 진행했다. 새로운 일정을 등록하면 DB에 추가되고 삭제하면 DB에 삭제되는 것을 구현했다. JavaScript 코드와 Java 코드 모두를 사용했는데, 이후에 코드에 익숙해진다면 JS 만으로도 구현할 수 있다.</p>
<br>
<br>

]]></description>
        </item>
        <item>
            <title><![CDATA[9주차]]></title>
            <link>https://velog.io/@cheol2_y/9%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@cheol2_y/9%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Mon, 27 Nov 2023 01:45:52 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>Java는 이론적인 설명보다 실제 코드가 어떻게 되는지를 보며 이해하는 것이 좋을 것으로 생각되어 코드를 많이 넣을 예정이다. Python이나 다른 언어와 비슷한 면이 약간 있기에 배우는데 어렵진 않을 것이다.</p>
</blockquote>
<h2 id="array">Array</h2>
<blockquote>
<p>java 에서 array를 구현하는 코드는 아래와 같다. for문과 if문도 들어가 있다.
class 내부에서 실행하면 되는 코드이다.</p>
</blockquote>
<pre><code class="language-java">    public static void main(String[] args) {
        // TODO Auto-generated method stub
        // 해위
        int[] score = new int[5]; // 크기가 3인 배열 생성
        score[0] = 10; // 0번 index에 값 할당
        score[1] = 15; // 1번 index에 값 할당
        score[2] = 13; // 2번 index에 값 할당
        score[3] = 20;
        score[4] = 30;
        int sum = 0 ;
        int max = 0;
        for (int i = 0; i&lt; score.length; i++) {
            sum += score[i];
            System.out.println(sum);
            if(max &lt; score[i]) {
                max = score[i];
            }
        }

        double avg = (double)sum / score.length;
        System.out.println(&quot;점수 합계 : &quot; + sum);
        System.out.println(&quot;점수 평균 : &quot; + avg);
        System.out.println(&quot;점수 최고 : &quot; + max);
    }</code></pre>
<br>

<h2 id="list">List</h2>
<blockquote>
<p>Java에서 List를 만드는 코드이다. List를 만드는 방법은 다양하다.</p>
</blockquote>
<pre><code class="language-java">List&lt;String&gt; s = new ArrayList&lt;String&gt;() {
            {
                add(&quot;1&quot;);
                add(&quot;2&quot;);
                add(&quot;3&quot;);
            }
        };
        List&lt;String&gt; s1 = new ArrayList&lt;String&gt;(Arrays.asList(new String[]{ &quot;4&quot;, &quot;5&quot;, &quot;6&quot; }));
        List&lt;String&gt; s2 = new ArrayList&lt;String&gt;(Arrays.asList(&quot;7&quot;, &quot;8&quot;, &quot;9&quot;)); // 
        List&lt;String&gt; s3 = new ArrayList&lt;&gt;(Arrays.asList(&quot;17&quot;, &quot;8&quot;, &quot;9&quot;));

        System.out.println(&quot;1:&quot;+s);
        System.out.println(&quot;2:&quot;+s1);
        System.out.println(&quot;3:&quot;+s2);
        System.out.println(&quot;4:&quot;+s3);

        List&lt;String&gt; lst1 = new ArrayList&lt;&gt;(Arrays.asList(&quot;17&quot;, &quot;8&quot;, &quot;9&quot;));
        System.out.println(&quot;5:&quot;+lst1);
        s.add(&quot;34&quot;);
        s.set(0, &quot;10&quot;);
        System.out.println(&quot;6:&quot;+s);
        for(int i =0; i &lt; s.size(); i++) {
            System.out.println(s.get(i));
        }</code></pre>
<p>리스트는 .get(index)를 사용하여 내부원소를 호출한다.
배열은 [index]를 사용하여 호출한다.<br></p>
<h2 id="for문과-list">for문과 List</h2>
<br>
for 문은 아래와 같이 실행할 수 있다. list 대신 array를 써도 되지만 그러면 두번째 방법에서 array.length()를 사용해야한다.
첫번째 방법은 i가 lst의 원소들이 할당되고 두번째에서 i는 index의 값을 갖게 된다.

<pre><code class="language-java">for (int i : lst){ 실행할 코드 }
for (int i =0; i &lt; lst.size(); i++) { 실행할 코드 }</code></pre>
<br>
list 생성하는 방법은 다양하다 아래와 같이 생성 할 수 있다.

<pre><code class="language-java">List&lt;Integer&gt; lst = Arrays.asList(1,2,3,4,5,7,8,9);
List&lt;Integer&gt; lst = List.of(20,40,70,70,80,70,100);
List&lt;String&gt; s1 = new ArrayList&lt;String&gt;(Arrays.asList(new String[]{ &quot;4&quot;, &quot;5&quot;, &quot;6&quot; }));
  List&lt;String&gt; s2 = new ArrayList&lt;String&gt;(Arrays.asList(&quot;7&quot;, &quot;8&quot;, &quot;9&quot;));</code></pre>
<p>첫번째와 두번째 방법이 좋은 것이라 생각되니 기억해두자
<br></p>
<h2 id="class">Class</h2>
<pre><code class="language-java">public class Korean {
    String nation=&quot;대한민국&quot;;
    String name;
    String ssn;

    public Korean(String name, String ssn) {
        this.name = name;
        this.ssn = ssn;
    }
}</code></pre>
<pre><code class="language-java">// 만든 class를 호출하여 사용하는 방법
public class KoreanExample {
    public static void main(String[] args) {
        Korean k1 = new Korean(&quot;윤x철&quot;,&quot;9708xx&quot;);
        System.out.println(k1.name);
        System.out.println(k1.ssn);
        k1.name = &quot;파평윤씨&quot;;
        System.out.println(k1.name);
    }
}</code></pre>
<p>하나의 Java Class 파일에 꼭 하나의 Class만 사용해야하는 것은 아니다. 여러개의 Class를 지정해줄 수 있다. this는 그 class 내부에서만 작용하는 변수이다.</p>
<br>

<h2 id="java에서-mysql-사용하기">Java에서 MySQL 사용하기</h2>
<blockquote>
<p>Java에서 MySQL을 사용하려면 라이브러리를 다운 받아야한다. 다운받는 곳은 <a href="https://mvnrepository.com/artifact/mysql/mysql-connector-java/8.0.28">여기서</a> 받으면 된다.
다운 받은 라이브러리를 Eclipse에서 Java project 폴더에 넣어주면 된다. 접근 권한은 아래와 같이 받아와서 실행하면 된다.</p>
</blockquote>
<pre><code class="language-java">package java_mysql;

import java.sql.*;

public class ex01 {
    public static void main(String[] args) {
        // DBSM -&gt; jdbc:mysql:
        // localhost는 mysql 설치위치
        // 어떤 Database 사용하는 건지 -&gt; /examplesdb
        String url = &quot;jdbc:mysql://localhost:3306/classicmodels&quot;;
        String id = &quot;MYSQL 썼을 때 사용했던 아이디&quot;;
        String pw = &quot;비밀번호&quot;;

        // 커넥션 객체 만들자
        try {
            Class.forName(&quot;com.mysql.jdbc.Driver&quot;);
            Connection conn = DriverManager
                    .getConnection(url,id,pw);

            String sql = &quot;show tables;&quot;;    //사용할 MySQL 코드
            PreparedStatement pstmt = conn
                    .prepareStatement(sql);
            ResultSet rs = pstmt.executeQuery();
            while(rs.next()) {
                String table_name = rs.
                        getString(&quot;Tables_in_classicmodels&quot;);
                System.out.println(&quot;테이블 이름은 &quot;+table_name);
            }            
}
        catch (ClassNotFoundException | SQLException e) {     
            } 
    }}</code></pre>
<p>String sql에 해당하는 코드 명령어를 입력해주면 된다.</p>
<h2 id="참고-정보">참고 정보</h2>
<p>eclipse에서 window -&gt; preferences -&gt; java -&gt; editor -&gt; templates에서 단축키를 설정할 수 있다.
이미 존재하는 단축키도 많으니 활용하면 좋다.
ex) sysout을 치고 ctrl + space 를 누른 후 엔터를 치면 println문이 완성된다.
class 안에서 main을 치고 ctrl + space을 하면 public static void가 생성된다.
<br></p>
<p>옆에 툴이나 탭이 사라졌다면, window -&gt; show view 에서 찾아 쓰면 된다.</p>
<p>public, protected, private으로 class를 생성해줄 수 있다. 기본 값은 public이다. 이것들은 접근 가능성에서 차이가 있다. class로 객체를 생성하거나 상속을 하여 자식 class를 만들 수 있다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/4628dde6-35cf-4b0b-90ba-2a416b5bb1e1/image.png" alt=""></p>
<p>class에서는 필드와 메서드가 존재한다. 필드는 변수이고 메서드는 실행하는 함수라고 보면 된다. 필드와 메서드를 선언할 때 public, protected, private을 선언하여 접근 가능성을 지정해줄 수 있다. 이때 static을 뒤에 붙여준다면 정적으로 지정되어 수정이 불가능해진다.</p>
<p>싱글톤 패턴</p>
<blockquote>
<p>소프트웨어 디자인 패턴에서 싱글턴 패턴(Singleton pattern)을 따르는 클래스는, 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. 이와 같은 디자인 유형을 싱글턴 패턴이라고 한다. 주로 공통된 객체를 여러개 생성해서 사용하는 DBCP(DataBase Connection Pool)와 같은 상황에서 많이 사용된다.<br>
출처: 위키피디아</p>
</blockquote>
<p>final 이라는 함수를 사용하면 더이상 변경하지 못하는 변수가 된다.
<br>
메모리 영역
<img src="https://velog.velcdn.com/images/cheol2_y/post/5bd56549-5ea8-465d-a469-c978b89b41f3/image.png" alt=""></p>
<h2 id="html-css">HTML, CSS</h2>
<p>HTML(Hypertext Markup Language)은 웹페이지를 구성하는 코드이다. 이것을 꾸며주기 위하여 CSS(Cascading Stylesheet)를 사용할 수 있다. HTML은 사람들에게 보여주는 영역이기에 보통 프론트엔드로 본다. 그렇기때문에 어떻게 설계하냐도 중요하긴 하지만, 대부분 반복작업이 많이 필요하다. BootStrap, TailWind와 같은 툴이 있고, 많은 frame들이 존재하기 때문에 그런것을 활용하여 HTML코드를 구성하면 도움이 될 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[8주차]]></title>
            <link>https://velog.io/@cheol2_y/8%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@cheol2_y/8%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Mon, 20 Nov 2023 03:50:33 GMT</pubDate>
            <description><![CDATA[<p>데이터 모델링 순서</p>
<ol>
<li>업무파악(요구사항 수집 및 분석)</li>
<li>개념적 데이터 모델링(ERD 작성)</li>
<li>논리적 데이터 모델링</li>
<li>물리적 데이터 모델링</li>
</ol>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/de476135-158c-41e8-ba5f-864c18d2218b/image.png" alt=""></p>
<p>ERD
ERD (Entity Relationship Diagram)는 단어에서 의미하는 그대로 &#39;Entity 개체&#39;와 &#39;Relationship 관계&#39;를 중점적으로 표시하는 데이터베이스 구조를 한 눈에 알아보기 위해 그려놓는 다이어그램이다. 개체 관계도라고도 불리며 요구분석사항에서 얻은 엔티티와 속성들의 관계를 그림으로 표현한 것이다.</p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/77781e8f-2be2-425d-add0-8413bb4c66c4/image.png" alt=""></p>
<p>Entity: 객체, 개체, 테이블, 엔티티</p>
<p>MySQL
MySQL을 설치하는 방법은 Docker를 사용하여 설치하였다. 설치하는 과정이 약간 오래걸리긴 하지만, 사용하거나 삭제할 때 편리하여 많이 사용하는 방법이다. 설치한 MySQL은 DBeaver라는 프로그램으로 실행시켰다. DBeaver는 MySQL의 편집기라고 생각하면 된다.
MySQL에서는 root계정이 존재하는데 이건 모든 권한이 있는 관리자 계정이기에 이 계정으로 바로 편집하는 것은 추천되지 않고, user계정을 만들어서 편집하는 것을 추천한다.
<br></p>
<p>MySQL에는 크게 3개의 언어가 있다</p>
<p>DDL(Data Definition Language)
DCL(Data Control Language)
DML(Data Manipulation Language)</p>
<p>DCL은 관리자가 하는 영역으로 데이터의 보안, 무결성, 회복 등을 제어하는 구문이다. DDL은 데이터의 테이블을 정의 수정 삭제하는 부분이다. DML은 테이블의 데이터를 삽입, 조회, 수정, 삭제하는 구문으로 가장 많이 사용하게 될 부분이다.</p>
<p>auto_increment가 있다면 자동으로 값이 증가하며 넣어지기 때문에 입력을 주면 안된다. 자동으로 index가 먹어진다고 생각하면 된다.</p>
<p>쿼리문에서 조건을 만들때, 같은 지를 비교하는 = 연산이 가장 빠르므로 먼저 쓰는 것이 좋다</p>
<p>간단한 예제 코드</p>
<pre><code class="language-sql"># Shipped, Resolved, Cancelled인 경우이면서
# 주문수가 5개 이상인 경우에서
# 주문별(orderNumber) 총 금액이 큰 city 순서로 정렬하자!!

SELECT
    c.city,
    o.orderNumber,
    SUM(od.quantityOrdered * od.priceEach) AS totalAmount
FROM
    orders o
JOIN
    orderdetails od ON o.orderNumber = od.orderNumber
JOIN
    customers c ON o.customerNumber = c.customerNumber
WHERE
    o.status IN (&#39;Shipped&#39;, &#39;Resolved&#39;, &#39;Cancelled&#39;)
    AND od.quantityOrdered &gt;= 5
GROUP BY
    c.city, o.orderNumber
ORDER BY
    totalAmount DESC, c.city;</code></pre>
<p>같은 코드인데 다중 쿼리문을 사용한 경우이다.</p>
<pre><code class="language-sql"># Shipped, Resolved, Cancelled인 경우이면서
# 주문수가 5개 이상인 경우에서 
# 주문별(orderNumber) 총 금액이 큰 city 순서로 정렬하자!!
select 
    t1.city 
    , t3.order_sum
from customers t1,
(
    select 
        orderNumber
        , customerNumber 
    from orders
    where 1=1
    # Shipped, Resolved, Cancelled인 경우이면서
    and status in (&#39;Shipped&#39;, &#39;Resolved&#39;, &#39;Cancelled&#39;) 
) t2, 
(
    select 
        orderNumber
        , count(orderLineNumber) as order_cnt
        # 주문별(orderNumber) 총 금액이
        , sum(quantityOrdered * priceEach) as order_sum
    from orderdetails
    where 1=1
    group by orderNumber
    # 주문수가 5개 이상인 경우에서
    HAVING order_cnt &gt;= 5
) t3
where 1=1
and t1.customerNumber = t2.customerNumber
and t2.orderNumber = t3.orderNumber
# 총 금액이 큰 city 순서로 정렬하자
order by t3.order_sum desc
;</code></pre>
<br>

<p>출처: <a href="https://inpa.tistory.com/entry/DB-%F0%9F%93%9A-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81-1N-%EA%B4%80%EA%B3%84-%F0%9F%93%88-ERD-%EB%8B%A4%EC%9D%B4%EC%96%B4%EA%B7%B8%EB%9E%A8#erd_entity_relationship_diagram_%EA%B7%B8%EB%A6%AC%EA%B8%B0">https://inpa.tistory.com/entry/DB-📚-데이터-모델링-1N-관계-📈-ERD-다이어그램#erd_entity_relationship_diagram_그리기</a> [Inpa Dev 👨‍💻:티스토리]</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[6주차]]></title>
            <link>https://velog.io/@cheol2_y/6%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@cheol2_y/6%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Thu, 02 Nov 2023 08:43:00 GMT</pubDate>
            <description><![CDATA[<h1 id="cnn">CNN</h1>
<p>image processing의 하나의 기법으로 Convolutional neural network이다. </p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/6a68fde7-6135-4044-8f55-2f164f7fadd1/image.png" alt=""></p>
<p>딥러닝에서는 데이터의 shape이 중요하기 때문에 각각의 Layer를 지날 때 shape이 어떻게 변하는 지를 잘 확인하여야 한다.
CNN에서 Output의 Shape는 아래와 같다. </p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/a7c847b2-5234-44e0-81f8-4a1615248e26/image.png" alt=""></p>
<p>이 공식과 위에 있는 Layer들을 확인해 보며, shape를 보면 공부에 도움이 된다.
<br>
<br></p>
<h1 id="vgg--resnet">VGG &amp; ResNet</h1>
<h2 id="vgg">VGG</h2>
<p>VGG는 CNN을 여러겹 겹쳐서 모델을 구성한 것이다.
하지만 layer의 수를 늘려서 성능을 높혔지만 layer를 증가시킬 수록 모델의 학습시간이 증가하는 문제가 있다. 또한, layer의 수가 충분히 많아지면 그 이상 layer를 증가시켜도 성능이 크게 변하지 않는 구간이 발생한다.</p>
<h2 id="resnet">ResNet</h2>
<p>ResNet은 단순히 layer를 늘리는 것이 아닌 새로운 기법을 추가하였다. 입력 데이터를 출력 데이터를 내보내기 전에 추가하여 연산에 변화를 주는 것이다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/869221cc-6f09-4237-913a-f3d65e82ddd8/image.png" alt="">
이와 같이 학습을 시키면 H(x) = F(x) + x가 된다. 모델은 H(x)를 얻기위하여 학습을 하는 것이 아닌 F(x) = H(x) - x로 학습을하여 그것의 방향은 F(x)가 0이되는 방향으로 학습을 진행한다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/4df8c232-460c-4c9c-9b2e-9c69ca1789c2/image.png" alt=""></p>
<h3 id="overfitting을-관리하는-방법">Overfitting을 관리하는 방법</h3>
<ul>
<li>Get more data</li>
<li>Simplify your model</li>
<li>Use data augmentation</li>
<li>Use transfer learning</li>
<li>Use dropout layers</li>
<li>Use learning rate decay</li>
<li>Use early stopping<br>
<br>
# Fine Tuning</li>
<li>Pre training(사전 학습)
데이터셋을 기반으로 충분히 학습을 완료한 모델을 말한다.<br></li>
<li>Transfer Learning(전이 학습)
pretrained model을 새로운 데이터셋(features, label)로 다시 학습시키는 것을 말한다.<br></li>
<li>Fine tuning(미세 조정)
Transfer Learning과는 달리 pretrained model의 일부 layer를 수정하여 새로운 데이터셋(features, label)로 다시 학습시키는 것을 말한다.<br>

</li>
</ul>
<p>pretrained data를 가져올때 모델 전부를 해석할 수 있다면 좋지만, 그렇지 못한다면, input과 output의 shape만 확인해도 된다. 그리고 그 shape들을 내가 사용할 input과 output에 맞게 변경해주는 tuning 작업을 하면 된다.</p>
<p>Pretrained Model은 아래 링크를 통해서 얻을 수 있다.</p>
<ul>
<li><a href="https://pytorch.org/vision/stable/models.html#models-and-pre-trained-weights">Pytorch Pre-trained Models</a></li>
<li><a href="https://huggingface.co/models">HuggingFace Hub</a></li>
<li><a href="https://github.com/huggingface/pytorch-image-models">timm</a></li>
<li><a href="https://paperswithcode.com/">Paperswithcode</a><br>
<br>
# 생성 모델 GAN

</li>
</ul>
<p>GAN은 Generative Adversarial Networks이다. GAN은 단순히 특정한 이미지를 이해하고 분류하는 것을 넘어서 실제 데이터와 흡사한 가짜 데이터를 생성하는 알고리즘입니다. GAN은 생성자(Generator) 모델과 구분자(Discriminator) 모델로 두 개의 모델이 학습하는 방식으로 동작합니다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/b500004a-b703-41d7-ba5f-78fd2459afd0/image.png" alt=""></p>
<p>학습은 Generator가 최대한 Real한 image를 발생할 수 있도록 하는 방향으로 진행된다. GAN은 내부 식도 복잡하고 이해하기에 어려움이 있기 때문에 간단하게만 설명하고 넘어가겠다. GAN은 데이터가 부족할 때 학습을 통하여 새로운 데이터를 만들어낼 수 있기에 좋은 방법이다. 하지만 최근에는 많이 쓰이진 않는다.
<br>
<br></p>
<h1 id="nlp">NLP</h1>
<p>NLP는 Natural Language Processing으로 언어처리 모델이다. 언어를 기계가 학습해야하므로 언어를 전처리해주는 과정이 필요하다. 전처리 과정에는 정체, 추출, 불용어 등이 있다. 
전처리된 언어를 토큰화하여 작업을 진행하야한다. 토큰화는 단어를 의미를 갖는 최소단위로 쪼개는 작업이라고 보면 된다. 토큰화를 진행한 후 embedding을 진행해주어 문자를 숫자로 바꿔 학습할 수 있게 바꿔준다.</p>
<p>전체 적인 과정을 요약하면 다음과 같다</p>
<ul>
<li>load data</li>
<li>data preprocessing
data cleaning
data tokenization
make vocabulary
data embedding
data padding</li>
<li>data loader</li>
<li>model design</li>
</ul>
<p>text data를 처리해야하기 때문에 data preprocessing과정이 복잡해졌다. text 처리 방식에 익숙해진다면 다른 전처리과정과 똑같이 느껴질 것으로 생각된다.</p>
<p>data cleaning 과정에서는 앞 뒤 공백을 제거해주고, 불필요한 값들을 제거해준다.</p>
<p>vocabulary는 중복을 제거한 어휘와 index가 정의된 집합이다. 어휘집을 통해 문자를 숫자로 변환할 수 있다.<img src="https://velog.velcdn.com/images/cheol2_y/post/e9a9234b-489b-41ce-b28f-c5f37a9e5131/image.png" alt=""></p>
<p>dataset의 shape은 2차원이고 (데이터의 량, 가장 큰 token의 갯수) 이다. token의 갯수는 데이터마다 다르기에 가장 큰 token에 맞게 빈 token은 0이나 특정 값으로 padding을 진행한다.</p>
<p>data embedding은 text를 벡터로 변환하는 과정이다. 가장 흔히 사용되는 것은 word2vec이다.</p>
<p>모델 설계는 conv1D를 사용한 모델을 예시로 들겠다.</p>
<pre><code>import torch

class Conv1dModel(torch.nn.Module):
    def __init__(self,vocab_size,embedding_dim=128):
        super().__init__()
        # 각 토큰(index)을 의미있는 숫자리스트(벡터)로 표현.......
        # vocab_size -&gt; 전체 토큰의 수
        # embedding_dim -&gt; 각 토큰을 표현할 수 있는 벡터의 크기
        self.emb_layer = torch.nn.Embedding(vocab_size, embedding_dim)

        self.seq = torch.nn.Sequential(
            # CNN 1D
            torch.nn.Conv1d(in_channels=embedding_dim, out_channels=embedding_dim*2, kernel_size=3),
            torch.nn.ReLU(),
            torch.nn.MaxPool1d(2),
            torch.nn.Conv1d(in_channels=embedding_dim*2,out_channels=embedding_dim*4,kernel_size=3),
            torch.nn.ReLU(),
            torch.nn.MaxPool1d(2),
            torch.nn.AdaptiveAvgPool1d(1),
            # FC
            torch.nn.Flatten(),
            torch.nn.Linear(embedding_dim*4, 1)
        )

    def forward(self,x): # x (배치 크기, 문장 최대 길이)
        emb_out = self.emb_layer(x) # emb_out(배치 크기, 문장 최대 길이, 임베딩 아웃풋 크기)
        emb_out_premute = emb_out.permute(0,2,1) # emb_out_premute(배치 크기, 임베딩 아웃풋 크기, 문장 최대 길이)
        seq_out = self.seq(emb_out_premute) # seq_out(배치 크기, 1)
        return  seq_out</code></pre><p>모델에 들어가는 input의 크기는 (배치 크기, 문장 최대 길이)이고 여기서 embedding이 진행되어 1개의 차원이 추가되고 permute를 사용하여 차원의 순서를 바꿔준다. 그리고 Sequential을 거쳐 최종적으로 (배치크기, target)의 shape가 된다. 이 모델은 리뷰가 긍정적인지 부정적인지를 확인하는 모델이기 때문에 target의 값은 0과 1의 값을 갖는다.</p>
<br>

]]></description>
        </item>
        <item>
            <title><![CDATA[5주차]]></title>
            <link>https://velog.io/@cheol2_y/5%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@cheol2_y/5%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Mon, 23 Oct 2023 05:49:42 GMT</pubDate>
            <description><![CDATA[<h1 id="deep-learning">Deep Learning</h1>
<h2 id="introduction-of-deep-learning">Introduction of Deep Learning</h2>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/86912af4-7830-4323-84a8-5a833479cb15/image.png" alt=""></p>
<p>딥러닝은 머신러닝안에 있는 하나의 범주이다. AI, ML, DL 순으로 세부 집단이 정의된다. 딥러닝은 머신러닝이 처리하기 어려운 데이터, 예를 들면 비정형 데이터와 같은 것을 처리하기 위하여 만들어진 기법이다.</p>
<p>딥러닝의 진행방식을 가장 간단히 표현한 것은 아래 사진과 같다. (퍼셉트론)</p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/141908cb-1b5c-497c-b3f2-a0866f13515e/image.png" alt=""></p>
<p>여러개의 input data(x)를 각각의 해당하는 가중치(w)를 곱해주고 그것들을 Sum한다. 여기서 bias를 더해주고 활성화 함수에 넣어주어 output(y)를 구한다. 이곳이 가장 간단한 딥러닝 모델이고 여기에 여러가지 기법과 손실함수(Loss Function)와 다양한 활성화 함수를 적용시켜 세분화한다.</p>
<p>input layer -&gt; hidden layer -&gt; output layer</p>
<h3 id="activation-function-활성화-함수">Activation Function (활성화 함수)</h3>
<p>활성화 함수는 hidden layer를 활성화하기 위하여 필요한 함수이다. 그냥 수치로만 되어있는 입력값을 함수에 넣어 데이터를 가공시켜준다고 생각하면 될 것 같다. 뒤에서 나오겠지만 활성화 함수를 어떤 것을 사용하는 지에 따라서 Gradient Vanishing이 발생할 수 있다. 요즘 가장 많이 사용하는 것은 ReLU이다. </p>
<h3 id="loss-function-손실-함수">Loss Function (손실 함수)</h3>
<p>손실함수는 예측값과 실제값의 차이를 어떻게 계산할지를 정의하는 함수이다. Loss Function은 어떤 기능을 하는 모델을 구현할 지에 따라서 다양한 손실함수가 존재한다.</p>
<h3 id="gradient-descent-경사-하강법">Gradient Descent (경사 하강법)</h3>
<p>손실함수로 구한 Loss값을 통하여 새로운 weight와 bias를 만들어 loss를 줄여가는 방법이다. 여기서 Learning rate를 어떻게 설정하냐에 따라서 어느 지점을 loss 최솟값을 만드는 weight와 bias로 정의할지가 정해진다. 학습율이 너무 작을 때는 local minimum에서 벗어나지 못하는 경우가 발생할 수 있고 학습율이 높을 경우에는 아예 minimum값을 찾지 못할 수도 있다.</p>
<h3 id="back-propagation-역전파">Back Propagation (역전파)</h3>
<p>역전파는 Loss가 계산되는 output layer에서부터 input layer로 이동해가면서 weight와 bias를 최신화해준다. Loss를 구함으로써 weight와 bias를 새로 정의해준다.</p>
<h3 id="gradient-vanishing-기울기-소실">Gradient Vanishing (기울기 소실)</h3>
<p>Gradient를 구하는 과정에서 활성화 함수를 미분하여 계산한다. 이때, 활성화 함수의 미분값이 매우 작을 경우 layer를 거쳐가면서 점점 gradient 값이 소실되어가는 것을 말한다. ReLU는 미분값이 0과 1이기 때문에 이러한 소실이 적게 발생한다. 하지만 미분이 0이되는 구간에서는 그 node를 사용할수 없게 되기떄문에 그러한 소실이 발생할 수는 있다.</p>
<h3 id="batch">Batch</h3>
<p>배치는 한번에 처리되는 집단이다. 처리할 뭉탱이라고 생각하면 된다. Batch normalization을 통해 각 batch마다 분포도의 차이를 일반화 시켜준다.</p>
<h3 id="epoch">Epoch</h3>
<p>전체 학습을 한바퀴 도는 것을 의미한다. for문으로 만들면 된다.</p>
<h3 id="optimizer">Optimizer</h3>
<p>Gradient Descent의 한 종류로 기존의 단점들을 보완하였다. 두개를 함께 쓰는게 일반적이다.</p>
<h2 id="tensor">Tensor</h2>
<p>Tensor는 다차원의 배열을 나타낸다.</p>
<h3 id="torch의-간단-함수들">torch의 간단 함수들</h3>
<ul>
<li><p>torch.tensor(a) : a를 tensor로 바꾼다.</p>
</li>
<li><p>torch.from_numpy(a) : a라는 numpy array를 tensor로 바꾼다.
하지만 여기서는 a의 값이 변하면 해당 tensor값도 변한다. (깊은 복사)</p>
</li>
<li><p>torch.ones_like(a) : a라는 tensor와 같은 shape을 갖고 원소를 1로 갖는 tensor를 만듦</p>
</li>
<li><p>torch.rand_like(a) : 위와 같은데 0~1의 랜덤한 원소를 갖음</p>
</li>
<li><p>torch.rand(shape) : shape에 맞는 0~1의 랜덤한 원소를 갖는 tensor</p>
</li>
<li><p>torch.randn(shape) : 정규분포 -1 ~ 1로 반환</p>
</li>
<li><p>torch.ones(shape) , torch.zeros(shape), torch.empty(shape) 위와 같음</p>
</li>
<li><p>torch.cat((a,b),dim = 1) : a랑 b를 합친다, dim은 axis라 보면 될듯</p>
</li>
<li><p>torch.mm(a,b) : a와 b의 행렬곱을 진행한다. 크기가 맞아야 곱샘가능</p>
</li>
<li><p>torch.matmul(a,b) : a와 b의 행렬곱을 진행하는데, 크기가 맞지 않으면 broadcasting 해준다.</p>
</li>
<li><p>broadcasting : 이것은 크기를 맞춰준다는게 아니라 차원은 맞는 상황에서 부족한 부분이 생긴다면 그 부분을 채워주는 것이다. 확장개념</p>
</li>
<li><p>torch.mul(a,b) : 크기가 맞지 않으면 a에 맞춰서 b의 형태를 바꿔준다.</p>
</li>
<li><p>torch.bmm(a,b) : a와 b는 (x,y,z) 형태를 가지고 있다고 하면 x는 batch를 의미한다. 따라서 torch.bmm(a,b)는 batch x는 그대로 두고 y,z에 대해여 행렬곱을 진행한다. a @ b로도 표현 가능</p>
</li>
<li><p>.item() : 형변환해준다. tensor에서 python으로 형변환</p>
</li>
<li><p>X.add_(a) : 앞에 변수(X)에 a를 더하고 변수를 대체한다. (inplace =True)</p>
</li>
<li><p>X.reshape(a,b) : X의 모양을 a * b의 크기로 바꾼다. a,b중 -1로 설정할 경우 나머지 인자에 의해서 결정된다. ex) X의 크기가 4x6일때 X.reshape(2,-1)이면 2x12 tensor로 변환된다. 이것은 행렬곱에서 활용하면 좋다. numpy에서도 사용가능하긴함.
view함수에 관해서는 메모리가 절약된다고는 하는데 자세한 사항은 필요할때 알아보자.</p>
</li>
<li><p>X.permute(a,b,c) : .transpose()의 확장판으로 3개 이상의 차원을 한번에 변경할 수 있다. 지금같은 경우에서 3차원에서 변경하는 것이기때문에, a,b,c는 0,1,2 정수중 하나의 값을 갖는다.</p>
</li>
<li><p>X.squeeze() : 차원의 값이 1이면 삭제한다. 인자로 dim = n이 오면 n차원의 값이 1이면 삭제한다.</p>
</li>
<li><p>X.unsqueeze(dim=n) : n번째 차원을 1으로 생성한다.</p>
</li>
</ul>
<h2 id="dataset">Dataset</h2>
<h3 id="dataloader">Dataloader</h3>
<p>DataLoader는 test data를 batch size로 나누는 클래스이다. &amp;nbsp
test_dataloader = DataLoader(test_data, batch_size=64, shuffle =True)
↑ 인스턴스 &amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp ↑ 클래스</p>
<p>image의 shape는 ex) (1,28,28)이면 1은 color를 나타내고 28은 높이와 너비이다.</p>
<ul>
<li><p>next(iter(test_dataloader)) : 다음 batch data를 가져온다.</p>
</li>
<li><p>nn.flatten() : dim으로 이루어진 것을 tensor로 바꾼다.( 1자로 쭉 늘린다는 뜻 )</p>
</li>
<li><p>nn.sequential() : 괄호에 들어가는 것을 순서대로 실행시킨다.</p>
</li>
<li><p>nn.linear(x,y) : input의 size는 x, output의 사이즈는 y로 간다. x와 y는 tensor이기에 flatten 되어 있다고 보면 된다. 내부 계산은 y=xA+b 이다.</p>
</li>
<li><p>nn.ReLU() : ReLU활성화 함수를 진행한다.</p>
</li>
<li><p>nn.Softmax(dim= a)(b) : a에는 보통 1이 들어간다 dim=0은 batch size가 할당되었기 때문에 dim =1에서 진행된다. b는 softmax에 들어갈 값이다. 출력 값은 0~1까지의 확률값이다.</p>
</li>
<li><p>x.detach() : 학습이나 연산부분에서 떼어낸다는 뜻이다. 즉 모델과 상관없어진다.</p>
</li>
</ul>
<h3 id="loss-function">Loss Function</h3>
<p>어떤 역할을 수행하는 모델이냐에 따라서 사용되는 Loss function이 다르다</p>
<p>회귀 모델에서는 MSELoss가 사용되고 L1Loss가 주로 사용된다.
이진분류에서는 BCELoss와 BCEWithLogitsLoss가 사용된다.
다중분류에서는 CrossEntropyLoss가 사용된다.
이것보다 더 다양한 함수가 사용될 수 있으니 찾아보기.</p>
<p>Training loop
<img src="https://velog.velcdn.com/images/cheol2_y/post/58ab1ccb-f380-46c3-bcd2-8609a52bed3d/image.png" alt=""></p>
<p>Test loop
<img src="https://velog.velcdn.com/images/cheol2_y/post/d64f6f7b-b6df-4169-bca0-ea0ed7da7ba5/image.png" alt=""></p>
<p>with torch.inference_mode()
with torch.no_grad()
위 두개는 인스턴스(모델)의 파라미터(weight, bias etc..)를 고정한 모드로 설정한다. 평가할 때는 위에 범위 안에서 작동해야한다.</p>
<p>model save와 load하는법이 있다.
torch.save(obj=model_0.state_dict(), f=MODEL_SAVE_PATH)</p>
<p>loaded_model_0 = LinearRegressionModel()    #인스턴스 생성
loaded_model_0.load_state_dict(torch.load(f=MODEL_SAVE_PATH</p>
<h2 id="모델을-향상시키는-방법">모델을 향상시키는 방법</h2>
<ul>
<li>Layer를 증가시킨다.</li>
<li>Hidden unit을 추가한다.</li>
<li>Epoch를 증가시킨다.</li>
<li>Activation function을 바꿔본다</li>
<li>Loss function을 바꿔본다.</li>
<li>Learning rate를 변경시킨다.</li>
</ul>
<h2 id="modular">Modular</h2>
<ul>
<li>data_setup.py : data를 준비하고 전처리 하는 파일</li>
<li>engine.py : 사용되는 training function들을 저장</li>
<li>model_builder.py : model을 만드는 파일</li>
<li>train.py : 다른 파일들을 모두 사용하고 학습을 진행하는 파일</li>
<li>utils.py : 유용한 utility function들의 파일</li>
</ul>
<h2 id="image-processing">Image Processing</h2>
<p>이미지를 가공하여 학습에 용이한 data로 바꾸는 과정을 말한다.
Gaussian processing, padding, resizing 등이 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Tintanic 생존 예측 ML]]></title>
            <link>https://velog.io/@cheol2_y/Tintanic-%EC%83%9D%EC%A1%B4-%EC%98%88%EC%B8%A1-ML</link>
            <guid>https://velog.io/@cheol2_y/Tintanic-%EC%83%9D%EC%A1%B4-%EC%98%88%EC%B8%A1-ML</guid>
            <pubDate>Fri, 20 Oct 2023 06:58:55 GMT</pubDate>
            <description><![CDATA[<h1 id="nbspnbspnbspnbspnbspnbspnbspnbspnbspnbspnbspnbspnbspnbspnbspnbsptintanic-ml-report-">&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsp*<em>Tintanic ML Report *</em></h1>
<p>데이터 엔지니어링 28기 
<br></p>
<p>결과
<img src="https://velog.velcdn.com/images/cheol2_y/post/be4b70f7-1db1-4cad-a129-7fc33b6e18e6/image.png" alt=""></p>
<br>
RFC의 Test 결과 confusion matrix

<p><img src="https://velog.velcdn.com/images/cheol2_y/post/b13b792f-0404-4ef3-8abb-b504445c3e4a/image.png" alt=""></p>
<br>
RFC의 Test 결과 confusion matrix

<p> <img src="https://velog.velcdn.com/images/cheol2_y/post/4bdfe830-8105-4c6d-8372-bd3ff118721d/image.png" alt=""></p>
 <br>
 RFC의 Feature importance

<p> <img src="https://velog.velcdn.com/images/cheol2_y/post/1b190546-5a79-44db-85c1-dfa9cb382149/image.png" alt="">
<BR></p>
<p>Cat의 Feature importance
<img src="https://velog.velcdn.com/images/cheol2_y/post/e0a5b4e3-7416-402a-958f-b4414e7798e9/image.png" alt=""></p>
<p>점수를 올리기위한 노력부터 적어보려 한다. </p>
<h1 id="feature-분석-및-추가">Feature 분석 및 추가</h1>
<p>&amp;nbsp모델이 학습을 잘 시키기 위해서는 좋은 Feature를 분석하고 새로운 Feature 를 추가하는 것이 정말 중요하다. 처음 EDA를 진행했을 때, 생존과 연관이 높은 Feature 2개를 발견하였다. 그것은 gender Pclass였다. 여자의 평균 생존율이 남자에 비하여 상당히 높게 나왔다. 그리고 Pclass에서도 1등석에 탄 승객이 2, 3등석에 탄 승객보다 생존율이 높게 나왔다. 이것은 궁금하여 조금 더 찾아보니 타이타닉호의 설계도에서 1등석은 위쪽에 위치하여 있었고, 3등석은 배 아래 부분에 위치하고 있었다. 다음으로 확인된 것은 age와 fare인데, 이것은 특정 구간에서 생존율이 다른 구간에 비하여 높게 측정된 구간이 몇 개 존재하였다. 그래서 그 구간을 따로 뽑아내고 특정성이 없는 구간은 others로 분류하였다. 이렇게 하나의 Feature에서 특정성을 확인하여 새로운 Feature를 만들어 낼 수도 있지만, 두개의 Feature를 하나로 합쳐 또 다른 Feature를 만들어 낼 수 있었다. 내가 만들어 낸 것 중 하나는 Pclass_gender로 Pclass 3가지와 성별 2가지를 합쳐 특정성이 있는 부분을 찾아내어 새로운 Feature를 만들었다. 특정성이 크지 않은 구간은 마찬가지로 others로 묶어 뒀다. </p>
<p> &amp;nbsp 처음 EDA를 진행했을 때 확인했던 것처럼 gender Pclass가 높은 생존과 직결되는 지표였다. 하지만 모델을 학습 시키고 결과를 확인했을 때, gender Pclass의 중요도가 높게 측정되지 않았었다. 이것을 해결하기 위하여 모델의 Feature별 Weight를 각기 다르게 넣어주어 학습을 진행시키려 했지만, 이 부분에서는 아직 숙련도가 부족하여 진행하지 못하였다. 이것을 해결하기 위하여 이 두 Feature들과 연관된 다른 Feature를 추가로 만들어 주었다. 그 결과  Pclass의 중요도는 크게 증가하지 않았지만, gender 관련된 Feature들은 상당히 증가한 것을 확인할 수 있었다. </p>
<p> 코드
 name으로 만든 feature</p>
<pre><code># designation feature를 추가할시 해야할것:
# 위에 feature drop에서 name 지우기, enc cols에 desigantion 추가하기
# 종류가 다양하지만 Mr. Mrs. Miss. 3가지로만 분류했다.


train[&quot;name&quot;] = train[&quot;name&quot;].map(lambda x: x.strip())
test[&quot;name&quot;] = test[&quot;name&quot;].map(lambda x: x.strip())
ori_te[&quot;name&quot;] = ori_te[&quot;name&quot;].map(lambda x: x.strip())

dict_designation = {
    &#39;Mr.&#39;: &#39;남성&#39;,
    &#39;Master.&#39;: &#39;남성&#39;,    #남
    &#39;Sir.&#39;: &#39;남성&#39;,       #남
    &#39;Miss.&#39;: &#39;미혼 여성&#39;,
    &#39;Mrs.&#39;: &#39;기혼 여성&#39;,    
    &#39;Ms.&#39;: &#39;미혼/기혼 여성&#39;,#여 Miss
    &#39;Lady.&#39;: &#39;숙녀&#39;,  #여   Miss
    &#39;Mlle.&#39;: &#39;아가씨&#39;,#여   Miss
    # 직업
    &#39;Dr.&#39;: &#39;의사&#39;,    #남 시대상.
    &#39;Rev.&#39;: &#39;목사&#39;,   #남
    &#39;Major.&#39;: &#39;계급&#39;, #남
    &#39;Don.&#39;: &#39;교수&#39;,   #남
    &#39;Col.&#39;: &#39;군인&#39;,   #남
    &#39;Capt.&#39;: &#39;군인&#39;,  #남 
    # 귀족
    &#39;Mme.&#39;: &#39;영부인&#39;, #여   Mrs.
    &#39;Countess.&#39;: &#39;백작부인&#39;,    #여 Mrs.
    &#39;Jonkheer.&#39;: &#39;귀족&#39;         #남
}

Mr = [&#39;Mr.&#39;,&#39;Master.&#39;, &#39;Sir.&#39;, &#39;Dr.&#39;, &#39;Rev.&#39; ,&#39;Major.&#39;,  &#39;Don.&#39; , &#39;Col.&#39; , &#39;Capt.&#39;]
Miss = [&#39;Miss.&#39;, &#39;Ms.&#39;, &#39;Lady.&#39;, &#39;Mlle.&#39;]
Mrs = [&#39;Mrs.&#39;, &#39;Mme.&#39;,&#39;Countess.&#39;, &#39;Jonkheer.&#39; ]
#위의 호칭중 없는것이 있다면 Miss으로 대체

#호칭함수
def add_designation(name): 
  designation = &quot;Miss.&quot;
  for i in Mr:
    if i in name:
      designation = &#39;Mr.&#39;
      break
  for j in Miss:
    if j in name:
      designation = &#39;Miss.&#39;
      break
  for k in Mrs:
    if k in name:
      designation = &#39;Mrs.&#39;
      break
  return designation


train[&#39;designation&#39;] = train[&#39;name&#39;].map(lambda x: add_designation(x))
test[&#39;designation&#39;] = test[&#39;name&#39;].map(lambda x: add_designation(x))
ori_te[&#39;designation&#39;] = ori_te[&#39;name&#39;].map(lambda x: add_designation(x))

train.drop(&#39;name&#39;, axis=1, inplace=True)
test.drop(&#39;name&#39;, axis=1, inplace=True)
ori_te.drop(&#39;name&#39;, axis=1, inplace=True)</code></pre><p>pclass와 gender로 만든 feature</p>
<pre><code> #특정성이 없는 구간은 others로 설정하였다.
def make_pclass_gender(p,g):
    p_g=&#39;&#39;
    if p ==1:
        if g ==&#39;female&#39;:
            p_g= 1
        else:
            p_g=5
    elif p ==2:
        if g ==&#39;female&#39;:
            p_g= 2
        else:
            p_g=4
    else:
        if g ==&#39;female&#39;:
            p_g=5
        else:
            p_g=5
    return p_g

train[&#39;pclass_gender&#39;]= train.apply( lambda x : make_pclass_gender(x[&#39;pclass&#39;], x[&#39;gender&#39;]), axis =1 )
test[&#39;pclass_gender&#39;]= test.apply( lambda x : make_pclass_gender(x[&#39;pclass&#39;], x[&#39;gender&#39;]), axis =1 )
ori_te[&#39;pclass_gender&#39;]= ori_te.apply( lambda x : make_pclass_gender(x[&#39;pclass&#39;], x[&#39;gender&#39;]), axis =1 )

train[&#39;family&#39;]=train.apply(lambda x : x[&#39;sibsp&#39;] + x[&#39;parch&#39;],axis = 1)
test[&#39;family&#39;]=test.apply(lambda x : x[&#39;sibsp&#39;] + x[&#39;parch&#39;],axis = 1)
ori_te[&#39;family&#39;]=ori_te.apply(lambda x : x[&#39;sibsp&#39;] + x[&#39;parch&#39;],axis = 1)</code></pre><p>특정성이 있는 나이와 성별로 분류한 Feature</p>
<pre><code>def add_infant(age):
    result = 0
    try:
        if age &lt;= 4:
            result = 1
    except:
        pass
    return result

train[&#39;infant&#39;] = train[&#39;age&#39;].map(lambda x: add_infant(x))
test[&#39;infant&#39;] = test[&#39;age&#39;].map(lambda x: add_infant(x))
ori_te[&#39;infant&#39;] = ori_te[&#39;age&#39;].map(lambda x: add_infant(x))


train.shape, test.shape, ori_te.shape     

train[&#39;gender_infant&#39;] = train.apply(lambda row: row[&#39;gender&#39;]+&#39;_&#39;+str(row[&#39;infant&#39;]), axis=1)
test[&#39;gender_infant&#39;] = test.apply(lambda row: row[&#39;gender&#39;]+&#39;_&#39;+str(row[&#39;infant&#39;]), axis=1)
ori_te[&#39;gender_infant&#39;] = ori_te.apply(lambda row: row[&#39;gender&#39;]+&#39;_&#39;+str(row[&#39;infant&#39;]), axis=1)

train.drop([&#39;infant&#39;],axis=1, inplace=True)
test.drop([&#39;infant&#39;],axis=1, inplace=True)
ori_te.drop([&#39;infant&#39;],axis=1, inplace=True)</code></pre><h1 id="test-size를-변경해가며-스코어-확인하기">Test size를 변경해가며 스코어 확인하기</h1>
<p>&amp;nbsp 이번 Kaggle에서 사용된 데이터의 수는 900개 정도로 매우 작은 수의 데이터이다. 그렇기에 처음에 주어진 0.3으로 데이터를 학습시킬경우 학습하는 데이터양이 부족할 수 있기 떄문에 최적의 Test size를 확인하는 과정을 거쳤다. Manual Search를 통하여 확인하였다. Grid search를 사용하여 확인했을 때는 0.4의 Test size일 때 스코어가 가장 높다고 나왔는데, 이것을 믿을 수 없었기에 Manual Search 기법을 사용하였다. 코드에 대한 이해도가 부족할 때는 Manual Search기법도 좋은 방법이라고 생각되지만, 이러한 기간이 길어지면 최종적으로는 악영향을 끼칠 수 있기 때문에 코드에 대한 이해도를 높여야한다고 생각된다. 
<br>
이부분은 따로 코드를 작성하지 않겠다. 위에서 설명한대로 코드를 사용하여 확인하였을 때보다 손으로 확인하였을 때가 더 정확한 결과를 알려주기 때문이다.
최적의 Test size = 0.2</p>
<h1 id="최적의-파라미터를-찾기">최적의 파라미터를 찾기</h1>
<p>&amp;nbsp 모델의 스코어가 높게 나오기 위해선 파라미터를 튜닝하는 것도 좋은 방법이라고 생각했다. 처음에는 하나하나 손으로 바꿔가며 찾는 Manual Search 기법을 사용하였다. 반복 작업을 하는 도중 이런 걸 해결해 놓은 코드가 있지 않을까 싶어 구글링을 통해 Grid Search함수를 찾아 활용하였다. 이전에는 CPU만을 사용해도 실행되는 시간이 그렇게 길지 않았지만, 반복을 통해 파라미터를 찾기 때문에 코드가 무거워졌다. 마지막으로 알게된 Randomized Search는 Grid Search를 알게되고 사용한지 하루가 지난 날 수업에서 진행해여 더 좋은 파라미터 튜닝 방법을 알게 되었다. 이제는 이것을 통해 최적의 파라미터를 찾아내고 그것을 다시 모델에 넣어 Cross Validation을 진행하여 학습의 효율을 더 증가시켰다. </p>
<h1 id="예측이-틀린-것을-eda">예측이 틀린 것을 EDA</h1>
<p>&amp;nbsp Data의 전처리를 충분히 진행했고, 모델링 또한 어느정도 완성되었다고 생각된 후에 진행한 분석이다. 예측결과중 실제값과 틀린 부분들을 분석하였다. 우선 FP보다 FN이 높게 측정되었기 때문에 파라미터 튜닝 과정에서 평가로 사용된 Score를 roc_auc에서 recall으로 변경하였다. FN은 Precision과 연관된 값이기에 Precision의 값을 높일수 있게끔 Recall을 기준으로 튜닝을 진행했었다. 또한 예측결과중 틀린 값들만 모아서 EDA를 진행했다. FP 부분에서는 age는 20<del>30, 3등석에 1명 이하의 관련자(친인척)과 탑승한 여자 승객을 잘못 예측하였다. 이 부분은 새로운 Feature 추가해주었다. 마찬가지로 FN에서도 EDA를 진행하여 확인해본 결과, 2명 이하의 관련자와 탑승한 20</del>40세의 남성 승객이 많이 확인되었다. 이 부분도 새로운 Feature를 추가해주었다.</p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/4c450f26-636a-4c67-a96f-7e94fcdb39a7/image.png" alt=""></p>
<h1 id="모델링">모델링</h1>
<p>&amp;nbsp 사용한 모델은 RandomForestClassifeir, XGClassifier, CatboostClassifier, lgbmclassifier 총 4가지이다. RFC는 경진대회가 시작된 첫날부터 사용한 모델이기에 긴 분석 시간이 주어지기도 했고, 학습 결과 또한 잘 나왔다. 다른 3개의 학습 모델은 주어진 시간이 부족하여 숙달하는데 어려움이 있었다. 학습 결과가 가장 잘나오는 모델은 RFC와 Catboost 두가지였다. 결과적으로 가장 높은 점수가 나온 것은 RFC였다. 이번 대회 기간에서 모델이 어떤 방식으로 학습을 하는 지 분석은 하지 못하고 사용을 했지만, 이 학습 모델들이 좋은 것은 알겠다. </p>
<h1 id="개선점">개선점</h1>
<p>&amp;nbsp 대회에 사용한 모델에 대하여 조금 더 공부를 해야겠다고 생가되었고, 마지막 날 수업했던 내용을 아직 정리하지 못하여 지식이 부족하다. 또한 모델에서 클래스별 가중치를 부여하는 방법에 대하여 공부해보고 싶다는 생각이 들었다. 마지막으로 다음에 ML을 해야하는 상황이 있다면 catboost나 lgbm를 사용할 생각이다. 이 두가지 모델에 data를 encoding하지않고 바로 집어넣는 방법에 대하여 알아보면 좋을 것이라 생각된다.</p>
<p>중요도가 높은 feature를 잘 활용하였고, 조금 원리적인 부분에 대한 학습을 하면 좋을 것이라고 생각된다.</p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/db79fadf-3c09-450a-a2cf-ac06e733d035/image.png" alt=""></p>
<p>  오버피팅이 하나도 발생하지 않은 모델을 확인했으나, 따로 저장해두지 않아서 찾을수가 없었다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[4주차]]></title>
            <link>https://velog.io/@cheol2_y/4%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@cheol2_y/4%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Mon, 16 Oct 2023 03:01:09 GMT</pubDate>
            <description><![CDATA[<h1 id="11일차">11일차</h1>
<h2 id="타이타닉-생존률-경진대회">타이타닉 생존률 경진대회</h2>
<h3 id="eda">EDA</h3>
<p>데이터를 분석하여 어떤 feature가 결과의 영향을 크게 주는 지 확인한다. 또한, 새로운 feature를 만들어 데이터의 량을 증가시킨다.</p>
<h2 id="scaling">Scaling</h2>
<p>수치형 데이터는 Feature별로 숫자 값의 범위가 모두 다르기에 학습할 때 잘못 학습할 염려가 있다. 그렇기에 값의 범위를 feauture내에서 처리하여 값을 반환하여 이러한 문제를 해결할 수 있다. 이것을 Scaling이라고 한다.</p>
<p>Scaling을 할 때도 주의해야할 것은 test 데이터를 scaling할 때 train 데이터로 학습시키고 적용시켜야 한다. train데이터에는 fit_transform을 해주고 test에는 transfrom만 적용시키면 된다.</p>
<h3 id="scaling-종류">Scaling 종류</h3>
<p>Normalizer
PowerTransformer
QuantileTransformer
StandardScaler
RobustScaler
MinMaxScaler
MaxAbsScaler</p>
<p>Transformer와 Scaler를 동시에 사용해야 할 때는 Transformer를 먼저 사용한 후에 Scaler를 적용해야 데이터의 손상이 거의 없다.</p>
<p>Scaling을 하면 정확도가 높아지지만 모든 상황에서 좋아지는 건 아니다.</p>
<p>가장 많이 사용하는 Scaler는 StandardScaler와 MinMaxScaler이다. StandardScaler는 이상치가 클 때 좋게 작용하지 않을 때가 있다.
<br>
<br></p>
<p>4주차의 정리사항은 Titanic ML 정리글로 대체하겠습니다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2주차]]></title>
            <link>https://velog.io/@cheol2_y/2%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@cheol2_y/2%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Wed, 11 Oct 2023 00:56:35 GMT</pubDate>
            <description><![CDATA[<h1 id="4일차">4일차</h1>
<p>함수</p>
<pre><code>def 함수명(입력변수):
    수행할 프로그램1
    수행할 프로그램2
    ...
    return 출력변수
</code></pre><p>입력변수는 여러개일 수 있다.
출력변수는 변수로 출력되는 것이 아니라 값으로 출력된다.
함수 내부에서 선언된 변수들은 함수 외부에서는 정의되지 않은 것으로 간주된다.
지역 변수: 함수 내부에서 선언된 변수    (local)
전역 변수: 함수 외부에서 선언된 변수    (global)</p>
<p>입력변수 칸에 ex)a=3, b=2라고 적어두면 입력변수를 넣지 않는다면 입력변수를 a=3,b=2가 들어간다고 보면 된다.</p>
<pre><code>def add(*args):
    print(sum(args))</code></pre><p>args는 가변 파라미터로 입력을 임의의 개를 받을 수 있게해준다.</p>
<p>**kwargs는 딕셔너리 형태의 입력을 받을 수 있다.
보통 args는 리스트로 kwargs는 딕셔너리 형태라고 보면 된다.</p>
<p>1회용 람다함수 lambda <img src="https://velog.velcdn.com/images/cheol2_y/post/6a94d993-0262-4d2d-bcf1-b1572b36eb3b/image.png" alt=""></p>
<p>콜백함수</p>
<pre><code>def call_func(a,func):
    return func(a)</code></pre><p>입력변수로 함수가 올 수 있다.</p>
<p>isinstance(입력값,type형태)
ex) isinstance(130,int) -&gt; 결과: True</p>
<h1 id="5일차">5일차</h1>
<h2 id="class">Class</h2>
<p>클래스는 설계도와 같다고 볼 수 있다. 이 설계도를 사용하여 인스턴스를 생성한다고 생각하자.</p>
<pre><code>class class이름 :
    속성(attribute,클래스 내부 변수)=state(속성의 값)

    def 함수명(self):        (이걸 method라고 함, 클래스 내부 함수)
        실행할 것</code></pre><p>method의 인자(parameter)는 여러개 올 수 있는데 self가 제일 먼저 써져야한다.</p>
<p>attribute를 호출하려면 class이름.속성명 을 하면 된다. 호출 되는 값은 속성의 값인 state이다.
method는 이 방식으로 호출할 수 없다.
class 이름을 Class, method명을 print_self하고 새로운 변수를 x라고 예를 들어 보자.
Class.print_self()  는 오류가 발생하고</p>
<p>x=Class()
x.print_self()  는 실행이 된다.
<br></p>
<pre><code>def __init__(self,name,age):
    self.name=name
    self.age=age
    self.home=&#39;seoul&#39;</code></pre><p>class내부에 존재하는 method인 init은 생성함수라고 한다. 이걸 만들지 않으면 class를 만들 때 python이 자동으로 생성해준다. return값을 만들어주면 오류가 발생하므로 넣어주면 안된다.
<br></p>
<p>상속(inheritance)</p>
<p>부모 class의 정보들을 자식 class에게 상속시켜준다. 두 class 모두에서 같은 attribute가 있다면 자식 class에 있는 attribute의 state값을 갖는다. 이렇게 수정하는 것을 override라고 한다. 만약 자식의 자식class, 즉 손자 class가 있다면 부모와 자식 class의 정보 모두를 받는다.</p>
<p>public과 private method 설정법
method 이름 앞에 __ 을 넣어주면 private해진다.
private해졌다면 객체 외부에서 호출이 불가능해진다. 이걸 굳이 사용할 필요는 없을 것 같다고 생각된다.</p>
<p>magic method
파이썬의 내장함수인데, class를 선언할때 추가해주면 불러온 함수의 특성을 사용할 수 있다. init도 magic method이다.</p>
<pre><code>def __call__(self):
    실행할것들</code></pre><p>클래스 안에 call magic method가 있을 때 클래스이름.함수()가 아닌 그냥 인스턴스이름()만 해도 call 함수가 실행된다.</p>
<p>class 안에 있는 method(def 함수)는 method 밖에 있고 class 안에 있는 attribute는 서로 공유가 된다. 그 이유는 method에서 인자로 self를 항상 쓰기때문에 self에 의해서 공유가된다.</p>
<h1 id="6일차">6일차</h1>
<p>5일차까지 python에 대하여 공부를 했고, 이제 머신러닝쪽을 배워보려고 한다.</p>
<p>Feature
: input data, 학습용 데이터, 독립변수</p>
<p>Label, Target, Class
: 결과 값, 예측된 값 종속변수</p>
<p>Parameter
: 모델이 학습과정에서 업데이트하는 파라미터</p>
<p>Hyper parameter
: 사용자가 직접 세팅해주는 파라미터</p>
<p>Loss
: 정답값과 예측값의 오차</p>
<p>Metric
: 평가할때 사용되는 지표</p>
<p>머신러닝은 대부분 코랩에서 scikit learn을 사용될 예정이다.</p>
<p>axis=1은 col이다. 0이면 row이다.</p>
<p>train, test, target</p>
<p>numpy</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[3주차]]></title>
            <link>https://velog.io/@cheol2_y/3%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@cheol2_y/3%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Tue, 10 Oct 2023 10:10:40 GMT</pubDate>
            <description><![CDATA[<h1 id="7일차">7일차</h1>
<h2 id="python-마무리-pandas-numpy-입문">Python 마무리, pandas, numpy 입문</h2>
<h3 id="python-마무리">Python 마무리</h3>
<h4 id="가상환경-만들기">가상환경 만들기</h4>
<p>py 3.11 -m venv .venv
python -m pip install --upgrade pip
pip install jupyter numpy pandas
pip list</p>
<h4 id="함수-만들기">함수 만들기</h4>
<p>간단한 절댓값 만드는 함수 만들어보기</p>
<pre><code>def fnc_abs(lst:list) -&gt; list:
    result_lst=[]
    for i in lst:
        if i &gt;= 0 :
            result_lst.append(i)
        else:
            result_lst.append(i*-1)
    return result_lst

a=[1,-3,2,4,-4,-6,-7]
fnc_abs(a)</code></pre><br>

<h2 id="pandas-입문">pandas 입문</h2>
<pre><code>s=pd.Series(data= np.random.randn(5), index=[&#39;a&#39;,&#39;b&#39;,&#39;c&#39;,&#39;d&#39;,&#39;e&#39;])
s
s[(s&lt;0.21) &amp; (-2.0&lt;s)]  # 0.21 보다 작고, -2.0보다 큰 숫자만 뽑기</code></pre><p>.min()
.max()
.mean()
.describe()
조건에 not을 붙이려면 앞에 ~ 하면된다. (ex. iris[~cond] )</p>
<h3 id="df--pddataframe값-index행-columns열">df = pd.DataFrame(값, index=행, columns=열)</h3>
<h3 id="iloc와-loc">iloc와 loc</h3>
<h4 id="dfilocab">df.iloc[a,b]</h4>
<p>위치정보로 정보를 가져온다. (숫자를 넣어 사용)
a행 b열의 정보를 가져온다.
b가 공백일경우 모든 열의 정보를 가져온다.
<br></p>
<h4 id="dfloc">df.loc[]</h4>
<p>위치정보가 아닌 진짜 이름을 이용하여 가져온다. (숫자도 사용하지만 진짜 이름을 사용)
<br></p>
<h4 id="df--칼럼이름--하나의-열만-인덱싱">df [ &#39;칼럼이름&#39; ] 하나의 열만 인덱싱</h4>
<h4 id="df---칼럼이름---하나의-열만-인덱싱-하는데-데이터프레임모양으로-출력">df [ [ &#39;칼럼이름&#39; ] ] 하나의 열만 인덱싱 하는데 데이터프레임모양으로 출력</h4>
<br>

<h4 id="dfisnullsum-컬럼별-널-확인">df.isnull().sum(): 컬럼별 널 확인</h4>
<br>

<h4 id="dfinfo-전체-수-null이-있는-컬럼-데이터-타입-등을-알-수-있음">df.info(): 전체 수, null이 있는 컬럼, 데이터 타입 등을 알 수 있음</h4>
<br>

<h4 id="df_number--dfselect_dtypesincludenpnumber">df_number = df.select_dtypes(include=np.number)</h4>
<br>

<h4 id="df_objectwhovalue_counts">df_object[&#39;who&#39;].value_counts()</h4>
<br>

<h4 id="xmapy">x.map(y)</h4>
<p>맵은 도킹하는 걸 의미하는듯 x의 value값과 y의 index값이 같을때 두개를 합쳐줌
x의 value값을 바꾸는 것이기때문에 이것을 활용하여 value의 값들을 바꿀 수 있다. 
ex) df[&#39;성별&#39;].map({&#39;male&#39;:0, &#39;female&#39;:1})
참고: wikidocs
<br></p>
<p>df.apply(lambda x:x.sum(), axis=1)
axis=0은 column에 대하여 진행하라는 뜻 default는 axis=0이다.
행끼리 연산을 원할경우 axis=1으로 두면된다.
<br></p>
<h4 id="pivot_table">pivot_table</h4>
<p>pd.pivot_table(df, index=&#39;b&#39;, columns=&#39;c&#39;,values=&#39;d&#39;,aggfunc=&#39;e&#39;)
df라는 DataFrame을 index에는 &#39;b&#39;열의 값을, columns에는 &#39;c&#39;열의 값을 가져오고 index의 값은 &#39;d&#39;에서 가져오는데 가져올때 값들을 어떤 형태로 가져올지 정하는게 &#39;e&#39;이다. &#39;e&#39;에는 min, meanm, max 등이 올 수 있다.
<br></p>
<h4 id="groupby">groupby</h4>
<p>df.groupby([&#39;열이름&#39;])
해당 열의 인덱스 값들로 그룹화한다. 분석하기 용이하게 해준다. 
<br></p>
<h4 id="agg">agg</h4>
<p>df[&#39;열이름&#39;].agg(함수)
해당 column값을 함수로 계산하여 통계낸다. 함수에는 &#39;mean&#39;, &#39;sum&#39;, lambda와 같은 것들이 올 수 있다.
<br></p>
<h1 id="8일차">8일차</h1>
<h4 id="pdmergedf1df2-on-column-이름">pd.merge(df1,df2, on=[&quot; column 이름&quot;]</h4>
<p>두개의 DataFrame을 합쳐주는 함수이다. on뒤에 써주는 column에 맞춰서 합쳐진다. on 뒤에 들어간 컬럼은 df1과 df2 모두에 존재해야한다. 같은 column이름을 갖더라도 row값이 다를 수도 있는데, 그때 다른 row값을 갖는 row는 제외하고 같은 값만 갖는 row만 합쳐진다.
위 함수에 인자로 how=&#39;&#39;이 올수 있는데 &#39;&#39; 사이에 left, right, inner, outer가 올 수 있다. 합치는 기준에 대한 것인데, 간단하다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/ade89707-0f3e-43c3-aae3-a782713c28bf/image.png" alt=""></p>
<h4 id="pdconcatdf1-df2-axis1">pd.concat(df1, df2, axis=1)</h4>
<p>df1과 df2를 그냥 붙인다. concat은 index를 정리해주지 않고 그냥 가져와서 냅다 붙여버리기 때문에 주의해야한다. 재정의를 해주지 않는다.</p>
<h3 id="matplotlib">matplotlib</h3>
<p>그래프를 그려주는 모듈
x축은 인덱스 y축은 column 값이라고 볼 수 있다.</p>
<h4 id="pltplot그릴거">plt.plot(그릴거)</h4>
<p>그릴거를 괄호안에 넣는다.</p>
<h4 id="pltshow">plt.show()</h4>
<p>도화지 켜기</p>
<h4 id="pltsubplot221">plt.subplot(2,2,1)</h4>
<p>도화지를 분할하여 사용하기</p>
<h4 id="fig-ax--pltsubplots22figsize155">fig, ax = plt.subplots(2,2,figsize=[15,5])</h4>
<p>도화지 분할하는 다른 방법, (2,2)로 나눠서 총 4개를 사용가능
ax[0].plot(x,y)
ax를 사용해서 0~3까지 사용가능</p>
<h4 id="figsuptitlefigure-title">fig.suptitle(&quot;figure title&quot;)</h4>
<p>도화지의 제목을 설정한다.</p>
<h4 id="set_xlabel">.set_xlabel(&#39;&#39;)</h4>
<p>x축 이름을 설정한다.</p>
<h4 id="tick_paramsaxisx-labelrotation90">.tick_params(axis=&quot;x&quot;, labelrotation=90)</h4>
<p>눈금 설정</p>
<h4 id="ax01plotymarkervlinestyle--colory">ax[0,1].plot(y,marker=&quot;v&quot;,linestyle=&#39;--&#39;,color=&quot;y&quot;)</h4>
<p>눈금 모양, 색깔 등 설정가능</p>
<h4 id="pltbar">plt.bar()</h4>
<p>막대모양 그래프</p>
<h4 id="pltscatter">plt.scatter()</h4>
<p>산점도 그래프</p>
<h4 id="plthist">plt.hist()</h4>
<p>히스토그램</p>
<h4 id="pltboxplot">plt.boxplot()</h4>
<p>박스 플롯
<br></p>
<h3 id="pandas-eda">Pandas EDA</h3>
<p>데이터를 분석할때, test data는 모델과 분리되어 있어야하는것이 중요하다.
분석방법으로는 상관관계를 확인하는 상관계수를 분석하는 것이 있다. 상관계수는 -1 ~ 1의 값을 갖고 음의 상관관계, 양의 상관관계, 상관관계 없음으로 세가지가 존재한다.</p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/8cbad62e-8dd7-4e3f-8e20-ca36f2dd517a/image.png" alt="">상관관계 분석표</p>
<h3 id="이상치">이상치</h3>
<p>데이터 분석을 할 때, 평균이나 표준편차를 많이 사용한다. 이런 경우 데이터에 이상치가 있으면 왜곡된 의미를 전달할 가능성이 높다. 그래서 이상치가 있는지를 확인할 필요가 있고, 박스플롯을 활용하면 이상치가 얼마나 포함되어 있는지를 쉽게 판단할 수 있다.</p>
<h1 id="9일차">9일차</h1>
<h2 id="eda-data-cleaning-feature-extraction">EDA, Data Cleaning, Feature Extraction</h2>
<h2 id="데이터의-결측치를-확인해서-관리한다">데이터의 결측치를 확인해서 관리한다.</h2>
<p>(이상치도 관리해야할까?)</p>
<h3 id="치환과-삭제로-결측치-관리">치환과 삭제로 결측치 관리</h3>
<p>df.isnull().sum().sum()하면 모든 feature의 결측치의 갯수를 알려준다
각 feature의 결측치를 index갯수로 나눠서 결측치 비율을 확인할 수 있다. 결측치 비율이 너무 높다면 해당 index는 제거하는 방향으로 가는 것이 좋다. 결측치 비율이 크게 높지 않다면 결측치를 치환하여 문제를 해결할 수 있다. 아예 결측치가 발생한 행또는 열을 제거하는 방법도 있다.결측치 비율은 50퍼정도를 기준으로 잡고 판단하는 것이 좋다고 생각한다.</p>
<p>치환할때 수치형 데이터는 전체 값의 median이나 mean을 사용하여 치환한다. 범주형 데이터는 최빈값으로 치환하는 것이 괜찮을 때가 많다. 또는 다른 feature와 연관이 있다면 그것을 활용하여 치환하는 것도 좋다.
예를 들어 age에서 결측치가 20퍼정도로 발생하였을때, 중앙값이나 평균으로 막연하게 채우는 것보단, age와 pclass 성분으로 묶고 pclass=1일떄 age의 결측값을 이떄의 평균이나 중앙값으로 치환하는 것이 좋다.</p>
<p>df.dropna(axis=0) 결측치가 발생한 행을 삭제한다.
df.fillna() 결측치를 원하는 값으로 채운다.
df.fillna( method = &#39;ffill&#39; ) 을 사용하면 결측치를 앞의 값으로 채운다.
 이것은 sort를 한 후에 사용하면 좋을 때가 있지만 맨앞과 맨뒤값은 채우기 곤란한 경우가 있다.
apply, lambda를 사용하여 결측치를 채울 수 있다. 아래 두줄 참고
fill_func = lambda x: x.fillna(fill_values[x.name])
df.group(&#39;그룹화할col명&#39;).apply(fill_func)</p>
<p>결측치를 랜덤한 값으로 변경하는 방법도 있다.</p>
<p>Test값의 결측치를 채울때 Test 데이터만을 사용하여 결측치를 채워야한다.</p>
<p>value_count()에서 dropna=False를 인자로 넣어주면 결측값이 몇개인지도 같이 세준다.</p>
<h3 id="모델기반으로-결측치를-채울-수-있다">모델기반으로 결측치를 채울 수 있다.</h3>
<h4 id="sklearn의-simpleimputer를-사용">sklearn의 SimpleImputer를 사용</h4>
<pre><code>from sklearn.impute import SimpleImputer

# strategy = mean, median, most_frequent
imputer = SimpleImputer(strategy=&quot;mean&quot;)

X_tr[&#39;age_simple_mean&#39;] = imputer.fit_transform(X_tr[[&quot;age&quot;]])
X_te[&#39;age_simple_mean&#39;] = imputer.transform(X_te[[&quot;age&quot;]])

X_tr[[&#39;age&#39;, &#39;age_simple_mean&#39;]].isnull().sum()</code></pre><p>평균값을 학습한 후에 결측치를 평균값(strategey=&quot;mean&quot;이기에)으로 채운다. 학습은 train data로만 해야하고, test data를 채울때는 train data로 학습한 것으로 채운다.</p>
<h4 id="sklearn의-knnimputer를-사용">sklearn의 KNNImputer를 사용</h4>
<pre><code>from sklearn.impute import KNNImputer

imputer = KNNImputer(n_neighbors=5)

X_tr[&#39;age_knn&#39;] = imputer.fit_transform(X_tr[[&quot;age&quot;]])
X_te[&#39;age_knn&#39;] = imputer.transform(X_te[[&quot;age&quot;]])

X_tr[[&#39;age&#39;, &#39;age_knn&#39;]].isnull().sum()</code></pre><p>인접한 5개(n_neighbors=5이기에)의 값을 바탕으로 학습하여 결측치를 채운다.</p>
<h4 id="sklearn의-iterativeimputer를-사용">sklearn의 IterativeImputer를 사용</h4>
<pre><code>from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer

imputer = IterativeImputer(random_state=SEED)

X_tr[&#39;age_iter_none&#39;] = imputer.fit_transform(X_tr[[&quot;age&quot;]])
X_te[&#39;age_iter_none&#39;] = imputer.transform(X_te[[&quot;age&quot;]])

X_tr[[&#39;age&#39;, &#39;age_iter_none&#39;]].isnull().sum()</code></pre><h4 id="sklearn의-randomforestregressor를-사용">sklearn의 RandomForestRegressor를 사용</h4>
<pre><code>from sklearn.ensemble import RandomForestRegressor

imputer = IterativeImputer(estimator=RandomForestRegressor(verbose=0, random_state=SEED),
max_iter=10, verbose=0, imputation_order=&#39;ascending&#39;, random_state=SEED)

X_tr[&#39;age_iter_none&#39;] = imputer.fit_transform(X_tr[[&quot;age&quot;]])
X_te[&#39;age_iter_none&#39;] = imputer.transform(X_te[[&quot;age&quot;]])

X_tr[[&#39;age&#39;, &#39;age_iter_none&#39;]].isnull().sum()</code></pre><p>커스터마이징이 가능하다.
<br><br><br>
tqdm 모듈을 사용하면 진행 정도를 알 수 있다.</p>
<h1 id="10일차">10일차</h1>
<h2 id="data-encoding">Data Encoding</h2>
<p>컴퓨터는 숫자로 된 값으로 읽기 떄문에, 범주형 데이터들을 encoding하여 컴퓨터가 이해하기 쉽게 만들어준다. 범주형 데이터에는 순서형 데이터(Ordinal)와 명목형 데이터(Nominal)이 있다.
Encoding의 종류로는 One hot Encoding, Mean Encoding, Target guided ordinal Encoding, Label Encoding 등이 있다. Encoding하기 전에 결측치는 모두 제거해줘야한다.</p>
<h3 id="one-hot-encoding">One Hot Encoding</h3>
<p>흔히 사용하는 Encoding 방식 중 하나이다. 범주를 가장 잘 나타낼 수 있다.
Feature의 항목이 많을 때 연산이 오래걸리는 단점이 있다.</p>
<h3 id="mean-encoding">Mean Encoding</h3>
<p>데이터량이 늘어나 연산이 오래걸리는 점을 해결하기 위하여 평균값으로 encoding한다.
하지만 이 경우에 컴퓨터는 이 data가 범주형 데이터라고 인지할 수 없다.</p>
<p>위 두 Encoding은 명목형 데이터에 사용하면 좋다.</p>
<p>아래 Encoding들은 순서형 데이터에 사용하면 좋다.</p>
<h3 id="label-encoding">Label Encoding</h3>
<p>각각의 자연어에 라벨로 숫자를 붙인다.</p>
<h3 id="target-encoding">Target Encoding</h3>
<p>Mean Encoding과 Label Encoding을 합쳐서 적용한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1주차 ]]></title>
            <link>https://velog.io/@cheol2_y/1%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@cheol2_y/1%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Tue, 03 Oct 2023 23:59:22 GMT</pubDate>
            <description><![CDATA[<p>1일차 파이썬 개발환경 구축</p>
<h1 id="1-python-설치">1. Python 설치</h1>
<p>파이썬 3개의 버전(3.9.13, 3.10.11, 3.11.5)을 설치하였다.</p>
<p>과정은 매우 간단하니 생략한다.</p>
<h1 id="2-설치된-python-확인">2. 설치된 Python 확인</h1>
<p>기기에 설치된 Python의 버전들을 확인해보기 위해서 윈도우키 -&gt; 시스템 환경 변수 편집 -&gt; 환경변수 -&gt; path와 편집 버튼을 눌러 설치한 python이 잘 설치되어있나 확인가능합니다. 나중에 나의 개인 컴퓨터에서도 파이썬 버전을 확인해보자. 아마 많은 파이썬 버전이 설치되어 있을 것으로 확인된다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/07d27cc9-7bf8-415a-9380-fb262ea87cfc/image.png" alt=""></p>
<h1 id="3-powershell-실행-권한-설정">3. Powershell 실행 권한 설정</h1>
<p>Powershell에서 실행 권한 관련하여 설정을 하였다.
IDE 통합개발환경에서 개발을 진행하기 위하여 로컬 스크립트를 모두 승인하는 RemoteSigned상태로 변경하였다. 
<img src="https://velog.velcdn.com/images/cheol2_y/post/c066e19d-e4ac-4bd8-bd3d-b485d8f9b148/image.png" alt=""></p>
<p>IDE라는 단어가 생소하여 구글링을 해보았다. 가장 직관적인 설명은 &quot;소프트웨어 개발에 관련된 모든 작업, 즉 패키지 인클루딩, 문서 편집, 컴파일, 디버그, 원격 서버 액세스, 바이너리 배포 등을 하나의 프로그램 안에서 모두 처리하는 환경을 제공하는 툴. 비슷한 말로는 고속 개발 도구가 있다.&quot;</p>
<p>IDE 종류는 익숙한 IDLE, Jupyter Notebook, Visul Studio와 Visual Studio Code가 있다. 그 중에서도 이번 교육 기간 동안에는 VS Code를 사용할 예정이다. VScode를 새로 설치할 때마다 항상 생각나는 것이 한가지 있다. 개발자는 영어를 많이 사용하기 때문에 VScode의 언어를 영어로 설정하고 해보자는 생각을 한다. 하지만 항상 킹받아서 다시 한글로 변경했던 기억이 있다. 물론 이번에도 영어로 설정하고 진행할 예정이다. :D</p>
<h1 id="4-vs-code-설치-및-환경-설정">4. VS Code 설치 및 환경 설정</h1>
<p>VS Code 설치과정 역시 간단하기에 생략한다. 
<img src="https://velog.velcdn.com/images/cheol2_y/post/d443de09-8f63-43ea-8ee5-901973486c87/image.png" alt=""></p>
<p>VSCode를 설치했다면 이후에는 확장자들을 추가하고 설정을 변경해주면 개발 환경이 더욱 용이해진다. </p>
<p>먼저 Extention은 보기 편하게 해주는 Prettier, indent-rainbow, Material icon theme과 D2coding font를 추가하여 코드의 가독성을 높였다. </p>
<p>그리고 기본 언어인 Python과 Jupyter를 설치하여 주었다.</p>
<h4 id="-d2coding-font">-D2coding font</h4>
<p>D2coding font는 네이버에서 만든걸로 한국인에게 친화적이다. Git hub에서 D2coding font를 다운 받은 후 설정해두면 된다. 설정하는 과정은 File -&gt; Preference -&gt; Settings 에서 검색에 font를 검색한다. 검색 결과에서 Font Family칸에서 제일 앞에 D2Coding ligature를 추가하고 콤마를 찍어주고 아래에 Edit in settings.json을 클릭하고 editor.fontLigatures가 false로 되어있을텐데 이것을 true로 바꿔주면 D2Coding font가 설정완료 된다.</p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/f339d8c8-53a8-4759-9c68-8a13e357d91d/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/ce27aa0a-67fd-4286-a0b7-ae376e7524f1/image.png" alt=""></p>
<h1 id="5-가상환경-만들기">5. 가상환경 만들기</h1>
<p>마지막으로 가상환경을 만드는 것을 정리해보자. 가상환경은 하나의 컴퓨터에서 다양한 개발을 진행하기 위하여 만드는 것이라고 생각된다. 많은 프로젝트를 진행해야하는데 그때마다 컴퓨터를 포멧시키고 새로운 환경을 만드는 것은 현실적으로 불가능하기에 가상환경을 만들어 그곳에 필요한 모듈들을 집어넣고 프로젝트를 진행할 수 있다. 위에서 ExecutionPolicy를 RemoteSigned로 변경해주어 IDE 환경을 만들었기때문에 VS Code내부에서 가상환경을 쉽게 설정할 수 있다. 하나의 폴더를 잡고 새로운 터미널을 개통한다. 그리고 사용할 파이썬 버전을 정한 후 가상환경을 만들어주면 된다. 
Powershell 터미널에서 py 3.? -m venv .venv 라는 코드를 입력해주면 된다. ?에는 원하는 파이썬 버전을 넣으면 된다. venv는 가상환경을 설정한다는 명령어이고 뒤에 .venv에는 다른 이름의 가상환경을 넣어줘도 되지만 통상적으로 .venv를 사용한다.</p>
<p><img src="https://velog.velcdn.com/images/cheol2_y/post/43b84555-fb2e-4aa8-9bb0-e1f584c538dd/image.png" alt=""></p>
<p>이제 만들어준 가상환경을 활성화해보자. 
.\.venv\Scripts\activate
이 과정을 조금 더 간단하게 해주는 방법은 .v 탭, S 탭, a 탭을 눌러주면 된다. 탭키를 누르면 뒤에는 폴더내에 있는 파일이름을 자동으로 완성시켜준다. 이후에는 활성화된 가상환경에 자유롭게 모듈을 추가하여 활용하면 된다. 가상환경을 종류할 때는 deactivate를 입력해주면 된다.</p>
<p>마무리 과제:
3개의 폴더 Naver, Kakao, Samsung을 만들고 파이썬 버전이 각각 11,10,9인 가상환경을 만들기.</p>
<h1 id="2일차">2일차</h1>
<p>새로 배운 함수들을 알아보자</p>
<h3 id="str3-인덱싱">str[3] 인덱싱</h3>
<p> 인덱싱이라는 것은 객체에 부여된 번호를 의미한다. 이건 대괄호로 사용할 수 있는데 예시를 보면서 설명하는 것이 쉬울 것이라고 생각한다. 코딩 공부라는 것이 이론적인 것보다는 직관적인 것이 중요하기 때문이다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/6235b592-455c-4821-9c21-1c44a007aa7f/image.png" alt="">
a라는 문자열이 있는데 이것에 부여된 인덱스가 있다. b는 그냥 a의 인덱스를 직관적으로 보여주기위해 만들어 놓은 것이니 크게 신경쓰지 않아도 된다.</p>
<h3 id="find">.find()</h3>
<p>find 함수는 ()안에 들어가는 것이 문자열안에 존재하는가를 확인시켜준다. 존재한다면 인덱스 번호를 알려주고 없다면 -1을 출력한다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/3bf6d748-dfca-45a3-8c00-cc705e1e982e/image.png" alt=""></p>
<h3 id="count">.count()</h3>
<p>count 함수는 문자열안에 ()에 들어가는 문자가 얼마나 들어가는 지를 알려준다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/26e84484-2d46-4ed5-b354-82826307b07e/image.png" alt=""></p>
<h3 id="len문자열">len(문자열)</h3>
<p>len은 그냥 뒤에 들어가는 문자열의 길이를 정수로 알려준다.</p>
<h3 id="join문자열">&quot;?&quot;.join(문자열)</h3>
<p>join은 ?에 들어갈 문자를 ()안에 있는 문자열의 인덱스 사이사이에 넣어주는 함수이다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/65784ca2-2872-46c4-bae3-976aefbae0b3/image.png" alt="">
첫 줄은 공백, 즉 띄어쓰기를 하나씩 넣어준 것이다.</p>
<h3 id="문자열split나누는-기준이-되는-것">문자열.split(나누는 기준이 되는 것)</h3>
<p>이쯤되면 위에 함수 형태만봐도 어떤 함수인지 유추할 수 있다. split은 join과 연계를 하면 문자열이 list 타입으로 변한다. 근데 그냥 list 함수 써도 결과는 같다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/88332bcd-b7c5-4e19-9d58-84bfc817f7ec/image.png" alt=""></p>
<h3 id="문자열upper">문자열.upper()</h3>
<p>문자열을 모두 대문자 만들어주는 함수</p>
<h3 id="문자열lower">문자열.lower()</h3>
<p>문자열을 모두 소문자 만들어주는 함수</p>
<h3 id="strip-lstrip-rstrip">.strip(), .lstrip(), .rstrip()</h3>
<p>차례로 전체 공백을 제거, 왼쪽 공백을 제거, 우측 공백을 제거해주는 함수이다. 하지만 아쉽게도 문자와 문자사이에 공백은 제거해주지 않는다.</p>
<h3 id="문자열replaceab">문자열.replace(a,b)</h3>
<p>문자열 안에있는 a들을 b로 바꿔주는 함수이다. 꽤나 유용하다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/9a86ef2b-e918-40ed-a505-fb8911e4e62b/image.png" alt=""></p>
<h3 id="del-리스트">del 리스트[]</h3>
<p>리스트에서 [] 적용되는 인덱스를 제거해준다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/46161e4b-f4e4-4c09-afd0-86055bcb72ef/image.png" alt=""></p>
<h3 id="리스트append">리스트.append()</h3>
<p>리스트 맨뒤에 ()에 들어가는 것을 추가해준다.</p>
<h3 id="sort">.sort()</h3>
<p>리스트를 오름차순, 알파벳 순으로 정렬해준다</p>
<h3 id="리스트reverse">리스트.reverse()</h3>
<p>리스트를 뒤집어준다.</p>
<h3 id="리스트index">리스트.index()</h3>
<p>index는 ()안에 들어가는 값이 리스트 안에 있다면 몇번째 인덱스에 있는지 번호로 알려준다.</p>
<h3 id="튜플은-요소값을-바꿀-수-없는-특징이-있다-소괄호로-만든다">튜플은 요소값을 바꿀 수 없는 특징이 있다. 소괄호로 만든다.</h3>
<h3 id="딕셔너리">딕셔너리</h3>
<p>dic은 key값과 value값을 갖는다. 중괄호를 사용하여 지정한다. 이것은 복잡할 수있으니 괄호를 하나씩 천천히 넘어가며 분석하는 것이 좋다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/0304f52b-c21b-458e-baea-e3af9bc1606f/image.png" alt=""></p>
<p>name과 age는 key이고 그 안에 들어가 있는 두개의 값들이 value이다.</p>
<h3 id="딕셔너리keys">딕셔너리.keys()</h3>
<p>dic안에 있는 key값들을 모두 알려준다</p>
<h3 id="딕셔너리values">딕셔너리.values()</h3>
<p>dic안에 있는 value값들을 모두 알려준다.</p>
<p>오늘은 정리할게 많았던 것같아. 강의 중에 제대로 집중하여 바로 정리할 수 있는 습관을 들이는게 좋을것으로 보인다. 수업중 문제를 몇개 내주셨는데 문제푸는 재미가 있었다.
<br>
<br></p>
<h1 id="3일차">3일차</h1>
<pre><code>if 조건문:
    위 조건이 참이면 실행할 코드
elif 조건문:
    위 조건이 참일때 실행할 코드
else:
    if와 elif의 조건이 거짓일때 실행할 코드</code></pre><p>if의 조건과 elif의 조건이 겹치면 위에 있는 if의 값을 출력한다. 그렇기때문에 if와 elif의 조건을 겹치게 설정하는 것은 좋지 못하다. 즉 if문이 참이면 그 아래 조건들은 확인하지 않는다.</p>
<br>
for문
```
for i in 인덱싱 가능한 자료형(list, tup, str):
    위가 참이면 실행할 코드
```
for문의 반복 횟수는 인덱스의 크기와 같다.

<p>Pass: 딱히 실행하는 것은 없다. 다음 줄으로 이동한다.
Break: 현재 반복문 밖으로 나간다.
continue: 다음 회차의 loop를 시작한다.
<br>
for 
else
for문도 else를 추가할 수 있는데 이것은 for문이 완전히 다 끝난 경우에 실행되는 else 구문이다.</p>
<br>
while문
```
while 조건
    실행하는 코드
```
while문은 조건이 true일때 아래에 코드를 실행하는 반복문이다. 조건이 항상 참이게 두면 무한 루프가 발생하므로 주의하여야한다. 이러한 문제를 해결하기 위하여 조건에 값을 매 루프마다 1씩 더하는 등의 방법을 사용한다. 다른 방법으로는 

<br>
예외처리
try:

<p>except:</p>
<p>형태로 되어있다. 오류가 발생하여도 오류코드가 나오는 것이 아닌 except에 있는 코드를 실행한다.
<br></p>
<p>range(a,b)
a~b-1까지의 정수들을 갖는 range값이다. range(a,b,c)일 때 c는 정수 사이의 간격이다.
<img src="https://velog.velcdn.com/images/cheol2_y/post/e386a767-07d0-4817-b93f-e07858ed5994/image.png" alt=""></p>
<br>
input()
사용자로부터 값을 입력받을 수 있는 함수이다. 괄호 안에는 사용자에게 전할 말을 넣을 수 있다. 입력 받은 값은 문자열로 받는 것을 주의해야한다.

<br>
random 함수들
random.random()
0~1사이에 랜덤한 float형태의 숫자를 출력한다. ()안에 인자를 받을 수 없다.
random.uniform(a,b)
두개의 인자(a,b)사이에 랜덤한 float형태의 숫자를 출력한다.
random.randint(a,b)
두 범위 사이에 랜덤한 int형태의 숫자를 출력한다.

<br>
round는 반올림이다.
![](https://velog.velcdn.com/images/cheol2_y/post/b79b76ee-2db1-4f25-b569-733396b2da9f/image.png)


]]></description>
        </item>
    </channel>
</rss>