<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>chaewon.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Mon, 10 Feb 2025 08:11:17 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>chaewon.log</title>
            <url>https://images.velog.io/images/jerry_bak/profile/bba73c8b-0e14-4071-9c68-01d5df5ea7da/1.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. chaewon.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jerry_bak" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[MySQL] JOIN 되는 일부 컬럼은 그룹화가 필요 없다.]]></title>
            <link>https://velog.io/@jerry_bak/MySQL-JOIN-%EB%90%98%EB%8A%94-%EC%9D%BC%EB%B6%80-%EC%BB%AC%EB%9F%BC%EC%9D%80-%EA%B7%B8%EB%A3%B9%ED%99%94%EA%B0%80-%ED%95%84%EC%9A%94-%EC%97%86%EB%8B%A4</link>
            <guid>https://velog.io/@jerry_bak/MySQL-JOIN-%EB%90%98%EB%8A%94-%EC%9D%BC%EB%B6%80-%EC%BB%AC%EB%9F%BC%EC%9D%80-%EA%B7%B8%EB%A3%B9%ED%99%94%EA%B0%80-%ED%95%84%EC%9A%94-%EC%97%86%EB%8B%A4</guid>
            <pubDate>Mon, 10 Feb 2025 08:11:17 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/284529">이 문제</a>를 풀면서 평소와 같이 쿼리를 아래처럼 작성했다.</p>
<pre><code>SELECT
    DEPT_ID,
    DEPT_NAME_EN,
    ROUND(AVG(SAL)) AS AVG_SAL
FROM HR_EMPLOYEES
LEFT JOIN HR_DEPARTMENT 
    USING(DEPT_ID)
GROUP BY DEPT_ID,
    DEPT_NAME_EN
ORDER BY AVG_SAL DESC;</code></pre><p>근데 계속 이런 쿼리에서 걸리는 점이 GROUP BY할 때 사실 DEPT_ID 하나만 해도 상관없는데, GROUP BY 사용할 때 SELECT 절에 올 수 있는 건 그룹화 대상이거나, 집계함수라고 알고 있었어서 계속 써왔다.</p>
<p>근데! 다른 사람 코드를 보니까 안써도 된다지 뭐야?</p>
<pre><code>SELECT
    DEPT_ID,
    DEPT_NAME_EN,
    ROUND(AVG(SAL)) AS AVG_SAL
FROM HR_EMPLOYEES
LEFT JOIN HR_DEPARTMENT AS D
    USING(DEPT_ID)
GROUP BY DEPT_ID
ORDER BY AVG_SAL DESC;</code></pre><p>그래서 GROUP BY에 DEPT_ID만 썼는데도 문제가 없는게 아니던가???????</p>
<p>그래서 GPT한테 물어봤다.
<img src="https://velog.velcdn.com/images/jerry_bak/post/1664f14d-d63b-4a20-b9c7-9e8b6dd3e958/image.png" alt="">
이렇다는거지....
생각해보니까 그렇다! 내가 지금 이 쿼리에서 DEPT_ID를 기준으로 DEPT_NAME_EN을 가져오고있기 때문에 DEPT_ID에 있어 DEPT_NAME_EN은 1:1 매칭이다. (N:1이어도 N인 컬럼이 그룹화 대상이라면 상관 없다.)
그리고 내가 지금 DEPT_ID로 그룹화를 하고있으니까 필요없는거임!</p>
<p>그렇기 때문에 GROUP BY에 DEPT_NAME_EN을 포함시키지 않아도 된다고 한다!
대박.</p>
<h3 id="결론">결론</h3>
<p>JOIN을 통해 특정 컬럼과 1:1 매칭 되는 컬럼 X의 경우 특정 컬럼으로 GROUP BY시, 컬럼 X를 그룹화 대상으로 두지 않고 SELECT 절에 이용할 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MySQL] GROUP BY와 PARTITION BY의 차이]]></title>
            <link>https://velog.io/@jerry_bak/MySQL-GROUP-BY%EC%99%80-PARTITION-BY%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@jerry_bak/MySQL-GROUP-BY%EC%99%80-PARTITION-BY%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Mon, 10 Feb 2025 07:02:06 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/284527">이 문제</a>에서 사원별 SCORE(상반기 score+하반기 score)를 기준으로 랭킹을 매겨야하는데, 윈도우 함수를 사용하며 어려움이 있었다.</p>
<h3 id="1차-시도">1차 시도</h3>
<pre><code>WITH SCORES AS(
    SELECT
        DISTINCT EMP_NO,
        SUM(SCORE) OVER(PARTITION BY EMP_NO) AS SCORE,
        RANK() OVER(PARTITION BY EMP_NO ORDER BY SUM(SCORE)) AS R
    FROM HR_GRADE
)

SELECT
    SCORE,
    EMP_NO,
    EMP_NAME,
    POSITION,
    EMAIL
FROM HR_EMPLOYEES
LEFT JOIN SCORES
    USING(EMP_NO)
WHERE R=1;
</code></pre><p>처음엔 이렇게 CTE로 SCORE와 RANKING을 구해서 1위 데이터만 뽑아보려고 했는데, 오류가 났다!
GROUP BY를 사용하지 않고 OVER 내에서 집계함수인 <code>SUM(SCORE)</code>를 사용해서 난 오류였다.</p>
<p>결론적으론 RANK()부분이 문제였는데,<br>나의 의도는 PARTITION BY로 EMP_NO 기준으로 그룹화하고, 그룹별로 SUM(SCORE)의 값으로 정렬해 랭크를 매기는 것이엇따.</p>
<p>근데 저렇게 하면, EMP_NO으로 그룹화하고 그룹 내에서만 정렬이 이뤄진다! 근데 그룹내에서 SUM(SCORE)은 같은 값이니 의미가 없는 것임. (차피 실행도 안되고)</p>
<p>그렇기에 저걸 제대로 수정한다면,</p>
<pre><code>WITH SCORES AS(
    SELECT
        EMP_NO,
        SUM(SCORE) AS SCORE,
        RANK() OVER(ORDER BY SUM(SCORE) DESC) AS R
    FROM HR_GRADE
    GROUP BY EMP_NO
)

SELECT
    SCORE,
    EMP_NO,
    EMP_NAME,
    POSITION,
    EMAIL
FROM HR_EMPLOYEES
LEFT JOIN SCORES
    USING(EMP_NO)
WHERE R=1;</code></pre><p>이렇게 전체에서 GROUP BY를 사용하는 것으로 수정하면 깔끔해진다.
여기서 또 궁금했던 건 그러면 OVER안의 SUM은 GROUP BY의 영향을 받는건가?였는데 그렇다고 한다.</p>
<blockquote>
<p>SUM(SCORE) OVER(PARTITION BY EMP_NO)는 각 행에서 반복되지만,
SUM(SCORE) + GROUP BY는 그룹별로 한 번만 계산된다!
by. 챗지피티</p>
</blockquote>
<p>결국 중요한 건 집계함수를 사용하기 위해선  </p>
<p>1) GROUP BY를 쓰거나, 
2) 그 집계함수를 위해 OVER를 쓰는 수밖에! </p>
<hr>
<p>역시나 윈도우 함수는 복잡하다.
내가 제대로 이해하지 못하고 쓰고 있던게 크긴 하다만,,,ㅎㅎ</p>
<p>+) 제대로 적어두자면, 내가 첫번째에 작성한 쿼리는 EMP_NO으로 그룹화를 하고 그 그룹 내에서 정렬을 하고자 하는거였고(의도와 다름), 두번째 제대로 된 쿼리가 EMP_NO으로 그룹화하고 그룹별 SUM(SCORE) 값으로 각 그룹을 ORDER해 랭킹을 매기는 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] 뒤에 있는 큰 수 찾기]]></title>
            <link>https://velog.io/@jerry_bak/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%92%A4%EC%97%90-%EC%9E%88%EB%8A%94-%ED%81%B0-%EC%88%98-%EC%B0%BE%EA%B8%B0</link>
            <guid>https://velog.io/@jerry_bak/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EB%92%A4%EC%97%90-%EC%9E%88%EB%8A%94-%ED%81%B0-%EC%88%98-%EC%B0%BE%EA%B8%B0</guid>
            <pubDate>Tue, 26 Nov 2024 15:24:33 GMT</pubDate>
            <description><![CDATA[<h3 id="링크">링크</h3>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/154539">https://school.programmers.co.kr/learn/courses/30/lessons/154539</a></p>
<h3 id="문제">문제</h3>
<p>리스트가 주어질 때, 각 원소의 뒤에 있는 원소 중 자신보다 크며, 가장 가까이 있는 수를 뒷 큰수라고 할 때, 각 원소별 뒷 큰수가 담긴 리스트를 반환
*뒷 큰수가 없을 경우 -1</p>
<h3 id="코드">코드</h3>
<pre><code>def solution(numbers):
    answer = [-1 for _ in range(len(numbers))]
    stack = [0]

    for i in range(1, len(numbers)):
        now = numbers[i]
        while stack:
            if numbers[stack[-1]]&lt;now:
                answer[stack.pop()]=now
            else:
                break
        stack.append(i)
    return answer</code></pre><h3 id="사족">사족</h3>
<p><strong>포인트를 바꿔라</strong>
나는 단순히 &#39;특정 원소의 뒷 큰수를 구하자&#39;에 초점을 뒀는데, 이 문제는 &#39;내가 누군가의 뒷 큰수게 아니게&#39; 로 봐야한다. </p>
<p><strong>stack을 사용하라</strong>
이 문제에서 주목할 점은, a, b, c (순서대로) 값이 있을 때, b가 a보다 크지 않고 c가 b보다 크지 않을 때, c도 a보다 클 수 없다는 것이다. 
그렇기 때문에 이 문제에서 스택을 사용할 수 있는 것이다.
머리로 떠올리자면 어렵지만,,, 한 번 봤으니까 외워라</p>
<p><strong>반환할 리스트를 미리 정해두고 인덱스로 수정해라</strong>
그래야 스택에서 인덱스를 사용하면서 뒷 큰수를 구할 수 있다.</p>
<h3 id="유사-문제">유사 문제</h3>
<ul>
<li><a href="https://school.programmers.co.kr/learn/courses/30/lessons/42584">주식가격</a> <ul>
<li>거의 풀이가 동일하다. 이걸 풀어보면서 원리를 이해해도 좋을 것 같다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 level 1,2 정리]]></title>
            <link>https://velog.io/@jerry_bak/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-level-1-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jerry_bak/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-level-1-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Thu, 14 Nov 2024 16:19:04 GMT</pubDate>
            <description><![CDATA[<h3 id="range">range</h3>
<ul>
<li>증가폭이 0이면 안된다.<ul>
<li>range에서 3번째 인자인 증가폭(step)이 0일 경우 오류 남! 유의해서 코드 작성하기</li>
</ul>
</li>
</ul>
<h3 id="string">string</h3>
<ul>
<li>reversed<ul>
<li>문자열을 뒤집어주는 함수. </li>
<li><em>참고: 리스트는 [::-1]과 같이 쓸 수 있음</em></li>
</ul>
</li>
<li>zfill<ul>
<li><code>str.zfill(n)</code>과 같이 사용하며, str이 n 길이 만큼 0으로 채워줌(왼쪽)</li>
<li>ex) &#39;234&#39;.zfill(5) -&gt; &#39;00234&#39; 반환</li>
</ul>
</li>
<li>rjust, ljust<ul>
<li><code>str.rjust(n,&#39;0&#39;)</code>과 같이 사용하며, rjust는 왼쪽, ljust는 오른쪽에 특정 문자를 str의 길이가 n이 되도록 채워줌</li>
</ul>
</li>
<li>replace<ul>
<li><code>str.replace(&#39;.&#39;,&#39;&#39;,1)</code> 이런식으로 세번째 인자로 해당 문자를 replace할 횟수를 지정할 수 있다.</li>
</ul>
</li>
<li>capitalize, title<ul>
<li><code>str.capitalize()</code>과 같이 사용하며, 맨 첫번째 문자를 대문자로 변환해 반환</li>
<li><code>str.title()</code>과 같이 사용하며, 숫자/특수문자/공백으로 구분된 각 단어의 첫 문자를 대문자로 변환해 반환.</li>
</ul>
</li>
<li>split<ul>
<li><code>str.split(&#39; &#39;)</code>과 같이 공백으로 문자열을 split 했을 때, 공백이 두 번 연속되는 경우 &#39;&#39;가 두 공백 사이 문자로써 split된다.</li>
</ul>
</li>
</ul>
<h3 id="리스트-특정-원소-제거">리스트 특정 원소 제거</h3>
<ul>
<li>del<ul>
<li><code>del arr[1]</code>과 같이 사용함</li>
</ul>
</li>
<li>pop<ul>
<li><code>arr.pop(1)</code>과 같이 사용</li>
<li>del과 같이 인덱스를 사용해 값을 반환 받고 제거한다.</li>
<li>만약 인덱스를 지정하지 않고 <code>arr.pop()</code>과 같이 쓴다면, 마지막 원소를 반환 후 제거</li>
<li><code>pop(0)</code>은 O(n)임을 인지하고 있을 것!</li>
</ul>
</li>
<li>remove<ul>
<li><code>arr.remove(x)</code>와 같이 <strong>제거할 값</strong>을 인자로 사용.</li>
<li>x가 여러개 있을 경우, 가장 앞의 x를 삭제</li>
<li>반환값이 없는 함수!</li>
</ul>
</li>
</ul>
<h3 id="약수">약수</h3>
<ul>
<li>약수 개수가 홀수? 짝수?<ul>
<li>제곱수만 약수 개수가 홀수임</li>
</ul>
</li>
<li>약수 빠르게 구하기<ul>
<li>바로 <code>for i in range(1, num**(0.5)+1)</code>의 범위에서 나머지 연산이 0인지 확인하고, 그 값이 제곱수만 아니라면 i와 num//i를 약수로 추가하면 됨<h3 id="문자열">문자열</h3>
</li>
</ul>
</li>
<li>정렬<ul>
<li>리스트처럼 sort, sorted 모두 사용 가능</li>
<li>대문자가 소문자보다 아스키코드 값이 작기 때문에 작은 것으로 sort됨</li>
</ul>
</li>
<li><code>.isdigit()</code><ul>
<li>해당 문자열이 숫자로만 이루어져있는지 확인할 수 있는 함수</li>
</ul>
</li>
</ul>
<h3 id="min함수-사용법">min함수 사용법</h3>
<ul>
<li><a href="https://school.programmers.co.kr/learn/courses/30/lessons/82612">이 문제</a>에서 min을 특이하게 return 조건문에 사용할 수 있다.</li>
</ul>
<h3 id="itertools">itertools</h3>
<ul>
<li>combinations<ul>
<li><code>combinations(list, n)</code>과 같이 사용해, list에서 n개의 원소를 갖는 조합을 뽑을 수 있다.</li>
</ul>
</li>
<li>permutations<ul>
<li><code>permutations(list, n)</code>과 같이 사용해, list에서 n개의 원소를 갖는 순열을 뽑을 수 있다.</li>
</ul>
</li>
<li>product<ul>
<li>두 개 이상의 리스트/집합 끼리의 데카르트 곱을 구할 수 있다. 두 개 이상의 리스트의 조합을 구할 수 있음</li>
<li><code>product(*a)</code>와 같이 사용해, 이중 리스트인 a에서 조합들을 구할 수 있음</li>
<li><a href="https://school.programmers.co.kr/learn/courses/30/lessons/43165">이 문제</a> 참고</li>
<li><code>product(&#39;AEIOU&#39;, repeat=i)</code>와 같이 repeat 인자를 사용해 같은 리스트/문자열/집합의 조합들을 구할 수도 있음</li>
</ul>
</li>
</ul>
<h3 id="math">math</h3>
<ul>
<li>comb (조합)<ul>
<li><code>comb(a,b)</code>와 같이 사용해 aCb를 구할 수 있다.</li>
</ul>
</li>
</ul>
<h3 id="collections">collections</h3>
<ul>
<li>deque<ul>
<li>데크라고 하며, queue이지만 앞 뒤로 pop, append가 가능한 자료형이다.</li>
<li>popleft, appendleft 등의 함수로 앞에서 데이터를 뽑고, 넣을 수 있다. (리스트를 queue로 사용하며 <code>pop(0)</code>을 하면 빅오가 O(n)이지만 <code>popleft()</code>는 빅오가 O(1)이다.</li>
<li>리스트와 유사하며, 메소드도 대부분 동일하다.</li>
</ul>
</li>
</ul>
<h3 id="sort">sort</h3>
<ul>
<li>정렬 조건 여러개 지정하기<ul>
<li><code>key=lambda x: x[0]</code>과 같이 정렬 조건을 지정해줄 수 있는데, 여러 개의 조건을 사용하고싶을 경우, <code>key=lambda x: (x[0],x)</code>와 같이 정렬 조건을 괄호로 묶어 전달하면 된다.</li>
</ul>
</li>
<li>조건 여러개 오름/내림 차순 다르게 설정<ul>
<li><code>key=lambda x: (-x[0],x)</code>와 같이 <code>-</code>를 사용하면 해당 조건에 대해선 내림차순으로 정렬할 수 있다.</li>
</ul>
</li>
</ul>
<h3 id="bin">bin</h3>
<ul>
<li>10진수 -&gt; 2진수 변환시 사용하는 함수이다.</li>
<li>이진수 &amp;, | 연산<ul>
<li><code>bin(de1|de2)</code>와 같이 사용하면, 십진수인 de1과 de2를 이진수로 변환 후 or 연산을 한 이진수 값을 반환받을 수 있다.</li>
</ul>
</li>
</ul>
<h3 id="dictionary">dictionary</h3>
<ul>
<li><code>dict(zip(arr1, arr2))</code>해서 두 리스트를 하나의 딕셔너리로 만들 수 있다.</li>
<li><code>dictionary.get(name, 0)</code>과 같이 get을 써서 value를 가져올 때, key가 없는 경우 오류가 나는 것을 막을 수 있다.</li>
</ul>
<h3 id="for-else-문">for-else 문</h3>
<p>for문에서 break로 빠져나오지 않고 끝까지 실행되었다면 else문이 실행된다!</p>
<pre><code>for i in range(2,num+1):
    if num%i==0:
        break
else:
    cnt+=1</code></pre><p>이런식으로 나의 경우엔 소수인지 아닌지 판별할 때 사용했다!</p>
<p><strong>while에서도 동일하게 while-else문을 사용할 수 있다.</strong></p>
<h3 id="counter">Counter</h3>
<ul>
<li>뺄셈, 덧셈 지원<ul>
<li>Counter 객체(?)끼리 뺄셈, 덧셈이 가능하다! 두 카운트의 차이를 확인할 수 있음</li>
</ul>
</li>
<li>교집합, 합집합 지원<ul>
<li>교집합 시 최솟값을 취하고, 합집합 시 최대값을 취한다.</li>
</ul>
</li>
<li>Counter(~).most_common()<ul>
<li>value 기준으로 내림차순 정렬된 items 값을 반환한다. 그냥 Counter(~).items()를 for문으로 돌면 정렬되지 않은 값을 반환하기 때문에 주의!</li>
</ul>
</li>
<li><code>==</code><ul>
<li>당연히 같은지 아닌지도 비교 가능</li>
</ul>
</li>
<li>dict to Counter dict<ul>
<li>그냥 Counter(dictionary)와 같이 감싸주면 끝!</li>
</ul>
</li>
</ul>
<h3 id="집합-set">집합, set</h3>
<ul>
<li>add<ul>
<li>list의 append와 같이 원소를 추가하는 함수</li>
</ul>
</li>
<li>in<ul>
<li>set의 in은 리스트보다 훨씬 빠르다. set이 해시테이블을 기반으로 구현되어있기 때문에 빅오가 O(1)임</li>
</ul>
</li>
</ul>
<h3 id="부등호">부등호</h3>
<ul>
<li><code>if 8&lt;n&lt;10</code>과 같이 양쪽에 부등호를 동시에 사용할 수 있다..! 왜 까먹고있었지</li>
</ul>
<h3 id="리스트가-비어있는지-확인">리스트가 비어있는지 확인</h3>
<ul>
<li><code>len(my_list)==0</code> </li>
<li><code>not my_list</code> -&gt; 리스트가 비어있으면 True를 반환</li>
</ul>
<h3 id="최대공약수-최소공배수">최대공약수, 최소공배수</h3>
<ul>
<li>최대 공약수 (Greatest Common Divisor, gcd)<ul>
<li>math 라이브러리의 gcd 함수 사용</li>
<li>두 수 a,b (a&gt;b)가 주어졌을 때, a%b를 r이라고 할 때, a와 b의 최대 공약수는 b와 r의 최대 공약수와 같다.</li>
<li>요렇게 말하면 복잡한데, 결론은 큰수를 작은 수로 나눠, 나머지가 0이 될 때의 작은 수가 최대공약수라는 것임. 파이썬으로 코드를 작성하면 아래와 같다.<pre><code>def gcd(a,b):
while b!=0:
  a,b = b, a%b
return a</code></pre></li>
</ul>
</li>
<li>최소 공배수 (Least Common Multiple)<ul>
<li>최소공배수는 최대 공약수를 이용해 구할 수 있다!</li>
<li>두 수 a,b가 주어졌을 때, <code>a*b/gcd(a,b)</code>가 a와 b의 최소 공배수이다.</li>
</ul>
</li>
</ul>
<h3 id="ziparr">zip(*arr)</h3>
<ul>
<li>zip은 여러 iterable을 병렬로 묶어 각 요소를 튜플로 반환한다.</li>
<li>*는 리스트나 튜플을 언패킹한다! 이중 리스트를 단일 리스트 각각으로 반환하는 것</li>
<li>즉, <em>로 이중 리스트를 각각의 리스트로 반환하고, 각 리스트에서 요소를 병렬로 반환하는 것이므로 *</em>이차원 리스트를 전치**해서 for문을 돌고싶을 때 사용할 수 있다.</li>
<li><code>for column in zip(*arr)</code>와 같이 사용 가능</li>
</ul>
<h3 id="all-any">all, any</h3>
<ul>
<li><code>all(iterable)</code>: iterable 자료형에서 모든 값이 True라면 True를 반환</li>
<li><code>any(iterable)</code>: iterable 자료형 중 하나라도 True 값을 가지면 True를 반환
예문: <code>any([i&gt;max_value for i in list])</code> -&gt; list를 돌며 하나의 값이라도 max_value보다 크다면 True를 반환</li>
</ul>
<h3 id="10진수---n진수">10진수 -&gt; n진수</h3>
<pre><code>## 변환하고싶은 수
num = 18
## 변환하고싶은 진수
n = 16 

result = &#39;&#39;
while num&gt;0:
  num, div = num//n, num%n
  result+=str(div)
print(result[::-1])</code></pre><p>n진수로 변환하고싶을 때, 위와 같이 몫과 나머지를 이용해서 진수 변환이 가능하다.
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/17687">이 문제</a>에서 사용했다.</p>
<p>진수 변환이 주 task가 아닌 경우, 2진수 &lt;-&gt; 10진수는 아래와 같이 함수를 사용할 수 있음</p>
<ul>
<li>이진수 to 십진수: int(binary_value, 2) (이때 binary_value는 str)</li>
<li>십진수 to 이진수: bin(decimal) (이때 decimal은 int)<ul>
<li>bin의 반환 타입은 str이며 0b1010와 같은식. 그렇기 때문에 우리가 직접 이진수를 다루기 위해선 bin(decimal)[2:]와같이 사용</li>
</ul>
</li>
</ul>
<h3 id="heapq">heapq</h3>
<ul>
<li>heap<ul>
<li>최대값, 최소값 연산을 빠르게 할 수 있는 자료구조. 완전이진트리</li>
<li>최대 힙(부모노드 &gt;= 자식노드), 최소 힙(부모노드 &lt;= 자식노드)<pre><code>from heapq import heapify, heappush, heappop
</code></pre></li>
</ul>
</li>
</ul>
<p>num = [1,2,5,2,5,6,8]</p>
<h2 id="list-to-heap">list to heap</h2>
<p>heapify(num)
heappush(num, 4)</p>
<h2 id="최소값-pop">최소값 pop</h2>
<p>heappop(num)</p>
<h2 id="최소값-단순-확인">최소값 단순 확인</h2>
<p>print(num[0])</p>
<pre><code>노드의 삽입과 삭제의 빅오가 O(logN)이다! 여기서 logN은 힙(완전이진트리)의 높이에 해당
최대값, 최소값 연산 및 데이터 삽입 및 삭제 시 유용하게 사용될 것 같다.

### re (정규표현식)
- `re.split(pattern, string)`: 패턴에 따라 문자열을 분리하여 리스트로 반환
- `re.findall(pattern, string)`: 패턴에 매칭되는 모든 부분을 찾아 리스트로 반환

**예제)**
[파일명 정렬](https://school.programmers.co.kr/learn/courses/30/lessons/17686)</code></pre><p>sorted(files, key=lambda file : (re.split(&#39;\d+&#39;, file.lower())[0],int(re.findall(&#39;\d+&#39;, file)[0])))</p>
<p>```</p>
<ul>
<li><code>/d</code>는 숫자(0-9)를 의미</li>
<li><code>+</code>는 하나 이상의 숫자에 매칭</li>
<li>즉 첫번째는 정규표현식은 연속된 숫자 문자열을 기준으로 file.lower()을 분리해 리스트로 반환</li>
<li>두번째 정규표현식은 연속된 숫자 문자열을 찾아 리스트로 반환</li>
<li>만약 숫자가 아닌 문자를 기준으로 분리하거나, 찾고싶다면 <code>/d+</code> 대신 <code>/D+</code>를 사용하면 된다.<h3 id="warning">warning!</h3>
making odd character -&gt; 공백을 다루는 방법
시저암호 -&gt; 아스키코드 활용
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/42840">모의고사</a> -&gt; 같은 리스트를 뺑글뺑글 돌아야할 때, 인덱스에 % 연산을 사용하자
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/42889">실패율</a> -&gt; 나누기 연산할 때, 분모가 0이 되지 않도록! (런타임 에러)
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/133502#">햄버거 만들기</a> -&gt; 슬라이싱과 pop 사용에서 성능 차이가 크게 남. 주의할 것<ul>
<li><code>arr = arr[:-4]</code>(O(4))와 <code>for _ in range(4): arr.pop()</code>(O(1))의 차이</li>
</ul>
</li>
</ul>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/178871">달리기 경주</a> -&gt; 리스트와 dictionary 둘을 모두 이용해 문제를 풀어야함 (딕셔너리가 index 용도로 사용됨)
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/87390">n^2 배열 자르기</a> - 아이디어로 풀어야하는 문제
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/42578">의상</a> - 조합을 사용하면 너무나 쉽게 풀 수 있는 문제 (경우의 수를 생각)
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/42577">전화번호 목록</a> - 문자열의 특성을 이해하면 쉽게 풀 수 있는 문제 (sort!)</p>
<h3 id="알고리즘">알고리즘</h3>
<ul>
<li><a href="https://school.programmers.co.kr/learn/courses/30/lessons/12914">멀리뛰기</a>: DP/피보나치 수열마냥 풀 수 있는 문제</li>
<li>[구명보트] (<a href="https://school.programmers.co.kr/learn/courses/30/lessons/42885">https://school.programmers.co.kr/learn/courses/30/lessons/42885</a>): 투포인트를 써서 idx 조절하는 문제</li>
<li>[캐시] (<a href="https://school.programmers.co.kr/learn/courses/30/lessons/17680">https://school.programmers.co.kr/learn/courses/30/lessons/17680</a>): LRU(Least Recently Used) - 가장 오랫동안 참조되지 않은 페이지를 교체 (queue)</li>
<li><a href="https://school.programmers.co.kr/learn/courses/30/lessons/43165">타겟 넘버</a>: DFS, 재귀 사용</li>
<li><a href="https://school.programmers.co.kr/learn/courses/30/lessons/1844">게임 맵 최단거리</a>: BFS, deque 사용</li>
<li><a href="https://school.programmers.co.kr/learn/courses/30/lessons/42626">더 맵게</a>: heap(heapq 라이브러리) 사용</li>
<li><a href="https://school.programmers.co.kr/learn/courses/30/lessons/154538">숫자 변환하기</a>: BFS의 정석 문제 (deque, visited set 사용)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MySQL] 자동차 대여 기록 별 대여 금액 구하기]]></title>
            <link>https://velog.io/@jerry_bak/MySQL-%EC%9E%90%EB%8F%99%EC%B0%A8-%EB%8C%80%EC%97%AC-%EA%B8%B0%EB%A1%9D-%EB%B3%84-%EB%8C%80%EC%97%AC-%EA%B8%88%EC%95%A1-%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jerry_bak/MySQL-%EC%9E%90%EB%8F%99%EC%B0%A8-%EB%8C%80%EC%97%AC-%EA%B8%B0%EB%A1%9D-%EB%B3%84-%EB%8C%80%EC%97%AC-%EA%B8%88%EC%95%A1-%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 19 Sep 2024 07:30:24 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-링크">문제 링크</h3>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/151141">https://school.programmers.co.kr/learn/courses/30/lessons/151141</a></p>
<h3 id="쿼리">쿼리</h3>
<pre><code>with rent_history as(
    select history_id, car_id, datediff(end_date,start_date)+1 as rent_day 
    from CAR_RENTAL_COMPANY_RENTAL_HISTORY
),
discount_int as(
    select car_type, discount_rate, case
        when duration_type=&#39;7일 이상&#39; then 7
        when duration_type=&#39;30일 이상&#39; then 30
        when duration_type=&#39;90일 이상&#39; then 90
        end as duration_int
    from CAR_RENTAL_COMPANY_DISCOUNT_PLAN
), 
last_table as (
    select history_id, 
        C.car_type, 
        rent_day, 
        daily_fee, 
        ifnull(duration_int,0) as duration_int, 
        ifnull(discount_rate,0) as discount_rate, 
        ifnull(max(duration_int) over(partition by history_id),0) as max_duration_type
    from rent_history R
    left join CAR_RENTAL_COMPANY_CAR C using(car_id)
    left join discount_int D on C.car_type=D.car_type and rent_day&gt;=duration_int
)

select history_id, 
    floor(rent_day*daily_fee*(1-discount_rate*0.01)) as fee
from last_table
where car_type=&#39;트럭&#39;
    and max_duration_type=duration_int
order by fee desc, history_id desc;</code></pre><p>길게도 썼다. 처음 생각했던 구성에서 오류난 걸 고치고 고치다보니 이렇게까지 길어졌다.</p>
<p>처음엔 7일 이하의 렌트에 대해선 할인이 적용되지 않기 때문에, 그 경우 ifnull을 사용해 discount_rate를 0으로 대체해줬어야했는데 그 부분을 잊고 discount_rate가 null인 경우를 제외하고 select 했어서 애를 먹었다.</p>
<h3 id="문제점">문제점</h3>
<p>이 쿼리에서 적폐는 저 last_table CTE에서 마지막 join 조건인 <code>rent_day&gt;=duration_int</code>이다.</p>
<p>저렇게 쓰니까 예를 들어 렌트 일수가 90일 이상인 경우는 7,30,90일 이상인 discount 정보와 전부 조인되다보니 내가 원하는 데이터가 아니었음. 그래서 max(duration_int)를 써서 내가 원하는 데이터만 골라줘야 했음</p>
<p>근데! <strong>discount_int CTE</strong>와 <strong>조인 조건</strong>을 합쳐서! 그냥 조인 조건을 case문으로 써주면 훨씬 단순하게 작성할 수 있다. 아래처럼</p>
<h3 id="새로-작성한-것">새로 작성한 것</h3>
<pre><code>select history_id, 
    floor((datediff(end_date,start_date)+1)*daily_fee*(1-ifnull(discount_rate,0)*0.01)) as fee
from CAR_RENTAL_COMPANY_RENTAL_HISTORY R
left join CAR_RENTAL_COMPANY_CAR C using(car_id)
left join CAR_RENTAL_COMPANY_DISCOUNT_PLAN D 
    on C.car_type=D.car_type 
    and duration_type = (case 
        when datediff(end_date,start_date)+1 &gt;=90 then &#39;90일 이상&#39;
        when datediff(end_date,start_date)+1 &gt;=30 then &#39;30일 이상&#39;
        when datediff(end_date,start_date)+1 &gt;=7 then &#39;7일 이상&#39;
        end)
where C.car_type=&#39;트럭&#39;
order by fee desc, history_id desc;</code></pre><p>case문에서 약간의 하드코딩(?)이 들어가긴 하나 문제의 조건 자체가 duration_type은 90일, 30일, 7일 이상으로 정해져있다 했으니 이렇게 해도 될 것 같다.</p>
<p>만약 datediff가 계속 계산되는 게 싫다면 아래처럼 CTE를 사용해 좀 더 깔끔하게 작성할 수 있다.</p>
<pre><code>with rent_day as (
    select history_id, car_id, datediff(end_date,start_date)+1 as day
    from CAR_RENTAL_COMPANY_RENTAL_HISTORY
)

select history_id, 
    floor(day*daily_fee*(1-ifnull(discount_rate,0)*0.01)) as fee
from rent_day R
left join CAR_RENTAL_COMPANY_CAR C using(car_id)
left join CAR_RENTAL_COMPANY_DISCOUNT_PLAN D 
    on C.car_type=D.car_type 
    and duration_type = (case 
        when day &gt;=90 then &#39;90일 이상&#39;
        when day &gt;=30 then &#39;30일 이상&#39;
        when day &gt;=7 then &#39;7일 이상&#39;
        end)
where C.car_type=&#39;트럭&#39;
order by fee desc, history_id desc;</code></pre><h3 id="알게-된-것">알게 된 것</h3>
<ul>
<li>윈도우 함수: <code>집계함수() over(partition by ~ order by ~)</code>와 같이 윈도우 함수를 사용해 각 partition 별 집계 함수 값을 구할 수 있다.</li>
<li>연산 우선순위: 부등호는 사칙 연산보다 우선순위가 낮기 때문에, 부등호를 사용한 조건 작성에선 괄호를 쓰지 않아도 됨 <ul>
<li><code>datediff(end_date,start_date)+1 &gt;=90</code> 얘처럼 왼쪽 연산을 괄호로 묶을 필요 없다.</li>
</ul>
</li>
<li>반올림/버림: round를 쓰면 반올림되고, floor를 쓰면 소수점을 버리게 된다. 해당 문제에선 <strong>fee가 정수 부분만 출력되어야 한다.</strong> 라고 했으니 반올림보다는 버림이 적절해보인다.</li>
<li>case문 else, as 생략<ul>
<li>else를 생략하면 when 조건에 해당되지 않는 경우는 모두 null이 반환된다고 한다. 즉 <code>else null</code> 쓸 거면 안써도 된다.</li>
<li>as는 단순히 별칭을 달아주는 것이기 때문에 생략해도 문제 없다. 위 쿼리에서 case문의 값을 참조해 사용할 수 없으니 굳이 as를 쓰지 않았다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[mysql] group by와 case문 함께 사용하기]]></title>
            <link>https://velog.io/@jerry_bak/mysql-group-by%EC%99%80-case%EB%AC%B8-%ED%95%A8%EA%BB%98-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jerry_bak/mysql-group-by%EC%99%80-case%EB%AC%B8-%ED%95%A8%EA%BB%98-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 15 Sep 2024 14:18:10 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/276036">https://school.programmers.co.kr/learn/courses/30/lessons/276036</a>
위 문제를 풀다가 난관에 봉착했다.</p>
<pre><code>select case
    when &#39;Front End&#39; in category then &#39;A&#39;
    else NULL
    end as grade,
    id, email
from skill_of_d
group by id, email</code></pre><p>개발자 별로 스킬을 확인해야하기에, group by를 사용해야하는데 그 안에서 등급 지정을 위해 case문을 써야했다. (대충 위와 같이 작성하고싶었음.)</p>
<p>근데 case문에 사용되는 컬럼(categroy)이 group by에 사용된 컬럼(id, email)이 아님.
그래서 집계함수를 써야하는 상황...!</p>
<pre><code>with skill_of_d as (
    select *
    from developers
    join skillcodes on skill_code &amp; code = code
)

select case
    when group_concat(category) like &#39;%Front End%&#39; and group_concat(name) like &#39;%Python%&#39; then &#39;A&#39;
    when group_concat(name) like &#39;%C#%&#39; then &#39;B&#39;
    when group_concat(category) like &#39;%Front End%&#39; then &#39;C&#39;
    else NULL
    end as grade,
    id, email
from skill_of_d
group by id, email
having grade is not null
order by grade, id</code></pre><p>그래서 위 쿼리처럼 group_concat 함수를 사용해 해결했다. </p>
<h3 id="group_concat">group_concat</h3>
<p>group_concat은 그룹화된 결과의 특정 컬럼의 값들을 하나로 concat해주는 함수이다.</p>
<pre><code>select id, group_concat(category) from skill_of_d group by id</code></pre><p>이와 같이 작성하면 개발자별로 갖고있는 skill category를 전부 합쳐서 볼 수 있다.
즉 <code>&#39;Front End,Back End&#39;</code>와 같은 결과를 얻을 수 있는 것!</p>
<p>여기서 주의할 점은 구분자를 따로 지정하지 않으면 쉼표(,)가 디폴트라는 것이다.
만약 구분자를 따로 지정하고싶다면,<code>group_concat(category seperator &#39;|&#39;)</code>와 같이 지정해줄 수 있다.</p>
<h3 id="근데-왜-having에선-group-by에-사용하지-않은-컬럼을-쓸-수-있지">근데 왜 HAVING에선 group by에 사용하지 않은 컬럼을 쓸 수 있지?</h3>
<p>왜 having에선 그룹화 때 사용하지 않은 컬럼을 사용할 수 있나 잠깐 헷갈렸다.</p>
<p>위 쿼리대로라면, id와 email로 그룹화 해서 개발자 별로 하나의 grade를 할당 받으니 grade 또한 having 조건에서 사용할 수 있다.</p>
<p>즉, group by에 사용되진 않았지만 집계함수가 사용된 컬럼에 대해서는 having에서 사용할 수 있는 것이다.
</br>
&lt;chat gpt 曰&gt;</p>
<ul>
<li>집계 함수가 사용된 경우, GROUP BY에 없는 컬럼도 HAVING에서 사용할 수 있습니다.</li>
<li>집계 함수가 없는 경우, GROUP BY에 포함되지 않은 컬럼은 HAVING에서 사용할 수 없습니다.</li>
</ul>
<h3 id="근데-having에서-select절의-alias를-사용할-수-있나">근데 having에서 select절의 alias를 사용할 수 있나?</h3>
<p>having 다음 select가 실행되는데 안되는게 아닌가 싶었다.</p>
<p>chat gpt에 따르면,,, group by 후에 집계함수가 계산되고 having이 실행된다는데, 정확한 정보인지는 잘 모르겠다. 이건 좀 더 알아보고 추가하도록 하겠다.</p>
<h3 id="결론">결론</h3>
<ul>
<li>group by에 사용하지 않은 컬럼을 select 절에서 사용하기 위해선 집계함수를 써야함</li>
<li>having엔 집계함수를 사용한 컬럼 혹은 group by에 사용한 컬럼만 쓸 수 있다.</li>
<li>group_concat을 이용해 그룹화 된 값에 대해 문자열들을 쉼표로 concat할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MySQL] group by에서 select 절의 alias를 사용할 수 있나? 인덱스는?]]></title>
            <link>https://velog.io/@jerry_bak/MySQL-group-by%EC%97%90%EC%84%9C-select-%EC%A0%88%EC%9D%98-alias%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%A0-%EC%88%98-%EC%9E%88%EB%82%98-%EC%9D%B8%EB%8D%B1%EC%8A%A4%EB%8A%94</link>
            <guid>https://velog.io/@jerry_bak/MySQL-group-by%EC%97%90%EC%84%9C-select-%EC%A0%88%EC%9D%98-alias%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%A0-%EC%88%98-%EC%9E%88%EB%82%98-%EC%9D%B8%EB%8D%B1%EC%8A%A4%EB%8A%94</guid>
            <pubDate>Fri, 13 Sep 2024 15:16:41 GMT</pubDate>
            <description><![CDATA[<p>코테 연습을 하다가 갑작스레 궁금해졌다.</p>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/d19fc352-2658-44c6-8547-95a23952441e/image.png" alt=""></p>
<p>group by절은 select보다 먼저 실행되는데 어떻게 alias를 사용해도 되지?</p>
<p>대답은,, mysql에서 가능한 것이라고 한다. 즉 DBMS가 알아서 처리해준다는 말씀</p>
<p>사실 내가 궁금했던건 따로 있는데, 
바로 <code>group by 1</code>과 같이 컬럼 이름이나 alias가 아닌 <strong>인덱스</strong>를 사용해도 실행 순서에 의한 문제가 없는지였다.
나는 인덱스도 별칭이라고 착각하고 있었는데, 챗 지피티에게 질문해보니 차이를 알 수 있었다</p>
<h3 id="챗-지피티-답변">챗 지피티 답변</h3>
<p>좋은 질문이에요! 원칙적으로는 GROUP BY 절이 SELECT 절보다 먼저 실행되기 때문에, SELECT 절의 별칭(alias)은 GROUP BY 절에서 사용할 수 없습니다. 그런데 GROUP BY에서 숫자를 사용하는 것은 조금 다른 경우입니다. 이 경우는 SQL 쿼리의 실행 순서와는 상관이 없습니다.</p>
<p>왜 GROUP BY에서 숫자를 사용하는 것이 가능한가?
GROUP BY 1과 같은 구문은 별칭(alias)을 사용하는 것이 아니라, SELECT 절에서의 열의 위치를 참조하는 것입니다. SQL은 GROUP BY 절을 해석할 때 SELECT 절의 열 위치를 먼저 파악하고, 그 위치에 해당하는 실제 열을 사용하여 그룹화를 수행합니다.</p>
<p>즉, GROUP BY 1이라고 쓰면, SQL 쿼리 엔진은 SELECT 절의 첫 번째 열을 기준으로 그룹화하라는 의미로 해석합니다. 이 과정은 SQL 엔진 내부에서 실행 순서와는 별도로 동작하며, 열의 이름이나 별칭을 사용하지 않고, 단순히 열의 순서를 참조하는 것입니다.</p>
<p>실행 순서와 무관한 이유
SQL 쿼리의 일반적인 실행 순서는 다음과 같습니다:</p>
<p>FROM 절에서 테이블이나 데이터를 가져옴
WHERE 절을 평가하여 필터링
GROUP BY 절로 그룹화
그룹화된 결과에 대해 HAVING 절을 평가
SELECT 절에서 최종적으로 열을 선택
ORDER BY 절로 결과 정렬</p>
<p>이 순서에 따르면 GROUP BY가 SELECT보다 먼저 실행되지만, GROUP BY 1에서의 1은 SELECT 절의 첫 번째 열을 참조하기 때문에, SELECT 절의 정의 자체가 아닌, 열의 위치를 기준으로 참조하는 것이므로 실행 순서와는 무관하게 동작합니다.</p>
<p>결론
GROUP BY 1과 같은 구문이 가능한 이유는, SQL 쿼리 엔진이 GROUP BY 절을 해석할 때 SELECT 절에서 열의 위치를 참조하기 때문입니다. 이 방식은 실행 순서와는 무관하게 열의 순서를 참조하는 것이므로 별칭(alias)이 아닌, 위치(index)로 그룹화할 수 있는 것입니다.</p>
<hr>
<p>즉 단순히 말하자면 alias는 select가 실행 되어 반환할 열을 선택하고 별칭이 지정되는 것이지만, 인덱스는 단순히 <strong>열의 위치를 기준으로 참조</strong>하는 것이므로 sql 실행 순서와 무관하다는 것이다.</p>
<h3 id="근데-만약-해당-인덱스에서-함수가-사용되었다면">근데 만약 해당 인덱스에서 함수가 사용되었다면?</h3>
<pre><code>select count(id) as fish_count, month(time) as month
from fish_info
group by 2
order by 2;</code></pre><p>위 쿼리와 같이 MONTH로 함수가 사용된 열의 인덱스를 사용해 그룹화를 하고자 한다면 오류가 날까?</p>
<p>안난다. </p>
<p>이 또한 sql 자체에서 먼저 함수를 실행한 후 그룹화가 진행된다고 한다. 
(chat gpt 曰: sql엔진이 select 절의 열을 먼저 평가한 후 그 결과를 기반으로 그룹화 진행)</p>
<h3 id="즉-">즉 ~</h3>
<ul>
<li>alias는 별칭(as ~)을 의미하고 인덱스는 select절의 열 위치를 의미함</li>
<li>alias는 select가 실행될 때 지정된다.</li>
<li>alias는 select가 group by보다 늦게 실행되므로 원래는 group by에서 사용할 수 없다. (하지만 mysql에서는 DBMS의 처리로 사용 가능함)</li>
<li>group by에서 인덱스의 사용은 단순히 열의 위치를 기준으로 열을 참조하는 것이므로 sql실행 순서와 무관함</li>
<li>SQL 엔진은 GROUP BY 절에서 인덱스를 사용할 때, <strong>그 위치의 열을 먼저 계산</strong>하고, 이를 바탕으로 그룹화를 수행</li>
</ul>
<h3 id="참고">참고</h3>
<p><a href="https://jaehoney.tistory.com/191">https://jaehoney.tistory.com/191</a> (실행 순서 이미지 참고)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MYSQL) Recursive 문법]]></title>
            <link>https://velog.io/@jerry_bak/MYSQL-Recursive-%EB%AC%B8%EB%B2%95</link>
            <guid>https://velog.io/@jerry_bak/MYSQL-Recursive-%EB%AC%B8%EB%B2%95</guid>
            <pubDate>Wed, 07 Aug 2024 09:02:07 GMT</pubDate>
            <description><![CDATA[<hr>
<p>sql에서 재귀를 쓰는 방법이다!</p>
<p>나는 <a href="https://school.programmers.co.kr/learn/courses/30/lessons/301650">해당 문제</a>를 풀 때, 하드코딩(?)을 사용했는데 다른 사람들이 푼 걸 보니 재귀를 사용하길래 찾아봤다.</p>
<pre><code>WITH RECURSIVE CTE (CNT) AS(
    SELECT 1 

    UNION ALL

    SELECT CNT+1
    FROM CTR
    WHERE CNT&lt;4
)

SELECT *
FROM CTE;</code></pre><p>기본 구조는 위와 같다.
UNION ALL 윗 부분이 비재귀 부분이며 초기값을 설정한다.
UNION ALL을 통해서 위와 아래 쿼리를 엮어준다.
UNION ALL의 아래 부분이 재귀 부분이며 WHERE의 조건을 만족하는 동안 반복해 진행한다.
<em>여기서 CNT가 4가 될 때까지 반복됨. 3까지 아님!!! 주의!!!</em></p>
<p>초 심플 !
예시는 항상 쉽지..
</BR></p>
<h3 id="실제-사용한-재귀-쿼리">실제 사용한 재귀 쿼리</h3>
<pre><code>WITH RECURSIVE R AS (
    SELECT ID, PARENT_ID, 1 AS GEN
    FROM ECOLI_DATA
    WHERE PARENT_ID IS NULL

    UNION ALL

    SELECT A.ID, A.PARENT_ID, R.GEN+1 AS GEN
    FROM ECOLI_DATA A
    JOIN R ON A.PARENT_ID = R.ID
)</code></pre><p>내가 하고싶었던 건 parent id를 사용해 각 레코드의 세대를 구하고 싶었다.
그러기 위해선 1세대 부터 시작해 parent id를 이용해 join하고 gen+1을 통해 세대를 구해야했다.</p>
<p>그래서 비재귀 부분에 PARENT_ID가 NULL값인, 즉 1세대인 데이터만을 SELECT 했고,
재귀 부분에서 원본 데이터를 재귀 데이터(?)와 조인해 1세대의 자식 데이터만 SELECT해 GEN을 1씩 증가해줬다.</p>
<p>이렇게 하면 모든 데이터에 대해 세대를 계산할 수 있게된다!</p>
</BR>
여기서 키포인트는 INNER JOIN을 사용해서 원본 데이터에서 자식 레코드만 SELECT한다는 점인 것 같다.
(근데 재귀로 하다보면 계속해서 선택되는 레코드가 있지 않나? 그건 어떻게 처리되는거지?)

<p>*JOIN의 디폴트는 INNER JOIN이라는 점...! 계속 까먹는데 잊지 말자.
</BR></p>
<p>++) 재귀 과정에서 처리된 데이터를 구분해서 다룬다고 한다!! </p>
<pre><code>재귀 CTE는 내부적으로 처리된 데이터와 처리되지 않은 데이터를 구분하여 동작합니다.
각 재귀 단계에서 새로운 데이터만 추가되며, 이전에 추가된 데이터는 다시 처리되지 않습니다.
by chat gpt</code></pre><h3 id="union-all이-뭐였더라">UNION ALL이 뭐였더라...</h3>
<p>UNION ALL은 두 쿼리의 결과를 수직으로 합치는 것이다.</p>
<p>여기서 UNION은 두 쿼리 결과에서 중복되는 레코드를 제거하며,
UNION ALL은 중복되는 레코드 모두 제거하지 않고 합친다.</p>
<p>그렇기 때문에 UNION ALL이 UNION보다 빠른 실행 속도를 보임
하지만 이를 사용하는건 장기적으론 좋지 않음. 모델링 차원에서 테이블을 통합하는게 좋다고 한다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MYSQL) RANK 함수]]></title>
            <link>https://velog.io/@jerry_bak/MYSQL-RANK-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@jerry_bak/MYSQL-RANK-%ED%95%A8%EC%88%98</guid>
            <pubDate>Wed, 07 Aug 2024 07:40:56 GMT</pubDate>
            <description><![CDATA[<hr>
<p>RANK 함수는 말 그대로 순위를 매기는 함수이다.</p>
<p><code>RANK() OVER([PARTITION BY COLUMN_1] ORDER BY COLUMN_2 [DESC])</code></p>
<p>위와 같이 사용되는데, 여기서 파티션은 그룹별로 그룹 내에서 랭킹을 매길 때 사용한다.</p>
<p>나같은 경우는 <a href="https://school.programmers.co.kr/learn/courses/30/lessons/301649">해당 문제</a>를 풀다가 RANK에 대해 찾아보게 됐는데, 여기서는 SIZE에 대해서 상위 25%, 25%~50% 와 같이 SIZE별로 구간을 나눌 필요가 있었다. </p>
<p><code>RANK() OVER(ORDER BY SIZE_OF_COLONY DESC)</code>와 같이 사용했다.
</br></p>
<h3 id="다른-랭킹-함수">다른 랭킹 함수</h3>
<ul>
<li>DENSE_RANK</li>
</ul>
<p>RANK와 같이 중복되는 수에 대해서 같은 순위를 할당하나, <strong>다음 순위는 건너뛰지 않는다</strong>.</p>
<p>ex) 월급이 300으로 동일한 데이터가 있을 때, 이 두 데이터엔 23위라는 순위를 할당하고 다음 데이터인 280에 대해 24위를 할당한다.</p>
<ul>
<li>ROW_NUMBER</li>
</ul>
<p>RANK, DENSE_RANK와 달리 중복되는 값에 대해 같은 순위를 할당하지 않고, 모든 데이터가 <strong>고유한 순위</strong>를 갖는다.</p>
<p>ex) 월급이 300으로 동일한 데이터가 있을 때, 두 데이터에 각각 23위, 24위라는 순위를 할당한다. 동일한 값의 데이터에 대해선 데이터의 물리적 위치에 따라 순위가 결정됨</p>
<ul>
<li>PERCENT_RANK</li>
</ul>
<p>ORDER BY에 따라 백분위수 순위를 구하는 함수이다. 즉 0~1 사이의 값을 가짐.
ORDER에 따라 0부터 PERCENT RANK를 가짐. 즉 데이터가 어떤 수치에 있어 상위 몇퍼센트인지 확인하고 싶을 때 사용한다.
<code>(rank - 1) / (total_rows - 1)</code>로 계산된다.
</br></p>
<h3 id="over은-무엇인가">OVER은 무엇인가?</h3>
<blockquote>
<p>윈도우 함수(또는 분석 함수)와 함께 사용되어 특정 파티션이나 전체 데이터 집합에 대해 계산을 수행할 수 있도록 합니다. <em>by Chat GPT</em></p>
</blockquote>
<p>rank와 같은 윈도우 함수와 같이 사용되며, count, sum과 같은 집계 함수와도 함께 사용된다.</p>
<p><strong>예시)</strong> <code>ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC, employee_id)</code></p>
<p>위 쿼리는 부서별로 그룹화해(PARTITION BY) 연봉을 기준으로 내림차순 정렬하고 사원 번호로 오름차순 정렬해(ORDER BY) 고유한 순위로 rank를 매긴다(ROW_NUMBER).</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[데브코스 50일차 - 딥러닝(CNN, RNN, 교차검증, 평가지표)]]></title>
            <link>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-50%EC%9D%BC%EC%B0%A8-%EB%94%A5%EB%9F%AC%EB%8B%9D</link>
            <guid>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-50%EC%9D%BC%EC%B0%A8-%EB%94%A5%EB%9F%AC%EB%8B%9D</guid>
            <pubDate>Fri, 26 Apr 2024 04:50:46 GMT</pubDate>
            <description><![CDATA[<h3 id="키워드">키워드</h3>
<p>딥러닝, CNN, RNN</p>
<h2 id="딥러닝-개요">딥러닝 개요</h2>
<ul>
<li><p>학습을 통해 (사람처럼) 예측을 진행 → 어떻게 학습? (사람의 인지과정)</p>
</li>
<li><p>사람의 신경망(사람을 모방)을 기반으로 학습과 추론을 진행하는 학문</p>
<ul>
<li>사람의 신경 구조는 뉴런을 기본 단위로 함 (뉴런 → 신경계)</li>
<li>뉴런을 모방한 퍼셉트론을 수학적으로 모델링. 이를 기본단위로함. (퍼셉트론 → 모델)<ul>
<li>풀어야 하는 문제에 따라 다른 구조의 퍼셉트론 모임(모델)을 사용</li>
</ul>
</li>
<li>퍼셉트론을 잇는 게 <strong>가중치</strong>임</li>
<li>앞선 퍼셉트론에서 정보 출력 → 가중치를 기반으로 신호 필터링 → 신호 수신 → 연산 및 신호 전달 여부 결정 → 신호 출력 → 반복</li>
<li>퍼셉트론을 다양하게 배치해 데이터 특성에 맞는 구조를 설계 가능(모델 크기 조절 가능)</li>
</ul>
</li>
<li><p>이미지 데이터는 CNN이 기본 구조임</p>
</li>
<li><p>텍스트 데이터는 attention 모듈이 주로 사용됨. 초기엔 RNN이 사용되었음</p>
</li>
</ul>
<h2 id="이미지-처리cnn와-텍스트-처리rnn">이미지 처리(CNN)와 텍스트 처리(RNN)</h2>
<h3 id="cnn">CNN</h3>
<ul>
<li><p>사람의 ‘본다’</p>
<ul>
<li><p>분석 단위를 설정 후 정보를 추출</p>
</li>
<li><p>주변 정보를 통합해 차츰 상위 개념을 구성</p>
</li>
<li><p>목적하는 상위 개념에 도달할 때까지 반복</p>
<p>  ⇒ 즉 우리는 작은 곡선과 직선의 의미를 통합하는 과정으로 이미지를 판단</p>
</li>
</ul>
</li>
<li><p>CNN의 본다</p>
<ul>
<li><p>Convolutional filter (이미지를 부분적으로 보는 정보 처리기)</p>
</li>
<li><p>pooling (주변 정보를 모아 상위 개념을 만듦)</p>
</li>
<li><p>반복</p>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/85988127-58d1-4c3e-8531-4af16b3e1fe3/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<h3 id="rnn">RNN</h3>
<ul>
<li><p>사람이 ‘읽는다’</p>
<ul>
<li>문장 앞에서부터 한 단어씩 읽음</li>
<li>새로운 단어가 들어오면 읽고 이해</li>
<li>앞서 해석해 만들어낸 기억 정보에 정보를 추가해 <strong>기억</strong>을 업데이트</li>
<li>반복</li>
</ul>
</li>
<li><p>딥러닝(RNN)의 본다</p>
<ul>
<li>앞에서 한 단어씩 입력으로 받음</li>
<li>새 단어가 들어오면 처리해서 정보 추출</li>
<li>앞서 해석해 만들어낸 정보 덩어리에 추출한 정보를 추가해 정보를 업데이트</li>
<li>반복</li>
</ul>
</li>
<li><p>RNN</p>
<ul>
<li>이웃한 텍스트 글자 간의 연관성을 표현하는 방식으로 정보 처리 (hidden state가 기억을 담당)</li>
</ul>
</li>
<li><p>Attention</p>
<ul>
<li>모든 데이터를 같은 중요도로 처리하지 않음 → 이를 딥러닝 모델에 적용</li>
</ul>
</li>
</ul>
<h2 id="이미지-분류-실습">이미지 분류 실습</h2>
<ul>
<li><p>선택 가능한 모든 클래스에 대한 정답 점수값을 예측</p>
</li>
<li><p>ResNet ← 실습에서 사용할 모델</p>
<ul>
<li>layer 수에 따라 성능, 학습 속도가 달라짐 (이 둘은 trade-off 관계)</li>
</ul>
</li>
<li><p>데이터</p>
<ul>
<li>머신러닝 모델은 학습 과정과 똑같은 전처리를 진행한 뒤 추론을 진행해야함<ul>
<li>학습 결과물 객체(ResNet18_Weights)안에 전처리 과정이 저장되어있음</li>
<li>weights = getattr(models, weight_name).DEFAULT</li>
<li>transform = weights.transforms() → 전처리 함수</li>
<li>즉, transform(image_data) 하면 데이터가 전처리 되는 것</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="실습">실습</h3>
<ul>
<li>즉 데이터를 새롭게 불러와서 모델 학습시 사용됐던 전처리 적용</li>
<li>전처리된 데이터를 모델의 input으로 넘겨줌</li>
<li>해당 모델의 경우 학습된 클래스가 100개이므로 100개에 대한 logit(?)이 출력됨</li>
<li>softmax를 사용해 각 클래스 별 확률을 뽑고 가장 높은 확률을 갖는 클래스로 추론</li>
</ul>
<h2 id="성능-평가">성능 평가</h2>
<h3 id="교차-검증-cross-validation">교차 검증 (Cross Validation)</h3>
<p>검증 → 모델의 학습이 잘 진행되었는지(<strong>일반화 능력</strong>)를 판단하는 평가 과정</p>
<ul>
<li><p>검증 데이터가 너무 쉬우면 학습 과정과 결과를 명확히 확인할 수 없으며, 실제 적용에선 좋은 결과를 얻을 수 없음</p>
</li>
<li><p>이를 방지하기 위해 교차검증이 사용됨</p>
</li>
<li><p>교차검증</p>
<ul>
<li>전체 데이터를 여러개의 하위 데이터로 나누고, 하위 세트들의 조합은 서로 다른 방법으로 훈련과 검증에 사용해 일반화 능력을 충분히 측정하는 것</li>
<li>시간 복잡도 측면을 제외하고 일반적인 랜덤 검증 데이터 활용 방법보다 좋은 방법<ul>
<li>일반화 능력 추정, 데이터 활용 최대화</li>
</ul>
</li>
<li>조합을 어떻게 만들어내냐에 따라 여러 방법이 존재</li>
</ul>
</li>
<li><p>K-Fold CV</p>
<ul>
<li>전체 데이터를 k개의 덩어리(fold)로 나누고 각 덩어리를 순차적으로 검증 데이터로 사용</li>
<li>K번의 학습 및 평과 과정이 반복</li>
<li>모든 데이터가 학습 및 평가로 사용됨</li>
</ul>
</li>
<li><p>계층적 교차 검증</p>
<ul>
<li>k-fold와 유사하지만, 각 폴드에서 클래스의 비율을 원본 데이터셋의 클래스 비율과 유사하게 유지 (stratified)</li>
<li>각 클래스 별로 데이터를 k개로 분할해서 조합</li>
<li>k-fold의 장점과 더불어, 클래스 사이의 불균형이 있는 경우의 <strong>편향</strong>까지 고려</li>
</ul>
</li>
<li><p>LOOCV (Leave-One-Out Cross Validation)</p>
<ul>
<li>하나의 데이터만을 검증 데이터로 사용 (극단적인 K-Fold CV)</li>
<li>전체 데이터 수 = K</li>
<li>매우 정확하지만, 데이터의 크기가 크다면 매우 많은 시간이 소요됨. 작은 데이터셋에 유용</li>
</ul>
</li>
</ul>
<pre><code class="language-python"># k-fold
np.mean(cross_val_score(logistic_reg, X, y, cv=5)
# stratified 
np.mean(cross_val_score(logistic_reg, X, y, cv=StratifiedKFold(5))
# LOOCV
np.mean(cross_val_score(logistic_reg, X, y, cv=LeaveOneOut())</code></pre>
<ul>
<li><em>그러면 이렇게 교차 검증을 사용한다면 학습은 어떻게 진행되는거지..? 모든 데이터에 최소 한번 이상 학습되는건가? 아니면 평균을 내는거면, 그중 어떤 모델을 사용하는거지?</em></li>
</ul>
<h3 id="성능-평가-지표메트릭">성능 평가 지표(메트릭)</h3>
<ul>
<li><p>성능 평가: 모델의 성능을 객관적으로 측정하고 비교하는 과정에서 사용</p>
<ul>
<li>풀고자 하는 문제에 적지않은 경우로 적절한 메트릭이 없을 수 있음 → 생성 모델의 성능같은 경우</li>
</ul>
</li>
<li><p>분류 문제</p>
<ul>
<li><p>Confusion Matrix</p>
<ul>
<li>TP, FN, TN, FN (correcteness, prediction 순서)</li>
<li>precision: TP / TP+FP (positive로 예측한 것 중 실제 Positive의 비율)</li>
<li>recall: TP / TP+FN (실제 Positive 중 positive로 예측한 것의 비율)</li>
</ul>
</li>
<li><p>ROC curve</p>
<ul>
<li><p>이진 분류 문제에서 널리 사용되는 성능 측정 도구</p>
</li>
<li><p>양성과 음성을 나누는 <strong>임계값(threshold)의 변화에 따른 성능</strong>을 시각화한 그래프</p>
</li>
<li><p>X축: FPR (FP/TN+FP),  Y축: TPR (TP/FN+TP)</p>
</li>
<li><p>fpr은 작아야하고, tpr은 커야함</p>
</li>
<li><p>threshold를 조절하며 roc 값이 달라지는 걸 확인하고 적절한 threshold를 찾는다.</p>
<p>  <img src="https://velog.velcdn.com/images/jerry_bak/post/4012e037-65d3-45bd-874c-9b4d082261f1/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code>- AUC (Area Under the Curve)
    - 음성, 양성을 잘 구분할수록 좋은 분류기임 → roc curve 아래 면적으로 판단할 수 있음
    - 최대=1, 최소=0.5(사각형의 반)
    - negative와 positive를 잘 구분하지 못한 경우 auc가 작아짐

        ![](https://velog.velcdn.com/images/jerry_bak/post/32b941fd-ff1d-40be-bdec-a15585963277/image.png)</code></pre><ul>
<li>회귀 문제<ul>
<li>R^2 (결정계수)<ul>
<li>회귀 모델의 성능을 평가하는 통계적 지표임. 모델이 데이터의 변동성을 얼마나 잘 설명하는지</li>
<li>R^2 = 1- SSres/SStot</li>
<li>SSres = 모델 예측값과 실제 값 사이의 제곱합, SStot=실제 값들의 평균과 실제 값 사이의 차이 제곱합. (실제 데이터 내의 <strong>총 변동량</strong>을 나타냄, 모델이 설명해야하는 전체 변동성의 양)</li>
<li>R^2가 0이면 변동성을 설명하지 못함을 의미. 단순히 모델의 평균값을 예측</li>
<li>R^2가 1이면 모델이 데이터의 변동성을 완벽하게 설명함을 의미</li>
<li>R^2가 클수록 설명력이 크지만, <strong>과적합</strong>의 위험성을 주의해야함</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="복습">복습</h2>
<ul>
<li>독립 변수끼린 상관성이 없어야함 → 다중 공선성</li>
<li>파라미터의 선형 결합으로 수치를 계산 → 선형 회귀<ul>
<li>비용함수로 MSE 사용하며, 정규 방정식, 경사 하강법을 사용해 최적화</li>
</ul>
</li>
<li>선형 모델로 logit을 예측해 확률 추정으로 선형 분류<ul>
<li>비용함수로 로그 손실을 사용하고, 경사하강법으로 최적화</li>
</ul>
</li>
<li>SVM은 두 데이터를 분류하는 최적의 직선을 찾는 문제 → 마진을 최대화(최대 마진 초평면)<ul>
<li>하드, 소프트 마진(슬랙변수), 선형, 비선형 SVM (커널 트릭 활용)</li>
</ul>
</li>
<li>데이터 내에 존재하는 엔트로피, 지니 불순도를 줄이는 방향으로 Tree를 생성 → Decision Tree</li>
<li>사람이 보는 방식으로 모델이 시각적 능력을 얻게함 → CNN (convolutional filter, pooling)</li>
<li>텍스트와 같은 순차 데이터를 처리하기 위해 RNN 사용 (hidden state)</li>
<li>전체 데이터를 K개의 클러스터로 나누는 비지도 학습법 (엘보우 메소드로 k를 찾기)<ul>
<li>sse, 실루엣 계수로 평가</li>
</ul>
</li>
<li>이상치 데이터 고립은 낮은 수준의 분할 과정으로도 가능 → Isolation Forest</li>
</ul>
<h2 id="다음-스텝-소개">다음 스텝 소개</h2>
<ul>
<li>지도학습 알고리즘<ul>
<li>앙상블, 랜덤 포레스트, GBM, XGBoost</li>
</ul>
</li>
<li>비지도학습 알고리즘<ul>
<li>차원축소(PCA, t-SNE), DBSCAN</li>
</ul>
</li>
<li>캐글 데이터 분석 추천<ul>
<li>공부하고 싶은 분야, 관심있는 데이터 (취업 희망 회사가 다루는 데이터면 좋을듯)</li>
<li>기본적이지만 매우 중요한 EDA 진행</li>
<li>전처리(논리 필요)와 학습 진행</li>
<li>해석 → 본인 나름대로 모델 결과 해석 진행</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[데브코스 49일차 - 머신러닝(K-means Clustering, Isolation Forest)]]></title>
            <link>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-49%EC%9D%BC%EC%B0%A8-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9DK-means-Clustering-Isolation-Forest</link>
            <guid>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-49%EC%9D%BC%EC%B0%A8-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9DK-means-Clustering-Isolation-Forest</guid>
            <pubDate>Thu, 25 Apr 2024 06:44:29 GMT</pubDate>
            <description><![CDATA[<h3 id="키워드">키워드</h3>
<p>k-means clustering</p>
<h2 id="k-means-clustering">K-means Clustering</h2>
<ul>
<li><p>K-평균 군집화</p>
<ul>
<li>전체 데이터를 K개의 덩어리(클러스터)로 나누는 비지도 학습법</li>
<li>각 클러스터의 좌표 값의 평균으로 중심을 정할 수 있음</li>
</ul>
</li>
<li><p><strong>로이드 알고리즘</strong> vs 엘칸 알고리즘(거리 계산시 삼각 부등식 사용)</p>
</li>
<li><p>순서</p>
<ul>
<li>초기화<ul>
<li>K개의 클러스터 중심점(최종 결과에 큰 영향을 미칠 수 있음)을 임의로 선택</li>
<li>각 중심점이 최대한 멀어질 수 있도록 k-means++ 초기화 방법을 많이 사용</li>
</ul>
</li>
<li>할당<ul>
<li>각 데이터 포인트를 각 클러스터 중심과 (유클리드) 거리를 계산해 가장 가까운 중심의 클러스터에 할당됨</li>
</ul>
</li>
<li>업데이트<ul>
<li>각 클러스터의 데이터 평균 위치로 중심의 위치를 업데이트</li>
</ul>
</li>
<li>반복<ul>
<li>다시 클러스터 중심과 각 데이터 포인트들과의 거리를 계산해 클러스터 재할당</li>
<li>중심의 위치 변화가 없거나, 클러스터 변화가 없거나, 지정된 횟수에 도달할 때까지 반복</li>
</ul>
</li>
</ul>
</li>
<li><p>엘보우 메소드</p>
<ul>
<li>적절한 K를 고르는 방법. 적절한 K를 선택해야 데이터가 잘 나뉘게 됨</li>
<li>클러스터 수를 늘려가며 각각에 대한 클러스터링 성능을 측정</li>
<li>클러스터의 성능은 SSE(Sum of Squared Errors-각 클러스터 내의 데이터포인트와 클러스터 중심간의 거리의 제곱합) 값을 활용<ul>
<li>무조건 SSE가 낮다고 좋은 게 아님 → SSE의 감소율이 급격히 줄어드는 지점을 최적 클러스터 수(K)로 간주</li>
</ul>
</li>
<li>직접 보고 골라야함</li>
</ul>
</li>
<li><p>실루엣 계수 (보조적인 평가 방법)</p>
<ul>
<li>클러스터 안의 응집도와 서로 다른 클러스터 간의 분리도를 고려해 군집화의 품질을 평가하는 방법</li>
<li>응집도(↓, a(i)): 특정 데이터에 대해 동일한 클러스터 안에 들어있는 다른 데이터들과의 평균 거리</li>
<li>분리도(↑, b(i)): 특정 데이터에 대해 다른 클러스터 중 가장 가까운 클러스터의 중심까지의 거리</li>
<li>s(i) = b(i) - a(i) / max(a(i), b(i))<ul>
<li>최대값 1 → a(i)가 거의 0에 근접해 b(i)만 남는 상황 → 좋은 상황</li>
<li>최소값 -1 → b(i)가 작아지고 오히려 a(i)가 커지는 경우 → 나쁜 상황</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="실습">실습</h3>
<ul>
<li><p>데이터: mall customer data: 200명의 쇼핑몰 고객에 대한 정보 데이터</p>
<ul>
<li>나이, 연간 소득, 쇼핑 점수와 같은 수치형 데이터는 스케일 매칭해줘야 함 → 이는 거리 기반 군집화에서 중요한 요소임</li>
</ul>
</li>
<li><p>문제: 주어진 고객 데이터를 바탕으로 고객을 세분화, 군집화</p>
<ul>
<li>즉 나이, 성별, 소득, 쇼핑 점수 등이 입력으로 들어오면 몇 번 클러스터인지 분류해냄</li>
</ul>
</li>
<li><p>전처리</p>
<ul>
<li>성별 (카테고리 데이터) 원핫 인코딩</li>
<li>수치형 데이터 스케일링 (standard scale)</li>
</ul>
</li>
<li><p>K 값을 찾으려면 sse, 실루엣 계수를 살펴보고 결정</p>
<ul>
<li>실루엣 계수 간 차이가 크지 않다면 작은 K를 기준으로 하는 게 좋은 선택</li>
</ul>
</li>
<li><p>sse, 실루엣 계수들을 이용해 결과를 평가하는 것도 좋지만, 결국은 데이터를 그려보고 해석해야함</p>
</li>
<li><p>t-sne를 이용해 4차원 데이터를 2차원으로 변환</p>
</li>
<li><p>kmeans.labels_ 로 각 데이터에 클래스 번호를 붙인 데이터를 볼 수 있음</p>
</li>
<li><p>이 데이터의 기술 통계를 확인해 각 클러스터의 특징을 살펴본다.</p>
<ul>
<li>만들어진 클러스터가 어떤 의미가 있는지 도메인 지식을 이용해 추측해야함</li>
</ul>
</li>
</ul>
<h2 id="이상탐지">이상탐지</h2>
<ul>
<li>이상치 판단 및 제거 (전통적인 통계 기반 방법)<ul>
<li>IQR  → 1사분위수(Q1), 3사분위수(Q3)</li>
<li>계산이 복잡하지 않고 해석이 직관적임. 하지만 데이터가 대칭이 아니거나 복잡한 분포를 갖고있다면 오인식의 가능성 커짐</li>
</ul>
</li>
<li>머신러닝을 활용한 이상탐지<ul>
<li>모델로 데이터의 패턴을 익히고 그 패턴에서 벗어난 데이터를 이상치로 취급</li>
<li>복잡한 데이터의 패턴에 적응적</li>
<li>but, 모델이 복잡하고 사람이 해석하기 어려울 수 있으며, 양질의 데이터가 다수 필요</li>
</ul>
</li>
</ul>
<h3 id="isolation-forest">Isolation Forest</h3>
<ul>
<li><p>정상 데이터는 다른 비슷한 데이터와 밀도있게 모여있을 것. 반면 이상치 데이터는 밀도가 낮은 공간에 존재 → 하나의 데이터를 고립하도록 어떤 특성과 그것의 분할값을 기준으로 나눔</p>
<ul>
<li><p>like Decision Tree..</p>
</li>
<li><p>이상치 데이터는 낮은 수준(depth)의 분할 과정으로도 쉽게 고립시킬 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/3b0f758e-c737-4c76-b237-60cd4facd932/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>![](https://velog.velcdn.com/images/jerry_bak/post/7dfcaed1-c88c-4c80-b64d-b9d450a47af3/image.png)</code></pre><ul>
<li>과정<ul>
<li>데이터 준비<ul>
<li>전체에서 무작위로 서브 데이터셋 선택 (하나의 데이터가 여러 서브 데이터셋에 포함될 수 있음)</li>
</ul>
</li>
<li>트리 생성<ul>
<li>하나의 서브 데이터셋마다 개별 Isolation Tree(ITree)를 준비</li>
</ul>
</li>
<li>고립 시작<ul>
<li>각 트리에 소속된 데이터셋을 하나씩 고립</li>
<li>임의의 특성과 임의의 특성 분할값을 선택. 데이터셋이 리프 노드에 도달할 때까지 반복</li>
<li>각 데이터포인트는 리프노드까지 도달한 깊이를 저장하고있음</li>
</ul>
</li>
<li>고립 완료<ul>
<li>하나의 트리에 소속된 모든 데이터셋을 전부 고립</li>
</ul>
</li>
<li>이상치 점수 계산<ul>
<li>평균 깊이를 바탕으로 특정 함수를 통해 각 데이터 포인트의 이상치 점수를 계산</li>
</ul>
</li>
<li>이상치 추출<ul>
<li>이상치 점수와 특정 임계값을 비교해 이상치 추출</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="language-python">n_estimators = 고립 트리의 수(=서브 데이터셋 수, 이 값이 클수록 안정성과 정확성 향상 but 메모리 사용량도 증가)
max_samples = 서브 데이터셋에 포함될 최대 데이터 포인트의 수
contamination = 전체 데이터셋에서 이상치 데이터가 차지할 비율 (모른다면 &#39;auto&#39;로 설정)</code></pre>
<ul>
<li>평가<ul>
<li>이상치 데이터 정답을 알고 있다면, 이상 데이터를 양성으로 놓고 분류 형태의 문제로 평가 가능</li>
<li>정확도, 재현율, 정밀도, f1 score 등을 이용</li>
<li>정답이 없다면, 시각화를 통한 전문가 검토 진행</li>
</ul>
</li>
</ul>
<h3 id="실습-1">실습</h3>
<ul>
<li><p>credit card fraud detection 데이터</p>
</li>
<li><p>입력: 거래 관련 데이터(time, amount, v1~v28) 출력: 이상치 여부</p>
</li>
<li><p>time(시계열 데이터)의 경우 주기성을 갖고있음 → 주기함수를 적용하는 것도 좋은 방법이지만, 여기선 추가적인 정보가 부족.</p>
<ul>
<li>큰 outlier가 없어보이므로 min-max scaler을 사용</li>
</ul>
</li>
<li><p>amount는 치우침이 있지만 의미가 있기 때문에 log 스케일링 진행</p>
</li>
<li><p>V 데이터는 pca를 통해 차원 축소된 데이터기 때문에 어떤 의미를 갖는 데이터인지는 알 수 없음</p>
</li>
<li><p>confusion matrix를 통해 결과 확인. TP 값이 커야 잘 한 분류임</p>
</li>
<li><p>쉬운 task는 아니다.. (데이터에서 양성의 비율이 작기 때문에)</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[데브코스 48일차 - 머신러닝(SVM, Decision Tree, 비지도 학습)]]></title>
            <link>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-48%EC%9D%BC%EC%B0%A8-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9DSVM-Decision-Tree-%EB%B9%84%EC%A7%80%EB%8F%84-%ED%95%99%EC%8A%B5</link>
            <guid>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-48%EC%9D%BC%EC%B0%A8-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9DSVM-Decision-Tree-%EB%B9%84%EC%A7%80%EB%8F%84-%ED%95%99%EC%8A%B5</guid>
            <pubDate>Thu, 25 Apr 2024 06:43:16 GMT</pubDate>
            <description><![CDATA[<h3 id="키워드">키워드</h3>
<p>SVM, Decision Tree, 비지도학습</p>
<h2 id="svm">SVM</h2>
<h3 id="svm-선형-이론">SVM (선형 이론)</h3>
<ul>
<li><p>각 클래스의 데이터 샘플로부터 거리(마진)가 가장 멀리 위치해있다 → 일반화 성능이 좋다</p>
</li>
<li><p>마진을 구성하는 데이터 포인트를 서포트 벡터 라고 함</p>
</li>
<li><p>SVM의 경우 마진을 최대화하는 최적 직선(최대 마진 초평면)을 만드는 것이 목적임</p>
</li>
<li><p>최적화 문제</p>
<ul>
<li>평행한 두 직선 위에 서포트 벡터가 존재</li>
<li>서포트 벡터에 대해 |w^Tx+b|</li>
<li>마진 = 2/||w||</li>
</ul>
</li>
<li><p>최적화 문제 2</p>
<ul>
<li>마진을 키우면서 모든 데이터를 알맞게 분류</li>
</ul>
</li>
<li><p>SVM 종류</p>
<ul>
<li>하드 마진 svm<ul>
<li>어떠한 오분류도 허용하지 않고 완벽한 선형 모델로 분리가 가능</li>
</ul>
</li>
<li>소프트 마진 svm<ul>
<li>데이터가 섞인 경우 완벽한 선형 분리가 불가능함</li>
<li>어느정도의 오분류를 허용하면서 오차 발생에 따른 패널티를 비용함수에 부과</li>
<li>하드마진 svm 최적화 과정에 규제 패널티를 도입해 일반화 성능을 올림</li>
</ul>
</li>
</ul>
</li>
<li><p>슬랙 변수</p>
<ul>
<li><p>소프트 마진 svm에서 사용하는 개념. 각 데이터 포인트 당 하나의 슬랙변수가 할당</p>
</li>
<li><p>마진을 얼마나 위반하는지를 수치적으로 나타냄</p>
</li>
<li><p>슬랙변수를 최소화하고자 함 → 규제로 사용, 규제의 정도를 정해주기 위해 c라는 하이퍼 파라미터를 사용</p>
<p>  <img src="https://velog.velcdn.com/images/jerry_bak/post/9b14d37e-264b-4a2a-a9ac-baa47df0081e/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>- 마진을 위반하지 않은 데이터, 슬랙변수=0
    - 서포트 벡터, 서포트벡터보다 멀리있는 데이터
- 마진을 위반한 데이터
    - 마진 경계~결정 경계: 0&lt;슬랙변수&lt;1
    - 결정 경계 이후: 1&lt;슬랙변수 → 올바르지 못한 클래스로 분류됨
- 1-슬랙변수: 결정 경계에서 슬랙변수만큼 벗어날 수 있음을 허용하는 과정</code></pre><h3 id="선형-실습">선형 실습</h3>
<pre><code class="language-sql">SVC(kernel=&#39;linear&#39;, C=0.1)</code></pre>
<ul>
<li>C의 값이 크면 경계를 위반하는 것을 허용하지 않는 것이고, C값이 작으면 어느정도의 위반을 허용하는 것이다.</li>
<li>C에 따라서 슬랙 변수 크기도 달라짐</li>
<li>C가 커지면 경계를 위반한 것에 대해 강한 패널티 적용, 결정 경계와 마진 경계 사이 거리가 좁아짐</li>
</ul>
<h3 id="svm-비선형">SVM (비선형)</h3>
<ul>
<li><p>데이터의 복잡성으로 인해 선형 결정 경계로 데이터를 분류할 수 없는 경우가 많음</p>
</li>
<li><p>저차원에서 선형으로 나뉘지 않는 데이터를 고차원으로 변형하면 초평면으로 분리할 수 있음</p>
<p>  <img src="https://velog.velcdn.com/images/jerry_bak/post/d0eeda70-c2c6-4472-b861-550d50386658/image.png" alt=""></p>
</li>
</ul>
<pre><code>- 차원이 증가하면 데이터 포인트 간의 상대 거리는 증가
- 하지만 계산량이 늘어난다는 단점이 있음
- 이를 해결하기 위해 커널 트릭이 제시됨 → 높은 차원의 장점을 취하면서도 계산의 복잡성이 증가되지 않는 기법</code></pre><ul>
<li>커널 트릭<ul>
<li>데이터 포인트 사이 내적 계산이 수행되어야 함 → 계산량이 매우 많이 소모됨(고차원 벡터)</li>
<li>이때, 고차원의 내적 연산 결과와 똑같은 결과를 보여주는 저차원 벡터끼리의 연산 함수가 있다면? → 이게 <strong>‘커널’</strong></li>
<li>비선형 SVM에서 많이 사용하는 커널 함수<ul>
<li>다항 커널: 다항식으로 보냈을 때의 효과를 누리게 함</li>
<li>RBF 커널 (가우시안 커널): 데이터 간 거리에 초점을 맞춘 커널, 일반적으로 많이 사용됨</li>
<li>시그모이드 커널: 이진 분류에 최적화</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="svr-support-vector-regression">SVR (Support Vector Regression)</h3>
<ul>
<li><p>회귀 문제로 확장한 SVM 방법</p>
</li>
<li><p>주어진 데이터에서 가능한 많은 데이터 포인트를 포함하는 마진 구역(엡실론(허용 오차) 내부의 구역)을 설정</p>
<ul>
<li><p>그 구역안에서 회귀 곡선(혹은 초평면)을 찾는 걸 목표로 함</p>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/aac72b60-1fc8-4221-8dbb-61bdec30c234/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<h2 id="decision-tree">Decision Tree</h2>
<ul>
<li>데이터를 나누기 위한 조건은 다양함. 어떤 조건을 선택하냐에 따라 분류 속도가 달라질 수 있음</li>
</ul>
<h3 id="용어">용어</h3>
<ul>
<li>노드: 데이터에 대한 특정 질문이나 조건. 데이터 분류 과정에서 사용<ul>
<li>루트 노드: 트리 가장 상단에 위치한 노드</li>
<li>분할 노드(=결정 노드): 데이터를 더 작은 하위 집합으로 나누는 데 사용되는 중간 노드</li>
<li>리프 노드(=터미널 노드): 트리 말단에 위치한 노드. 자식 노드가 없음</li>
</ul>
</li>
<li>엣지: 노드와 노드 연결 선</li>
</ul>
<h3 id="분류-decision-tree">분류 Decision tree</h3>
<ul>
<li><p>데이터 분할하는 기준을 결정하는 데 사용되는 방법론</p>
</li>
<li><p>엔트로피: 어떤 상황이나 현상이 품고있는 불확실성 (포함하는 정보량과 반비례)</p>
<p>  <img src="https://velog.velcdn.com/images/jerry_bak/post/b405157f-1217-4140-b4e8-9f8d81093aa8/image.png" alt=""></p>
</li>
</ul>
<pre><code>- 불확실성이 높은 상황일수록, 다양한 사건의 발생 확률이 균일
- 결정 트리 관점에서 본다면, 각 노드에 포함되는 데이터의 순도(클래스)에 따라 엔트로피가 계산될 수 있음
- 순도가 높아지도록(엔트로피가 낮아지도록) 트리 구성
- 부모 노드와 자식 노드들의 엔트로피를 계산해, 엔트로피가 낮아지는 방향으로 결정 경계를 선정! → **정보 이득** (최대화)</code></pre><ul>
<li><p>지니 불순도: 데이터의 클래스 분포의 불균형을 평가하는 방법 (순도를 측정하는 또다른 방법)</p>
<ul>
<li><p>0~1의 값을 가짐 → 0: 순도가 높은 상태</p>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/e6661061-8e4b-42a1-acb7-2c9a6a72e4df/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>- 즉 하나의 클래스로만 구성되어있다면(순도가 높다면) p^2의 sum이 1이 되어 지니 불순도가 0이 됨(불균형이 없다는 것을 의미 → 순도가 높음을 의미)
- 마찬가지로 순도가 높아지도록(지니 불순도가 낮아지도록) 트리를 구성</code></pre><pre><code class="language-python">DecisionTreeClassifier(criterion=&#39;entropy&#39;, # &#39;entropy&#39;, &#39;gini&#39;
                                             max_depth=3, # 최대 깊이
                                             min_sample_split=3) # 데이터 분류를 위한 최소 데이터 수</code></pre>
<h3 id="회귀-decision-tree">회귀 Decision tree</h3>
<ul>
<li><p>MSE 최소화 방식</p>
<ul>
<li><p>각 노드에서 실제 정답과 예측값 사이의 평균 제곱 오차(mse)의 평균을 계산하고 이 값을 최소화하는 노드를 찾아가는 방식으로 트리가 만들어짐</p>
</li>
<li><p>특정 포인트(x)에서 데이터를 두 그룹으로 나누고 각각에서 mse가 최소가 되는 선(x 평행)을 그음 → 각 그룹을 또 두 그룹으로 나눔 → 반복…</p>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/7e28bc9e-affb-47af-95f5-b64659a6b0b2/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>- max depth가 너무 크면 각 데이터에 너무 맞춰져서 오버피팅 되는 선을 그을것</code></pre><ul>
<li><p>장점</p>
<ul>
<li>해석 용이성</li>
<li>스케일링에 둔감함</li>
</ul>
</li>
<li><p>단점</p>
<p>  <img src="https://velog.velcdn.com/images/jerry_bak/post/76831051-5846-49c5-86e8-eda5bc99be28/image.png" alt=""></p>
</li>
</ul>
<pre><code>- 축에 수직인 방향으로 데이터가 분할됨 → 모서리 부분에서 오버피팅이 나타나 일반화가 어려울 수 있음
    - 필요시 주성분 분석을 통한 데이터 회전이 필요할 수 있음
- 노이즈에 굉장히 민감 (결정 경계면 지정에 영향을 줄 수 있음)
- depth가 깊다면 강한 오버피팅의 위험이 큼</code></pre><ul>
<li>여러개의 tree를 만들어서 다수결 결정을 할 수도 있음 → random forest</li>
</ul>
<h2 id="실습">실습</h2>
<p>SVM 학습 시간은 선형 모델에 비해 오래 걸림</p>
<p>Decision Tree는 SVM에 비해 짧음</p>
<ul>
<li><p>성능 평가 지표</p>
<ul>
<li>정확도 (accuracy)<ul>
<li>전체 중 얼마나 정답을 맞췄는지 (TP+TN/all)</li>
</ul>
</li>
<li>정밀도 (precision)<ul>
<li>예측한 양성 결과 중 실제로 얼마나 진짜 양성인지 (TP / TP+FP)</li>
<li>ex) 스팸 메일 중 100% 스팸 메일만 분류해내는 게 중요</li>
</ul>
</li>
<li>재현율 (recall)<ul>
<li>실제 양성 중 얼마나 양성을 찾아냈는지 (TP / TP+FN)</li>
<li>ex) 암의 경우, 100% 암이 아니더라도 골라내는 게 중요</li>
</ul>
</li>
<li>정밀도와 재현율은 trade-off 관계에 있음</li>
<li>f1 score<ul>
<li>재현율과 정밀도의 조화 평균</li>
<li>둘 다 적당히 좋은 값을 가져야 높은 f1 score를 가질 수 있음</li>
</ul>
</li>
</ul>
</li>
<li><p>learning curve</p>
<ul>
<li>모델의 크기가 커지고 복잡도가 증가하면 모델의 성능은 올라감</li>
<li>하지만 과적합이 발생하면 오히려 성능 하락 → 학습 데이터에 대한 성능은 지속적으로 상승하지만, 평가 데이터에 대한 성능이 하락</li>
<li>평가 데이터에 대한 성능이 낮아지기 시작하는 지점의 세팅을 이용해 모델을 최적화해야함</li>
</ul>
</li>
<li><p>Decision Tree에서 max_depth를 변경해 실험해보며 러닝 커브를 그려보고 적합한 max_depth를 찾음 → 더 높은 성능을 보임</p>
</li>
<li><p>SVM도 C 상수값을 변경해보거나, 커널을 변경해봄으로써 최적화해볼 수 있음</p>
</li>
</ul>
<h2 id="비지도학습">비지도학습</h2>
<h3 id="비지도-학습-un-supervised-learning">비지도 학습 (un-supervised learning)</h3>
<ul>
<li><p>정답 레이블이 지정되지 않은 데이터로부터 <strong>패턴</strong>을 찾아내는 학습 방법론</p>
</li>
<li><p>라벨링 할 필요가 없어 비용과 시간이 절약</p>
</li>
<li><p>데이터 내부의 구조를 탐색하기때문에 다양한 통찰이 도출될 수 있음</p>
</li>
<li><p>but, 결과를 해석하기 어려울 수 있음</p>
</li>
<li><p>명확한 정답이 없어 모델의 성능 객관화와 평가가 어려움</p>
</li>
<li><p>노이즈에 매우 민감함</p>
</li>
<li><p>군집화 (Clustering)</p>
<ul>
<li>데이터를 유사한 특성(내재된 구조)을 가진 하위 그룹으로 분할</li>
<li>군집화 한 데이터의 의미는 사람이 부여해야함!! → 전문가가 투입돼야함</li>
</ul>
</li>
<li><p>차원 축소 (Dimensionality Reduction)</p>
<ul>
<li>고차원 데이터를 핵심적인 특성을 유지하면서 특성(컬럼)을 줄여 더 낮은 차원의 표현으로 만드는 과정</li>
<li>데이터 시각화, 노이즈 감소, 데이터 해석 등을 목적으로 함</li>
</ul>
</li>
<li><p>이상 탐지</p>
<ul>
<li>데이터에서 비정상적인 패턴, 예외적 사례를 탐지</li>
<li>일반적인 특성에서 많이 벗어난 데이터를 식별하는 과정에 사용 → 보안, 금융, 의료 분야에서 중요한 역할</li>
</ul>
</li>
</ul>
<h3 id="비지도학습-대표-알고리즘">비지도학습 대표 알고리즘</h3>
<ul>
<li>군집화<ul>
<li>K-means<ul>
<li>데이터를 K개의 클러스터로 그룹화 → 각 클러스터의 중심을 계산하고 각 데이터 포인트를 가장 가까운 클러스터 중심에 할당 (반복을 통해 중심을 업데이트하며 최적화)</li>
</ul>
</li>
<li>계층적 군집화<ul>
<li>데이터 포인트를 개별 클러스터로 가정해 시작 → 점차 병합, 세분화</li>
</ul>
</li>
<li>DBSCAN<ul>
<li>데이터가 모여있는 밀도를 기반으로 클러스터 형성. 너무 저밀도면 이상치로 분류</li>
</ul>
</li>
</ul>
</li>
<li>차원 축소<ul>
<li>주성분 분석 (PCA)<ul>
<li>데이터의 <strong>분산</strong>을 최대한 보존하는 방향의 축을 찾아 해당 축을 기준으로 고차원 데이터를 저차원으로 변환</li>
</ul>
</li>
<li>t-SNE<ul>
<li>고차원 데이터의 <strong>구조적 특성</strong>을 보존하면서 저차원으로 매핑</li>
<li>이를 이용해 시각화를 많이 함</li>
</ul>
</li>
<li>오토 인코더 (Autoencoder: encoder+decoder)<ul>
<li>딥러닝을 이용한 차원 축소 기법 → 입력 데이터를 저차원으로 압축 후 다시 원래 차원으로 복원하는 방식으로 핵심 특징을 만들어냄</li>
</ul>
</li>
</ul>
</li>
<li>이상 탐지<ul>
<li>Isolation Forest<ul>
<li>tree를 기반으로 특정 데이터 포인트를 격리시키는 데 필요한 분할 수를 기준으로 이상치를 탐지 (떨어져있는 데이터의 경우 분할수가 작음)</li>
</ul>
</li>
<li>One-class SVM<ul>
<li>정상 데이터만을 이용해 SVM을 학습 → 이상치를 받으면 output 점수가 낮음 → 이상치 탐지</li>
</ul>
</li>
<li>LOF (Local Outlier Factor)<ul>
<li>주어진 데이터 주변의 데이터 밀도를 계산 (밀도가 낮으면 이상치!)</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[데브코스 47일차 - 머신러닝(선형회귀/분류)]]></title>
            <link>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-47%EC%9D%BC%EC%B0%A8-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%EC%84%A0%ED%98%95%ED%9A%8C%EA%B7%80%EB%B6%84%EB%A5%98</link>
            <guid>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-47%EC%9D%BC%EC%B0%A8-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%EC%84%A0%ED%98%95%ED%9A%8C%EA%B7%80%EB%B6%84%EB%A5%98</guid>
            <pubDate>Thu, 25 Apr 2024 06:40:09 GMT</pubDate>
            <description><![CDATA[<h3 id="키워드">키워드</h3>
<p>사이킷런</p>
<h3 id="패키지-소개">패키지 소개</h3>
<ul>
<li>사이킷런: 다양한 머신러닝 알고리즘이 구현되어있는 오픈소스 패키지<ul>
<li>데이터 처리, 파이프라인, 학습 알고리즘, 전/후 처리 등 다양한 기능</li>
</ul>
</li>
<li>객체 메소드<ul>
<li>Estimator: fit()으로 학습 진행</li>
<li>Predictor: predict()로 예측 수행</li>
<li>Transformer: transform(), fit_transform()으로 데이터 변환<ul>
<li>StandardScaler()가 이 중 하나임</li>
</ul>
</li>
<li>Model: score()로 성능 평가</li>
</ul>
</li>
<li>파이프라인: 머신러닝 워크플로우의 여러 단계를 하나의 수준으로 연결하는 작업<ul>
<li>가장 마지막을 제외하고는 모두 Transformer여야 함 (다음 과정으로 데이터를 넘겨주기 때문에</li>
<li>마지막은 estimator, predictor, transformer가 올 수 있다. 이에 따라 파이프라인의 용도가 정해짐</li>
</ul>
</li>
<li>Numpy<ul>
<li>파이썬에서 과학적인 계산을 위한 패키지. 사이킷런에서 사용하는 기본 데이터 구조가 np.array임</li>
</ul>
</li>
<li>Pandas<ul>
<li>데이터 분석 기능을 제공하며, 데이터를 읽어들이는 데 사용됨</li>
</ul>
</li>
<li>Matplotlib<ul>
<li>데이터를 파탕으로 선 그래프, 히스토그램, 산점도 등의 다양한 시각화를 지원</li>
</ul>
</li>
</ul>
<h3 id="지도학습의-개념과-대표-알고리즘">지도학습의 개념과 대표 알고리즘</h3>
<ul>
<li>문제(Task): 머신러닝 기법을 활용해 해결하고자 하는 대상</li>
<li>지도학습에서의 문제<ul>
<li>회귀 문제 (Regression): 입력 데이터를 바탕으로 정확한 숫자 형태의 결과를 예측</li>
<li>분류 문제 (Classification): 정해진 보기(class) 중 하나로 분류하는 문제</li>
</ul>
</li>
<li>데이터 분할<ul>
<li>학습(정보 습득 및 이해) → 검증 (연습, 학습 상태 확인) → 시험(검증을 통해 최적의 공부 상태를 만들고 시험)</li>
<li>학습 데이터: 순수하게 학습을 하는 데 사용하는 데이터 (전체 데이터의 약 80%)</li>
<li>검증 데이터: 모델이 어느정도 학습되었는지를 학습 중 주기적으로 확인하는 데 사용 (약 10%)</li>
<li>테스트 데이터: 모델의 최종 성능을 평가하기 위해 사용되는 데이터, 학습 과정에선 절대 사용되지 않음 (약 10%)</li>
</ul>
</li>
<li>오버피팅<ul>
<li>모델이 특정 훈련 데이터에 지나치게 학습되어 새로운 데이터에서 잘 작동하지 않는 상태를 의미. 즉 일반화 능력이 떨어진 상태</li>
<li>데이터 양을 늘리거나, 모델의 복잡도를 줄이거나, 규제(정규화 기법)를 사용해 문제 해결</li>
</ul>
</li>
<li>손실함수<ul>
<li>모델의 예측값과 실제 정답 사이의 차이를 측정하는 지표</li>
<li>모델의 학습은 손실을 줄이는 과정으로 진행됨</li>
<li>손실함수의 종류는 문제의 유형(회귀, 분류)에 따라 다름<ul>
<li>회귀 → mse, 분류 → ce</li>
</ul>
</li>
</ul>
</li>
<li>파라미터<ul>
<li>모델이 내부적으로 갖고있는 변수를 의미. 데이터로부터 학습하는 패턴 관계를 표현, 모델의 예측 성능에 직접적인 영향을 미침</li>
<li>최적화란, 모델의 성능을 최대화하거나 오류를 최소화하기 위해 파라미터를 조절하는 과정. 즉 loss가 최소가 되는 파라미터를 찾는 것을 목표로함</li>
</ul>
</li>
<li>분류 문제 대표 알고리즘<ul>
<li>로지스틱 회귀: 이진 분류에 적합. 각 클래스의 확률을 예측</li>
<li>결정 트리 분류기: 데이터를 잘 분할하는 결정 트리를 사용해 분류를 수행</li>
<li>랜덤 포레스트: 여러 결정 트리의 결합으로 앙상블 기법에 해당. 과적합 문제를 방지</li>
<li>서포트 벡터 머신: 데이터를 최적으로 분리하는 결정 경계를 찾는 데 강력한 알고리즘</li>
</ul>
</li>
<li>회귀 문제 대표 알고리즘<ul>
<li>선형 회귀: 독립 변수와 종속 변수간의 선형 관계를 모델링</li>
<li>라쏘 혹은 릿지 회귀: 규제 기법을 이용해 과적합을 방지하는 선형 모델</li>
<li>결정 트리 회귀: 결정 트리를 회귀 문제에 적용</li>
<li>서포트 벡터 회귀: SVM을 회귀에 적용한 알고리즘</li>
<li>K-최근접 이웃 회귀: 주어진 데이터 포인트에서 가장 가까운 k개의 이웃 데이터 평균으로 예측값을 결정. (데이터 의존도가 높음 → 비모수적 추정)</li>
</ul>
</li>
</ul>
<h2 id="선형-회귀와-선형-분류">선형 회귀와 선형 분류</h2>
<h3 id="선형-관계">선형 관계</h3>
<ul>
<li>예를 들어 과자와 우유를 구매한다면, 전체 비용은 구매하는 과자와 우유의 개수에 영향을 받음</li>
<li>구매하는 과자의 개수, 우유의 개수는 서로 영향을 받지 않음 (독립 변수→ 상관성이 없어야 함)</li>
<li>이처럼 독립 변수(과자/우유의 개수)가 파라미터(가격) 값 만큼 일정한 비율로 결과 종속 변수(총 가격)에 영향을 미치는 관계를 선형 관계라 함.</li>
<li>파라미터들이 어떤 실수와 가중합(곱셈, 덧셈)으로 표현된 것을 선형 결합이라고 함<ul>
<li><code>y = w1x1 + w2x2 + … + wnxn</code> → 여기서 x는 독립변수이자 입력 데이터이며, w는 파라미터를 의미함. y는 종속 변수를 의미</li>
</ul>
</li>
<li>만약 두 독립 변수 사이에 높은 상관관계가 있다면 다중공선성 이라는 문제를 일으킴</li>
</ul>
<h3 id="정규-방정식">정규 방정식</h3>
<ul>
<li>선형 회귀 모델을 사용한다는 것은 입력 데이터 특징 사이의 독립성을 가정하고, 데이터 특징에 대한 선형 결합으로 회귀 문제를 풀겠다는 의미</li>
<li><code>y햇 = w0 + w1x1 + w2x2 + … + wnxn = Xw</code> → 독립 변수들이 선형으로 결합되어있음<ul>
<li>w0은 y절편 (x랑 상관 없이 y에 직접적으로 영향을 미치는 변수) = 편향</li>
<li>X는 행렬(행은 하나의 데이터를 의미, 열은 특성을 의미), 0번째 열엔 모두 1이 들어감(w0을 위해)</li>
</ul>
</li>
<li>비용 함수<ul>
<li>목표값과 예측값 사이의 계산을 통해 비용 함수를 정의. 즉 비용이 작아지면 정답과 예측값의 차이가 작아지는 것</li>
<li>두 값 사이의 양적 차이(잔차)의 제곱 평균(MSE)로 비용함수를 정의<ul>
<li>J(w) = (y-Xw)^2</li>
<li>왜 절댓값을 사용할 수도 있는데 제곱을 사용하는걸까?</li>
</ul>
</li>
<li>즉 비용 함수를 최소화하는 파라미터들을 찾아야한다. min W ⇒ J(w)의 최소값 → 최소 제곱</li>
</ul>
</li>
<li>최적화 방법론<ul>
<li>최적화: 특정 문제에서 최적의 해(보통 최소값 혹은 최대값)를 찾는 과정</li>
<li>선형 회귀를 위한 최적화 방법은 <strong>정규 방정식</strong>(도함수가 0이 되는 지점을 계산)과 <strong>경사하강법</strong>이 존재</li>
</ul>
</li>
<li>정규 방정식<ul>
<li>비용함수의 도함수 값이 0이 되는 파라미터가 최소값을 갖는 지점임</li>
<li>w = (X^TX)^(-1) X^T y</li>
<li>이를 계산하는 시간 복잡도는 <code>O(p^3)</code><ul>
<li>p(특성 개수)의 3제곱에 비례. 즉 n(데이터 수)&gt;&gt;p(특성 개수)인 경우에 유용</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="확률적-경사-하강법">확률적 경사 하강법</h3>
<ul>
<li>경사하강법 (Gradient Decent)<ul>
<li>비용함수를 최소화하기 위해 <strong>반복해서</strong> 파라미터를 조정해가는 방법</li>
<li>임의로 잡은 초기 파라미터 값을 기준으로, 비용 함수의 기울기를 계산해 기울기가 줄어드는 방향으로 파라미터를 수정</li>
<li>비용 함수를 각 파라미터의 미분값(편미분)을 구해 기울기가 작아지는 방향(-기울기)로 learning rate만큼 이동<ul>
<li>J(w) 편미분 → <code>2X(Xw-y)</code></li>
<li>W = W - 편미분값 * lr(학습률)</li>
</ul>
</li>
<li>모든 학습 데이터에 대해 기울기를 계산하므로 학습 데이터가 많은 경우 시간 소요 큼<ul>
<li>이를 해결하기 위해 전체 데이터 중 임의로 <strong>일부 데이터를 샘플링</strong>하여 그것을 대상으로 경사 하강법을 진행 → 확률적 경사 하강법 (Stochastic Gradient Decent)</li>
<li>적은 데이터로 수정 이동을 반복하기 때문에 빠른 수렴이 가능</li>
</ul>
</li>
<li>적절한 학습률을 지정하는 것도 중요하다. 너무 크면 발산하고, 너무 작으면 학습이 잘 안된다.</li>
<li>특성 수와 샘플의 수에 민감도가 적음</li>
</ul>
</li>
</ul>
<h3 id="다중공선성">다중공선성</h3>
<ul>
<li><p>입력 데이터가 갖고있는 특징값들 사이에 상관관계가 존재할 때 발생하는 문제 상황</p>
<ul>
<li>이 상황에선 모델이 작은 데이터 변화에도 민감하게 반응 → 안정성과 해석력 저하</li>
</ul>
</li>
<li><p>정규방정식으로 해를 구하는 상황에선 치명적인 문제가 발생</p>
<ul>
<li>X^TX의 역행렬이 존재하지 않을 수 있음 → X^TX가 특이행렬인 경우</li>
</ul>
</li>
<li><p>정규 방정식이 작은 데이터셋에선 매우 효과적이므로 SVD-OLS라는 방법을 사용하고자 함</p>
<ul>
<li><p>정규방정식으로 풀 수 없는 해를 다른 방식으로 구하는 방법 제시</p>
</li>
<li><p>학습 데이터를 모아둔 행렬 X에 SVD를 적용해 특이값 분해(X = U sum V^T)</p>
</li>
<li><p>이를 OLS 방식의 풀이에 적용해 해를 구하면, V sum^-1 U^T y</p>
<p>  <img src="https://velog.velcdn.com/images/jerry_bak/post/8bf94c56-2374-4c39-81aa-e9b8f517cabd/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>- SVD-OLS는 O(np^2) ⇒ 대체로 n이 p보다 크기 때문에 SVD-OLS는 단순 OLS보다 오래걸림</code></pre><ul>
<li>만약 SVD-OLS를 사용했음에도 계산된 w값이 이상하다면(두 독립 변수 사이 상관 관계가 너무 크면),,, 선형이 아닌 다른 모델을 사용해야함</li>
</ul>
<h3 id="규제">규제</h3>
<ul>
<li><p>과적합이 발생하면 w의 값이 매우 커지게 됨. 따라서 w 값이 너무 커지지 않도록 규제를 가해 과적합 문제를 회피하고자 하는 방법</p>
<ul>
<li>줄여야하는 값인 비용함수에 w를 포함해 w도 줄이고자 함 → w 규제
<img src="https://velog.velcdn.com/images/jerry_bak/post/763ba842-72a6-4d0f-91a5-9ebb60350175/image.png" alt=""></li>
</ul>
</li>
<li><p>라쏘 회귀</p>
<ul>
<li><p>w를 L1 norm(절대값을 모두 더함) 시킴</p>
</li>
<li><p>w가 꼭짓점으로 수렴되는 경향이 있음. 이는 일부 파라미터의 값을 0으로 만들 수 있음 → 불필요한 특성을 무시하는 효과를 가져올 수 있음</p>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/b7d8f77f-52e1-49af-a93c-c7042ca8e206/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>릿지 회귀</p>
<ul>
<li><p>w를 L2 norm(제곱값을 모두 더해 루트를 씌움) 시킴</p>
</li>
<li><p>파라미터 값을 적당히 작게 만듦</p>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/aefdc855-2f5f-48f8-9ded-30a2fc473ef5/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<ul>
<li>각각에 알파를 곱해 규제 강도를 조절함</li>
</ul>
<h3 id="선형분류">선형분류</h3>
<ul>
<li><p>로지스틱 회귀</p>
<ul>
<li>이진 분류 문제에서 입력 데이터가 후보 클래스 중 <strong>각각의 클래스일 확률</strong>을 예측하는 모델</li>
<li>즉 분류 문제를 회귀 방식으로 접근</li>
<li>모델의 결과로 뽑아낸 logit을 로지스틱 함수(시그모이드)를 통해 로짓을 확률로 변경한다. 그리고 그 확률을 기준으로 0.5 이상이면 1, 아니면 0을 할당</li>
</ul>
</li>
<li><p>다중 클래스 분류 문제</p>
<ul>
<li>One vs One<ul>
<li>A냐 B냐, B냐 C냐, A냐 C냐</li>
</ul>
</li>
<li>One vs Rest<ul>
<li>A가 맞냐 아니냐, B가 맞냐 아니냐, C가 맞냐 아니냐</li>
</ul>
</li>
<li>Softmax Regression<ul>
<li>확률을 보고 클래스를 선택하는 것</li>
</ul>
</li>
</ul>
</li>
<li><p>오즈: 특정 사건이 발생할 확률과 발생하지 않을 확률의 비율 (p/1-p)</p>
</li>
<li><p>로그 오즈(로짓): 오즈에 로그 함수를 씌운 결과 (log(p/1-p))</p>
<ul>
<li>결과를 +- 무한대 범위를 갖도록 변환</li>
</ul>
</li>
<li><p>로지스틱 함수: 로짓을 입력으로 주면 확률 반환 (0~1사이의 값) → 시그모이드</p>
<ul>
<li>시그모이드 = 1 / (1+exp(-x)) = p → logit을 x로 두고 p를 기준으로 정리</li>
</ul>
</li>
<li><p>확률의 입장에서 변화량이 구간에 따라 다른 의미를 가짐 → 0.49 0.5 vs 0.98 0.99</p>
</li>
<li><p>비용함수</p>
<ul>
<li>로그 손실값을 사용</li>
<li>-(y<em>log(p햇) + (1-y)</em>log(1-p햇))</li>
<li>전체 학습 데이터에 대한 비용 함수는 모든 비용함수의 평균</li>
<li>비용함수를 <strong>최소화</strong> 시켜야하는 최적화 문제. 즉 비용함수를 최소화하는 파라미터(w)를 찾아야함. 하지만 정규방정식과 같이 직접적으로 계산 가능한 해가 없기 때문에 경사하강법을 사용해야함</li>
</ul>
</li>
</ul>
<h2 id="선형-회귀-모델-실습">선형 회귀 모델 실습</h2>
<ul>
<li>보험료 데이터, 선형 회귀</li>
</ul>
<h3 id="eda-탐색적-데이터-분석">EDA (탐색적 데이터 분석)</h3>
<ul>
<li>데이터 분석 초기 단계에서 진행됨. 데이터의 특징, 구조, 패턴, 이상치, 변수 간의 관계 이해</li>
<li>일반적으로 통계 분석(평균, 표준편차, 최소/최대값)<ul>
<li>df.info(), df.describe()을 이용해 데이터 구성 요소 및 통계 분석 가능</li>
</ul>
</li>
<li>시각화(패턴, 이상치, 경향성)<ul>
<li>분포 변환(log를 취해준다던지..), 이진 클래스로 변환 등</li>
<li>카테고리형 변수 인코딩 (수치형으로 변경)</li>
</ul>
</li>
<li>변수간 관계 파악(상관관계 분석)<ul>
<li>corr() 사용</li>
<li>두 변수간 너무 큰 상관관계를 갖는 경우 하나를 배제해야함 → 다중 공선성의 문제</li>
</ul>
</li>
<li>이상치 탐지<ul>
<li>boxplot으로 아웃라이어 확인</li>
</ul>
</li>
<li>결측치 분석</li>
</ul>
<h3 id="전처리">전처리</h3>
<ul>
<li>원-핫 인코딩 (pd.get_dummies(data, drop_first=True)<ul>
<li>카테고리 데이터를 찾아서 원핫인코딩으로 변환, 즉 성별이라면 성별_남성, 성별_여성이라는 열을 새로 만들고 각각은 0 혹은 1로 표현. 근데 여기서 drop_first를 사용해 두 열 중 하나만 남김. 왜냐면 두 열을 모두 남기면 두 열 간 상관관계(?)가 선형 분류에 영향을 줘서 다중공선성이 나타날 수 있기 때문에</li>
<li>그러면 지역 열을 get_dummies 할 때는 세개의 열이 남게되는데 그 사이의 상관관계는 문제가 되지 않는가?</li>
</ul>
</li>
<li>특성 스케일링<ul>
<li>서로 다른 수치형 데이터 특성 사이의 값 범위를 비슷하게 맞춰주는 과정</li>
<li>경사하강법을 사용하는 과정에서 수렴 속도를 높일 수 있음</li>
<li>StandardScaler(평균 0 표준편차 1로 조정, 데이터가 정규분포일때 사용), MinMaxScaler(최대값 1 최소값 0이 되도록 조정, 이상치가 큰 영향을 미치는 경우) 
⇒ 데이터 특성에 따라 다양한 스케일링 방법을 적용할 수 있음</li>
</ul>
</li>
</ul>
<h3 id="학습-후">학습 후</h3>
<ul>
<li><p>예측 성능 확인</p>
<p>  <img src="https://velog.velcdn.com/images/jerry_bak/post/a01f632c-95aa-4ccc-9497-c584b9b5469a/image.png" alt=""></p>
</li>
</ul>
<pre><code>- 결과를 scatter로 그려보고 y=x 그래프(real values == predict values)를 그려서 모델의 예측 정확성을 확인해볼 수 있음
- 값이 커질수록 예측 정확도가 낮아짐</code></pre><ul>
<li><p>잔차 확인</p>
<p>  <img src="https://velog.velcdn.com/images/jerry_bak/post/4d510f72-2ea0-4eb5-8100-9724408c2125/image.png" alt=""></p>
</li>
</ul>
<pre><code>- 잔차(residual)을 확인해볼 수 있음. 무작위로 분포되어야 좋은 상황</code></pre><ul>
<li><p>변수 중요도</p>
<p>  <img src="https://velog.velcdn.com/images/jerry_bak/post/498906f9-3089-4b79-9e38-fa0cb6715a60/image.png" alt=""></p>
</li>
</ul>
<ul>
<li><code>.coef_</code> 를 사용해 y 예측에서의 각 피쳐의 중요도를 뽑아볼 수 있음</li>
</ul>
<h2 id="선형-분류-실습">선형 분류 실습</h2>
<ul>
<li>비행 경험 만족도 데이터</li>
<li>탑승객의 개인 및 여행 경험 정보(독립변수)를 바탕으로 전반적인 비행 만족도(종속변수)를 예측</li>
</ul>
<h3 id="eda">EDA</h3>
<ul>
<li>데이터 타입<ul>
<li>수치형</li>
<li>서수형 : 순서나 등급을 나타냄. 순서는 중요하지만 그 차이는 균일하지 않음<ul>
<li>ex) 0<del>5점의 만족도 점수가 있다면 0</del>1 차이와 2~3 차이가 동일하지 않을 수 있음</li>
</ul>
</li>
<li>범주형</li>
</ul>
</li>
<li>시각화 (서수형 데이터)<ul>
<li>각 변수마다 보이는 분포가 상이함 → 상위점, 중간 점수에 몰림 현상</li>
<li>서비스 개선의 입장에서 분포를 볼 수 있음</li>
<li>만족과 불만족에 따라 분포를 확인할 수 있음</li>
<li>상관관계를 확인해 대체해야할 변수를 찾아봐야함. 이 데이터엔 크게 없음</li>
</ul>
</li>
</ul>
<h3 id="데이터-전처리">데이터 전처리</h3>
<ul>
<li>누락 데이터를 포함한 데이터 포인트는 제거 (dropna())</li>
<li>EDA를 통해 판단한 제외 데이터 제거 → ex) 지연 시간 5시간 이상은 제거(거의 불만족을 줬을 것으로 예상되니..)<ul>
<li>이 과정에 정답은 없음</li>
</ul>
</li>
<li>범주형 데이터에 대해 원핫 인코딩</li>
<li>데이터의 피쳐가 너무 많으니, 종속 변수와 상관관계가 큰 특성만 취하기<ul>
<li>결과 해석력/일반화 향상을 위해 상위 15개 변수를 취함</li>
</ul>
</li>
</ul>
<h3 id="학습">학습</h3>
<ul>
<li>logistic regression 사용 → 15개의 특성(feature)를 사용하니 15개의 파라미터를 가짐</li>
<li>분류 모델은 정확도로 모델을 평가할 수 있음<ul>
<li>confusion matrix를 사용할 수 있음</li>
</ul>
</li>
<li>coef를 이용해 각 특성의 중요도를 뽑아볼 수 있었음</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 SQL] 동명 동물 수 찾기]]></title>
            <link>https://velog.io/@jerry_bak/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-SQL-%EB%8F%99%EB%AA%85-%EB%8F%99%EB%AC%BC-%EC%88%98-%EC%B0%BE%EA%B8%B0-iv8cl7sj</link>
            <guid>https://velog.io/@jerry_bak/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-SQL-%EB%8F%99%EB%AA%85-%EB%8F%99%EB%AC%BC-%EC%88%98-%EC%B0%BE%EA%B8%B0-iv8cl7sj</guid>
            <pubDate>Wed, 24 Apr 2024 13:02:37 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-링크">문제 링크</h3>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/59041">https://school.programmers.co.kr/learn/courses/30/lessons/59041</a></p>
<h3 id="문제-설명">문제 설명</h3>
<ul>
<li>동명의 동물 수 세기 (두 번 이상)</li>
<li>이름이 없는 동물은 집계에서 제외</li>
</ul>
<h3 id="1차-시도">1차 시도</h3>
<pre><code>SELECT NAME, COUNT(NAME) COUNT
FROM ANIMAL_INS
WHERE NAME IS NOT NULL
GROUP BY 1
HAVING COUNT(NAME)&gt;1
ORDER BY 1;</code></pre><p>설명 그대로 동명의 동물 수를 세기 위해 name으로 group by해 count했다.
그리고 두번 이상 나타난 동물 이름만 조회하기 위해 having으로 조건을 줌!</p>
<p>그리고 where에서 name이 null이 아닌 애들만 걸러서 사용했는데, 어차피 count(name) 하면 null값은 count되지 않기 때문에 having에서 이름이 null인 애들은 필터링 된다.
데이터 수를 줄이고 시작하니 시간이 단축될 순 있겠으나,,, 중복되는 부분이었다!
그러니 where문을 제외해도 통과된다.</p>
<h3 id="정리">정리</h3>
<ul>
<li><strong>count</strong>: COUNT(*)의 경우 null값도 모두 포함해 count하지만, COUNT(NAME)과 같이 컬럼을 지정해 카운트한다면 null값은 카운트되지않는다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[데브코스 46일차 - 머신러닝 (개념, 선형대수, 확률)]]></title>
            <link>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-46%EC%9D%BC%EC%B0%A8-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EA%B0%9C%EB%85%90-%EC%84%A0%ED%98%95%EB%8C%80%EC%88%98-%ED%99%95%EB%A5%A0</link>
            <guid>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-46%EC%9D%BC%EC%B0%A8-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EA%B0%9C%EB%85%90-%EC%84%A0%ED%98%95%EB%8C%80%EC%88%98-%ED%99%95%EB%A5%A0</guid>
            <pubDate>Mon, 22 Apr 2024 08:03:45 GMT</pubDate>
            <description><![CDATA[<h3 id="키워드">키워드</h3>
<p>머신러닝, 선형대수, 확률</p>
<h3 id="머신러닝-기초-개념">머신러닝 기초 개념</h3>
<ul>
<li><p>머신러닝이란?</p>
<ul>
<li>데이터에서 지식을 추출. 머신 스스로가 데이터의 <strong>특징</strong>과 <strong>패턴</strong>을 찾아냄</li>
<li>명시적 프로그래밍의 한계를 극복할 수 있는 기법</li>
</ul>
</li>
<li><p>인공지능: (단순히) 기계가 사람의 지적 능력을 모방하는 것</p>
<ul>
<li>어떻게 할 것이냐? → <strong>학습</strong>을 통해 예측을 진행 (머신러닝)</li>
<li>어떻게 학습할거냐? → 사람의 인지과정을 모방 (딥러닝)</li>
</ul>
</li>
<li><p>명시적 프로그램</p>
<ul>
<li>규칙 기반(rule-based) 전문가 시스템</li>
<li>처리과정이 이해가 쉬우며, 작은 데이터에서 효과적</li>
<li>하지만 특정 작업에만 국한되며, 변경에 대응이 어려움, 전문가가 필요</li>
</ul>
</li>
<li><p>머신러닝</p>
<ul>
<li>데이터 내부에서 자주 발생하는 특징과 패턴을 감지</li>
<li>예상치 못한 상관관계를 파악하는데 탁월함</li>
<li>머신 학습을 위해 다양한 데이터가 필요하며, 결과 분석 과정에서 사람이 이해할 수 없는 포인트가 존재할 수 있음 (블랙박스)</li>
<li>활용 사례<ul>
<li>추천, 페이스아이디, 의료 영상 처리, 음성처리, 금융 데이터 예측</li>
</ul>
</li>
<li>프로젝트<ul>
<li>문제정의 → 데이터 확인 → 데이터 처리 및 분할 → 알고리즘 탐색(선행 연구 참고) → 데이터 전처리(모델 input의 형태로 변경) → 학습과 검증 → 최종 테스트(데이터 문제, 코드 에러, 새로운 알고리즘) → 시스템 런칭(모니터링, 유지보수)</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="머신러닝-종류">머신러닝 종류</h3>
<ul>
<li><p>데이터 종류</p>
<ul>
<li>메타 데이터: 기본 데이터에 추가적으로 제공되는 정보 (대체로 학습에 사용 X), 데이터 출처, 형식, 위치 등</li>
<li>레이블 (타겟): 특정 문제에 해당하는 데이터의 설명 혹은 답변을 의미(데이터가 속할 범주), 회귀 문제라면 데이터가 표현할 특정 숫자<ul>
<li>대부분 사람이 직접 생성해줘야하는 경우가 많음</li>
</ul>
</li>
</ul>
</li>
<li><p>지도학습</p>
<ul>
<li>레이블(정답) 정보를 활용해 알고리즘을 학습하는 학습 방법 → 비교적 쉽고 잘 학습되며 성능을 쉽게 측정할 수 있다.</li>
<li>데이터와 레이블 사이의 관계를 파악</li>
<li>하지만 레이블을 만들어내기 위해 드는 비용이 큼</li>
</ul>
</li>
<li><p>비지도 학습</p>
<ul>
<li>정답 레이블 정보 없이 입력 데이터만을 활용해 알고리즘을 학습 (데이터 내부에 존재하는 패턴을 스스로 파악)</li>
<li>레이블 준비할 필요 없어 비용적 이점이 있으며 사용자가 의도한 패턴 외의 새로운 패턴을 찾을 가능성이 있음</li>
<li>하지만 성능 측정의 기준이 없어 해석이 주관적일 수 있으며 신뢰할 수 있는 결과를 얻기 위해선 다수의 데이터가 필요</li>
</ul>
</li>
<li><p>준지도 학습</p>
<ul>
<li>일부의 데이터만 정답이 존재, 다수의 데이터에는 레이블이 없는 상황에서 알고리즘을 학습</li>
<li>레이블링 된 데이터로 특성을 파악하고, 레이블링 되지 않은 데이터로 전체 데이터의 패턴을 파악하는 방식으로 학습이 진행</li>
<li>레이블이 부족한 데이터셋에서 유용하며 많은 데이터를 활용할 수 있으므로 일반화 성능을 향상시킬 수 있음</li>
<li>하지만 품질이 낮은 데이터 존재에 취약할 수 있으며, 알고리즘의 복잡성이 증가</li>
</ul>
</li>
<li><p>자기 지도 학습</p>
<ul>
<li>정답이 하나도 없는 데이터에서 정답을 강제로 생성 후 학습하는 학습 방법론</li>
<li>데이터를 훼손하고 그 데이터를 예측하도록 함</li>
<li>이렇게 만들어진 알고리즘은 해당 데이터를 이용한 다른 문제에 적용 (pre-training)</li>
<li>n회 이상의 추가적인 학습 과정이 필요할 수 있으며 알고리즘이 잘못된 패턴을 학습할 위험이 있음</li>
</ul>
</li>
<li><p>강화학습</p>
<ul>
<li>어떤 환경(마당)에서 상호작용하는 에이전트(강아지)가 보상(간식)을 통해 특정 행동(앉기)을 하도록 유도하는 학습 방법론 (like 강아지 훈련)</li>
</ul>
</li>
</ul>
<h3 id="머신러닝에-필요한-선형대수1">머신러닝에 필요한 선형대수1</h3>
<ul>
<li><p>선형대수: 수 들이 모여있는 개념과 관련된 식을 연구하는 분야 (벡터, 행렬 등)</p>
</li>
<li><p>수의 집합</p>
<ul>
<li>스칼라: 수 하나</li>
<li>벡터: 한 방향(차원)으로 숫자가 모인 형태 (1차원)</li>
<li>행렬: 두 방향(차원)으로 숫자가 모인 형태 (2차원)</li>
<li>텐서: 벡터와 행렬을 일반화한 개념</li>
</ul>
</li>
<li><p>행렬의 덧셈과 뺄셈</p>
<ul>
<li>같은 크기의 행렬 끼리만 가능 (element-wise operation)</li>
</ul>
</li>
<li><p>행렬의 곱셈</p>
<ul>
<li>하나의 행렬의 각 행과 다른 행렬의 각 열 간의 내적</li>
<li>(m<em>n) * (n</em>k) = (m*k)</li>
<li>하마다르 프로덕트(element-wise product)가 우리가 아는 곱셈임</li>
</ul>
</li>
<li><p>전치 행렬</p>
<ul>
<li>행과 열을 바꾼 행렬 (n<em>m → m</em>n)</li>
<li>기존 행렬과 전치 행렬이 같은 경우, 그 행렬을 대칭 행렬이라고 함</li>
</ul>
</li>
<li><p>역행렬</p>
<ul>
<li>행렬 A에 행렬 B를 곱했을 때 결과가 항등행렬(대각성분이 모두 1, 나머지는 0)이면, B를 A의 역행렬이라고 함 (B = A^(-1))</li>
<li>모든 행렬이 역행렬을 갖는 건 아님. (행렬이 가역이 아닌 경우, det(A)=0 )</li>
</ul>
</li>
<li><p>선형 변환</p>
<ul>
<li><p>Av = v’ → 어떤 벡터에 특정 행렬을 곱해 새로운 벡터를 만듦. v와 v’는 A행렬에 의해 방향이 바뀌는데 이를 <strong>선형 변환</strong>이라고 함(벡터의 방향과 크기)</p>
</li>
<li><p>Av = λv (v가 크기만 변화) 라고 한다면, 그런 벡터를 <strong>고유 벡터</strong>라고 하고, 그런 상수를 <strong>고유 값</strong>이라고 한다.</p>
</li>
<li><p>행렬 A의 고유 벡터 v는 행렬 A의 값이 가장 많이 분산되는(많은 정보를 갖고있는) 방향을 나타냄. 즉 데이터가 담고있는 여러 정보 중 가장 의미가 큰 방향이 고유 벡터가 됨. 분산이 크면 람다(고유값)가 크다.</p>
<p>  <img src="https://velog.velcdn.com/images/jerry_bak/post/a625fa10-9542-4860-a899-2a57a94af0ae/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>- 고유 벡터와 고유 값은 복수개가 가능하다. 행렬이 n차원이면 고유 벡터, 고유값도 n개
- 고유값을 기준으로 나열된 고유벡터는 해석력이 큰 방향의 순서를 의미</code></pre><h3 id="특이값-분해-svd">특이값 분해 (SVD)</h3>
<ul>
<li>like 소인수분해…</li>
<li>복잡한 행렬 A(m*n)을 더 간단한 세 가지 행렬(U, Σ, V^T)로 분해<ul>
<li>U의 열벡터들은 A의 왼쪽 특이 벡터로 AA^T(m<em>m)의 고유 벡터 (*</em>행 정보**를 바탕으로 중요도를 파악)</li>
<li>V의 열벡터들은 A의 오른쪽 특이 벡터로 A^TA(n<em>n)의 고유 벡터 (*</em>열 정보**를 바탕으로 중요도를 파악)</li>
<li>Σ의 대각선 위의 값들로 A의 특이값 (AA^T와 A^TA의 <strong>고유값의 제곱근</strong> 값)</li>
</ul>
</li>
<li>고유 벡터와 고유값은 행렬 A가 정사각 행렬(m*m)일 경우에만 사용 가능<ul>
<li>그렇기 때문에 AA^T와 A^TA가 만들어짐 → 직사각 행렬도 고유벡터, 고유값 분석을 할 수 있게 함</li>
</ul>
</li>
</ul>
<h3 id="확률-이론">확률 이론</h3>
<ul>
<li><p>확률: 특정 사건이 일어날 가능성을 수치로 표현한 것 (0~1)</p>
</li>
<li><p>P(x): x라는 사건이 일어날 확률 ⇒ 확률 변수 x가 특정 값을 가질 확률</p>
</li>
<li><p>합의 법칙: 두 사건 A, B가 배타적이라면 A또는 B 확률: P(A) + P(B)</p>
</li>
<li><p>곱의 법칙: 두 사건 A, B가 독립일 때, A와 B가 동시에 발생할 확률: P(A) * P(B)</p>
</li>
<li><p>조건부 확률: 사건 B가 일어난 상태에서 사건 A가 일어날 확률: P(A|B)</p>
</li>
<li><p>확률 분포</p>
<ul>
<li>확률 변수가 취할수 있는 값(x)과 그 값들이 발생하는 확률(y)을 설명하는 개념</li>
<li>이산 확률 분포<ul>
<li>확률 변수가 취할 수 있는 값이 개별적이며 셀 수 있는 경우</li>
<li>각 변수에 해당하는 확률 값의 총 합은 1</li>
</ul>
</li>
<li>연속 확률 분포<ul>
<li>확률 변수가 연속적인 범위의 값을 취할 수 있는 경우</li>
<li>모든 확률 변수 전 구간의 적분 값은 1</li>
<li>ex) 표준 정규 분포 ⇒ 평균이 0, 표준편차가 1</li>
</ul>
</li>
</ul>
</li>
<li><p>확률 변수</p>
<ul>
<li>실험, 관찰, 또는 무작위 과정의 결과로 나타날 수 있는 수치적인 값</li>
<li>확률 분포로부터 확률 변수를 임의로 생성하는 것을 샘플링이라고 함</li>
<li>특정 분포 D를 따르는 확률 변수 X를 n개 샘플링 하면 <code>X1, X2, … , Xn ~D</code>로 표현 가능</li>
</ul>
</li>
<li><p>확률론적 모델링과 추론</p>
<ul>
<li>주어진 데이터를 확률 이론의 관점에서 해석하고 모델을 설계하는 과정을 의미</li>
<li>데이터가 특정 확률 분포를 따른다고 가정 (데이터에 존재하는 불확실성을 인지)</li>
<li>머신러닝 모델의 출력은 확률론적 관점에서 예측된 결과물이므로 실제 결과물과 차이가 있을 수 있음<ul>
<li>모델의 예측은 y햇으로 표시</li>
</ul>
</li>
<li>입력 데이터는 X로 표시하며, 각 개념(컬럼)은 독립변수이고, 정답이 되는 레이블(y)은 종속변수가 됨</li>
</ul>
</li>
</ul>
<h3 id="요약-숙제">요약 숙제</h3>
<ol>
<li>머신러닝<ol>
<li>머신러닝은 데이터에서 특징과 패턴을 스스로 학습하는 방법을 의미한다. 크게는 인공지능에 속해있으며, 딥러닝을 포함하는 개념이다. 사람이 발견하지 못한 새로운 상관관계를 발견하는 데 용이함. 추천 시스템, 음성 처리 등에 사용된다.</li>
</ol>
</li>
<li>머신러닝의 장단점<ol>
<li>예상치 못한 상관관계를 발견하는데 탁월하지만, 학습을 위해서 다양한 데이터가 필요하며, 결론 도출 과정을 일부 이해할 수 없는 블랙박스의 문제가 존재</li>
</ol>
</li>
<li>머신러닝 프로젝트 로드맵<ol>
<li>문제를 정의하고 학습에 사용할 데이터를 살펴본 후 데이터를 일부 처리 후 분할한다. 선행 연구를 참고해 알고리즘을 선정하고, 데이터를 모델 input으로 적절하게 전처리 해주며 학습과 검증을 진행한다. 그렇게 최종적으로 학습된 모델을 테스트하고 문제가 없는 경우 시스템을 런칭한다.</li>
</ol>
</li>
<li>머신러닝의 종류<ol>
<li>지도학습 : 정답(label)이 있는 학습 방법으로 비교적 학습이 쉽지만, 라벨링 작업에 비용이 든다는 단점이 있음</li>
<li>비지도학습 : 정답이 없는 학습 방법으로 입력 데이터만을 통해 학습. 라벨링 작업이 필요 없다는 장점이 있지만 성능 측정의 기준이 없다는 단점도 존재</li>
<li>준지도학습 : 일부 데이터만 정답이 존재하는 학습 방법으로, 레이블이 부족한 데이터셋에 유리하지만, 잘못된 데이터에 영향을 받을 확률이 높음</li>
<li>자기지도학습 : 정답을 임의로 만들어 학습하는 방법으로, 이를 통해 학습된 알고리즘은 다른 문제에 적용된다.</li>
<li>강화학습 : 특정 환경에서 상호작용하는 에이전트가 보상을 통해 학습하는 방법으로 특정 행동을 하도록 유도한다.</li>
</ol>
</li>
<li>선형대수<ol>
<li>수의 집합을 연구하는 분야로, 스칼라, 벡터, 행렬, 텐서 등의 수의 집합을 공부</li>
<li>행렬을 덧셈과 뺄셈은 element-wise로 이루어지며 곱셈은 두 행렬의 행과 열의 내적으로 이루어짐</li>
<li>Av = v’ 이를 선형 변환이라고 하며, 이 때 Av = λv인 경우 v를 A의 고유 벡터, λ를 A의 고유값이라고 한다. 고유 벡터는 A의 값이 가장 많이 분산되는 방향을 나타낸다.</li>
</ol>
</li>
<li>확률 분포<ol>
<li>이산확률 분포의 경우, 동전 던지기와 같이 확률 변수가 이산적이며 셀 수 있는 경우를 의미하고, 모든 확률 변수의 확률 값의 합은 1이다.</li>
<li>연속 확률 분포의 경우, 특정 그룹의 키 분포와 같이 확률 변수가 연속적인 범위의 값을 취할 수 있는 경우를 의미하고, 모든 확률 변수 전 구간의 적분 값은 1이다.</li>
</ol>
</li>
</ol>
<h3 id="궁금">궁금</h3>
<ul>
<li>선형 변환이랑 pca랑 뭔가 비슷한 구석이 있는 것 같다.</li>
<li>샘플링이 잘 이해가 안되네...! 다시 한 번 봐야겠다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[데브코스 40일차 - 데이터 웨어하우스 심화]]></title>
            <link>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-40%EC%9D%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%9B%A8%EC%96%B4%ED%95%98%EC%9A%B0%EC%8A%A4-%EC%8B%AC%ED%99%94</link>
            <guid>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-40%EC%9D%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%9B%A8%EC%96%B4%ED%95%98%EC%9A%B0%EC%8A%A4-%EC%8B%AC%ED%99%94</guid>
            <pubDate>Mon, 15 Apr 2024 10:24:26 GMT</pubDate>
            <description><![CDATA[<h3 id="키워드">키워드</h3>
<p>데이터 웨어하우스, ETL, ELT, 데이터 파이프라인</p>
<h3 id="데이터-웨어하우스">데이터 웨어하우스</h3>
<ul>
<li><p>데이터 웨어하우스</p>
<ul>
<li>고정비용 옵션 (redshift)</li>
<li>가변비용 옵션 (bigquery, 스노우 플레이크)</li>
</ul>
</li>
<li><p>데이터 레이크</p>
<ul>
<li>구조화 데이터 + 비구조화 데이터(로그 파일)</li>
<li>보통 클라우드 스토리지가 됨</li>
<li>데이터 레이크에 있는 정보를 정제해 데이터 웨어하우스에 적재(기록)할 수도 있음 ⇒ ELT</li>
<li>바깥의 데이터를 시스템 안으로 가져오는 과정 (ETL)<ul>
<li>ETL이 실패했을 경우 이를 빨리 고쳐 다시 실행하는 것이 중요 → 이를 적절하게 스케줄하고 관리하는 것이 중요해짐, ETL 스케줄러 혹은 프레임웍이 필요해짐<ul>
<li>Airflow가 대표적인 프레임웍 (ETL 스케줄러)</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p>데이터 소스</p>
<ul>
<li>프로덕션 데이터베이스(mysql, postgres 등)의 데이터</li>
<li>이메일 마케팅 데이터</li>
<li>크레딧카드 매출 데이터</li>
<li>사용자 이벤트 로그</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/4f7dad93-fde8-43b9-b3dc-ace7eab20013/image.png" alt=""></p>
<ul>
<li><p>ELT</p>
<ul>
<li>데이터 웨어하우스 내부 데이터를 조작해 (보통은 좀 더 추상화되고 요약된) 새로운 데이터를 만드는 프로세스</li>
<li>데이터 레이크에서 데이터 웨어하우스로 ELT 하는 과정에서 빅데이터 처리 기술이 필요해짐 (spark 등)</li>
</ul>
</li>
<li><p>빅데이터 처리 프레임웍</p>
<ul>
<li>분산 파일 시스템(저장)과 분산 컴퓨팅 시스템(처리)이 필요</li>
<li>분산 환경 기반 (한 대 혹은 그 이상의 서버로 구성)</li>
<li>소수의 서버가 고장나도 동작해야함 (fault tolerance)</li>
</ul>
</li>
<li><p>빅데이터 프로세싱 시스템</p>
<ul>
<li>하둡, spark</li>
</ul>
</li>
</ul>
<h3 id="데이터-웨어하우스-옵션들">데이터 웨어하우스 옵션들</h3>
<ul>
<li>AWS Redshift<ul>
<li>AWS 기반의 데이터웨어하우스로 PB 스케일 데이터 분산 처리 가능</li>
<li>Avro, Parquet과 같은 다양한 데이터 포맷을 지원</li>
</ul>
</li>
<li>Snowflake<ul>
<li>클라우드 기반 데이터웨어하우스로 시작됨</li>
<li>SQL 기반으로 빅데이터 저장, 처리, 분석을 가능하게 해줌</li>
<li>실시간 데이터 처리 지원</li>
</ul>
</li>
<li>Google Cloud Bigquery<ul>
<li>Bigquery SQL이란 SQL로 데이터 처리 가능</li>
<li>nested fields, repeated fields 지원</li>
<li>가변비용 옵션</li>
</ul>
</li>
<li>Apache Hive<ul>
<li><strong>하둡 기반으로 동작</strong>하는 SQL 기반 데이터 웨어하우스 서비스</li>
<li>한 번에 처리할 수 있는 데이터의 양이 크다. (디스크 기반?)</li>
</ul>
</li>
<li>Apache Presto<ul>
<li>Facebook의 아파치 오픈소스 프로젝트 (Hive와 동일하게 하둡 기반으로 동작)</li>
<li>빠른 응답 속도에 좀 더 최적화 (메모리 기반)</li>
<li>Hive와 Presto가 서로 유사해지는 경향성이 있음</li>
</ul>
</li>
<li>Apache Iceberg<ul>
<li>넷플릭스가 시작한 아파치 오픈소스 프로젝트 (데이터 웨어하우스 기술 X)</li>
<li>HDFS, S3, Azure Blob Storage 등의 클라우드 스토리지 지원</li>
<li>ACID 트랜잭션과 타임여행(과거 버전으로 롤백과 변경 기록 유지 등등)</li>
<li>다른 아파치 시스템과 연동 가능</li>
</ul>
</li>
<li>Apache Spark<ul>
<li>UC 버클리 AMPLab이 시작한 아파치 오픈소스 프로젝트</li>
<li>빅데이터 처리 관련 종합선물세트</li>
<li>다양한 분산처리 시스템 <strong>지원</strong></li>
<li>다양한 언어 지원(자바, 파이썬 스칼라, R)</li>
</ul>
</li>
</ul>
<h3 id="실리콘밸리-회사들의-데이터-스택-트렌드">실리콘밸리 회사들의 데이터 스택 트렌드</h3>
<ul>
<li>데이터 플랫폼 방전 단계<ul>
<li>초기: 데이터 웨어하우스 + ETL</li>
<li>발전: 데이터 양 증가 (Spark와 같은 빅데이터 처리시스템/데이터 레이크(비구조화된, 스케일이 큰 데이터를 위해) 도입)</li>
<li>성숙: 현업단의 데이터 활용 증대 (ELT단이 더 중요해지면서 dbt 등의 분석 엔지니어링 도입)<ul>
<li>MLOps 등 머신러닝 개발 운영 관련 효율성 증대 노력 증대</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>클라우드: AWS, Googld cloud, on-premise(자체 서버) 등 ⇒ 데이터 웨어하우스
Big Data 시스템: Spark, snowflake, Hive 등 ⇒ 빅데이터 프로세싱 프레임웍
대시보드: Looker, Tableau 등 ⇒ 시각화 툴
데이터 파이프라인 프레임웍: Airflow, dbt 등 ⇒ ETL 스케쥴러</p>
<h3 id="데이터-파이프라인이란">데이터 파이프라인이란?</h3>
<ul>
<li>ETL<ul>
<li>Extract, Transform, Load</li>
<li>동의어: 데이터 파이프라인, ETL, 데이터 웍플로우, DAG(Airflow에서 사용하는 용어)</li>
</ul>
</li>
<li>데이터 파이프라인<ul>
<li>데이터를 소스로부터 목적지(대체로 데이터 웨어하우스, 데이터가 크면 데이터 레이크)로 복사하는 작업<ul>
<li>보통 코딩 혹은 SQL을 통해 이뤄짐</li>
</ul>
</li>
</ul>
</li>
<li>Raw data ETL Jobs<ul>
<li>외부/내부 데이터 소스에서 데이터를 읽어다가(API 사용) 적당한 데이터 포맷 변환 후(데이터의 크기가 커지면 spark 등이 필요해짐) 데이터 웨어하우스 로드</li>
<li>이 작업은 보통 데이터 엔지니어가 함</li>
</ul>
</li>
<li>Summary/Report Jobs<ul>
<li>소스와 목적지가 동일</li>
<li>데이터 시스템 (DW, DL)에서 데이터를 읽어 다시 데이터시스템에 쓰는 ETL</li>
<li>sql만으로 만들거나, dbt를 이용. 데이터 분석가가 하는 일</li>
</ul>
</li>
<li>Production Data Jobs<ul>
<li>DW로부터 데이터를 읽어 다른 storage(대체로 프로덕션 환경)로 쓰는 ETL</li>
<li>강의 수강생 수, 별점 등의 데이터 처리를 위함</li>
</ul>
</li>
</ul>
<h3 id="데이터-파이프라인을-만들-때-고려할-점">데이터 파이프라인을 만들 때 고려할 점</h3>
<ul>
<li>데이터 파이프라인의 실패<ul>
<li>데이터 소스상의 이슈(포맷 변화)</li>
<li>데이터 파이프라인들간의 의존도 이해 부족 (마케팅 채널 정보가 업데이트 안된다면 마케팅 관련 다른 모든 정보들이 갱신되지 않음)</li>
</ul>
</li>
<li>Best Practices<ul>
<li>가능하다면 매번 통채로 복사해서 테이블을 만들기 (full refresh)</li>
<li>변경된 부분만 복사 (incremental update)<ul>
<li>데이터 소스가 프로덕션 데이터베이스라면 다음 필드가 필요 (created, modified, deleted)</li>
</ul>
</li>
<li>데이터 파이프라인이 멱등성을 보장해야함<ul>
<li>멱등성: 동일한 입력으로 데이터 파이프라인을 다수 실행해도 최종 테이블의 내용이 달라지면 안됨. 예를 들면 중복 데이터가 생기면 안됨</li>
<li>데이터 파이프라인이 중간에 실패하면, 이전 상태로 롤백해야함(SQL transaction과 유사)</li>
</ul>
</li>
<li>실패한 데이터 파이프라인 재실행이 중요함<ul>
<li>과거 데이터를 다시 채우는 과정(Backfill)이 쉬워야함</li>
<li>incremental update할 때 특히 중요</li>
</ul>
</li>
<li>데이터 파이프라인의 입력과 출력을 명확히하고 문서화<ul>
<li>비지니스 오너 명시 (데이터 요청한 사람)</li>
</ul>
</li>
<li>주기적으로 쓸모없는 데이터들을 삭제</li>
<li>데이터 파이프라인 사고시마다 사고 리포트(posst-mortem) 쓰기<ul>
<li>동일한 혹은 아주 비슷한 사고가 또 발생하는 것을 막기 위함임</li>
</ul>
</li>
<li>중요 데이터 파이프라인의 입력과 출력을 체크하기</li>
</ul>
</li>
</ul>
<h3 id="간단한-etl-작성하기-실습">간단한 ETL 작성하기 (실습)</h3>
<ul>
<li>ETL<ul>
<li>Extract(데이터 소스에서 읽어내는 과정), Transform(원본 데이터의 포맷을 원하는 형태로 변경시키는 과정), Load(DW에 테이블로 집어넣는 과정)</li>
</ul>
</li>
<li>웹에 있는 csv파일을 redshift에 있는 테이블로 복사</li>
</ul>
<pre><code class="language-python">import requests

def extract(url):
    f=requests.get(url)
    return (f.text)

def transform(text):
    lines = text.strip().split(&#39;\n&#39;)
    records = []
    for l in lines[1:]: # 첫 레코드는 헤더이므로
        (name, gender) = l.split(&quot;,&quot;)
        records.append([name, gender])
    return records

def load(records):
    cur = get_Redshift_connection() # 미리 정의해둔 함수 호출
    cur.excute(&quot;BEGIN;&quot;) # 트랜잭션 열기(멱등성)
    try:
        # full fresh
        cur.execute(&quot;DROP TABLE IF EXISTS ~.name_gender; CREATE TABLE ~.name_gender (name varchar(32) primary key,gender varchar(8));&quot;)
        for r in records:
            name = r[0]
            gender = r[1]
            print(name, &#39;-&#39;, gender)
            sql = &quot;INSERT INTO ~.name_gender VALUES (&#39;{n}&#39;, &#39;{g}&#39;)&quot;.format(n=name, g=gender)
            cur.execute(sql)
        cur.excute(&#39;END&#39;)
    except (Exception, psycopg2.DatabaseError) as error:
        print(error)
        cur.execute(&quot;ROLLBACK&quot;)</code></pre>
<h3 id="생각해볼-것">생각해볼 것</h3>
<p>여러분이 좋아하는 주제를 바탕으로 여러분만의 가상의 데이터 웨어하우스를 만든다면 어떤 데이터 소스들을 ETL로 읽어오고 그걸 정리해서 어떻게 요약 정보 (ELT)를 만들어볼지 생각해서 구글닥으로 만들어서 아래 이메일로 공유해주세요!</p>
<p>예를 들어 내가 특정 분야의 음악에 관심이 많다면 관련 내용을 어디서 읽어올 수 있을지 (ETL) 생각해보고 이걸 어떻게 요약을 하면 (ELT) 시각화나 분석이 쉬워질지 생각해보세요. 다시 한번 가상입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[:< [프로그래머스 SQL] 물고기 종류 별 대어 찾기]]></title>
            <link>https://velog.io/@jerry_bak/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-MySQL-%EB%AC%BC%EA%B3%A0%EA%B8%B0-%EC%A2%85%EB%A5%98-%EB%B3%84-%EB%8C%80%EC%96%B4-%EC%B0%BE%EA%B8%B0</link>
            <guid>https://velog.io/@jerry_bak/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-MySQL-%EB%AC%BC%EA%B3%A0%EA%B8%B0-%EC%A2%85%EB%A5%98-%EB%B3%84-%EB%8C%80%EC%96%B4-%EC%B0%BE%EA%B8%B0</guid>
            <pubDate>Fri, 05 Apr 2024 07:56:14 GMT</pubDate>
            <description><![CDATA[<h3 id="문제-링크">문제 링크</h3>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/293261">https://school.programmers.co.kr/learn/courses/30/lessons/293261</a></p>
<h3 id="문제-간단-설명">문제 간단 설명</h3>
<p>물고기 종류 별 가장 큰 사이즈의 물고기의 ID, FISH_NAME, LENGTH을 조회</p>
<h3 id="쿼리-where-사용">쿼리 (WHERE 사용)</h3>
<pre><code>SELECT ID, FISH_NAME, LENGTH
FROM FISH_INFO
JOIN FISH_NAME_INFO USING(FISH_TYPE)
WHERE (FISH_TYPE, LENGTH) IN (SELECT FISH_TYPE, MAX(LENGTH) FROM FISH_INFO GROUP BY 1)
ORDER BY 1;</code></pre><ol>
<li>물고기 종류 별 가장 큰 사이즈를 조회하는 서브쿼리</li>
<li>(FISH_TYPE, LENGTH)을 묶어 이를 포함하는 데이터만 조회</li>
</ol>
<h3 id="다른-쿼리-join-사용">다른 쿼리 (JOIN 사용)</h3>
<pre><code>WITH MAX_LENGTH AS(
    SELECT FISH_TYPE, MAX(LENGTH) M_LENGTH
    FROM FISH_INFO 
    GROUP BY 1
)

SELECT ID, FISH_NAME, LENGTH
FROM FISH_INFO I
JOIN FISH_NAME_INFO N USING(FISH_TYPE)
JOIN MAX_LENGTH M ON M.FISH_TYPE = I.FISH_TYPE 
                AND M.M_LENGTH = I.LENGTH
ORDER BY 1;</code></pre><ol>
<li>물고기 종류 별 가장 큰 사이즈를 조회하는 WITH문 작성</li>
<li>CTE(Common Table Expressions)를 통해 정의한 MAX_LENGTH 테이블을 JOIN해 피쉬타입과 길이가 동시에 동일한 데이터만 조회 (INNER JOIN)</li>
</ol>
<h3 id="깨달은-것">깨달은 것</h3>
<ul>
<li>IN을 사용할 때 두 컬럼을 튜플로 묶어 함께 포함되는 데이터를 걸러낼 수 있다.</li>
<li>WITH문(CTE)으로 작성하고 해당 테이블을 INNER JOIN 해 원하는 조건의 데이터만 조회할 수 있다.</li>
</ul>
<h3 id="궁금한-것">궁금한 것</h3>
<pre><code>WITH MAX_LENGTH AS (
    SELECT FISH_TYPE, MAX(LENGTH) 
    FROM FISH_INFO 
    GROUP BY 1
)

SELECT ID, FISH_NAME, LENGTH
FROM FISH_INFO
JOIN FISH_NAME_INFO USING(FISH_TYPE)
WHERE (FISH_TYPE, LENGTH) IN MAX_LENGTH
ORDER BY 1;</code></pre><ul>
<li>IN의 우측엔 테이블이 올 수 없다.. IN의 우측에 MAX_LENGTH가 오는 것과, 서브쿼리로 FROM MAX_LENGTH의 데이터를 전부 가져오는 것이랑 뭐가 다른가?</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[데브코스 35일차 - 데이터 모델링(2)]]></title>
            <link>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-35%EC%9D%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%812</link>
            <guid>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-35%EC%9D%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%812</guid>
            <pubDate>Fri, 05 Apr 2024 06:32:05 GMT</pubDate>
            <description><![CDATA[<h3 id="키워드">키워드</h3>
<p>평가/분석 방법</p>
<h3 id="naive-bayes">Naive Bayes</h3>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/f7d984ac-4905-44a1-b49d-a52402e7d4bb/image.png" alt=""></p>
<ul>
<li>문 같이 생긴 기호가 product</li>
<li>sklearn.naive_bayes의 CaussianNB를 import 해 사용</li>
</ul>
<h3 id="evaluation">Evaluation</h3>
<ul>
<li><p>모델을 어떻게 평가할지, 기준을 정해야함</p>
</li>
<li><p>회귀 평가 방법</p>
<ul>
<li><p>MSE (Mean Squared Error)</p>
<ul>
<li>오차 제곱의 평균</li>
<li>오차값이 큰 데이터점(outlier)에 대해 민감하게 반응 ! 유의</li>
</ul>
</li>
<li><p>MAE (Mean Absolute Error)</p>
<ul>
<li>오차의 <strong>절대값의</strong> 평균</li>
<li>오차값이 큰 데이터점에 대해 MSE 대비 덜 민감하게 반응</li>
</ul>
</li>
<li><p>R-squared (결정계수)</p>
<p>  <img src="https://velog.velcdn.com/images/jerry_bak/post/e5810bcd-1258-4303-bc24-10f677f25da8/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>    - 독립변수 x가 종속변수 y(분산)를 얼마나 잘 설명하는지를 나타냄, 이 값이 1에 가까울 수록 X와 Y가 선형관계를 갖는다! 라고 할 수 있음
    - 전체 관측값 y의 평균(y 바)으로부터 각 y값이 멀리 떨어질수록, 예측한 y값과 실제 y값이 가까울수록 1에 가까워짐
        - 즉 관측값과 평균 사이 오차 제곱(종속 변수의 분산)이 커질수록, 오차 제곱(예측 오차, 잔차)가 작을 수록 좋은 값을 가짐
        - 만약 모델의 예측값이 샘플 평균보다 낮으면 결정계수는 마이너스 값을 가짐</code></pre><ul>
<li>분류 평가 방법<ul>
<li>분류 성능 평가 지표<ul>
<li>(분류값이 정답인지 아닌지: True/False)(분류한 것: Positive/Negative)</li>
<li>ex) FN: 네거티브(N)로 분류했는데 틀림(F) → 사실은 True</li>
</ul>
</li>
<li>precision<ul>
<li>실제로 positive인 샘플 중 몇 개를 positive로 분류했는지</li>
<li>TP / TP+FP</li>
</ul>
</li>
<li>recall<ul>
<li>positive로 분류한 샘플 중 몇 개가 실제 positive인지</li>
<li>TP / TP+FN</li>
</ul>
</li>
<li>precision, recall은 positive threshold로 조절이 가능</li>
<li>FP가 늘어나는 것이 문제인 경우엔 precision을 높이는 것이 중요하지만, 
FP가 늘어나도 어떻게든 positive를 잡아내야되는 경우(전염병, 암 진단) recall을 높이는 것이 중요<ul>
<li>precision이 중요한지, recall이 중요한지 잘 판단해야함</li>
</ul>
</li>
<li>F1-score (precision과 recall의 조화평균)<ul>
<li>2<em>precision</em>recall / precision+recall</li>
<li>조화평균은 <strong>역수의 산술평균의 역수</strong>를 의미한다.</li>
<li>precision과 recall을 둘 다 고려한 metric이다.</li>
<li>둘 중 작은 값에 영향을 많이 받음 → 즉 둘 다 균형있게 좋은 값을 내야 좋은 f1 값을 냄</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="pca">PCA</h3>
<ul>
<li>Principal component analysis (주성분 분석)<ul>
<li>주성분: 데이터들의 분산이 가장 큰 방향벡터</li>
<li>고차원(feature가 많은) x에 대해서 데이터의 분포를 가장 잘 설명하는 새로운 축을 찾아내는 기술 (차원축소)</li>
<li>새로운 축(PC)은 각 점들이 퍼져있는 정도인 분산이 최대로 보존될 수 있도록 해야함</li>
<li>분산이 커져야 데이터들 사이의 차이점이 명확해지고 그것이 모델을 더 좋은 방향으로 만들 수 있을 것이기 때문에</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/cde38039-a382-4460-9edd-a6f3b5e2c05a/image.png" alt=""></p>
<ul>
<li>각 x의 평균값을 새로운 축으로 설정 → 새로운 축들의 교차점이 원점이 되도록</li>
<li>수선의 발과 원점 사이의 거리의 제곱들의 합(SS)이 최대가 되는 축을 PC1으로, 또 그에 직교하는 축을 PC2로 설정. N개의 PC 축 설정</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/51c6b42b-ba79-4e86-9876-295f5a27f7d8/image.png" alt=""></p>
<ul>
<li>모델의 feature 개수를 줄여 효과적인 학습을 목표로 함</li>
<li>하지만 이 좌표의 의미를 해석하기 쉽진 않음</li>
</ul>
<h3 id="feature-analysis">Feature Analysis</h3>
<ul>
<li>어떤 feature가 y를 설명하는 데 있어 중요한 feature인지 아는 것 또한 매우 중요</li>
<li>LogisticRegression(), LinearRegression(), SVC이 학습 된 상태에서 .coef_와 .intercept_를 조회<ul>
<li>.coef_: feature들에 대해서 각각 곱해지는 값을 의미, 가중치</li>
<li>.intercept_: 절편을 의미</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/7c1f30a5-b19f-4329-a849-d62356406f17/image.png" alt=""></p>
<ul>
<li><p>실제로 coef의 절대값이 큰 feature만 뽑아서 scatter로 그려보면 클래스별 구분이 되어있는 것을 볼 수 있음 → label을 잘 설명하는 feature!</p>
</li>
<li><p>Random Forest 모델들에서는 자체적으로 <code>feature_importances_</code>를 제공</p>
</li>
</ul>
<h3 id="상관관계-분석">상관관계 분석</h3>
<ul>
<li><p>feature들과 label 간의 상관관계 분석을 통해 feature의 중요도를 알아볼 수 있다.</p>
</li>
<li><p>상관관계: 다른 두 통계적 변인이 <strong>공변</strong>하는 함수관계 (not 인과관계!!)</p>
</li>
<li><p>scipy.stats에서 import 해 사용 가능</p>
</li>
<li><p>피어슨 상관계수 (pearsonr())</p>
<ul>
<li>두 변수간의 <strong>선형 상관관계</strong>의 정도를 나타냄</li>
</ul>
</li>
<li><p>스피어만 상관계수 (spearmanr())</p>
<ul>
<li><p>두 변수간의 <strong>크기 순서상의 상관관계</strong>의 정도를 나타냄</p>
</li>
<li><p>단조관계만 유지되면 잘 나옴</p>
<ul>
<li><p>단조관계: 두 변수가 함께 증가하지만 같은 비율로 증가하진 않는 관계</p>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/037c8dd0-5a3c-4bee-a50e-2dfcdad882a4/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li>두 상관계수 모두 1/-1에 가까울 수록 양/음의 상관관계가 있다고 할 수 있다</li>
<li>같이 나오는 p-value(가설검정)의 경우 ‘H0: 두 변수는 상관관계가 없다’ 라고 하는 가설에 대한 p-value이다. 즉 p-value가 낮으면 두 변수가 상관관계가 있다고 볼 수 있음</li>
</ul>
<h3 id="궁금한-점">궁금한 점</h3>
<ul>
<li>R-squared에서 모델을 평가하는 데 왜 식에 라벨의 분산이 포함되는지 이해가 안된다.</li>
<li>PCA에서 SS가 잘 이해가 되지 않는다. 원점과 수선의 발 사이 거리가 분산을 대표하는 건가?</li>
<li>naive bayes는 통계 복습하고 와서 다시 봐야겠다.. 수식이 잘 이해가 안된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[데브코스 34일차 - 데이터 모델링 (1)]]></title>
            <link>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-34%EC%9D%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81</link>
            <guid>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-34%EC%9D%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81</guid>
            <pubDate>Thu, 04 Apr 2024 10:17:17 GMT</pubDate>
            <description><![CDATA[<h3 id="키워드">키워드</h3>
<p>데이터 모델링, 회귀분석</p>
<h3 id="데이터-모델링이란">데이터 모델링이란?</h3>
<ul>
<li><p>주어진 데이터에서 사용하고자 하는 x(feature, input, 독립변수), 알고싶은 값 y(label, output, 종속변수)이 있을 때 y=f(x)라는 함수를 통해서 x와 y의 관계를 설명할 수 있다면?</p>
</li>
<li><p>y와 x의 관계를 효과적으로 설명하는 f() 함수를 만드는 일</p>
<ul>
<li>y 값이 존재할 때 → supervised learning</li>
<li>y 값이 존재하지 않는 경우 unsupervised learning</li>
<li>y값이 연속형인 경우 regression task</li>
<li>y 값이 categorical 값인 경우 classification task</li>
</ul>
</li>
<li><p>Bayes theorem의 관점</p>
<ul>
<li><p>조건부 확률: 어떤 사건이 일어났다는 ‘전제 하에’ 다른 사건이 일어날 확률</p>
<ul>
<li><p>P(B|A) = P(A∩B)/P(A), P(A|B) = P(B∩A)/P(B) ⇒ P(B|A) = P(A|B)P(B) / P(A)</p>
</li>
<li><p>데이터 모델링 관점에선 P(세타|X) = <strong>P(X|세타)</strong>P(세타)/P(X)</p>
<ul>
<li>X는 관측된 데이터, 세타는 데이터에 대한 가설, 즉 모델의 파라미터 값을 의미한다.</li>
<li>P(세타)는 데이터 관측 이전의 파라미터의 확률 분포를 의미. 보통 모든 값에 대한 확률이 동일하다고 가정</li>
<li><strong>P(X|세타)</strong>는 likelihood, 즉 파라미터가 주어졌을 때 X데이터가 관측될 확률 분포</li>
<li>P(세타|X)는 X가 주어졌을 때 파라미터의 확률 분포</li>
</ul>
</li>
<li><p>궁극적인 목적은 P(세타|X)를 최대화하는 세타를 찾는 것</p>
<ul>
<li>P(세타)가 일정하다는 가정 하에 <strong>P(X|세타)</strong>(likelihood)를 최대화하는 세타를 추정(MLE)</li>
<li>그렇지 않을 때는 P(X|세타)P(세타)를 최대화 하는 세타를 추정(MAP)</li>
</ul>
<p>⇒ 이게 데이터 모델링이다..</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>데이터 모델링 과정</p>
<ul>
<li><p>데이터 전처리 및 간단한 분석(통계적 분석, 시각화 등)</p>
</li>
<li><p>training set/test set으로 분리 (validation set도 나누기도 함)</p>
</li>
<li><p>training set으로 사용할 모델을 학습 (model.fit(training_set))</p>
</li>
<li><p>학습된 모델의 test set에 대한 예측값을 통해 모델의 성능을 평가 (실제값과 예측값의 비교)</p>
</li>
<li><p>새로운 데이터에 대해 학습된 모델을 이용해 y 값을 예측 (추론)</p>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/34f7a375-5b83-489e-8dae-97140b0e261b/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<h3 id="선형회귀-linear-regression">선형회귀 (Linear Regression)</h3>
<ul>
<li>x와 y 간에 선형의 관계가 있다고 가정할 때 주로 사용됨 (y=wx + b)<ul>
<li>예측값 y와 실제 y가 최대한 가까워지는 w와 b 값을 찾도록 학습됨</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/60af603e-29c5-4c99-85a8-978bd29f806b/image.png" alt=""></p>
<ul>
<li><p>선형회귀의 가정</p>
<ul>
<li>오차항(엡실론)의 기대치는 0이다</li>
<li>오차항은 일정한 분산을 가진다</li>
<li>i≠j일 때, 엡실론 i와 엡실론 j는 서로 독립이다.</li>
<li>독립변수 X와 엡실론은 서로 독립이다.</li>
<li>엡실론은 정규분포 N(0, 시그마^2)를 따른다.</li>
</ul>
</li>
<li><p>가정</p>
<ul>
<li>회귀 모형은 선형성을 가진다.<ul>
<li>E(Y) = E(b+wX+엡실론) = b+wX+E(엡실론) ⇒ b+wX</li>
</ul>
</li>
<li>종속변수 Y의 분산은 일정한 값을 갖는다.</li>
<li>엡실론 i와 엡실론 j는 서로 독립이며, 엡실론은 자기상관성이 없다.<ul>
<li>시계열 데이터의 경우는 자기상관성이 존재할 수 있다.</li>
</ul>
</li>
<li>Y는 정규분포를 따른다.<ul>
<li>E(Y) = b+wX, Var(Y) = 시그마^2</li>
<li>Y~N(b+wX, 시그마^2)</li>
</ul>
</li>
</ul>
</li>
<li><p>비용함수</p>
<ul>
<li>실제 Y와 Ypred의 오차를 계산하는 식을 세우고, 이 오차를 최소화하는 w,b를 찾아야함</li>
<li>오차에 대한 식을 <strong>손실함수, 비용함수, 목적함수</strong> 라고 한다. (조금씩 차이가 있음)</li>
<li>선형회귀에선 Residual sum of squares(RSS), 혹은 Mean squared error(MSE)를 사용<ul>
<li>mse: 오차(예측-실제) 제곱의 합의 평균</li>
</ul>
</li>
<li>비용함수가 미분가능하고 아래로 볼록할 때, cost의 최저점은 비용함수를 w와 b로 각각 편미분 했을 때 0이 되는 지점</li>
</ul>
</li>
<li><p>Ordinary Least Squares (최소제곱법)</p>
<ul>
<li>오차 엡실론을 최소화하는 w,b를 추정하는 방법</li>
</ul>
</li>
<li><p>Gradient descent (경사하강법)</p>
<ul>
<li>최적화(정답과 예측값의 차이를 최소화하는 네트워크 구조의 파라미터를 찾는 과정) 방법</li>
<li>변수가 많아지거나 비용함수가 복잡해지는 경우 최소 제곱법을 통해 한번에 loss가 최소인 파라미터를 추정하기 어려워짐</li>
<li>이 경우, 파라미터에 대해서 비용함수를 편미분한 값(gradient)을 learning rate만큼 여러번 업데이트 해주는 것을 경사하강법이라고 한다.<ul>
<li>모든 학습 데이터에 대해 한번에 gradient descent step을 계산하는 batch gradient descent보다는 매 스텝에서 미니배치만큼의 데이터를 샘플링 해서 학습하는 mini-batch stochastic gradient descent(SGD) 방식으로 학습한다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="ridge-lasso">Ridge, Lasso</h3>
<ul>
<li><p>overfitting (과적합)</p>
<ul>
<li>학습 데이터에 과하게 fitting 되는 경우를 의미</li>
<li>테스트 셋에서의 로스가 증가. 즉 일반화되지 못한 상태를 의미</li>
<li>데이터에 내재된 복잡도보다 모델의 복잡도가 더 과한 경우, 데이터셋 사이즈가 작은 경우</li>
<li>선형 회귀에선, 고려하는 변수가 많아질수록 과적합이 발생할 가능성이 높아짐</li>
</ul>
</li>
<li><p>Generalization (일반화)</p>
<ul>
<li>학습할 때와 추론할 때의 성능 차이가 많이 나지 않는 경우. 즉 모델이 여러 추론 상황에서 잘 쓰일 수 있음을 의미</li>
</ul>
</li>
<li><p>오버피팅 해결 방법</p>
<ul>
<li>모델의 복잡도 줄이기<ul>
<li>모델이 가질 수 있는 파라미터를 줄이기</li>
<li>모델이 고려하는 피쳐 중 상대적으로 중요한 피쳐들만 모델의 인풋으로 사용해볼 수 있다.</li>
</ul>
</li>
<li>정규화<ul>
<li>모델이 가지는 복잡도를 제한하는 방법</li>
<li>모델의 파라미터가 가지는 값의 크기를 cost function에 추가해주는 방식으로 파라미터 값의 크기를 제한한다. (파라미터를 cost function에 추가해 해당 파라미터를 조절하도록)</li>
</ul>
</li>
</ul>
</li>
<li><p>Ridge regression</p>
<ul>
<li><p>선형 최귀 모델에 L2 loss를 추가해서 파라미터를 정규화해줌</p>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/f3a06b9a-be5d-4b78-88ad-c53235d7e2b3/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>- 람다(하이퍼파라미터) 값을 조절해 패널티를 조절
- sklearn.linear_model에서 ridge를 import해서 linearRegression과 동일하게 사용</code></pre><ul>
<li>Lasso<ul>
<li>위의 ridge 식에서 패널티의 sum에 베타의 절댓값을 사용</li>
</ul>
</li>
</ul>
<h3 id="로지스틱-회귀-svm">로지스틱 회귀, SVM</h3>
<ul>
<li><p>로지스틱 회귀</p>
<ul>
<li><p>회귀가 아닌 분류 task에서 사용되는 모델</p>
</li>
<li><p>y에 시그모이드를 적용해 y의 값이 0~1 사이 값이 되도록 만든다.</p>
<p>  <img src="https://velog.velcdn.com/images/jerry_bak/post/4ba148ff-57d1-4028-b35a-2d7361635965/image.png" alt="시그모이드"></p>
</li>
</ul>
</li>
</ul>
<pre><code>- 0 이상의 인풋에 대해 0.5 이상의 값을 내고, 0 이하의 인풋에 대해선 0.5 이하의 값을 반환</code></pre><ul>
<li><p>SVM (Support Vector Machine)</p>
<ul>
<li><p>어느정도 허용 오차(C) 안에 있는 오차값은 허용해준다! (+-엡실론 범위 안에 있는 값에 대해선 loss를 계산하지 않는다.)</p>
<p>  <img src="https://velog.velcdn.com/images/jerry_bak/post/e26c7b1c-7f20-4e1c-9bd8-1b3967389476/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>- 허용오차 값 C를 잘 설정해야 모델이 좋은 성능을 낼 수 있다.
- SVR은 regression task, SVC는 classification task에서 사용</code></pre><h3 id="random-forest">Random forest</h3>
<ul>
<li>decision tree<ul>
<li>x를 기준삼아, ‘해당 기준을 만족/불만족시 y 값이 ~값일 것이다’라는 조건(x)-결과(y)를 나무처럼 발전시킴</li>
<li>classification에선 y가 클래스, regression에선 y값이 평균값</li>
</ul>
</li>
<li>랜덤 포레스트<ul>
<li>decision tree를 무작위로 여러개를 만든 후 각 트리마다 나온 decision들을 voting(ensemble)해 최종적인 y 값을 예측</li>
<li>파라미터<ul>
<li>n_estimators(트리 개수)</li>
<li>max_depth(각 트리의 길이)</li>
<li>무조건 트리 개수나 길이 값이 크다고 성능이 좋아지진 않으며, 학습 시간이나 차지하는 메모리가 지나치게 커질 수 있다.</li>
</ul>
</li>
<li>데이터셋이 작은 경우엔, 최적화가 잘 된 랜덤포레스트 모델이 성능이 좋음</li>
</ul>
</li>
</ul>
<h3 id="모르는-것">모르는 것</h3>
<ul>
<li><p><em>손실함수(비용함수)를 편미분한 값이 뭐더라</em></p>
<ul>
<li>기울기<ul>
<li>미분 가능한 N개의 다변수 함수 f를 각 축이 가리키는 방향마다 편미분한 것</li>
<li>즉 축이 x,y로 두개라면 x로 편미분한 값, y로 편미분한 값</li>
</ul>
</li>
<li>즉 기울기가 0이되는(낮아지는) 지점을 찾아 감</br></li>
</ul>
</li>
<li><p><em>편미분한 값에 learning rate를 곱한 만큼 파라미터를 조정하는건가?</em></p>
<ul>
<li><p>가중치의 경우, Wn = Wn-1 - lr*(손실함수 편미분 값)으로 계산됨</p>
</li>
<li><p>즉 학습률로 가중치를 얼마나 변경할지(step size, 가중치를 업데이트 하는 과정을 step이라고 함) 선택할 수 있는거다. 이렇게 수정하면서, 손실함수의 값이 거의 변하지 않을 때까지 가중치를 업데이트하는 과정을 반복</p>
</li>
<li><p>그래서 편미분값에 -를 붙여 기울기가 양수면 왼쪽(-)으로, 기울기가 음수면 오른쪽(+)이 되는쪽으로 가중치를 업데이트해 손실함수가 최소값을 갖도록 하는 것</p>
</li>
<li><p><em>그러면 손실함수를 각 파라미터로 편미분한 값으로 각 파라미터를 업데이트하는건가?</em></p>
<ul>
<li><p>어 맞음… 그니까 여기선 가중치 W를 갖고 설명한 것 처럼, 만약 내가 업데이트하고자 하는 파라미터 X가 있을 때 손실함수를 X에 대해 편미분한 값을 파라미터 X를 업데이트하는 데 사용하고자 하는거지</p>
<p>$$
θnew=θold−α∇L(θold)
$$</p>
</li>
<li><p><em>근데 그럴려면 손실함수에 세타(파라미터)가 포함되어있어야하는거 아니야?</em></p>
<ul>
<li>아 파라미터가 가중치랑 편향이잖슴. 근데 손실함수에 예측값이 들어가는 데 그 예측값이 wx+b니까 파라미터가 손실함수에도 포함되는 거임</br></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p>모든 학습 데이터에 대해 한번에 gradient descent step을 계산하는 batch gradient descent보다는 매 스텝에서 미니배치만큼의 데이터를 샘플링 해서 학습하는 mini-batch stochastic gradient descent(SGD) 방식으로 학습한다.</p>
<ul>
<li><em>배치마다 하지 않고 배치 내에서 쪼개서 한다는 말인가?</em><ul>
<li>그니까, <strong>경사하강법(BGD)</strong>은 한 번의 가중치 업데이트에 모든 데이터를 사용하므로 1 batch의 사이즈가 전체 데이터 크기라고 할 수 있음<ul>
<li>하지만 배치 경사하강법을 사용하면, 가중치 업데이트에 연산량이 많아지고 메모리 소비가 심해 시간이 오래 걸린다는 단점이 있음 ⇒ 결국 성능 저하로 이어짐</li>
</ul>
</li>
<li>그래서 <strong>SGD</strong>는 전체 데이터 대신 랜덤하게 하나의 데이터를 뽑아 한 번의 반복당 한개의 데이터를 이용해 가중치를 업데이트하는 방법이다.<ul>
<li>하지만 이는 하나의 데이터만 사용하기 때문에 최적값에 수렴하지 않을 가능성이 있어 수렴 안정성이 낮고 진폭이 매우 크다.</li>
</ul>
</li>
<li>그래서 나온 절충안이 <strong>미니배치 경사하강법(MSGD)</strong>임, 배치의 크기를 사용자가 정해 업데이트에 사용하는 방법. 즉 전체 데이터를 미리 정한 배치 사이즈만큼씩 묶어 각 묶음에 대해 경사 하강법을 적용대신 일부 데이터 모음(mini-batch)를 사용해 loss를 계산한다는 것<ul>
<li>BGD보다는 연산량이 적고, SGD보다는 안정적으로 수렴한다는 장점이 있다.</li>
</ul>
</li>
<li><a href="https://yhyun225.tistory.com/7">참조</a></br></li>
</ul>
</li>
<li><em>스텝이랑 배치랑 무슨 차이였지</em><ul>
<li>배치는 데이터를 배치 사이즈로 묶은 그룹을 의미하는 말</li>
<li>스텝은 그 배치 내의 데이터에 대해 기울기를 계산해 파라미터를 업데이트 하는 과정을 말한다. (텐서플로우에서는 이를 iteration이라고 하기도 함)</br></li>
</ul>
</li>
</ul>
</li>
<li><p><em>SVM이 그래서 무슨 역할을 하는거지?</em></p>
<ul>
<li>주로 2개의 값 분류(이진 분류)를 위해 사용 (확률(Y)을 1,0으로 변환해 사용, threshold를 지정)</li>
<li>x가 0보다 크면 긍정, 0보다 작으면 부정을 의미</li>
<li>나의 경우 모델 output을 0~1사이 값으로 변경해 확률로 사용했었다.</li>
<li>선형으로 나타낼 때보다 유한 결정?을 낼 수 있음</li>
<li>근데 이걸 분류모델로 사용한다고?<ul>
<li>만약에 분류하는 직선인 선형 모델의 경우 좀더 retricted한 분류가 될 것이다. 이를 SVM을 사용해 해결하고자 하고, 학습을 통해 그래프의 feature들을 조정해 높은 정확도의 분류 라인을 만들어내는 것이다. <a href="https://velog.io/@gayeon/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%EC%B4%88%EB%B3%B4%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-Logistic-Regression-with-Scikit-Learn">참고</a></li>
</ul>
</li>
</ul>
</li>
<li><p>SVM 이미지에서 초록색이 서포트 벡터래, 뭐지?</p>
<ul>
<li>support vector가 <strong>선과 가장 가까운 포인트</strong>를 말한다고 함. SVM은 오차 범위의 포인트까지 포함이니 오차범위 바깥의 가장 가까운 포인트를 의미하는 거겠지.</li>
<li>즉 서포트벡터와의 거리, 즉 Margin이 최대화(분리를 명확하게) 되는 것이 robustness를 최대화할 수 있는 것이라고 한다.</li>
</ul>
</li>
</ul>
<h3 id="느낀점">느낀점</h3>
<ul>
<li>했던 건데 모르는 게 너무 많다. 물론 좀 되긴 했지만 ... 나만 이러는 걸까 아니면 모두 이런걸까? 뭐 어쩌든 상관없이 꾸준이 공부하고 복습하는 게 답이다!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[데브코스 31일차 - 데이터 분석, 스케일링]]></title>
            <link>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-31%EC%9D%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%EC%8A%A4%EC%BC%80%EC%9D%BC%EB%A7%81</link>
            <guid>https://velog.io/@jerry_bak/%EB%8D%B0%EB%B8%8C%EC%BD%94%EC%8A%A4-31%EC%9D%BC%EC%B0%A8-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B6%84%EC%84%9D-%EC%8A%A4%EC%BC%80%EC%9D%BC%EB%A7%81</guid>
            <pubDate>Mon, 01 Apr 2024 09:50:37 GMT</pubDate>
            <description><![CDATA[<h3 id="키워드">키워드</h3>
<p>데이터분석, 스케일링</p>
<h3 id="데이터-분석이란">데이터 분석이란?</h3>
<ul>
<li><p>나스닥 시총 상위 기업을 보면 <code>제조업 → 서비스 기업</code>으로의 경향을 보임</p>
<ul>
<li>아마존 → 구매 <strong>예측</strong>을 통한 추천</li>
</ul>
</li>
<li><p>데이터를 정리, 변환, 조작, 검사하여 인사이트를 만들어내는 작업</p>
</li>
<li><p>의사 결정의 판단 기준이 ‘주관적인 직감’에서 ‘객관적인 데이터’로!</p>
</li>
<li><p>단순한 분석보단 어떻게 문제를 해결할지에 대한 고민이 중요</p>
</li>
<li><p>데이터 분석은 결국 수단임! → 본질(문제 해결)을 잊지 말아야함</p>
</li>
</ul>
<h3 id="데이터-분석-과정">데이터 분석 과정</h3>
<ul>
<li>문제 정의<ul>
<li><strong>풀고자하는 문제</strong>가 명확하지 않으면 데이터분석은 무용지물이 됨</li>
<li>큰 문제를 작은 단위의 문제들로 나눈 후</li>
<li>각 작은 문제들에 대해서 여러 가설들을 세우고</li>
<li>데이터 분석을 통해 가설을 검증 &amp; 결론을 도출하거나 피드백을 반영</li>
<li>해당 문제를 일으키는 원인이 뭔지, 지표가 무엇인지</li>
</ul>
</li>
<li>데이터 수집<ul>
<li>가설 검증에 필요한 데이터가 존재하는가?</li>
<li>어떤 종류의 데이터가 필요한가?<ul>
<li>데이터로부터 얻고자하는 정보가 무엇인지 명확하게 해야 필요한 데이터만 모을 수 있다.</li>
</ul>
</li>
<li>얻고자 하는 데이터의 지표가 명확한가?</li>
</ul>
</li>
<li>데이터 전처리<ul>
<li>데이터 추출, 필터링, 그룹핑, 조인 등 (sql)</li>
<li>이상치 제거, 분포 변환, 표준화, 카테고리화, 차원 축소 등</li>
</ul>
</li>
<li>데이터 분석<ul>
<li>EDA<ul>
<li>그룹별 평균, 합 등 기술적 통계치 확인</li>
<li>분포 확인</li>
<li>변수 간 관계 및 영향력 파악</li>
<li>데이터 시각화</li>
</ul>
</li>
<li>모델링 (머신러닝, 딥러닝)</li>
</ul>
</li>
<li>리포팅/피드백<ul>
<li>내용의 초점은 데이터 분석가가 아닌 상대방<ul>
<li>언어 선택에 주의, 목적을 수시로 상기&amp;재확인</li>
</ul>
</li>
<li>적절한 시각화 방법 활용<ul>
<li>항목간 비교시 원 그래프는 지양, 막대 그래프 위주</li>
<li>X,Y 축 및 단위 주의</li>
<li>시계열은 라인이나 실선으로,</li>
<li>분포는 히스토그램이나 박스플롯</li>
<li>변수간 관계는 산점도!</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="데이터-정규화와-스케일링-기법">데이터 정규화와 스케일링 기법</h3>
<ul>
<li><p>하나의 instance(sample) - 여러 속성값들(feature)</p>
</li>
<li><p>피쳐 간 크기 및 단위가 들쭉날쭉하거나 가지는 값의 범위가 크게 다른 경우, 혹은 이상치 문제가 심각한 경우, 데이터 분석이 어려워지거나 머신러닝, 딥러닝 방법을 적용하기 어려워지는 경우가 있음</p>
<ul>
<li>연봉, 나이, 보유 주택 수 등</li>
</ul>
</li>
<li><p>Normalization(정규화): 여러가지 값들이 가지는 범위의 차이를 왜곡하지 않으면서 범위를 맞추는 것</p>
<ul>
<li><p>min-max normalization</p>
<ul>
<li>모든 피쳐 값이 0~1 사이에 위치하도록 스케일링</li>
<li>(x-min(x))/max(x)-min(x))</li>
<li>피쳐들간의 variance(분산) 패턴은 유지한채로 스케일링됨<ul>
<li>variance가 유지된다는 것은 특정 피쳐의 variance가 매우 큰 경우엔 여전히 데이터분석에 적절치 않을 수 있음</li>
</ul>
</li>
</ul>
</li>
<li><p>z-score normalization(standardization)</p>
<ul>
<li>피쳐값이 평균=0, 표준편차=1 값을 갖는 정규 분포를 따르도록 스케일링</li>
<li>z = (x-평균)/표준편차 → 표준점수(z-score)</li>
<li>outlier 문제에 상대적으로 robust한 스케일링 방법임<ul>
<li>하지만 최소값 최대값 범위가 정해지지 않는 단점이 있음 (평균적으로 -2~2)</li>
</ul>
</li>
</ul>
</li>
<li><p>log scaling</p>
<ul>
<li><p>피쳐값들이 exponential한 분포(positive skewed, 한쪽으로 치우친?)를 가지는 경우 피쳐값들에 log 연산을 취해 스케일링</p>
<ul>
<li><p>ex 대한민국 국민 연봉의 분포</p>
<p><img src="https://velog.velcdn.com/images/jerry_bak/post/b1dd0049-9ed7-458b-8ce7-5820d594e404/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code>    - 비슷하게 square root 연산을 취하거나
    - 반대의 분포를 갖는 경우 power/exponential 연산을 통해 스케일링 할 수 있음
- 다양한 스케일링을 통해 데이터가 좀더 정규분포에 가까워지도록 스케일링하여 outlier 문제에도 좀 더 적극적으로 대응 가능</code></pre><h3 id="실습">실습</h3>
<ul>
<li><code>df[’age’].hist(bins=30)</code> → 특정 피쳐의 값으로 히스토그램을 그려볼 수 있음<ul>
<li>bins 값을 키우면 좀 더 촘촘한 히스토그램</li>
</ul>
</li>
</ul>
<pre><code class="language-python">scaler = MinMaxScaler()
df[&#39;fare_minmax&#39;] = scaler.fit_transform(df[&#39;fare&#39;].values.reshape(-1,1))
df[&#39;age_minmax&#39;] = scaler.fit_transform(df[&#39;age&#39;].values.reshape(-1,1))</code></pre>
<ul>
<li>min-max의 문제점은 variance가 그대로 유지된다는 것임 (분포의 패턴은 동일, 범위만 달라짐)</li>
</ul>
<pre><code class="language-python">scaler = StandardScaler()
df[&#39;fare_standard&#39;] = scaler.fit_transform(df[&#39;fare&#39;].values.reshape(-1,1))
df[&#39;age_standard&#39;] = scaler.fit_transform(df[&#39;age&#39;].values.reshape(-1,1))</code></pre>
<ul>
<li>실습 데이터에선 조금씩 달라진 걸 확인할 수 있음</li>
</ul>
<pre><code class="language-python"># 난수 생성
exp_scale_data = np.random.exponential(1,300)
df_exp = pd.DataFrame(columns=[&#39;x&#39;])
df_exp[&#39;x&#39;] = exp_scale_data

# log scaling
df_exp[&#39;log_x&#39;] = np.log(df_exp[&#39;x&#39;])
# outlier 값들이 조금 있지만 비교적 종 모양을 따라감</code></pre>
<pre><code class="language-python"># squre root를 이용한 스케일링
df[&#39;fare_sqrt&#39;] = np.sqrt(df[&#39;fare&#39;])</code></pre>
<ul>
<li>시각화를 통해 데이터의 <strong>분포</strong>를 살펴보면서 데이터를 스케일링 해주는 것이 효과적이다.</li>
</ul>
<h3 id="느낀점">느낀점</h3>
<ul>
<li>프로젝트를 하면서 느낀 것들을 압축해놓은 수업이었던 것 같다. 문제 정의를 하는 게 가장 중요하다는 점과, 단순한 분석보단 어떻게 문제를 해결할 것인지 고민하는 게 중요하다는 점.</li>
<li>프로젝트 하기 전에 이 내용을 배웠다면...! 그치만 몸소 느끼는 게 더 기억에 오래 남을 수도 있겠지</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>