<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>mios.velog</title>
        <link>https://velog.io/</link>
        <description>mios의 데이터 놀이터  |  Instagram@data.decision (하단 홈 아이콘 버튼)</description>
        <lastBuildDate>Tue, 07 Mar 2023 06:38:06 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>mios.velog</title>
            <url>https://velog.velcdn.com/images/mios_leo/profile/20d41265-b5b3-4368-adf8-8e09eab5048f/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. mios.velog. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/mios_leo" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[뱅크샐러드는 왜 돈 안되는 ‘유전자 검사’를 할까?]]></title>
            <link>https://velog.io/@mios_leo/%EB%B1%85%ED%81%AC%EC%83%90%EB%9F%AC%EB%93%9C%EB%8A%94-%EC%99%9C-%EB%8F%88-%EC%95%88%EB%90%98%EB%8A%94-%EC%9C%A0%EC%A0%84%EC%9E%90-%EA%B2%80%EC%82%AC%EB%A5%BC-%ED%95%A0%EA%B9%8C</link>
            <guid>https://velog.io/@mios_leo/%EB%B1%85%ED%81%AC%EC%83%90%EB%9F%AC%EB%93%9C%EB%8A%94-%EC%99%9C-%EB%8F%88-%EC%95%88%EB%90%98%EB%8A%94-%EC%9C%A0%EC%A0%84%EC%9E%90-%EA%B2%80%EC%82%AC%EB%A5%BC-%ED%95%A0%EA%B9%8C</guid>
            <pubDate>Tue, 07 Mar 2023 06:38:06 GMT</pubDate>
            <description><![CDATA[<p>링크: <a href="https://outstanding.kr/banksaladdna20220523">https://outstanding.kr/banksaladdna20220523</a></p>
<hr>
<h2 id="뱅크샐러드의-유전자-검사">뱅크샐러드의 유전자 검사</h2>
<p>  핀테크 회사인 뱅크샐러드에서는 현재 무료로 유전자 검사를 할 수 있는 서비스를 운영 중이다. 2021년 10월부터  2022년 5월까지 누적 12만명이 무료로 유전자 검사를 받았다. 매일 선착순으로 오전 10시에 700명을 신청받고 있다.</p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/c784d8a0-b91f-44c5-a443-6a2a0c2317ff/image.png" alt=""></p>
<p>  2021년 유전자 검사를 시작으로 마이데이터 전문업체로의 도약을 비전으로 삼고, 10대 질병 발병률 예측 서비스인 ‘내 위험 질병 찾기’ 런칭하며 건강 마이데이터 사업으로 확장중이다.</p>
<h2 id="뱅크샐러드는-건강-사업을-왜-하나요">뱅크샐러드는 건강 사업을 왜 하나요?</h2>
<p>핀테크 회사인 뱅크샐러드가 건강 관련 서비스 하는 이유?</p>
<ul>
<li>궁극적으로 지향하는 바는 ‘데이터’ 영역에서 전문성을 가진 회사</li>
<li>마이데이터라는 큰 틀에서 금융을 넘어 건강까지 아우르는 서비스</li>
<li>개인이 만들 수 있는 가장 근본적인 데이터는 ‘건강’ 이라고 생각</li>
</ul>
<h2 id="왜-유전자-검사로-시작했나요">왜 유전자 검사로 시작했나요?</h2>
<ul>
<li>우선, 자신의 건강에 대한 기본적인 이해가 필요하다고 생각했음</li>
<li>이 부분을 소비자에게 어떻게 이해시키고 전달할지 고민하다 보니 유전자 검사로 결정</li>
<li>마이데이터에 맞게 유전자 검사는 일반적인 정보가 아닌 개인 맞춤형 정보</li>
<li>일반적 유전자 검사 비용은 10~30만원인데, 이 서비스를 무료로 운영하는 이유<ul>
<li>유저를 모으기 위한 투자, 고객에게 건강 데이터에 대한 경험 제공</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/cfe7483a-0ea2-46b4-a5d4-a2300d7a6f46/image.png" alt=""></p>
<h2 id="유전자-검사를-보여주는-방식">유전자 검사를 보여주는 방식</h2>
<ul>
<li>만들어진 전문적인 의학 데이터에 대한 의미를 이해를 알기 쉽게 ‘보이는 형태’로 전달</li>
<li>실제 나의 행동과 인과관계가 느껴져야 이 데이터와 시너지를 만들어낼 것이라고 생각</li>
<li>유전자 검사 결과 카드</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/1fba620f-df5a-4977-84cc-e52bd79d9de2/image.png" alt=""></p>
<ul>
<li>유전자 검사를 통해 사람들이 내 행동과 습관을 연결하게 되어</li>
<li>유전자 검사를 보고 고민 될 때, 바로 진료나 검사를 해보는 것에 활용하는 것을 의도하고 있음</li>
</ul>
<h2 id="내-위험-질병-찾기는-어떤-서비스">‘내 위험 질병 찾기’는 어떤 서비스?</h2>
<ul>
<li>고객의 성별, 나이, 건강검진 정보 등 건강 데이터를 활용해서, 특정 질병에 걸릴 통계적 발병률을 알려주는 내용</li>
<li>유전자 검사가 ‘선천적 내 건강’을 알려줬다면, 내 위험 질병 찾기는 ‘후천적 건강 관리’에 초점을 맞춘 서비스</li>
<li>이 역시, 전문 의학 지식이 실제로 나에게 어떤 의미이고, 어떻게 해석해야하는 건지를 쉬운 메시지로 전달하는데 의의를 둠</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/51c28f12-dd0f-477f-b8ab-d2b1851d94f6/image.png" alt=""></p>
<h2 id="이걸로-돈을-벌-수-있을까요">이걸로 돈을 벌 수 있을까요?</h2>
<ul>
<li>솔직히 어렵다.</li>
<li>마이데이터로 건강 부분에 적용한 사업이 얼마 안되어, 수익까지 가려면 건강 관련된 비전을 많이 만들어놔야 함</li>
<li>건강과 관련된 많은 데이터가 쌓이면 구상해 볼 수 있을 듯</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 9. Text Analytics(1) (Encoding, Vectorize)]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-9.-Text-Analytics1-Encoding-Vectorize</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-9.-Text-Analytics1-Encoding-Vectorize</guid>
            <pubDate>Wed, 26 Oct 2022 03:41:34 GMT</pubDate>
            <description><![CDATA[<h1 id="text-analytics-텍스트-분석">Text Analytics 텍스트 분석</h1>
<ul>
<li>TA(Text Analytics or Text Mining)<ul>
<li>비정형 텍스트에서 의미있는 정보를 추출하는 것에 좀 더 중점을 두고 발전</li>
<li>머신러닝, 언어 이해, 통계 등을 활용해 모델을 수립하고 정보를 추출해 비즈니스 인텔리전스나 예측 분석 등의 분석 작업을 주로 수행한다.<ul>
<li>텍스트 분류 : 문서가 특정 분류/카테고리에 속하는 것을 예측하는 기법 ← 지도학습</li>
<li>감성 분석 : 텍스트에서 나타나는 감정/판단/믿음/의견/기분 등의 주관적인 요소들을 분석하는 기법 ← 지도&amp;비지도학습</li>
<li>텍스트 요약 : 텍스트 내에서 중요한 주제나 중심 사상을 추출하는 기법 ex) 토픽 모델링 (Topic Modeling)</li>
<li>텍스트 군집화와 유사도 측정 : 비슷한 유형의 문서에 대해 군집화를 수행하는 기법 ← 비지도학습</li>
</ul>
</li>
</ul>
</li>
<li>NLP(Nature Language Processing)<ul>
<li>머신이 인간의 언어를 이해하고 해석하는 데에 더 중점을 두고 발전</li>
<li>기계번역, 질의응답 시스템 등의 영역에서 텍스트 분석과 차별점 존재</li>
</ul>
</li>
</ul>
<h1 id="1-텍스트-분석의-이해">1. 텍스트 분석의 이해</h1>
<p>: 비정형 데이터인 텍스트를 분석하는 것. 머신러닝 알고리즘은 숫자형의 피처 기반 데이터만 입력받을 수 있기 때문에 비정형 텍스트 데이터를 피처 형태로 추출하고, 추출된 피처에 의미있는 값을 부여하는 게 중요하다.</p>
<ul>
<li><p>피처 벡터화(Feature Vectorization), 피처 추출(Feature Extraction)</p>
<p>  : 텍스트를 word(or word의 일부분) 기반의 다수의 피처로 추출하고, 이 피처에 단어 빈도수와 같은 숫자값을 부여하면 텍스트는 단어의 조함인 벡터값으로 표현될 수 있는데, 이렇게 텍스트를 변환하는 것</p>
<ul>
<li>방법: BOW(Bag of Words), Word2Vec (책에서는 BOW만 설명)</li>
</ul>
</li>
<li><p>과정</p>
<ol>
<li>텍스트 전처리<ol>
<li>클렌징 : 대소문자 변경, 특수문자, 기호 삭제 등</li>
<li>토큰화 : 문장/단어</li>
<li>불용어, 필터링, 철자수정 : 의미없는 단어(stop word) 등 제거</li>
<li>어간/표제어 추출 : 단어에서 어간 및 표제어 추출</li>
</ol>
</li>
<li>피처 추출 / 벡터화 (Encoding) : 피처를 추출하고 벡터값 할당<ol>
<li>BOW(Bag of Words) : Count 기반, TF-IDF 기반</li>
<li>Word2Vec</li>
</ol>
</li>
<li>ML 모델 수립 및 학습/예측/평가</li>
</ol>
</li>
<li><p>파이썬 기반의 NLP, 텍스트 분석 패키지</p>
<ul>
<li><p>NLTK(Natural Language Toolkit for Python): 가장 대표적인 NLP 패키지. 수행 성능, 속도, 신기술, 엔터프라이즈한 기능 지원 등에서 아쉬워 실제 업무에서는 잘 안쓰임</p>
</li>
<li><p>Gensim: 토픽 모델링 분야에서 가장 두각을 나타내는 패키지</p>
</li>
<li><p>SpaCy: 뛰어난 수행 성능으로 최근 가장 주목을 받는 NLP 패키지</p>
<p>⇒ 사이킷런과 더불어 이러한 NLP 전용 패키지와 결합해 애플리케이션을 작성하는 경우가 많다.</p>
</li>
</ul>
</li>
</ul>
<h1 id="2-텍스트-전처리">2. 텍스트 전처리</h1>
<ul>
<li><p>텍스트 정규화 : 텍스트를 머신러닝 알고리즘이나 NLP 애플리케이션에 입력 데이터로 사용하기 위해 클렌징, 정제, 토큰화, 어근화 등의 다양한 텍스트 데이터의 사전작업을 수행하는 것</p>
<p>  → 클렌징, 토큰화, 필터링 | 스톱워드 제거 | 철자 수정, Stemming, Lemmatization</p>
</li>
<li><p>클렌징(Cleansing) : 대소문자 변경, 특수문자, 기호 삭제 등</p>
</li>
<li><p>토큰화(Tokenization)</p>
<ul>
<li><p>문장 토큰화</p>
<ul>
<li><p>문서에서 문장을 분리</p>
</li>
<li><p>문장의 마침표(.), 개행문자(\n) 등 문장의 마지막을 뜻하는 기호에 따라 분리하는 게 일반적</p>
</li>
<li><p>정규 표현식에 따른 문장 토큰화도 가능</p>
</li>
<li><p>각 문장이 가지는 시맨틱적 의미가 중요한 요소로 사용될 때 사용</p>
</li>
<li><p>NLTK의 경우 단어 사전과 같이 참조가 필요한 데이터 세트의 경우 인터넷으로 다운 받을 수 있다.</p>
<pre><code class="language-python">  nltk.download(&#39;punkt&#39;)
  ---
  from nltk import sent_tokenize

  sent_tokenize(text=텍스트 파일) # 각각의 문장으로 구성된 list 객체 반환</code></pre>
</li>
</ul>
</li>
<li><p>단어 토큰화</p>
<ul>
<li><p>문장을 단어로 토큰화 하는 것</p>
</li>
<li><p>공백, 콤마(,), 마침표(.), 개행문자 등으로 단어를 분리하지만, 정규표현식으로 다양한 유형으로 토큰화 수행 가능</p>
<pre><code class="language-python">from nltk import word_tokenize

word_tokenize(문장) # 각각의 단어로 구성된 list 객체 반환</code></pre>
</li>
<li><p>단점 : 문맥적 의미가 무시된다.</p>
</li>
<li><p>n-gram</p>
<ul>
<li>위의 단점을 보완하기 위해 도입됨</li>
<li>연속된 n개의 단어를 하나의 토큰화 단위로 분리하는 것</li>
<li>n개 단어 크기 윈도우를 만들어 문장의 처음부터 오른쪽으로 움직이면서 토큰화 수행</li>
<li>예) Agent Smith knocks the door 를 2-gram(bigram)으로 만들면,
(Agent, Smith), (Smith, knocks), (knocks, the), (the, door)로 토큰화</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p>불용어(Stop Word) 제거</p>
<ul>
<li><p>불용어 : 분석에 큰 의미가 없는 단어 (예: 영어에서 is, the, a, will 등)</p>
</li>
<li><p>제거하는 이유 : 스톱워드는 문법적인 특성으로 인해 빈번하게 텍스트에 나타나므로 제거하지 않으면 빈번함으로 인해 중요 단어로 인식된다.</p>
</li>
<li><p>언어별로 불용어가 목록화 되어 있다.</p>
<pre><code class="language-python">nltk.download(&#39;stopword&#39;)

nltk.corpus.stopwords.words(&#39;english&#39;)
# 이후 for, if문을 이용하여 스톱워드를 제거한다.</code></pre>
</li>
</ul>
</li>
<li><p>추출(Stemming, Lemmatization) : 문법적, 의미적으로 변화하는 단어의 원형을 찾는 것</p>
<ul>
<li><p>어간 추출(Stemming): 원형 단어로 변환 시 일반적인 방법을 적용하거나 더 단순화된 방법을 적용해 원래 단어에서 일부 철자가 훼손된 어근 단어를 추출하는 경향이 있음</p>
<ul>
<li><p>어간 추출은 품사 정보를 갖고 있지 않음 : 단어의 뜻이 분명한 경우</p>
<pre><code class="language-python">from nltk.stem import LancasterStemmer

stemmer = LancasterStemmer()
stemmer.stem(&#39;working&#39;) # -&gt; work 로 변환</code></pre>
</li>
</ul>
</li>
<li><p>표제어 추출(Lemmatization) : 표제어 추출은  Stemming보다 정교하며 의미론적인 기반에서 단어의 원형을 찾음, 단어의 [품사 정보]를 포함하고 있음</p>
<ul>
<li><p>정확한 원형 단어 추출을 위해 단어의 품사를 입력해줘야 한다. 동사=’v’, 형용사=’a’</p>
</li>
<li><p>명사 / 동사로 쓰일 때 반어의 뜻이 완전히 달라지는 경우 ex) bear, taxi,</p>
</li>
<li><p>시간은 좀 더 걸린다.</p>
<pre><code class="language-python">from nltk.stem import WordNetLemmatizer

lemma = WordNetLemmatizer()
lemma.lemmatize(&#39;amusing&#39;, &#39;v&#39;) # -&gt; amuse로 변환</code></pre>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h1 id="3-피처-추출--피처-벡터화-encoding---bowbag-of-words--word2vec">3. 피처 추출 / 피처 벡터화 (Encoding) - BOW(Bag of Words) &amp; Word2Vec</h1>
<ul>
<li><p>피처 벡터화(Encoding) : ML알고리즘에 입력할 수 있도록, 텍스트를 특정 의미를 갖는 숫자형인 벡터값으로 변환하는 것</p>
<ol>
<li><p>각 문서의 텍스트를 단어로 추출해 피처로 할당</p>
</li>
<li><p>각 단어의 발생빈도와 같은 값을 피처 값으로 부여</p>
<p>⇒ 각 문서를 단어 피처의 발생 빈도값으로 구성된 벡터로 만드는 기법</p>
<p>: 기존 텍스트 데이터를 또 다른 형태의 피처의 조합으로 변경하는 것이기 때문에 피처 추출에 포함하기도 한다. (TA에서는 피처 벡터화와 피처 추출을 같은 의미로 사용하곤 한다.)</p>
</li>
</ol>
</li>
<li><p>BOW : 문서가 갖는 모든 단어(words)를 문맥이나 순서를 무시하고 일괄적으로 단어의 빈도 값을 부여해 피처값을 추출하는 모델</p>
<p>  <img src="https://velog.velcdn.com/images/mios_leo/post/368f2e20-52bf-499c-9ff5-920b0c61672f/image.png" alt=""></p>
</li>
</ul>
<pre><code>![](https://velog.velcdn.com/images/mios_leo/post/3520db12-42fe-4bb0-a735-19738c8859ff/image.png)


- 방식
    1. 문장 1과 문장 2에 있는 모든 단어에서 중복을 제거하고, 각 단어(feature or term)를 컬럼 형태로 나열
    2. 각 단어에 고유의 index를 부과 ex) ‘I’ : 0, ‘love’ : 1, ‘dogs’ : 3, ‘hate’ : 4 …
    3. 개별 문장을 로우로 잡고, 해당 단어가 나타나는 횟수(Occurrence)를 각 단어(단어 인덱스)에 기재합니다.
    4. 즉 M 개의 문장과 N 개의 단어 피처들로 이뤄진 MxN행렬이 구성되게 됨
- 장점 : 쉽고 빠른 구축
- 단점
    - 문맥의미(Semantic context) 반영 부족: 단어의 순서를 고려하지 않기 때문에 n-gram 기법 활용 가능하나 제한적이다.
    - 희소행렬 문제(희소성, 희소행렬): BOW로 피처 벡터화를 수행하면 희소행렬 형태의 데이터 세트가 만들어지기 쉽다. 희소행렬은 일반적으로 ML알고리즘의 수행시간과 예측 성능을 떨어뜨린다. (그래서 희소행렬을 위한 기법 마련되어 있음)</code></pre><ul>
<li><p>CountVectorizer : 단어에 피처 값을 부여 할 때, 각 문서에 해당 단어가 등장하는 횟수 Count로 Vector화</p>
<ul>
<li>CountVectorizer에서는 카운트 값이 높을 수록 중요한 단어로 인식</li>
<li>그러나 카운트만 부여할 경우, 그 문서의 특징을 나타내기 보다, 언어 특성상 자주 사용될 수 밖에 없는 단어까지 높은 값을 부여받게 됨</li>
<li>이러한 문제를 보완하기 위해 TF-IDF (Term Frequency Inverse Document Frequency) Vectorizer를 사용 함</li>
</ul>
</li>
<li><p>TF-IDFVectorizer : 개별 문서에서 자주 나타나는 단어에 높은 가중치를 주되, 모든 문서에 전반적으로 자주 나타나는 단어에 대해서는 패널티를 주는 방식으로 값을 부여</p>
<ul>
<li><p>문서마다 텍스트 길이가 길고, 문서의 갯수가 많은 경우에는, Count보다 TF-IDF 방식을 사용하느 것이 더 좋은 성능을 낼 가능성이 높음</p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/719f7a9a-3e5d-4e6f-a89c-af438fed670b/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<h2 id="31-countvectorizer-카운트-기반-벡터화">3.1. CountVectorizer (카운트 기반 벡터화)</h2>
<p>: 단어 피처에 값을 부여할 때 각 문서에서 해당 단어가 나타나는 횟수를 부여하는 경우</p>
<ul>
<li><p>카운트 값이 높을 수록 중요한 단어로 인식한다.</p>
</li>
<li><p>사이킷런 - CountVectorizer 클래스 제공</p>
<pre><code class="language-python">  from sklearn.feature_extraction.text import CountVectorizer</code></pre>
<ul>
<li>소문자 일괄 변환, 토큰화, 스톱워드 필터링 등 텍스트 전처리도 함께 수행해줌</li>
<li>파라미터 (TF-IDF도 동일)</li>
</ul>
</li>
</ul>
<pre><code>    | 파라미터 | 설명 |
    | --- | --- |
    | max_df | 전체 문서에 걸쳐서 너무 높은 빈도수를 가지는 단어 피처를 제외하기 위한 파라미터, int 입력: 주어진 값 이하로 나타나는 단어만 피처로 추출, float 입력: 빈도가 0~주어진 값% 까지만 피처로 추출 |
    | min_df | 전체 문서에 걸쳐서 너무 낮은 빈도수를 가진 단어 피처를 제외하기 위한 파라미터, int 입력: 주어진 값 이하로 나타나는 단어는 피처로 추출하지 않음, float 입력: 하위 주어진 값% 이하의 빈도를 가지는 단어는 피처로 추출하지 않음 |
    | max_features | int 입력 : 추출하는 피처의 개수를 제한, 가장 높은 빈도수를 가지는 단어순으로 정렬해 주어진 값 개수까지만 피처로 추출 |
    | stop_words | ‘english’로 지정하면 영어의 스톱워드로 지정된 단어는 추출에서 제외 |
    | n_gram_range | 단어 순서를 어느 정도 보강하기 위한 n_gram 범위 설정, 튜플 형태 (범위 최소값, 범위 최대값) |
    | analyzer | default = ‘word’, 피처 추출을 수행할 단위 지정, character의 특정 범위를 피처로 만드는 특정 경우에 사용 |
    | token_pattern | default = ‘\b\w\w+\b’ 공백 또는 개행 문자 등으로 구분된 단어 분리자(\b) 사이의 두 문자(영숫자) 이상의 단어를 토큰으로 분리, 정규 표현식 패턴 지정, analyzer=’word’일때만 변경 가능 (거의 변경X) |
    | tokenizer | 토큰화를 별도의 커스텀 함수로 이용시 적용, 일반적으로 CountTokenizer 클래스에서 어근 변화시 이를 수행하는 별도의 함수를 tokenizer 파라미터 적용하면 된다. |
- fit(), transform()을 통해 피처 벡터화된 객체 반환
    - 반드시 학습 데이터를 이용해 fit()이 수행된 객체를 이용해 테스트 데이터를 변환(transform)해야 한다.
    - 그래야만 학습시 설정된 CountVectorizer의 피처 개수와 테스트 데이터를 CountVectorizer로 변환한 피처 개수가 같아진다.
    - 테스트 데이터의 피처 벡터와 시 fit_transform() 사용 X

    ```python
    cnt_vect = CountVectorizer()
    cnt_vect.fit(X_train)
    X_train_cnt_vect = cnt_vect.transform(X_train)
    X_text_cnt_vect = cnt_vect.transform(X_test)
    ```

- Process
    1. 사전 데이터 가공(전처리): 모든 문자를 소문자로 변경 등
    2. 토큰화: 디폴트는 단어기준(analyzer = True), n_gram_range를 반영하여 토큰화 수행
    3. 텍스트 정규화
        1. stop words 필터링 수행
        2. Stemmer, Lemmatizer는 지원 X

            이를 위한 함수를 만들어 tokenizer 파라미터에 적용하거나 외부 패키지로 미리 텍스트 정규화 수행 필요

        3. 피처 벡터화: 토큰화 된 단어 피처로 추출, 단어 빈도수 벡터 값을 적용</code></pre><ul>
<li>단점: 문서의 특징을 나타내기 보다는 언어 특성상 문장에서 자주 사용될 수 밖에 없는 단어까지 높은 값을 부여 받는다.</li>
</ul>
<h2 id="32-tf-idf-term-frequency-inverse-document-frequency-vectorizer">3.2. TF-IDF (Term Frequency-Inverse Document Frequency) Vectorizer</h2>
<p>: 개별 문서에서 자주 나타나는 단어에 높은 가중치를 주되, 모든 문서에서 전반적으로 자주 나타나는 단어에 대해서는 패털티를 주는 방식으로 값을 부여한다.</p>
<ul>
<li>문서마다 텍스트가 길고 문서의 개수가 많을 경우 카운트 방식보다 TF-IDF 방식을 사용하는 게 좋다.</li>
</ul>
<p>$$
TFIDF_i = TF_i \times log{N\over DF_i}
$$</p>
<ul>
<li><p>$TF_i$: 개별 문서에서 단어 i 빈도, $DF_i$: 단어 i를 가지고 있는 문서 개수, N: 전체 문서 개수</p>
</li>
<li><p>사이킷런 - TfidfVectorizer 클래스 제공</p>
<ul>
<li><p>파라미터와 변환 방법은 CountVectorizer와 동일</p>
<pre><code class="language-python">from sklearn.feature_extraction.text import TfidfVectorizer</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="33-희소행렬">3.3. 희소행렬</h2>
<p>: 희소행렬(Sparse Matrix)은 행렬의 값이 대부분 0인 경우를 가리키는 표현 ↔ 밀집행렬(Dense Matrix)
: 모든 문서로 피처 벡터화를 수행하면 + n-gram (1,2) , (1,3) 등 주면 칼럼 수가 더욱 증가
: 희소행렬은 일반적으로 ML알고리즘의 수행시간과 예측 성능을 떨어뜨림
→ 메모리 공간이 많이 필요하고, 연산 시간이 오래 걸린다. 따라서, 물리적으로 적은 메모리 공간을 차지할 수 있도록 변환해야 한다.
$\therefore$ 희소행렬을 COO, CSR 형태의 희소행렬로 압축해줘야 함 (CSR을 더 많이 사용함)</p>
<p>: CountVectorizer, TfidfVectorizer 은 희소행렬을 반환(CSR 형태)</p>
<h3 id="331-coocoordinate--좌표-형식">3.3.1. COO(Coordinate : 좌표) 형식</h3>
<p>: 0이 아닌 데이터만 별도의 데이터 배열에 저장하고, 그 데이터가 가르키는 행과 열의 위치를 별도의 배열에 저장하는 방식</p>
<p>예) [ [3, 0, 1], [0, 2, 0] ] → (row, col): (0, 0), (0, 2), (1, 1) → row: [0, 0, 1], col: [0, 2, 1]</p>
<ul>
<li><p>희소행렬 변환은 주로 Scipy의 sparse 패키지 사용</p>
<pre><code class="language-python">  import numpy as np

  # BOW에서 좌표 기반으로 밀집행렬 추출
  dense = np.array( [ [ 3, 0, 1 ], [0, 2, 0 ] ] )

  from scipy import sparse

  # 0 이 아닌 데이터 추출
  data = np.array([3,1,2])

  # 행 위치와 열 위치를 각각 array로 생성 
  row_pos = np.array([0,0,1])
  col_pos = np.array([0,2,1])

  # sparse 패키지의 coo_matrix를 이용하여 COO 형식으로 희소 행렬 생성
  # 매개변수로 채워넣을 숫자인 순차적 data와, (row_pos, col_pos)의 좌표 정보를 tuple 형태로 주는 듯
  sparse_coo = sparse.coo_matrix((data, (row_pos,col_pos)))
  sparse_coo.toarray()

  &gt; array([3, 0, 1], [0, 2, 0])</code></pre>
</li>
<li><p>단점: 행과 열의 위치를 나타내기 위해서, 반복적인 위치 데이터를 사용해야 한다.</p>
</li>
</ul>
<h3 id="332-csrcompressed-sparse-row-형식">3.3.2. CSR(Compressed Sparse Row) 형식</h3>
<p>: 행 위치 배열 내에 있는 고유한 값의 시작 위치만 다시 별도의 위치 배열로 가지는 변환 방식</p>
<pre><code class="language-python">from scipy import sparse

dense2 = np.array([[0,0,1,0,0,5],
                         [1,4,0,3,2,5],
                         [0,6,0,3,0,0],
                         [2,0,0,0,0,0],
                         [0,0,0,7,0,8],
                         [1,0,0,0,0,0]])

# 0 이 아닌 데이터 값 배열
data2 = np.array([1, 5, 1, 4, 3, 2, 5, 6, 3, 2, 7, 8, 1])

# 열 위치와 행 위치를 각각 array로 생성 
col_pos = np.array([2, 5, 0, 1, 3, 4, 5, 1, 3, 0, 3, 5, 0])

row_pos = np.array([0, 0, 1, 1, 1, 1, 1, 2, 2, 3, 4, 4, 5])</code></pre>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/a475c714-4bcc-4919-96fc-41ecb60c7608/image.png" alt=""></p>
<pre><code class="language-python"># 행 위치 배열의 고유한 값들의 시작 위치 index를 배열로 생성
row_pos_ind = np.array([0, 2, 7, 9, 10, 12, 13])

# sparse 패키지의 csr_matrix를 이용하여 CSR 형식으로 희소 행렬 생성
# 매개변수로 채워넣을 숫자인 순차적 (data, row_pos_ind인 좌표의 위치 정보, col_pos인 좌표 정보) 를 tuple로
sparse_csr = sparse.csr_matrix((data2, col_pos, row_pos_ind))

print(&#39;COO 변환된 데이터가 제대로 되었는지 다시 Dense로 출력 확인&#39;)
print(sparse_coo.toarray())
print(&#39;CSR 변환된 데이터가 제대로 되었는지 다시 Dense로 출력 확인&#39;)
print(sparse_csr.toarray())

&gt; COO 변환된 데이터가 제대로 되었는지 다시 Dense로 출력 확인
&gt; [[0 0 1 0 0 5]
&gt;  [1 4 0 3 2 5]
&gt;  [0 6 0 3 0 0]
&gt;  [2 0 0 0 0 0]
&gt;  [0 0 0 7 0 8]
&gt;  [1 0 0 0 0 0]]
&gt; CSR 변환된 데이터가 제대로 되었는지 다시 Dense로 출력 확인
&gt; [[0 0 1 0 0 5]
&gt;  [1 4 0 3 2 5]
&gt;  [0 6 0 3 0 0]
&gt;  [2 0 0 0 0 0]
&gt;  [0 0 0 7 0 8]
&gt;  [1 0 0 0 0 0]]</code></pre>
<ul>
<li>실제 사용로 사용할 때 ⇒ 밀집 행렬을 매개변수(생성 파라미터)로 입력하면 COO나 CSR 희소 행렬로 생성한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 8. Clustering(2) (평균 이동, GMM, DBSCAN, 예제 실습)]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-8.-Clustering2-%ED%8F%89%EA%B7%A0-%EC%9D%B4%EB%8F%99-GMM-DBSCAN-%EC%98%88%EC%A0%9C-%EC%8B%A4%EC%8A%B5</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-8.-Clustering2-%ED%8F%89%EA%B7%A0-%EC%9D%B4%EB%8F%99-GMM-DBSCAN-%EC%98%88%EC%A0%9C-%EC%8B%A4%EC%8A%B5</guid>
            <pubDate>Tue, 18 Oct 2022 03:59:55 GMT</pubDate>
            <description><![CDATA[<h1 id="4-평균-이동-mean-shift">4. 평균 이동 Mean shift</h1>
<p>: K-평균과 유사하게, 군집의 중심을 지속적으로 움직이면서 군집화를 수행함
: 그러나, K-평균이 중심에 소속된 데이터의 평균 거리 중심으로 이동하는데 반해,
: 평균 이동은 데이터가 모여있는 밀도가 가장 높은 곳으로 이동시키면서 군집화하는 방법</p>
<ul>
<li><p>평균 이동 군집화는 데이터의 분포도를 이용해 군집 중심점을 찾음</p>
<ul>
<li><p>군집 중심점은 데이터 포인트가 모여있는 곳이라는 생각에서 착안</p>
</li>
<li><p>이를 위해 확률 밀도 함수를 이용 함</p>
</li>
<li><p>확률 밀도 함수가 피크인 점(가장 집중적으로 데이터가 모여 있을)을 군집 중심점으로 선정하며</p>
</li>
<li><p>주어진 모델의 확률 밀도 함수를 찾기 위해서 KDE(Kernel Density Estimation)을 이용</p>
</li>
<li><p>주변 데이터와의 거리 값을 KDE 함수 값으로 입력한 뒤, 그 반환 값을 현재 위치에서 업데이트하면서 이동하는 방식</p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/8d049af7-48a3-4ac8-b9e4-acbbe46babc4/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>KDE(Kernel Density Estimation)</p>
<p>  : 커널 함수를 통해 어떤 변수의 확률 밀도 함수를 추정하는 대표적인 방법</p>
<p>  : 개별 데이터 각각에, 커널 함수를 적용한 값을 모두 더한 뒤 데이터 건수로 나눠 확률 밀도 함수를 추정한다.</p>
<ul>
<li><p>확률 밀도 함수 PDF(Probability Density Function)</p>
<p>  : 확률 변수의 분포를 나타내는 함수 (정규 분포, 감마 분포, t-분포 등)</p>
<ul>
<li>확률 밀도 함수를 알면 특정 변수가 어떤 값을 갖게 될지에 대한 확률을 알게 되므로, 이를 통해 변수의 특성, 확률 분포 등 변수의 많은 요소를 알 수 있다.</li>
</ul>
</li>
<li><p>커널 함수의 예시) 가우시안 커널 함수 적용</p>
<p>  <img src="https://velog.velcdn.com/images/mios_leo/post/0ec8c5a6-f56c-4805-9ebe-eb7d054cb232/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>    ![](https://velog.velcdn.com/images/mios_leo/post/eb818ea7-9888-4ab4-b213-8d8f05bf1add/image.png)


- 수식

    $$
    KDE = {1\over n}\sum_{i=1}^nK_h(x-x_i) = {1\over nh}\sum_{i=1}^nK({x-x_i\over h})
    $$

    - $K$ : 커널 함수, $x$ : 확률 변수 값, $x_i$ : 관측값, $h$ : 대역폭(bandwidth)
    - 대역폭 $h$ : KDE 형태를 부드럽거나 뾰족한 형태로 평활화(smoothing)하는데 적용
        - 작은 $h$ 값: 좁고 뾰족한 KDE를 가짐. 과적합 되기 쉬움. 많은 수의 군집 중심점을 가짐
        - 큰 $h$ 값: 과도하게 평활화된 KDE를 가짐. 과소적합 되기 쉬움. 적은 수의 군집 중심점을 가짐

        ⇒ 적절한 h를 계산하는 것이 KDE 기반의 평균 이동에서 매우 중요하다.


    ![](https://velog.velcdn.com/images/mios_leo/post/c334ceb0-4755-4ccf-a10a-a1a40e330e66/image.png)


    ![](https://velog.velcdn.com/images/mios_leo/post/0989675b-902d-49da-a208-bdfcdcdff7e7/image.png)</code></pre><ul>
<li><p>사용</p>
<pre><code class="language-python">  import numpy as np
  from sklearn.datasets import make_blobs
  from sklearn.cluster import MeanShift

  X, y = make_blobs(n_samples=200, n_features=2, centers=3, 
                    cluster_std=0.7, random_state=0)

  meanshift= MeanShift(bandwidth=0.8)
  cluster_labels = meanshift.fit_predict(X)
  print(&#39;cluster labels 유형:&#39;, np.unique(cluster_labels))

  &gt; cluster labels 유형: [0 1 2 3 4 5]

  meanshift= MeanShift(bandwidth=1) # bandwidth 변경
  cluster_labels = meanshift.fit_predict(X)
  print(&#39;cluster labels 유형:&#39;, np.unique(cluster_labels))

  &gt; cluster labels 유형: [0 1 2]</code></pre>
<ul>
<li>bandwidth (=KDE의 h) 값을 작게 할수록 군집 개수가 많아진다.</li>
</ul>
</li>
<li><p>⭐️ <code>estimate_bandwidth(X)</code> ⭐️ : 최적의 대역폭 $h$ 찾아줌. 파라미터로 피처 데이터 세트(X) 입력</p>
<pre><code class="language-python">  from sklearn.cluster import estimate_bandwidth

  # estimate_bandwidth()로 최적의 bandwidth 계산
  bandwidth = estimate_bandwidth(X)
  print(&#39;bandwidth 값:&#39;, round(bandwidth,3))

  &gt; bandwidth 값: 1.816

  ------------------------------------------------------------
  import pandas as pd

  clusterDF = pd.DataFrame(data=X, columns=[&#39;ftr1&#39;, &#39;ftr2&#39;])
  clusterDF[&#39;target&#39;] = y

  # estimate_bandwidth()로 최적의 bandwidth 계산
  best_bandwidth = estimate_bandwidth(X)

  meanshift= MeanShift(bandwidth=best_bandwidth)
  cluster_labels = meanshift.fit_predict(X)
  print(&#39;cluster labels 유형:&#39;,np.unique(cluster_labels))

  &gt; cluster labels 유형: [0 1 2]</code></pre>
</li>
<li><p>평균 이동의 장점</p>
<ul>
<li>데이터 세트의 형태를 특정 형태로 가정한다든가, 특정 분포 기반의 모델로 가정하지 않기 때문에 유연한 군집화 가능</li>
<li>이상치의 영향력도 크지 않으며, 미리 군집의 개수를 정하지 않아도 된다.</li>
</ul>
</li>
<li><p>평균 이동의 단점</p>
<ul>
<li>수행 시간이 오래 걸리고, bandwidth의 크기에 따른 군집화 영향도가 크다.</li>
</ul>
</li>
<li><p>활용</p>
<ul>
<li>컴퓨터 비전 영역에서 많이 사용</li>
<li>이미지나 영상 데이터에서, 특정 개체를 구분하거나 움직임을 추적하는데 뛰어난 역할</li>
</ul>
</li>
</ul>
<h1 id="5-gmmgaussian-mixture-model-확률-기반-군집화">5. GMM(Gaussian Mixture Model) (확률 기반 군집화)</h1>
<p>: 군집화를 적용하고자 하는 데이터가, 여러 개의 가우시안 분포를 가진 데이터 집합들이 섞여서 생성된 것이라는 가정하에, 군집화를 수행하는 방식</p>
<hr>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/68cf1731-1021-44b0-98fb-9f642b418710/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/058778ab-9341-47ee-ba6a-5f32fe0ba7de/image.png" alt=""></p>
<ul>
<li>정규분포: 평균 $\mu$를 중심으로 높은 데이터 분포도를 가지고 있으며, 좌우 표준편차 1에 전체 데이터의 68.27%, 좌우 표준편차 2에 전체 데이터의 95.45%를 갖고 있다.</li>
<li>표준 정규 분포: 평균이 0, 표준편차가 1인 정규분포</li>
<li>섞인 데이터 분포에서 개별 유형의 가우시간 분포 추출, 개별 데이터가 이 중 어떤 정규분포에 속하는지 결정하는 방식</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/7d6e95d4-f44e-4319-a25a-97e6d5b49927/image.png" alt=""></p>
<ul>
<li><p>모수 추정 : 개별 정규 분포의 평균과 분산 추정, 각 데이터가 어떤 정규분포에 해당되는지의 확률 추정</p>
<ul>
<li>가령 1,000개의 데이터 세특 있다면, 이를 구성하는 여러 개의 정규 분포 곡선을 추출</li>
<li>개별 데이터가 이 중 어떤 정규 분포에 속하는지 결정하는 방식</li>
</ul>
</li>
<li><p>사용</p>
<pre><code class="language-python">  from sklearn.mixture import GaussianMixture

  gmm = GaussianMixture(n_components=3, random_state=0).fit(iris.data)
  gmm_cluster_labels = gmm.predict(iris.data)

  # 클러스터링 결과를 irisDF 의 &#39;gmm_cluster&#39; 컬럼명으로 저장
  irisDF[&#39;gmm_cluster&#39;] = gmm_cluster_labels
  irisDF[&#39;target&#39;] = iris.target

  # target 값에 따라서 gmm_cluster 값이 어떻게 매핑되었는지 확인. 
  iris_result = irisDF.groupby([&#39;target&#39;])[&#39;gmm_cluster&#39;].value_counts()
  print(iris_result)

  &gt; target  gmm_cluster
  &gt; 0       0              50
  &gt; 1       2              45
  &gt;         1               5
  &gt; 2       1              50
  &gt; Name: gmm_cluster, dtype: int64</code></pre>
<ul>
<li>n_components: 모델의 총 개수. 군집의 개수를 정하는데 중요한 역할 수행</li>
<li>fit(피처 데이터 세트), predict(피처 데이터 세트)를 수행해 군집을 결정</li>
</ul>
</li>
<li><p>장점 : KMeans보다 유연하게 다양한 데이터 세트에 잘 적용될 수 있다. (Not 원형 범위여도 작동 잘 함)</p>
<p>  <img src="https://velog.velcdn.com/images/mios_leo/post/ee82ced4-d297-4275-af94-ecfb447a26ec/image.png" alt=""></p>
</li>
</ul>
<pre><code>- 성능이 더 좋다는 뜻이 아니라, K-평균은 평균 거리 중심을 이동하면서 군집화를 수행하여,
개별 군집 내의 데이터가 원형으로 흩어져 있는 경우에 매우 효과적으로 군집화가 수행될 수 있음
⇒ 데이터 세트 구성에 따라 성능 달라짐
    - 따라서 K-평균은 길쭉한 타원형으로 늘어선 경우에는 군집화를 잘 수행하지 못함</code></pre><ul>
<li>단점 : 수행시간이 오래 걸린다.</li>
</ul>
<h1 id="6-dbscandensity-based-spatial-clustering-of-applications-with-noise-밀도-기반-군집화">6. DBSCAN(Density Based Spatial Clustering of Applications with Noise) (밀도 기반 군집화)</h1>
<p>: 입실론 주변 영역의 최소 데이터 갯수를 포함하는 밀도 기준을 충족시키는 데이터인, 핵심 포인트를 연결하면서 군집화를 구성하는 방식
: 데이터의 분포가 기하학적으로 복잡한 데이터 세트에도 효과적으로 군집화 가능</p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/8c15c450-52bd-428f-b0a2-f39c0efdf2c6/image.png" alt=""></p>
<ul>
<li><p>수행 방법</p>
<ol>
<li>P1 데이터 기준으로 입실론 반경(eps=0.6)내에 포함한 데이터(min_samples=6)가 7개 (자신 P1 포함하여, 이웃 데이터 P2, P6,  P7, P9, P11)로 최소 6개 이상을 만족하므로 P1은 핵심 포인트(Core Point)</li>
<li>다음으로 P2 데이터를 보면, P2 역시 반경 내에 6개 (자신 P2, P1, P3, P4, P9, P10) 데이터를 갖고 있으므로 핵심 포인트</li>
<li>핵심 포인트 P1의 이웃 ↔ 데이터 포인트 P2 역시 핵심 포인트일 경우 ⇒ P1에서 P2를 연결하여 <em>[직접 접근]</em></li>
<li>특정 핵심 포인트에서 *[직접 접근]*이 가능한 다른 핵심 포인트들을 서로 연결하면서 군집화를 구성 ⇒ 이런 군집화 영역을 확장해나가는 것이 DBSCAN의 군집화 방식</li>
<li>P3 데이터의 경우, 이웃 데이터로 P2, P4 2개이므로 군집을 구분할 수 있는 핵심포인트는 될 수 없음<ol>
<li>하지만 이웃 데이터 중에 핵심 포인트인 P2를 가지고 있음</li>
<li>이렇게, 자신은 핵심 포인트가 아니지만, 이웃 데이터로 핵심 포인트를 가지고 있는 데이터를 경계 포인트(Border Point)라고 부름</li>
<li>경계 포인트는 <em>군집의 외곽</em>을 형성</li>
</ol>
</li>
<li>P5와 같이 반경내 최소 데이터를 갖고 있지도 않고, 핵심 포인트를 이웃 데이터로 가지고 있지 않은 데이터를 잡음 포인트(Noise Point)라고 함</li>
</ol>
<ul>
<li>핵심 포인트(core point) : 주변 영역 내 최소 데이터 갯수 이상의 타 데이터를 가지고 있을 경우</li>
<li>이웃 포인트(neighbor point): 주변 영역 내에 위치한 타 데이터</li>
<li>경계 포인트(border point): 주변 영역 내에 최소 데이터 개수 이상의 이웃 포인트를 가지고 있지 않지만 핵심 포인트를 갖고 있는 데이터</li>
<li>잡음 포인트(noise point): 최소 데이터 개수 이상의 이웃 포인트를 가지고 있지 않으며, 핵심 포인트도 갖고 있지 않은 데이터</li>
</ul>
</li>
<li><p>사용</p>
<pre><code class="language-python">  from sklearn.cluster import DBSCAN

  dbscan = DBSCAN(eps=0.6, min_samples=8, metric=&#39;euclidean&#39;)
  dbscan_labels = dbscan.fit_predict(iris.data)

  irisDF[&#39;dbscan_cluster&#39;] = dbscan_labels
  irisDF[&#39;target&#39;] = iris.target

  iris_result = irisDF.groupby([&#39;target&#39;])[&#39;dbscan_cluster&#39;].value_counts()
  print(iris_result)

  &gt; target  dbscan_cluster
  &gt; 0        0                49
  &gt;         -1                 1
  &gt; 1        1                46
  &gt;         -1                 4
  &gt; 2        1                42
  &gt;         -1                 8
  &gt; Name: dbscan_cluster, dtype: int64

  # 군집 레이블이 -1인 것은 노이즈에 속하는 군집을 의미</code></pre>
<ul>
<li>군집 레이블이 -1인 것은 노이즈에 속하는 군집을 의미</li>
<li>Target 유형이 3가지 인데, 군집이 2개가 됐다고 군집화 효율이 떨어진다는 의미는 아님<ul>
<li>DBSCAN은 군집의 갯수를 알고리즘에 따라 자동으로 지정하므로, DBSCAN에서 군집의 갯수를 지정하는 것은 무의미</li>
<li>원래 iris 데이터의 경우는 군집을 3개로 하는 것 보다, 2개로 하는 것이 군집화의 효율로서 더 좋은 면도 실제로 있음</li>
</ul>
</li>
</ul>
</li>
<li><p>파라미터</p>
</li>
</ul>
<pre><code>| 파라미터 | 설명 |
| --- | --- |
| eps | 입실론(epsilon)
개별 데이터를 중심으로 입실론 반경을 가지는 원형의 영역
일반적으로 1 이하의 값 설정 |
| min_samples | 최소 데이터 개수(min points)
개별 데이터의 입실론 주변 영역에 포함되는 타 데이터의 개수 (자기 자신 포함) |
- eps 값을 크게 하면, 반경이 커져 포함하는 데이터가 많아지므로 노이즈 데이터 개수가 작아진다.
- min_samples를 크게 하면, 주어진 반경 내에서 더 많은 데이터를 포함시켜야 하므로 노이즈 데이터 개수가 커진다.</code></pre><h2 id="dbscan-적용하기---make_circles-데이터-세트---비교하기">DBSCAN 적용하기 - make_circles() 데이터 세트 +- 비교하기</h2>
<ul>
<li><p>make_circles() 원본</p>
<p>  <img src="https://velog.velcdn.com/images/mios_leo/post/67f0522b-a784-43bb-811a-2ce7a61e9435/image.png" alt=""></p>
</li>
</ul>
<pre><code>- make_circles는 내부 원과 외부 원으로 구분되는 데이트 세트를 생성해줌</code></pre><ul>
<li><p>Kmeans (거리기반 군집화)</p>
<p>  <img src="https://velog.velcdn.com/images/mios_leo/post/131366bb-b740-445c-ac7e-605de3d0c9c8/image.png" alt=""></p>
</li>
</ul>
<pre><code>- 거리를 기반으로, 위, 아래 군집 중심을 기반으로 군집화 됨</code></pre><ul>
<li><p>GMM (확률 기반 군집화)</p>
<p>  <img src="https://velog.velcdn.com/images/mios_leo/post/734c89af-ec89-4154-8ba4-7505111f473b/image.png" alt=""></p>
</li>
</ul>
<pre><code>- 일렬로 늘어선 데이터 세트(타원형)에서는 효과적으로 군집화 적용이 가능했으나,
- 내부와 외부의 원형으로 구성된 더 복잡한 형태의 데이터 세트에서는 군집화가 원하는 방향으로 되지 않았음</code></pre><ul>
<li><p>DBSCAN</p>
<p>  <img src="https://velog.velcdn.com/images/mios_leo/post/6ec6dd2f-20a3-48de-8e12-7b853d947d6c/image.png" alt=""></p>
</li>
</ul>
<pre><code>- 는 정확히 군집화가 됐음</code></pre><h1 id="7-실습">7. 실습</h1>
<h2 id="군집화-실습--고객-세그먼테이션">군집화 실습 : 고객 세그먼테이션</h2>
<ul>
<li>비지도학습 알고리즘의 하나인 군집화의 기능적 의미 ⇒ 숨어 있는 새로운 집단을 발견하는 것<ul>
<li>새로운 군집 내의 데이터 값을 분석하고 이해함으로써, 집단에 새로운 의미를 부여하고</li>
<li>전체 데이터를 다른 각도로 바라볼 수 있게 만들어줌</li>
</ul>
</li>
</ul>
<h1 id="8-정리">8. 정리</h1>
<p>: 각 군집화 기법은 나름의 장/단점을 가지고 있으며, 군집화 하려는 데이터의 특성에 맞게 선택해야 한다.</p>
<ul>
<li>KMeans: 거리 기반으로 군집 중심점을 이동시키며 군집화 수행. 평가는 실루엣 계수 이용</li>
<li>MeanShift: 거리 중심X, 데이터가 모여 있는 밀도가 가장 높은 쪽으로 군집 중심점을 이동하며 군집화 수행</li>
<li>GMM: 전체 데이터 세트에서 서로 다른 정규 분포 형태를 추출해 다른 정규 분포를 가진 데이터 세트를 각각 군집화</li>
<li>DBSCAN: 밀도 기반. 입실론 주변 영역 내에 포함되는 최소 데이터 개수의 충족 여부에 따라 데이터 포인트를 핵심 포인트, 이웃 포인트, 경계 포인트, 잡음 포인트로 구분하고 특정 핵심 포인트에서 직접 접근이 가능한 다른 핵심 포인트를 서로 연결하면서 군집화를 구성하는 방식</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 8. Clustering(1) (K-Mean, Cluster Evaluation)]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-8.-Clustering1-K-Mean-Cluster-Evaluation</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-8.-Clustering1-K-Mean-Cluster-Evaluation</guid>
            <pubDate>Thu, 13 Oct 2022 02:57:52 GMT</pubDate>
            <description><![CDATA[<h1 id="clustering-군집화">Clustering 군집화</h1>
<ul>
<li>분류와 유사해보일 수 있지만 성격이 다르다. 데이터 내에 숨어있는 별도의 그룹을 찾아서 의미를 부여하거나, 동일한 분류값에 속하더라도 그 안에서 더 세분화된 군집화를 추구하거나, 서로 다른 분류값의 데이터도 더 넓은 군집화 레벨화 등의 영역을 가진다.</li>
</ul>
<h1 id="1-k-meank평균">1. K-Mean(K평균)</h1>
<p>(거리기반 군집화)</p>
<p>: 군집 중심점(centroid)이라는 특정한 임의의 지점을 선택해 해당 중심에 가장 가까운 포인트들을 선택해 군집화하는 방식</p>
<ul>
<li>수행<ol>
<li>군집 중심점을 임의의 위치에 놓는다. (일반적으로는 초기화 알고리즘으로 적합한 위치에 놓음)</li>
<li>각 데이터는 가장 가까운 곳에 위치한 중심점에 소속된다.</li>
<li>군집 중심점을 소속된 데이터의 평균 중심으로 이동</li>
<li>각 데이터는 기존에 속한 중심점보다 더 가까운 중심점이 있다면 해당 중심점으로 다시 소속을 변경</li>
<li>다시 중심을 소속된 데이터의 평균으로 이동</li>
<li>중심점을 이동했는데 데이터의 중심점 소속 변경이 없으면 군집화를 종료</li>
</ol>
</li>
<li>장점<ul>
<li>일반적으로 가장 많이 사용되는 알고리즘으로 쉽고 간결하다.</li>
</ul>
</li>
<li>단점<ul>
<li>속성의 개수가 많을 경우 군집화 정확도가 떨어진다. (PCA가 필요할 수도)</li>
<li>반복이 많을수록 수행시간이 느려진다.</li>
<li>몇 개의 군집을 선택해야 할지 가이드하기 어렵다.</li>
<li>개별 군집 내의 데이터가 원형으로 흩어져 있는 경우에 효과적으로 군집화가 수행될 수 있지만,
데이터가 길쭉한 타원형으로 늘어선 경우와 같을 때는 군집화를 잘 수행하지 못한다.</li>
</ul>
</li>
</ul>
<table>
<thead>
<tr>
<th>하이퍼 파라미터</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>n_clusters</td>
<td>군집화할 개수(군집 중심점의 개수)</td>
</tr>
<tr>
<td>init</td>
<td>초기에 군집 중심점의 좌표를 설정할 방식. 보통은 임의로 설정하지 않고 K-Means++ 방식으로 설정</td>
</tr>
<tr>
<td>- 임의로 설정하고 싶으면 init=’random’</td>
<td></td>
</tr>
<tr>
<td>- K-means++ 방식</td>
<td></td>
</tr>
<tr>
<td>1. 데이터 포인트 중에서 무작위로 1개를 선택하여 중심점으로 지정</td>
<td></td>
</tr>
<tr>
<td>2. 나머지 데이터 포인트들에 대해 첫 번째 중심점까지의 거리 계산</td>
<td></td>
</tr>
<tr>
<td>3. 지정된 중심점으로부터 가장 멀리 있는 데이터 포인트를 다음 중심점으로 지정</td>
<td></td>
</tr>
<tr>
<td>4. 중심점이 K개가 될 때까지 2, 3번 반복</td>
<td></td>
</tr>
<tr>
<td>max_iter</td>
<td>최대 반복 횟수. 이 횟수 이전에 모든 데이터의 중심점 이동이 없으면 종료</td>
</tr>
<tr>
<td>- 속성</td>
<td></td>
</tr>
<tr>
<td>- labels_: 각 데이터 포인트가 속한 군집중심점 레이블</td>
<td></td>
</tr>
<tr>
<td>- cluster_centers_: 각 군집 중심점 좌표(shape=[군집개수, 피처개수]). 이를 이용해 시각화 가능</td>
<td></td>
</tr>
<tr>
<td>- 사용</td>
<td></td>
</tr>
</tbody></table>
<pre><code>```python
from sklearn.preprocessing import scale
from sklearn.datasets import load_iris
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
%matplotlib inline

iris = load_iris()
# 보다 편리한 데이터 Handling을 위해 DataFrame으로 변환
irisDF = pd.DataFrame(data=iris.data, columns=[&#39;sepal_length&#39;,&#39;sepal_width&#39;,&#39;petal_length&#39;,&#39;petal_width&#39;])
irisDF.head(3)

# 개정판 소스 코드 수정(2019.12.24)
kmeans = KMeans(n_clusters=3, init=&#39;k-means++&#39;, max_iter=300,random_state=0)
kmeans.fit(irisDF)

# irisDF[&#39;cluster&#39;]=kmeans.labels_ 개정 소스코드 변경(2019.12.24)
irisDF[&#39;target&#39;] = iris.target
irisDF[&#39;cluster&#39;]=kmeans.labels_
iris_result = irisDF.groupby([&#39;target&#39;,&#39;cluster&#39;])[&#39;sepal_length&#39;].count()
print(iris_result)

# iris 4개의 속성을 2차원 평면에 그리기 위해 PCA로 2개로 차원 축소
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
pca_transformed = pca.fit_transform(iris.data)

irisDF[&#39;pca_x&#39;] = pca_transformed[:,0]
irisDF[&#39;pca_y&#39;] = pca_transformed[:,1]

# cluster 값이 0, 1, 2 인 경우마다 별도의 Index로 추출
marker0_ind = irisDF[irisDF[&#39;cluster&#39;]==0].index
marker1_ind = irisDF[irisDF[&#39;cluster&#39;]==1].index
marker2_ind = irisDF[irisDF[&#39;cluster&#39;]==2].index

# cluster값 0, 1, 2에 해당하는 Index로 각 cluster 레벨의 pca_x, pca_y 값 추출. o, s, ^ 로 marker 표시
plt.scatter(x=irisDF.loc[marker0_ind,&#39;pca_x&#39;], y=irisDF.loc[marker0_ind,&#39;pca_y&#39;], marker=&#39;o&#39;) 
plt.scatter(x=irisDF.loc[marker1_ind,&#39;pca_x&#39;], y=irisDF.loc[marker1_ind,&#39;pca_y&#39;], marker=&#39;s&#39;)
plt.scatter(x=irisDF.loc[marker2_ind,&#39;pca_x&#39;], y=irisDF.loc[marker2_ind,&#39;pca_y&#39;], marker=&#39;^&#39;)

plt.xlabel(&#39;PCA 1&#39;)
plt.ylabel(&#39;PCA 2&#39;)
plt.title(&#39;3 Clusters Visualization by 2 PCA Components&#39;)
plt.show()
```</code></pre><p><img src="https://velog.velcdn.com/images/mios_leo/post/6ec5d7bc-de55-43d3-8bb4-0d9af79b8d5d/image.png" alt=""></p>
<h1 id="2-군집화-알고리즘-테스트를-위한-데이터-생성">2. 군집화 알고리즘 테스트를 위한 데이터 생성</h1>
<ul>
<li>사이킷런의 데이터 생성기: 여러 개의 클래스에 해당하는 데이터 세트를 만드는데, 하나의 클래스에 여러 개의 군집이 분포될 수 있게 데이터를 생성한다.<ul>
<li><code>make_blobs()</code>: 개별 군집의 중심점과 표준 편차 제어 기능이 추가되어 있다. 피처 데이터 세트, 타깃 데이터 세트가 튜플로 잔환</li>
</ul>
</li>
</ul>
<pre><code>    | 파라미터 | 설명 |
    | --- | --- |
    | n_samples | 디폴트 = 100
    생성할 총 데이터의 개수 |
    | n_features | 데이터의 피처 개수 |
    | centers | int로 입력: 군집의 개수
    ndarray로 입력: 개별 군집 중심점의 좌표 |
    | cluster_std | 생성될 군집 데이터의 표준편차
    float로 입력: 군집 내 데이터의 표준 편차
    [float, …]로 입력: 각 군집의 순서대로 각각의 표준편차가 만들어짐.
    ⇒ 군집별로 서로 다른 표준편차를 가진 데이터 세트를 만들 때 사용 |
- `make_classification()`: 노이즈를 포함한 데이터를 만든다.
- `make_circle(), make_moon()`: 중심기반의 군집화로 해결하기 어려운 데이터 세트를 만듦

```python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
%matplotlib inline

# 테스트 데이터 생성
X, y = make_blobs(n_samples=200, n_features=2, centers=3, cluster_std=0.8, random_state=0)
print(X.shape, y.shape)

# y target 값의 분포를 확인
unique, counts = np.unique(y, return_counts=True)
print(unique,counts)

&gt; (200, 2) (200,)
&gt; [0 1 2] [67 67 66]

# DataFrame에 적용
import pandas as pd
clusterDF = pd.DataFrame(data=X, columns=[&#39;ftr1&#39;, &#39;ftr2&#39;])
clusterDF[&#39;target&#39;] = y

target_list = np.unique(y)
# 각 target별 scatter plot 의 marker 값들. 
markers=[&#39;o&#39;, &#39;s&#39;, &#39;^&#39;, &#39;P&#39;,&#39;D&#39;,&#39;H&#39;,&#39;x&#39;]
# 3개의 cluster 영역으로 구분한 데이터 셋을 생성했으므로 target_list는 [0,1,2]
# target==0, target==1, target==2 로 scatter plot을 marker별로 생성. 
for target in target_list:
    target_cluster = clusterDF[clusterDF[&#39;target&#39;]==target]
    plt.scatter(x=target_cluster[&#39;ftr1&#39;], y=target_cluster[&#39;ftr2&#39;], edgecolor=&#39;k&#39;, marker=markers[target] )

plt.show()
```</code></pre><p><img src="https://velog.velcdn.com/images/mios_leo/post/ae32826d-a17f-4f0d-b126-59d4abb6d73a/image.png" alt=""></p>
<ul>
<li><p>KMeans 객체를 이용하여 X 데이터를 K-Means 클러스터링 수행 후, 시각화</p>
<pre><code class="language-python">  # KMeans 객체를 이용하여 X 데이터를 K-Means 클러스터링 수행 
  kmeans = KMeans(n_clusters=3, init=&#39;k-means++&#39;, max_iter=200, random_state=0)
  cluster_labels = kmeans.fit_predict(X)
  clusterDF[&#39;kmeans_label&#39;]  = cluster_labels

  #cluster_centers_ 는 개별 클러스터의 중심 위치 좌표 시각화를 위해 추출
  centers = kmeans.cluster_centers_
  unique_labels = np.unique(cluster_labels)
  markers=[&#39;o&#39;, &#39;s&#39;, &#39;^&#39;, &#39;P&#39;,&#39;D&#39;,&#39;H&#39;,&#39;x&#39;]

  # 군집된 label 유형별로 iteration 하면서 marker 별로 scatter plot 수행. 
  for label in unique_labels:
      label_cluster = clusterDF[clusterDF[&#39;kmeans_label&#39;]==label]
      center_x_y = centers[label]
      plt.scatter(x=label_cluster[&#39;ftr1&#39;], y=label_cluster[&#39;ftr2&#39;], edgecolor=&#39;k&#39;, 
                  marker=markers[label] )

      # 군집별 중심 위치 좌표 시각화 
      plt.scatter(x=center_x_y[0], y=center_x_y[1], s=200, color=&#39;white&#39;,
                  alpha=0.9, edgecolor=&#39;k&#39;, marker=markers[label])
      plt.scatter(x=center_x_y[0], y=center_x_y[1], s=70, color=&#39;k&#39;, edgecolor=&#39;k&#39;, 
                  marker=&#39;$%d$&#39; % label)

  plt.show()

  print(clusterDF.groupby(&#39;target&#39;)[&#39;kmeans_label&#39;].value_counts())

  &gt; target  kmeans_label
  &gt; 0       0               66
  &gt;         1                1
  &gt; 1       2               67
  &gt; 2       1               65
  &gt;         2                1</code></pre>
<p>  <img src="https://velog.velcdn.com/images/mios_leo/post/9d618396-ff09-4b31-bbf3-33eaee66ee13/image.png" alt=""></p>
</li>
</ul>
<h1 id="3-군집-평가-cluster-evaluation---실루엣-분석-silhouette-analysis">3. 군집 평가 Cluster Evaluation - 실루엣 분석 silhouette analysis</h1>
<p>: 대부분의 군집화 데이터 세트는 타깃 레이블을 가지고 있지 않다.
: 그래서 비지도 학습의 특성상 정확한 성능 평가는 어렵지만 군집화의 성능을 평가하는 방법으로는 실루엣 분석이 있다.</p>
<ul>
<li><p>실루엣 분석: 각 군집 간의 거리가 얼마나 효율적으로 분리되어 있는지 나타냄</p>
<ul>
<li>효율적 분리 ⇒ 다른 군집과는 떨어져 있고, 동일 군집끼리의 데이터는 서로 가깝게 잘 뭉쳐 있는것.</li>
<li>군집화가 잘 될수록 개별 군집은 비슷한 정도의 여유공간을 가지고 떨어져 있다.</li>
</ul>
</li>
<li><p>실루엣 계수(silhouette coefficient) : 개별 데이터가 가지는 군집화 지표</p>
<ul>
<li><p>해당 데이터가 같은 군집 내의 데이터와 얼마나 가깝게 군집화 돼있고,
다른 군집에 있는 데이터와는 얼마나 멀리 분리되어 있는지 나타내는 지표</p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/eb0e2a02-8d92-4ab4-8c8f-36d6d0cc23c4/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>- aij: i번째 데이터에서 [자신이 속한 클러스터 내]의 [다른 데이터 포인트]까지의 거리
- a(i): i번째 데이터에서 [자신이 속한 클러스터 내]의 [다른 데이터 포인트]들의 [평균] 거리 ⇒ a(1) = avg(a12, a13…)
- b(i): i번째 데이터에서 [가장 가까운 타 클러스터 내]의 [다른 데이터 포인트]들의 [평균] 거리 ⇒ b(1) = avg(b14, b15…)

    $$
    실루엣 계수S \&gt; (i)={b(i)-a(i)\over max(a(i), b(i))}
    $$

- 실루엣 계수는 -1~1 사이의 값을 가짐
    - 1로 가까울 수록, 근처의 군집과 더 멀리 떨여지 있다는 것
        - $b(i)$가 압도적으로 크면 → $\frac{b(i) - a(i)}{b(i)}$ → $\frac{1- \frac{a(i)}{b(i)}}{1}$ → $\frac{1 - 0.00…}{1}$ → 1에 가까워짐
    - 0에 가까울 수록, 근처의 군집과 가까워진다는 것
        - $b(i) - a(i) = 0$ →  $b(i) = a(i)$ : 클러스터내 거리랑, 타 클러스트내 거리랑 차이가 없다는 거니깐
    - - 값이면 다른 군집에 데이터 포인트가 할당되었다는 것
        - $b(i) &lt; a(i)$ → 클러스터내 거리가 타 클러스트내 거리보다 크다 → 다른 군집 데이터가 할당됐다고 볼 수 있음</code></pre><ul>
<li><p>사이킷런의 실루엣 분석 메소드</p>
<ul>
<li><p><code>silhouette_sample(X, labels, metric=&#39;euclidean&#39;, **kwds)</code></p>
<ul>
<li>인자로 X_feature 데이터 세트, 군집 레이블 값(labels) ⇒ 각 데이터의 실루엣 계수를 계산하여 반환</li>
</ul>
</li>
<li><p><code>silhouette_score(X, labels, metric=&#39;euclidean&#39;, sample_size=None, **kwds)</code></p>
<ul>
<li>인자로 X feature 데이터 세트, 군집 레이블 값(labels) ⇒ 전체 데이터의 실루엣계수 값을 평균하여 반환</li>
<li><code>np.mean(silhouette_samples())</code> 랑 같음</li>
<li>일반적으로 이 값이 높을수록 군집화가 어느정도 잘 됐다고 판단할 수 있지만, 무조건 그런건 아니다.</li>
</ul>
</li>
<li><p>사용</p>
<pre><code class="language-python">  from sklearn.preprocessing import scale
  from sklearn.datasets import load_iris
  from sklearn.cluster import KMeans
  # 실루엣 분석 metric 값을 구하기 위한 API 추가
  from sklearn.metrics import silhouette_samples, silhouette_score
  import matplotlib.pyplot as plt
  import numpy as np
  import pandas as pd

  %matplotlib inline

  iris = load_iris()
  feature_names = [&#39;sepal_length&#39;,&#39;sepal_width&#39;,&#39;petal_length&#39;,&#39;petal_width&#39;]
  irisDF = pd.DataFrame(data=iris.data, columns=feature_names)
  kmeans = KMeans(n_clusters=3, init=&#39;k-means++&#39;, max_iter=300,random_state=0).fit(irisDF)

  irisDF[&#39;cluster&#39;] = kmeans.labels_

  # iris 의 모든 개별 데이터에 실루엣 계수값을 구함. 
  score_samples = silhouette_samples(iris.data, irisDF[&#39;cluster&#39;])
  print(&#39;silhouette_samples( ) return 값의 shape&#39; , score_samples.shape)
  print(np.mean(silhouette_samples(iris.data, irisDF[&#39;cluster&#39;])))
  print(silhouette_score(iris.data, irisDF[&#39;cluster&#39;]))

  &gt; silhouette_samples( ) return 값의 shape (150,)
  &gt; 0.5528190123564095
  &gt; 0.5528190123564095

  # irisDF에 실루엣 계수 컬럼 추가
  irisDF[&#39;silhouette_coeff&#39;] = score_samples

  # 모든 데이터의 평균 실루엣 계수값을 구함. 
  average_score = silhouette_score(iris.data, irisDF[&#39;cluster&#39;])
  print(&#39;붓꽃 데이터셋 Silhouette Analysis Score:{0:.3f}&#39;.format(average_score))

  &gt; 붓꽃 데이터셋 Silhouette Analysis Score:0.553

  # 군집별 평균 실루엣 계수
  print(irisDF.groupby(&#39;cluster&#39;)[&#39;silhouette_coeff&#39;].mean())

  &gt; cluster
  &gt; 0    0.417320
  &gt; 1    0.798140
  &gt; 2    0.451105
  &gt; Name: silhouette_coeff, dtype: float64</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="군집별-평균-실루엣-계수의-시각화를-통한-군집-갯수-최적화-방법">군집별 평균 실루엣 계수의 시각화를 통한 군집 갯수 최적화 방법</h2>
<ul>
<li><p>전체 데이터의 평균 실루엣 계수 값이 높다고 해서, 반드시 최적의 군집 개수로 군집화가 잘 됐다고 볼 수 없음</p>
<ul>
<li>특정 군집만 실루엣 계수가 엄청 높고 나머지 군집들은 낮아도, 평균 실루엣 계수 자체는 높게 나올 수 있기 때문</li>
</ul>
</li>
<li><p>따라서, 좋은 군집의 조건으로</p>
<ol>
<li>전체 실루엣 계수의 평균값(<code>silhouette_score()</code>)은 0~1 사이의 값을 가지며, 1에 가까울 수록 좋다.</li>
<li>하지만 전체 실루엣 계수의 평균값과 더불어, 개별 군집의 평균값의 편차가 크지 않아야 한다.</li>
<li>즉, 개별 군집의 실루엣 계수 평균값이 전체 실루엣 계수 평균값에서 크게 벗어나지 않는 것이 중요하다.</li>
</ol>
</li>
<li><p><code>visualize_silhouette( [군집 갯수 list], X_feature )</code>을 통한 실루엣 시각화 분석</p>
<pre><code class="language-python">  ### 여러개의 클러스터링 갯수를 List로 입력 받아 각각의 실루엣 계수를 면적으로 시각화한 함수 작성
  def visualize_silhouette(cluster_lists, X_features): 

      from sklearn.datasets import make_blobs
      from sklearn.cluster import KMeans
      from sklearn.metrics import silhouette_samples, silhouette_score

      import matplotlib.pyplot as plt
      import matplotlib.cm as cm
      import math

      # 입력값으로 클러스터링 갯수들을 리스트로 받아서, 각 갯수별로 클러스터링을 적용하고 실루엣 개수를 구함
      n_cols = len(cluster_lists)

      # plt.subplots()으로 리스트에 기재된 클러스터링 수만큼의 sub figures를 가지는 axs 생성 
      fig, axs = plt.subplots(figsize=(4*n_cols, 10), nrows=2, ncols=n_cols)

      # 리스트에 기재된 클러스터링 갯수들을 차례로 iteration 수행하면서 실루엣 개수 시각화
      for ind, n_cluster in enumerate(cluster_lists):

          # KMeans 클러스터링 수행하고, 실루엣 스코어와 개별 데이터의 실루엣 값 계산. 
          clusterer = KMeans(n_clusters = n_cluster, max_iter=500, random_state=0)
          cluster_labels = clusterer.fit_predict(X_features)
          centers = clusterer.cluster_centers_

          sil_avg = silhouette_score(X_features, cluster_labels)
          sil_values = silhouette_samples(X_features, cluster_labels)

          y_lower = 10
          axs[0,ind].set_title(&#39;Number of Cluster : &#39;+ str(n_cluster)+&#39;\n&#39; \
                            &#39;Silhouette Score :&#39; + str(round(sil_avg,3)) )
          axs[0,ind].set_xlabel(&quot;The silhouette coefficient values&quot;)
          axs[0,ind].set_ylabel(&quot;Cluster label&quot;)
          axs[0,ind].set_xlim([-0.1, 1])
          axs[0,ind].set_ylim([0, len(X_features) + (n_cluster + 1) * 10])
          axs[0,ind].set_yticks([])  # Clear the yaxis labels / ticks
          axs[0,ind].set_xticks([0, 0.2, 0.4, 0.6, 0.8, 1])

          # 클러스터링 갯수별로 fill_betweenx( )형태의 막대 그래프 표현. 
          for i in range(n_cluster):
              ith_cluster_sil_values = sil_values[cluster_labels==i]
              ith_cluster_sil_values.sort()

              size_cluster_i = ith_cluster_sil_values.shape[0]
              y_upper = y_lower + size_cluster_i

              color = cm.nipy_spectral(float(i) / n_cluster)
              axs[0,ind].fill_betweenx(np.arange(y_lower, y_upper), 0, ith_cluster_sil_values, \
                                  facecolor=color, edgecolor=color, alpha=0.7)
              axs[0,ind].text(-0.05, y_lower + 0.5 * size_cluster_i, str(i))
              y_lower = y_upper + 10

              # 클러스터링된 데이터 시각화
              axs[1,ind].scatter(X_features[:, 0], X_features[:, 1], marker=&#39;.&#39;, s=30, lw=0, alpha=0.7, \
                  c=cluster_labels)
              axs[1,ind].set_title(&quot;Clustered data&quot;)
              axs[1,ind].set_xlabel(&quot;Feature space for the 1st feature&quot;)
              axs[1,ind].set_ylabel(&quot;Feature space for the 2nd feature&quot;)  

          # 군집별 중심 위치 좌표 시각화 
          unique_labels = np.unique(cluster_labels)
          for label in unique_labels:
              center_x_y = centers[label]
              axs[1,ind].scatter(x=center_x_y[0], y=center_x_y[1], s=70, color=&#39;k&#39;, edgecolor=&#39;k&#39;, 
                          marker=&#39;$%d$&#39; % label)

          axs[0,ind].axvline(x=sil_avg, color=&quot;red&quot;, linestyle=&quot;--&quot;)

  # make_blobs 을 통해 clustering 을 위한 4개의 클러스터 중심의 500개 2차원 데이터 셋 생성  
  from sklearn.datasets import make_blobs
  X, y = make_blobs(n_samples=500, n_features=2, centers=4, cluster_std=1, \
                    center_box=(-10.0, 10.0), shuffle=True, random_state=1)  

  # cluster 개수를 2개, 3개, 4개, 5개 일때의 클러스터별 실루엣 계수 평균값을 시각화 
  visualize_silhouette([ 2, 3, 4, 5], X)</code></pre>
<p>  <img src="https://velog.velcdn.com/images/mios_leo/post/e2668f58-4b3c-47bc-b51e-140670c5f633/image.png" alt=""></p>
</li>
</ul>
<ul>
<li><p>iris 데이터로 실루엣 시각화 분석</p>
<pre><code class="language-python">  from sklearn.datasets import load_iris

  iris=load_iris()
  visualize_silhouette([ 2, 3, 4,5 ], iris.data)</code></pre>
<p>  <img src="https://velog.velcdn.com/images/mios_leo/post/fdac2282-68f7-4808-a3f2-f6b9b3a69de9/image.png" alt=""></p>
</li>
</ul>
<ul>
<li>단점<ul>
<li>(직관적으로 이해하기 쉽지만) 각 데이터별로 다른 데이터와의 거리를 반복적으로 계산해야 하므로, 데이터 양이 늘어나면 수행시간이 크게 늘어난다.</li>
<li>또한 메모리 부족 등의 에러가 발생하기 쉬우며, 이 경우 군집별로 임의의 데이터를 샘플링 해 실루엣 계수를 평가하는 방안을 고민해야 한다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 7. Dimension Reduction(2) (SVD, NMF)]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-7.-Dimension-Reduction2-SVD-NMF</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-7.-Dimension-Reduction2-SVD-NMF</guid>
            <pubDate>Wed, 12 Oct 2022 01:42:36 GMT</pubDate>
            <description><![CDATA[<h1 id="3-svdsingular-value-decomposition-특이-값-분해">3. SVD(Singular Value Decomposition, 특이 값 분해)</h1>
<p>: PCA와 유사. 정방 행렬뿐만 아니라 행과 열의 크기가 다른 행렬에도 적용 가능</p>
<ul>
<li><p>Full SVD</p>
<ul>
<li><p>$A = U \sum V^T$</p>
</li>
<li><p>$A$ : 행렬,  $U$, $V$: 특이벡터(Singular vector)로 된 행렬,  $\sum$ : 대각행렬</p>
</li>
<li><p>$\sum$ : 대각행렬 : 행렬의 대각에 위치한 값만 0이 아니고 나머지 위치의 값은 모두 0인 행렬. 여기서 0이 아닌 값이 행렬 A의 특이값</p>
<p>  <img src="https://velog.velcdn.com/images/mios_leo/post/7ab04d91-a49c-4090-8068-25b02bc1d179/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>- $A$ : MxN 행렬일 때   —분해→  $U$: MxM 행렬,  $\sum$ : MxN 행렬,  $V^T$: NxN 행렬</code></pre><ul>
<li>Compact SVD (일반적)<ul>
<li>$U$ : MxP 행렬,  $\sum$ : PxP 행렬, $V^T$: PxN 행렬</li>
<li>$\sum$ 의 비대각인 부분과 대각원소 중에 특이값이 0인 부분도 모두 제거되고,
제거된 $\sum$에 대응되는 $U$와 $V$원소도 함께 제거해 차원을 줄인 형태로 SVD를 적용한다.</li>
</ul>
</li>
<li>Truncated SVD<ul>
<li>특이값 중 상위 일부 데이터만 추출해 분해하는 방식.</li>
<li>인위적으로 더 작은 차원의 행렬들로 분해하기 때문에 원본행렬을 정확하게는 복원할 수 없다.</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/91be9174-5c1a-4df9-92a7-f7c9e00f648d/image.png" alt=""></p>
<ul>
<li><p>SVD 사용: 보통 넘파이나 사이파이 라이브러리를 이용</p>
<pre><code class="language-python">  from numpy.linalg import svd
  # or
  from scipy.linalg import svd

  # numpy의 svd 모듈 import
  import numpy as np
  from numpy.linalg import svd

  # 4X4 Random 행렬 a 생성 
  np.random.seed(121)
  a = np.random.randn(4,4)
  print(np.round(a, 3))

  &gt; [[-0.212 -0.285 -0.574 -0.44 ]
  &gt; [-0.33   1.184  1.615  0.367]
  &gt; [-0.014  0.63   1.71  -1.327]
  &gt; [ 0.402 -0.191  1.404 -1.969]]

  U, Sigma, Vt = svd(a) # a = 원본 행렬
  print(U.shape, Sigma.shape, Vt.shape)
  print(&#39;U matrix:\n&#39;,np.round(U, 3))
  print(&#39;Sigma Value:\n&#39;,np.round(Sigma, 3)) # 대각행렬 =&gt; 대각에 위치한 값 == 1,  외에 나머지 값 0
  print(&#39;V transpose matrix:\n&#39;,np.round(Vt, 3))

  &gt; (4, 4) (4,) (4, 4)
  &gt; U matrix:
  &gt;  [[-0.079 -0.318  0.867  0.376]
  &gt;  [ 0.383  0.787  0.12   0.469]
  &gt;  [ 0.656  0.022  0.357 -0.664]
  &gt;  [ 0.645 -0.529 -0.328  0.444]]

  &gt; Sigma Value:
  &gt;  [3.423 2.023 0.463 0.079]

  &gt; V transpose matrix:
  &gt;  [[ 0.041  0.224  0.786 -0.574]
  &gt;  [-0.2    0.562  0.37   0.712]
  &gt;  [-0.778  0.395 -0.333 -0.357]
  &gt;  [-0.593 -0.692  0.366  0.189]]</code></pre>
</li>
<li><p>다시 행렬 A로 복원해보기 ⇒   $U &gt; * &gt;  \sum &gt; * &gt; V^T &gt; = A$</p>
<ul>
<li><p>단, $\sum$ 의 경우 0이 아닌 값만 1차원으로 추출했으므로, 다시 0을 포함한 대칭행렬로 변환 뒤 내적($*$) 수행</p>
<pre><code class="language-python"># Sima를 다시 0 을 포함한 대칭행렬로 변환
Sigma_mat = np.diag(Sigma)
a_ = np.dot(np.dot(U, Sigma_mat), Vt)
print(np.round(a_, 3))</code></pre>
</li>
<li><p>데이터 세트가 로 우간 의존성이 있을 경우, 어떻게 $\sum$ 값이 변하고, 이에 따른 차원 축소 진행되는지 알아보기</p>
</li>
<li><p>$A$ 행렬 ⇒ 3번째 로우 = 1번째 로우 + 2번째 로우 &amp; 4번째 로우 = 1번째 로우</p>
<pre><code class="language-python">  a[2] = a[0] + a[1]
  a[3] = a[0]
  print(np.round(a,3))

  &gt; [[-0.212 -0.285 -0.574 -0.44 ]
  &gt;  [-0.33   1.184  1.615  0.367]
  &gt;  [-0.542  0.899  1.041 -0.073]
  &gt;  [-0.212 -0.285 -0.574 -0.44 ]]</code></pre>
</li>
<li><p>이 $A$ 행렬을 다시 SVD 분해</p>
<pre><code class="language-python">  # 다시 SVD를 수행하여 Sigma 값 확인 
  U, Sigma, Vt = svd(a)
  print(U.shape, Sigma.shape, Vt.shape)
  print(&#39;Sigma Value:\n&#39;,np.round(Sigma,3))

  &gt; (4, 4) (4,) (4, 4)
  &gt; Sigma Value:
  &gt;  [2.663 0.807 0.    0.   ]</code></pre>
<ul>
<li>이전과 차원은 같지만, $\sum$ 값 중 2개가 0으로 변함 ⇒ 선형 독립의 로우 벡터의 수가 2개라는 의미 (행렬의 랭크가 2)</li>
</ul>
</li>
<li><p>이제 다시 행렬 A를 복원해볼 것
⇒ $U, \sum, V^T$ 전체 데이터 사용하지 않고, $\sum$ 의 0에 대응되는 $U, \sum, V^T$ 를 제외하고 복원해보겠음
⇒ 즉, $U$ 행렬 중 선행 두 개의 열만 추출 하고, $V^T$의 경우는 선행 두 개의 행만 추출 복원해보는 것</p>
<pre><code class="language-python">  # U 행렬의 경우는 Sigma와 내적을 수행하므로 Sigma의 앞 2행에 대응되는 앞 2열만 추출
  U_ = U[:, :2]
  Sigma_ = np.diag(Sigma[:2])

  # V 전치 행렬의 경우는 앞 2행만 추출
  Vt_ = Vt[:2]
  print(U_.shape, Sigma_.shape, Vt_.shape)

  # U, Sigma, Vt의 내적을 수행하며, 다시 원본 행렬 복원
  a_ = np.dot(np.dot(U_,Sigma_), Vt_)
  print(np.round(a_, 3))

  &gt; (4, 2) (2, 2) (2, 4)
  &gt; [[-0.212 -0.285 -0.574 -0.44 ]
  &gt;  [-0.33   1.184  1.615  0.367]
  &gt;  [-0.542  0.899  1.041 -0.073]
  &gt;  [-0.212 -0.285 -0.574 -0.44 ]]</code></pre>
</li>
</ul>
</li>
<li><p>Truncated SVD : $\sum$ 행렬에 있는 대각원소, 즉 특이값 중 상위 일부 데이터만 추출해 분해하는 방식</p>
<ul>
<li>이렇게 분해하면, 인위적으로 더 작은 차원의 $U, \sum, V^T$ 로 분해하기에, 원본 행렬을 정확히 원복할 수는 없음</li>
<li>그러나, 데이터 정보가 압축되어 분해됨에도 불구하고 상당한 수준으로 워본 행렬을 근사할 수 있음</li>
</ul>
</li>
<li><p>Truncated SVD 사용 : 사이파이에서만 지원됨</p>
<pre><code class="language-python">  from scipy.sparse.linalg import svds</code></pre>
<ul>
<li><p>검증 수행 순서</p>
<ol>
<li>임의의 원본 행렬 6x6을 Normal SVD로 분해해 ⇒ 행렬의 차원, $\sum$ 행렬 내 특이값 확인</li>
<li>다시 Truncated SVD로 분해해 ⇒ 행렬의 차원, $\sum$ 행렬 내 특이값 확인</li>
<li>Truncated SVD로 분해된 행렬의 내적을 계산해서 ⇒ 원상 복구하여 원본데이터와 비교</li>
</ol>
<pre><code class="language-python">import numpy as np
from scipy.sparse.linalg import svds # Truncated SVD
from scipy.linalg import svd # Nomarl SVD

# 원본 행렬을 출력하고, SVD를 적용할 경우 U, Sigma, Vt 의 차원 확인 
np.random.seed(121)
matrix = np.random.random((6, 6))
print(&#39;원본 행렬:\n&#39;,matrix)
U, Sigma, Vt = svd(matrix, full_matrices=False)
print(&#39;\n분해 행렬 차원:&#39;,U.shape, Sigma.shape, Vt.shape)
print(&#39;\nSigma값 행렬:&#39;, Sigma)

# Truncated SVD로 Sigma 행렬의 특이값을 4개로 하여 Truncated SVD 수행. 
num_components = 4
U_tr, Sigma_tr, Vt_tr = svds(matrix, k=num_components)
print(&#39;\nTruncated SVD 분해 행렬 차원:&#39;,U_tr.shape, Sigma_tr.shape, Vt_tr.shape)
print(&#39;\nTruncated SVD Sigma값 행렬:&#39;, Sigma_tr)
matrix_tr = np.dot(np.dot(U_tr,np.diag(Sigma_tr)), Vt_tr)  # output of TruncatedSVD

print(&#39;\nTruncated SVD로 분해 후 복원 행렬:\n&#39;, matrix_tr)

&gt; 원본 행렬:
&gt; [[0.11133083 0.21076757 0.23296249 0.15194456 0.83017814 0.40791941]
&gt;  [0.5557906  0.74552394 0.24849976 0.9686594  0.95268418 0.48984885]
&gt;  [0.01829731 0.85760612 0.40493829 0.62247394 0.29537149 0.92958852]
&gt;  [0.4056155  0.56730065 0.24575605 0.22573721 0.03827786 0.58098021]
&gt;  [0.82925331 0.77326256 0.94693849 0.73632338 0.67328275 0.74517176]
&gt;  [0.51161442 0.46920965 0.6439515  0.82081228 0.14548493 0.01806415]]

&gt; 분해 행렬 차원: (6, 6) (6,) (6, 6)

&gt; Sigma값 행렬: [3.2535007  0.88116505 0.83865238 0.55463089 0.35834824 0.0349925 ]

&gt; Truncated SVD 분해 행렬 차원: (6, 4) (4,) (4, 6)

&gt; Truncated SVD Sigma값 행렬: [0.55463089 0.83865238 0.88116505 3.2535007 ]

&gt; Truncated SVD로 분해 후 복원 행렬:
&gt;  [[0.19222941 0.21792946 0.15951023 0.14084013 0.81641405 0.42533093]
&gt;  [0.44874275 0.72204422 0.34594106 0.99148577 0.96866325 0.4754868 ]
&gt;  [0.12656662 0.88860729 0.30625735 0.59517439 0.28036734 0.93961948]
&gt;  [0.23989012 0.51026588 0.39697353 0.27308905 0.05971563 0.57156395]
&gt;  [0.83806144 0.78847467 0.93868685 0.72673231 0.6740867  0.73812389]
&gt;  [0.59726589 0.47953891 0.56613544 0.80746028 0.13135039 0.03479656]]</code></pre>
</li>
<li><p>6 ⇒ 4 차원 &amp; Truncated SVD 적용 후 원상 복구 하면, 완벽하진 않지만 근사하게 복원됨</p>
</li>
</ul>
</li>
<li><p>사이킷런 TruncatedSVD 클래스를 이용한 변환</p>
<ul>
<li><p>사이파이의 SVDs와 같이 $U, \sum, V^T$ 행렬을 반환하지는 않음.</p>
</li>
<li><p>사이킷런의 PCA 클래스와 유사하게, <code>fit()</code>, <code>transform()</code>으로 원본 데이터를 몇 개의 주요 컴포넌트로 차원축소해 변환</p>
</li>
<li><p>즉, 원본 데이터를 Truncated SVD 방식으로 분해된 $U * \sum$ 행렬에 선형변환하여 생성</p>
<pre><code class="language-python">from sklearn.decomposition import TruncatedSVD, PCA
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
%matplotlib inline

iris = load_iris()
iris_ftrs = iris.data
# 2개의 주요 component로 TruncatedSVD 변환
tsvd = TruncatedSVD(n_components=2)
tsvd.fit(iris_ftrs)
iris_tsvd = tsvd.transform(iris_ftrs)

# 2개의 주요 component로 TruncatedSVD 변환 (비교를 위해)
pca = PCA(n_components=2)
pca.fit(iris_ftrs)
iris_pca = pca.transform(iris_ftrs)

# TruncatedSVD 변환 데이터를 왼쪽에, PCA변환 데이터를 오른쪽에 표현 
fig, (ax1, ax2) = plt.subplots(figsize=(18,4), ncols=2)
ax1.scatter(x=iris_tsvd[:,0], y= iris_tsvd[:,1], c= iris.target)
ax2.scatter(x=iris_pca[:,0], y= iris_pca[:,1], c= iris.target)
ax1.set_title(&#39;Truncated SVD Transformed&#39;)
ax2.set_title(&#39;PCA Transformed&#39;)
ax1.set_xlabel(&#39;TruncatedSVD Component 1&#39;)
ax1.set_ylabel(&#39;TruncatedSVD Component 2&#39;)
ax2.set_xlabel(&#39;PCA Component 1&#39;)
ax2.set_ylabel(&#39;PCA Component 2&#39;)</code></pre>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/7fceb207-5ebf-4bb7-9a9a-f175d49e9d00/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>- TruncatedSVD 역시 PCA와 유사하게 변환 후 품종별로 어느정도 클러스터링이 가능할정도로 고유성 가지고 있음
- 사실 두 클래스를 모두 뜨덩보면, 모두 SVD를 이용해 행렬을 분해함 ⇒ 원본 데이터를 스케일링으로 변환 후에 적용해보면 거의 동일함

    ```python
    from sklearn.preprocessing import StandardScaler

    # iris 데이터를 StandardScaler로 변환
    scaler = StandardScaler()
    iris_scaled = scaler.fit_transform(iris_ftrs)

    # 스케일링된 데이터를 기반으로 TruncatedSVD 변환 수행 
    tsvd = TruncatedSVD(n_components=2)
    tsvd.fit(iris_scaled)
    iris_tsvd = tsvd.transform(iris_scaled)

    # 스케일링된 데이터를 기반으로 PCA 변환 수행 
    pca = PCA(n_components=2)
    pca.fit(iris_scaled)
    iris_pca = pca.transform(iris_scaled)

    # TruncatedSVD 변환 데이터를 왼쪽에, PCA변환 데이터를 오른쪽에 표현 
    fig, (ax1, ax2) = plt.subplots(figsize=(9,4), ncols=2)
    ax1.scatter(x=iris_tsvd[:,0], y= iris_tsvd[:,1], c= iris.target)
    ax2.scatter(x=iris_pca[:,0], y= iris_pca[:,1], c= iris.target)
    ax1.set_title(&#39;Truncated SVD Transformed&#39;)
    ax2.set_title(&#39;PCA Transformed&#39;)
    ```

    ![](https://velog.velcdn.com/images/mios_leo/post/5636be7d-2897-4ef8-80e6-b076af20d277/image.png)


- 두개의 변환 행렬값과, 원복 속성별 컴포넌트 비율값을 실제로 서로 비교하면 거의 같음

    ```python
    print((iris_pca - iris_tsvd).mean())
    print((pca.components_ - tsvd.components_).mean())

    &gt; 2.3419865583888347e-15
    &gt; 6.245004513516506e-17
    ```

    - 모두 0에 가까운 값이므로, 2개의 변환이 서로 동일함을 알 수 있음
    - 즉, 데이터 세트가 스케일링으로 데이터 중심이 동일해지면, SVD와 PCA는 동일한 변환을 수행
    - 이는 PCA가 SVD 알고리즘으로 구현됐음을 의미
    - 그러나, PCA는 밀집 행렬(Dense Matrix)에 대한 변환만 가능하며, SVD는 희소 행렬(Sparse Matrix)에 대한 변환도 가능
    - 또한 SVD는 텍스트의 토픽 모델링 기법인 LSA(Latent Semantic Analysis)의 기반 알고리즘임.</code></pre><h1 id="4-nmfnon-negative-matrix-factorization">4. NMF(Non-Negative Matrix Factorization)</h1>
<p>: 원본 행렬 내의 모든 원소값이 모두 양수(0 이상)라는 게 보장되면, 두 개의 기반 양수 행렬로 분해될 수 있는 기법
: Truncated SVD와 같이 낮은 랭크를 통한 행렬 근사 방식의 변형</p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/9d381012-aaa8-495f-bba2-b25fac4ca2ee/image.png" alt=""></p>
<ul>
<li><p>$W \times H \approx V$</p>
<ul>
<li>일반적으로 길고 가는 행렬 $W$(원본 행렬과 행크기 같고 열크기 보다 작은 행렬) X 작고 넓은 행렬 $H$ (원본 행렬의 행 크기보다 작고 열 크기와 같은 행렬)로 분해된다.</li>
<li>$W$ : 원본 행에 대해서 이 잠재요소의 값이 얼마나 되는지에 대응</li>
<li>$H$ : 이 잠재요소가 원본 열(원본 속성)로 어떻게 구성됐는지를 나타냄</li>
</ul>
</li>
<li><p>사용</p>
<pre><code class="language-python">  from sklearn.decomposition import NMF
  from sklearn.datasets import load_iris
  import matplotlib.pyplot as plt
  %matplotlib inline

  iris = load_iris()
  iris_ftrs = iris.data
  nmf = NMF(n_components=2)
  nmf.fit(iris_ftrs)
  iris_nmf = nmf.transform(iris_ftrs)
  plt.scatter(x=iris_nmf[:,0], y= iris_nmf[:,1], c= iris.target)
  plt.xlabel(&#39;NMF Component 1&#39;)
  plt.ylabel(&#39;NMF Component 2&#39;)</code></pre>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/6e94b243-5efd-406e-9557-a868effc0e4e/image.png" alt=""></p>
<ul>
<li>NMF와 SVD와 유사하게 이미지 압축을통한 패턴 인식, 텍스트의 토픽 모델링 기법, 문서 유사도 및 클러스터링, 추천 시스템에 활발히 적용 됨</li>
</ul>
<h1 id="5-정리">5. 정리</h1>
<ul>
<li>PCA<ul>
<li>입력 데이터의 변동성이 가장 큰 축을 구하고, 다시 이 축에 직각인 축을 반복적으로 축소하려는 차원의 개수만큼 구한 뒤 입력 데이터를 이 축들에 투영해 차원을 축소하는 방식</li>
<li>입력 데이터의 공분산 행렬을 기반으로, 고유 벡터를 생성하고, 이 고유 벡터에 입력 데이터를 선형변환하는 방식</li>
</ul>
</li>
<li>LDA<ul>
<li>입력 데이터의 결정값 클래스를 최대한으로 분리할 수 있는 축을 찾아 차원을 축소하는 방식</li>
</ul>
</li>
<li>SVD, NMF<ul>
<li>고차원 행렬을 두 개의 저차원 행렬로 분리하는 행렬기법</li>
<li>원본 행렬에서 잠재된 요소를 추출하기 때문에 토픽 모델이나 추천시스템에서 사용된다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 7. Dimension Reduction(1) (PCA, LDA)]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-7.-Dimension-Reduction1-PCA-LDA</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-7.-Dimension-Reduction1-PCA-LDA</guid>
            <pubDate>Tue, 11 Oct 2022 02:37:46 GMT</pubDate>
            <description><![CDATA[<h1 id="dimension-reduction-차원-축소">Dimension Reduction 차원 축소</h1>
<p>: 매우 많은 피처로 구성된 다차원 세트의 차원을 축소해 새로운 차원의 데이터 세트를 생성하는 것</p>
<ul>
<li>다차원 데이터 세트의 문제점<ol>
<li>차원이 증가할 수록 데이터 포인트 간의 거리가 기하급수적으로 멀어지고, 희소한Sparse 구조를 가져 예측 신뢰도가 떨어진다.</li>
<li>다중공선성 문제(독립변수 간의 상관관계가 높은 것)로 예측 성능 저하<ul>
<li>회귀분석의 전제 가정 위배 : 독립변수간 상관관계는 높으면 안된다</li>
</ul>
</li>
</ol>
</li>
<li>차원 축소의 분류<ul>
<li>피처(특성) 선택 : 특정 피처에 종속성이 강한 불필요 피처는 아예 제거 + 데이터 특징 잘 나타내는 주요 피처만 선택</li>
<li>피처(특성) 추출 : 기촌 피처를 저차원의 중요 피처로 압축하여 추출 ⇒ 기존 피처와 완전히 다른 새로운 값이 됨<ul>
<li>단순 압축이 아닌, 피처를 합축적으로 더 잘 설명할 수 있는 또 다른 공간으로 매칭하여 추출하는 것
ex) 학생의 모의고사성적, 내신성적, 수능성적, 봉사활동, 대외활동, 수상경력 등 ⇒ 학업 성취도, 커뮤니케이션 능력, 문제해결력 등 더 함축적인 요약 특성으로 추출할 수 있음</li>
<li>가장 중요한 의미 : 데이터를 더 잘 설명할 수 있음 잠재적인 요소 추출 <strong>PCA, SVD, NMF</strong> 등</li>
</ul>
</li>
</ul>
</li>
<li>차원 축소의 활용<ol>
<li>이미지 데이터에서 잠재된 특성을 피처로 도출해 함축적 형태의 이미지 변환과 압축 수행 ⇒ 원본보다 작은 차원으로 과적향 방지</li>
<li>텍스트 문서의 숨겨진 의미 추출. 문서 내 단어들의 구성에서 숨겨져 있는 시맨틱Semantic 의미나 토픽topic을 잠재 요소로 간주하고 이를 찾아낸다.</li>
</ol>
</li>
</ul>
<h1 id="1-pcaprincipal-component-analysis-주성분-분석">1. PCA(Principal Component Analysis, 주성분 분석)</h1>
<p>: 변수 간 상관관계를 이용해 이를 대표하는 주성분을 추출해 차원을 축소하는 방법</p>
<ul>
<li>PCA의 주성분: 정보 유실을 최소화하기 위해 가장 높은 분산을 가지는 데이터를 찾아, 이 축으로 차원을 축소한다. 즉, 분산이 데이터의 특성을 가장 잘 나타내는 것으로 간주한다.</li>
<li>PCA 차원 축소 하는 방법</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/2881cc6b-81c8-4768-813c-4b209ae57a5b/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/1d391350-61a4-4766-94f3-864f0cd6f92a/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/4095caa4-c1c9-4af8-a474-5fc2a0716a36/image.png" alt=""></p>
<ul>
<li><p>첫 번째 벡터 축 : 가장 큰 데이터 변동성(Variance)을 기반으로 생성</p>
</li>
<li><p>두 번째 벡터 축 : 첫 번째 벡터 축에 직각이 되는 벡터(직교 벡터)를 축으로 함</p>
</li>
<li><p>세 번째 벡터 축 : 다시 두 번째 축과 직각이 되는 벡터를 설정하는 방식으로 축 생성</p>
<ul>
<li>선형대수 관점 : 입력 데이터의 공분산 행렬(Covariance Matrix)을 고유값 분해하고, 이렇게 구한 고유벡터에 입력 데이터를 선형 변환하는 것</li>
</ul>
</li>
<li><p>PCA의 주성분 : 위에서 말하는 고유벡터. 입력 데이터의 분산이 가장 큰 방향을 나타낸다.</p>
</li>
<li><p>고유값(eigenvalue) : 고유벡터의 크기. 입력 데이터의 분산을 나타냄</p>
</li>
<li><p>선형 변환 : 특정 벡터에 행렬 A를 곱해 새로운 벡터로 변환하는 것, 특정 벡터를 하나의 공간(행렬을 공간으로 가정)에서 다른 공간으로 투영하는 개념</p>
</li>
<li><p>고유 벡터 : 행렬A를 곱하더라도 방향이 변하지 않고, 그 크기만 변하는 벡터</p>
<ul>
<li>Ax = ax (A: 행렬, x: 고유 벡터, a: 스칼라 값)</li>
<li>이 고유 벡터는 여러 개가 존재하며,</li>
<li>정방 행렬은 최대 그 차원 수 만큼 고유 벡터를 가질 수 있다. (예: 2x2 행렬은 최대 2개의 고유벡터를 가질 수 있음, 3x3은 3개)</li>
<li>이렇듯 고유벡터는 행렬이 작용하는 힘의 방향과 관계가 있어서, 행렬을 분해하는데 사용됨</li>
</ul>
</li>
<li><p>분산 : 한 개의 특정한 변수의 데이터 변동을 의미</p>
</li>
<li><p>공분산 : 두 변수 간의 변동을 의미</p>
<ul>
<li>사람의 키 변수를 X, 몸무게 변수를 Y로 둘 때, 공분산  $Cov(X,Y) &gt; 0$  == X(키)가 증가할 때 Y(몸무게)도 증가한다는 의미</li>
</ul>
</li>
<li><p>공분산 행렬 : 여러 변수와 관련된 공분산을 포함하는, 정방 행렬 &amp; 대칭 행렬</p>
</li>
</ul>
<pre><code>|  | X | Y | Z |
| --- | --- | --- | --- |
| X | 3.0 | -0.71 | -0.24 |
| Y | -0.71 | 4.5 | 0.28 |
| Z | -0.24 | 0.28 | 0.91 |
- 대각선 원소는 각 변수(X, Y, Z)의 분산을 의미
- 대각선 외의 원소는, 가능한 모든 변수 쌍 간의 공분산을 의미
- X와 Y의 공분산 = -0.71</code></pre><ul>
<li><p>정방 행렬(Diagonal Matrix) : 열과 행이 같은 행렬</p>
</li>
<li><p>대칭 행렬(Symmetric Matrix) : 정방 행렬 중에서 대각 원소를 중심으로 원소값이 대칭되는 행렬,  $A^T = A$대</p>
<ul>
<li>대칭 행렬은 항상 고유 벡터를 직교 행렬로, 고유값을 정방 행렬로 대각화 할 수 있음 ⇒ 고유값 분해</li>
</ul>
</li>
<li><p>공분산 행렬의 분해</p>
<ul>
<li><p>$C = P \sum P^T$</p>
<p>$C = [e_1\cdots e_n] \begin{bmatrix} \lambda_1 &gt; \cdots&gt; 0 \
\cdots &gt; \cdots &gt; \cdots \
0 &gt; \cdots &gt; \lambda_n \end{bmatrix}
\begin{bmatrix}
e_1^t \
\cdots \
e_n^t
\end{bmatrix}$</p>
<p>$C$ = 고유벡터의 직교 행렬 * 고유값 정방행렬 * 고유벡터 직교행렬의 전치 행렬</p>
<ul>
<li>$e_i$ 는 $i$ 번째 고유 벡터</li>
<li>$\lambda_i$ 는 $i$ 번째 고유벡터의 크기(고유값)</li>
<li>$e_1$ 는 가장 분산이 큰 방향을 가진 고유 벡터</li>
<li>$e_2$ 는 $e_1$ 에 수직이면서, 그 다음으로 분산이 큰 방향을 가진 고유벡터</li>
</ul>
</li>
</ul>
</li>
<li><p>PCA : 입력 데이터의 공분산 행렬이 고유벡터와 고유값으로 분해될 수 있으며, 이렇게 분해된 고유벡터를 이용해 입력 데이터를 선형 변환하는 방식</p>
</li>
<li><p>수행</p>
<ol>
<li>입력 데이터 세트의 공분산 행렬 생성 ( $C$ ) </li>
<li>공분산 행렬의 고유벡터( $e_i$ )와 고유값( $\lambda_i$ )을 계산</li>
<li>고유값( $\lambda_i$ )이 가장 큰 순으로 K개(PCA 변환 차수)만큼 고유벡터( $e_i$ )를 추출</li>
<li>고유값( $\lambda_i$ )이 가장 큰 순으로 추출된 고유벡터( $e_i$ )를 이용해 새롭게 입력 데이터 변환</li>
</ol>
</li>
</ul>
<hr>
<hr>
<h2 id="📐-pca의-구성--개념-정리">📐 PCA의 구성  개념 정리</h2>
<ul>
<li><p>PCA : 입력 데이터의 공분산 행렬(Covariance Matrix)을 고유값 분해하고, 이렇게 구한 고유벡터(주성분)에 입력 데이터를 선형 변환하는 것</p>
<ul>
<li>주성분 : 위에서 말하는 고유벡터. 입력 데이터의 분산이 가장 큰 방향을 나타낸다.</li>
<li>공분산 (행렬) : 두 변수 간의 변동을 의미 (여러 변수와 관련된 공분산을 포함하는 대칭 행렬)</li>
<li>공분산 행렬은 항상 고유 벡터를 직교 행렬로, 고유값을 정방 행렬로 대각화 할 수 있음 ⇒ 고유값 분해</li>
<li>고유값 ($\lambda$) : 고유벡터의 크기, 입력 데이터의 분산을 나타냄</li>
<li>고유 벡터 ($e$) : 행렬A 곱해도, 방향 변화 X &amp; 크기만 변화 O 벡터, 행렬이 작용하는 힘의 방향과 관계 있음</li>
<li>선형 변환 : 특정 벡터(고유 벡터)에 행렬 A(입력 데이터)를 곱해 새로운 벡터로 변환하는 것<ul>
<li>특정 벡터를 하나의 공간(행렬을 공간으로 가정)에서 다른 공간으로 투영하는 개념</li>
</ul>
</li>
</ul>
</li>
<li><p>공분산 행렬의 분해</p>
<ul>
<li><p>$C = [e_1\cdots e_n] \begin{bmatrix} \lambda_1 &gt; \cdots&gt; 0 \ \cdots &gt; \cdots &gt; \cdots \ 0 &gt; \cdots &gt; \lambda_n \end{bmatrix} \begin{bmatrix} e_1^t \ \cdots \ e_n^t \end{bmatrix}$</p>
<p>$[e_1\cdots e_n]$  =  고유 벡터 : 행렬이 작용하는 힘의 방향</p>
<p>$\begin{bmatrix} \lambda_1 &gt; \cdots&gt; 0 \
\cdots &gt; \cdots &gt; \cdots \
0 &gt; \cdots &gt; \lambda_n \end{bmatrix}$ = 고유값 : 입력데이터의 분산 &amp; 고유 벡터의 크기</p>
</li>
<li><p>$e_1$ 는 가장 분산이 큰 방향을 가진 고유 벡터, $e_2$ 는 $e_1$ 에 수직이면서, 그 다음으로 분산이 큰 방향을 가진 고유벡터</p>
</li>
</ul>
</li>
</ul>
<hr>
<hr>
<ul>
<li><p>PCA를 적용하기 위해서는 각 속성값을 동일한 스케일로 변환해야 한다. ⇒ StandardScaler</p>
<ul>
<li>여러 속성 값을 연상해야 하므로, 속성의 스케일에 영향을 받기 때문</li>
</ul>
</li>
<li><p>사용</p>
<pre><code class="language-python">
  from sklearn.preprocessing import StandardScaler

  # Target 값을 제외한 모든 속성 값을 StandardScaler를 이용하여 표준 정규 분포를 가지는 값들로 변환
  iris_scaled = StandardScaler().fit_transform(irisDF.iloc[:, :-1])

  from sklearn.decomposition import PCA

  pca = PCA(n_components=2)

  #fit( )과 transform( ) 을 호출하여 PCA 변환 데이터 반환
  pca.fit(iris_scaled)
  iris_pca = pca.transform(iris_scaled)
  print(iris_pca.shape)

  # PCA 환된 데이터의 컬럼명을 각각 pca_component_1, pca_component_2로 명명
  pca_columns=[&#39;pca_component_1&#39;,&#39;pca_component_2&#39;]
  irisDF_pca = pd.DataFrame(iris_pca, columns=pca_columns)
  irisDF_pca[&#39;target&#39;]=iris.target
  irisDF_pca.head(3)</code></pre>
<ul>
<li><p>n_components: PCA로 변환할 차원의 수</p>
</li>
<li><p>이후 fit()과 transform()을 호출해 PCA 변환 데이터 반환</p>
</li>
<li><p>explained_variance_ratio_: 전체 변동성에서 개별 PCA 컴포넌트별로 차지하는 변동성 비율 제공</p>
<pre><code class="language-python">  pca.explained_variance_ratio_

  &gt; [0.72962445 0.22850762]
  &gt;&gt; 원본 데이터의 0.95 변동성을 설명할 수 있음</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="신용카드-고객-데이터">신용카드 고객 데이터</h2>
<ul>
<li><code>df.corr()</code>로 각 속상간의 상관도를 구한 뒤, heatmap으로 보기</li>
<li>상관도 높은거 묶어서 하기(?)</li>
</ul>
<h1 id="2-ldalinear-discriminant-analysis-선형-판별-분석">2. LDA(Linear Discriminant Analysis, 선형 판별 분석)</h1>
<p>: PCA와 유사하지만, 지도 학습의 분류에서 사용하기 쉽도록 개별 클래스를 분별할 수 있는 기준을 최대한 유지하면서 차원 축소</p>
<ul>
<li>PCA는 입력 데이터의 변동성의 가장 큰 축을 찾았지만, LDA는 입력 데이터의 결정 값 클래스를 초대한 분리할 수 있는 축을 찾음</li>
<li>입력 데이터의 결정값 클래스를 최대한으로 분리할 수 있는 축을 찾기 위해, 클래스 간 분산(between)과 클래스 내부 분산(within)의 비율을 최대화하는 방식으로 차원 축소<ul>
<li>클래스 간 분산은 크게, 클래스 내부 분산은 작게</li>
</ul>
</li>
<li>$S_W^TS_B = [e_1\cdots e_n] \begin{bmatrix} \lambda_1 &gt; \cdots&gt; 0 \ \cdots &gt; \cdots &gt; \cdots \ 0 &gt; \cdots &gt; \lambda_n \end{bmatrix} \begin{bmatrix} e_1^T \ \cdots \ e_n^T \end{bmatrix}$</li>
</ul>
<p>$[e_1\cdots e_n]$  =  고유 벡터 : 행렬이 작용하는 힘의 방향</p>
<p>$\begin{bmatrix} \lambda_1 &gt; \cdots&gt; 0 \
\cdots &gt; \cdots &gt; \cdots \
0 &gt; \cdots &gt; \lambda_n \end{bmatrix}$ = 고유값 : 입력데이터의 분산 &amp; 고유 벡터의 크기</p>
<ul>
<li><p>수행</p>
<ol>
<li>입력 데이터의 결정값 클래스 별로 개별 피처의 평균 벡터(mean vector)를 기반으로 [클래스 내부, 클래스 간 분산 행렬]을 구한다.</li>
<li>클래스 내부 분산 행렬( $S_W$ ), 클래스 간 분산 행렬( $S_B$ ) ⇒ 두 행렬을 고유벡터( $e$ )로 분해</li>
<li>고유값이 가장 큰 순으로 K개(LDA 변환 차수)만큼 추출</li>
<li>고유값이 가장 큰 순으로 추출된 고유벡터를 이용해 새롭게 입력 데이터를 변환</li>
</ol>
</li>
<li><p>사용</p>
<pre><code class="language-python">  from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
  from sklearn.preprocessing import StandardScaler
  from sklearn.datasets import load_iris

  iris = load_iris()
  iris_scaled = StandardScaler().fit_transform(iris.data)

  lda = LinearDiscriminantAnalysis(n_components=2)
  lda.fit(iris_scaled, iris.target) # 지도학습이라, fit할 때, 클래스 결정값 (y) 넣어야함
  iris_lda = lda.transform(iris_scaled)
  print(iris_lda.shape)</code></pre>
<ul>
<li>LDA는 실제로는 PCA와 다르게 비지도학습이 아닌 지도학습 ⇒ 즉, 클래스 결정값이 변환시에 필요함.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 6. Regression(2) (규제, 로지스틱회귀, 회귀 트리 및 예제)]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-6.-Regression2-%EA%B7%9C%EC%A0%9C-%EB%A1%9C%EC%A7%80%EC%8A%A4%ED%8B%B1%ED%9A%8C%EA%B7%80-%ED%9A%8C%EA%B7%80-%ED%8A%B8%EB%A6%AC-%EB%B0%8F-%EC%98%88%EC%A0%9C</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-6.-Regression2-%EA%B7%9C%EC%A0%9C-%EB%A1%9C%EC%A7%80%EC%8A%A4%ED%8B%B1%ED%9A%8C%EA%B7%80-%ED%9A%8C%EA%B7%80-%ED%8A%B8%EB%A6%AC-%EB%B0%8F-%EC%98%88%EC%A0%9C</guid>
            <pubDate>Mon, 10 Oct 2022 01:52:40 GMT</pubDate>
            <description><![CDATA[<h1 id="5-규제-regularization">5. 규제 Regularization</h1>
<h2 id="1-릿지-회귀-ridge">1. 릿지 회귀 Ridge</h2>
<p>: $w^2$에 대해 패널티를 부여하는 방식. 주요 생성 파라미터는 alpha로, alpha가 커질 수록 회귀 계수 값을 작게 만든다.</p>
<ul>
<li>$RSS(w) + alpha*||w||_2^2$ 식을 최소화하는 w를 찾는 것</li>
</ul>
<pre><code class="language-python">from sklearn.linear_model import Ridge</code></pre>
<h2 id="2-라쏘-회귀-lasso">2. 라쏘 회귀 Lasso</h2>
<p>: $|w|$에 패널티를 부여하는 방식. 불필요한 회귀 계수를 급격하게 감소시켜 0으로 만든다.</p>
<ul>
<li>$RSS(w) + alpha*||w||_1$ 식을 최소화하는 w를 찾는 것</li>
</ul>
<pre><code class="language-python">from sklearn.linear_model import Lasso</code></pre>
<h2 id="3-엘라스틱넷-회귀-elasticnet">3. 엘라스틱넷 회귀 ElasticNet</h2>
<ul>
<li>L2규제와 L1규제를 결합한 회귀<ul>
<li>L1 라쏘 회귀가 중요 피처만 셀렉션하고 다른 피처들은 회귀 계수를 0으로 만드는 성향이 강함</li>
<li>alpha 값에 따라 회귀 계수 값이 급격히 변동할 수 있는데, 이를 완화하기 위해 L2 릿지를 L1 라쏘 회귀에 추가한 것</li>
<li>반대로 엘라스틱넷 회귀의 단점은 L1 + L2로 수행시간이 상대적으로 오래 걸린다는 것</li>
</ul>
</li>
<li>$RSS(w) + alpha1<em>||w||_1+alpha2</em>||w||_2^2$ 식을 최소화하는 w를 찾는 것<ul>
<li>엘라스틱 규제 : $a * L1 + b * L2$</li>
<li>릿지와 라쏘의 alpha값과는 다름</li>
<li>$a$ = L1 규제의 alpha값, $b$ = L2 규제의 alpha값</li>
<li>엘라스틱넷 회귀의 alpha값은 = $a+b$</li>
</ul>
</li>
<li>주요 생성 파라미터<ul>
<li><code>alpha</code> = $a + b$</li>
<li><code>l1_ratio</code> = $\frac{a}{a+b}$<ul>
<li><code>l1_ratio = 0</code>이면, a=0이므로 L2규제와 동일</li>
<li><code>l1_ratio = 1</code>이면, b=0이므로 L1 규제와 동일</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="language-python">from sklearn.linear_model import ElasticNet</code></pre>
<h2 id="4-선형-회귀-모델을-위한-데이터-변환">4. 선형 회귀 모델을 위한 데이터 변환</h2>
<ul>
<li><p>데이터 분포도의 정규화와 인코딩의 중요성</p>
</li>
<li><p>데이터 변환 : 선형 회귀 모델은 피처값과 타겟값의 분포가 정규분포로 된 형태를 선호</p>
<ul>
<li>정규분포 형태가 아니라, 특정값 분포로 치우친 왜곡(Skew)된 형태의 분포도일 경우, 성능에 부정적 영향 줄 가능성 높음</li>
</ul>
<ol>
<li><p>StandardScaler : 평균이 0, 분산이 1인 정규분포를 가진 데이터 세트로 변환</p>
<p> MinMaxScaler : 최소값이 0, 최대값이 1인 값으로 정규화 수행</p>
</li>
<li><p>스케일링/정규화를 수행한 데이터 세트에 다시 다항 특성을 적용하여 변환</p>
<ul>
<li>1번 방법을 통해 성능 향상이 없는 경우, 2번을 적용하는 경우가 많음</li>
</ul>
</li>
<li><p>⭐️로그 변환⭐️ :  log함수를 적용하여 정규분포에 가까운 형태로 변환</p>
<ul>
<li>이 방법을 주로 사용<ul>
<li>1번은 성능 향상을 크게 기대하기 어려우며</li>
<li>2번은 피처 갯수가 매우 많을 경우에는 다항 변환으로 생기는 피처 갯수가 기하급수로 늘어나서 과적합 이슈 발생 높음</li>
</ul>
</li>
<li>타깃값의 경우는 일반적으로 로그 변환을 적용
→ 타깃값을 다른류의 정규값으로 변환하면 원복이 어렵고, 왜곡된 타깃 분포도를 로그 변환하면 성능 향상된 경우가 많은 사례에서 검증됐음</li>
<li><code>np.log1p()</code> = $1 + log()$ 사용<ul>
<li>$log()$는 언더플로우 발생 가능성이 있기 때문</li>
</ul>
</li>
</ul>
</li>
</ol>
</li>
</ul>
<hr>
<h1 id="6-로지스틱-회귀-logistic-regression">6. 로지스틱 회귀 Logistic Regression</h1>
<p>: 선형 회귀 방식을 분류에 적용한 알고리즘 (이진 분류에 뛰어남)</p>
<p>: 시그모이드Sigmoid 함수 최적선을 찾고 이 시그모이드 함수의 반환값을 확률로 간주해 확률에 따라 분류를 결정한다.</p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/7e22b608-f096-412d-ab09-5bbbd7c579f5/image.png" alt=""></p>
<ul>
<li>시그모이드 함수 :  $y = \frac{1}{1+e^{-x}}$<ul>
<li>$x$ → $\infty$     : $y=1$</li>
<li>$x$ → $-\infty$ : $y=0$</li>
<li>$x$ → $0$       : $y=0.5$</li>
</ul>
</li>
<li>로지스틱 회귀 하이퍼 파라미터<ul>
<li><code>penalty</code> : 규제 유형 설정. ‘l2’, ‘l1’ (기본은 l2)</li>
<li><code>C</code> : 규제 강도 조절하는 alpha의 역수 (1/alpha) $\therefore$ 작을수록 규제강도 높아짐</li>
</ul>
</li>
</ul>
<h1 id="7-회귀-트리">7. 회귀 트리</h1>
<p>: 회귀를 위한 트리를 생성하고 이를 기반으로 회귀 예측 진행</p>
<p>: 리프 노드에 속한 데이터 값의 평균값으로 회귀 예측값을 계산</p>
<p>: 결정트리, 랜덤포레스트, GBM, LightGBM, XGBoost 등 모든 트리 기반 알고리즘은 회귀 계산 가능</p>
<p>(뒤에 Regressor. 예: DecisionTreeRegressor)</p>
<p>단, 선형 회귀와 다른 처리 방식이므로 회귀 계수를 제공하는 coef_ 속성은 없다. 대신 피처별 중요도를 알려주는 feature_importances_ 제공</p>
<h1 id="8-회귀-실습">8. 회귀 실습</h1>
<h2 id="81-캐글-자전거-대여-수요예측">8.1. 캐글 자전거 대여 수요예측</h2>
<ul>
<li><p>회귀 모델 전, 데이터 전처리시 주의점</p>
<ul>
<li>결괏값이 정규 분포로 돼 있는지 확인</li>
<li>카테고리형 회귀 모델의 경우 → 원-핫 인코딩으로 피처를 인코딩 하는 것</li>
</ul>
</li>
<li><p>예측 오류가 큰 경우 ⇒ Target 값의 분포가 왜곡된 형태를 이루고 있는지 확인하기</p>
<pre><code class="language-python">  def get_top_error_data(y_test, pred, n_tops = 5):
      # DataFrame에 컬럼들로 실제 대여횟수(count)와 예측 값을 서로 비교 할 수 있도록 생성. 
      result_df = pd.DataFrame(y_test.values, columns=[&#39;real_count&#39;])
      result_df[&#39;predicted_count&#39;]= np.round(pred)
      result_df[&#39;diff&#39;] = np.abs(result_df[&#39;real_count&#39;] - result_df[&#39;predicted_count&#39;])
      # 예측값과 실제값이 가장 큰 데이터 순으로 출력. 
      print(result_df.sort_values(&#39;diff&#39;, ascending=False)[:n_tops])

  get_top_error_data(y_test,pred,n_tops=5)

  y_target.hist()

  y_log_transform = np.log1p(y_target)
  y_log_transform.hist()</code></pre>
<ul>
<li><p>결괏값이 왜곡된 경우, 로그 변환 하면 좋다</p>
<pre><code class="language-python">y_log_transform = np.log1p(y_target)
y_log_transform.hist()</code></pre>
</li>
<li><p>로그 변환된 것 → 원상 복구 : <code>np.expm1(y_data)</code></p>
<pre><code class="language-python"># 타겟 컬럼인 count 값을 log1p 로 Log 변환
y_target_log = np.log1p(y_target)

# 로그 변환된 y_target_log를 반영하여 학습/테스트 데이터 셋 분할
X_train, X_test, y_train, y_test = train_test_split(X_features, y_target_log, test_size=0.3, random_state=0)
lr_reg = LinearRegression()
lr_reg.fit(X_train, y_train)
pred = lr_reg.predict(X_test)

# 테스트 데이터 셋의 Target 값은 Log 변환되었으므로 다시 expm1를 이용하여 원래 scale로 변환
y_test_exp = np.expm1(y_test)

# 예측 값 역시 Log 변환된 타겟 기반으로 학습되어 예측되었으므로 다시 exmpl으로 scale변환
pred_exp = np.expm1(pred)

evaluate_regr(y_test_exp ,pred_exp)</code></pre>
</li>
</ul>
</li>
<li><p>숫자로 되어 있지만, 카테고리형이어야 할 feature ⇒ one-hot 인코딩</p>
<pre><code class="language-python">  # &#39;year&#39;, month&#39;, &#39;day&#39;, hour&#39;등의 피처들을 One Hot Encoding
  X_features_ohe = pd.get_dummies(X_features, columns=[&#39;year&#39;, &#39;month&#39;,&#39;day&#39;, &#39;hour&#39;, &#39;holiday&#39;,
                                                &#39;workingday&#39;,&#39;season&#39;,&#39;weather&#39;])
                                  # X_features에서, columns=[] 들의 col을 o-h 인코딩 하겠다.

  X_features_ohe.head()</code></pre>
</li>
</ul>
<h2 id="82-캐글-주택-가격--고급-회귀-기법">8.2. 캐글 주택 가격 : 고급 회귀 기법</h2>
<h1 id="9-정리">9. 정리</h1>
<ul>
<li>기본 개념: 경사하강법 Gradient Descent</li>
<li>평가: MAE, MSE, RMSE, R^2</li>
<li>Linear Regressor<ul>
<li>단항 회귀</li>
<li>다항 회귀</li>
</ul>
</li>
<li>Reaularization<ul>
<li>Ridge</li>
<li>Lasso</li>
<li>ElasticNet</li>
</ul>
</li>
<li>Logistic Regression</li>
<li>Regression Tree</li>
</ul>
<p>+데이터 스케일링/정규화, 인코딩</p>
<p>+스태킹 기법 가능</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 6. Regression(1) (경사하강법, 평가지표, 선형회귀)]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-6.-Regression1-%EA%B2%BD%EC%82%AC%ED%95%98%EA%B0%95%EB%B2%95-%ED%8F%89%EA%B0%80%EC%A7%80%ED%91%9C-%EC%84%A0%ED%98%95%ED%9A%8C%EA%B7%80</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-6.-Regression1-%EA%B2%BD%EC%82%AC%ED%95%98%EA%B0%95%EB%B2%95-%ED%8F%89%EA%B0%80%EC%A7%80%ED%91%9C-%EC%84%A0%ED%98%95%ED%9A%8C%EA%B7%80</guid>
            <pubDate>Wed, 05 Oct 2022 01:17:48 GMT</pubDate>
            <description><![CDATA[<h1 id="regression-회귀">Regression 회귀</h1>
<p>: 여러 개의 독립 변수와 한 개의 종속 변수 간의 상관관계를 모델링 하는 기법</p>
<p>: 주어진 피처와 결정 값 데이터 기반에서 학습을 통해 최적의 회귀계수(Regression coefficients)를 찾아내는 것</p>
<ul>
<li>회귀계수: 독립변수 값에 영향을 미치는 Wn</li>
</ul>
<table>
<thead>
<tr>
<th>독립변수 갯수</th>
<th>회귀 계수의 결합</th>
</tr>
</thead>
<tbody><tr>
<td>1개 : 단일 회귀</td>
<td>선형 : 선형 회귀</td>
</tr>
<tr>
<td>1개(n) ⁍ : 다항 회귀</td>
<td>선형 : 선형 회귀</td>
</tr>
<tr>
<td>여러개 : 다중 회귀</td>
<td>비선형 : 비선형 회귀</td>
</tr>
</tbody></table>
<p>선형 회귀 : 실제 값과 예측 값의 차이(오류의 제곱 값)를 최소화하는 직선형 회귀선을 최적화하는 방식</p>
<ul>
<li>일반 선형 회귀 : 실제-예측값의 RSS(Residual_잔여의_ Sum of Squares)를 최소화할 수 있도록 회귀 계수를 최적화하며, 규제를 적용하지 않은 모델</li>
<li>릿지 : 선형 회귀 + L2 규제 ⇒ L2 : 상대적으로 큰 회귀 계수 값의 예측 영향도를 감소시키기 위해 회귀 계수값을 더 작게 만드는 규제</li>
<li>라쏘 : 선형 회귀 + L1 규제 ⇒ L1 : (L2는 회귀계수값 크기 줄이는데 반해) 예측 영향력이 작은 피처의 회귀 계수를 0으로 만들어, 회귀예측시 피처가 선택되지 않게 하는 것 → L1 규제는 피처 선택 기능으로 불림</li>
<li>엘리스틱넷 : L2, L1 규제를 함께 결합한 모델 → 주로 피처가 많은 데이터 세트에 적용됨</li>
<li>로지스틱 회귀 : 분류에 사용되는 선형 회귀 모델</li>
</ul>
<hr>
<h1 id="1-경사하강법-gradient-descent">1. 경사하강법 Gradient Descent</h1>
<ul>
<li><p>단순 선형 회귀로 이해해보기</p>
<ul>
<li>모델 : $f(x) = w_0 + w_1 * x$</li>
<li>실젯값 : $Y_i = w_0 + w_1 * X_i \cdots Error_i ; &gt; ,$</li>
<li>예측값 : $\hat{Y} = w_0 + w_1*X$</li>
</ul>
</li>
<li><p>RSS(Residual Sum of Square) : 오류에 제곱을 해서 더하는 방식</p>
<ul>
<li>(오류값(잔차)은 +,- 모두 될 수 있기 때문에) 오류값의 제곱을 더한 방식</li>
<li>$RSS(w_0,w_1) = 1/N\sum_{i=1}^{N}(y_i-(w_0+w_1x_i))^2$<ul>
<li>RSS에서는 독립변수 X, 종속변수 Y가 중심 변수가 아니라, 회귀 계수 w임을 인지하는 것이 매우 중요</li>
<li>학습 데이터로 입력되는 독립/종속변수는 RSS에서 모두 상수로 간주</li>
</ul>
</li>
</ul>
</li>
<li><p>회귀에서 이 RSS 값은 비용(Cost)이며, w변수(회귀계수) 구성되는 RSS를 비용 함수라고 함</p>
<ul>
<li>회귀 알고리즘은 이 비용 함수가 반환하는 값(즉, 오류 값)을 지속해서 감소시키고 최종적으로는 더 이상 감소하지 않는 최소의 오류값을 구하는 것</li>
<li>비용 함수를 손실 함수(loss function)라고도 함</li>
</ul>
</li>
<li><p>경사하강법: 점진적으로 반복적인 계산을 통해 W를 업데이트하면서 오류값이 최소가 되는 W를 구하는 방식</p>
<ul>
<li><p>2차함수의 최저점은 미분 값인 1차 함수의 기울기가 가장 최소일 때</p>
</li>
<li><p>$\begin{matrix}
R(w) &amp;=&amp; \frac{1}{N}\sum_{i=1}^N&gt;(y_i-&gt;(w_0+w_1*x_i)&gt;)^2 \ \
&amp;=&amp; \frac{1}{N}\sum_{i=1}^{N}&gt;(y_i - \hat{y_i})^2 \ \ &amp;=&amp; 평균(&gt;(실제값_i - 예측값_i)^2&gt;) \ \ &amp;=&amp; 평균(오차제곱) \ \ &amp;=&amp; MSE
\end{matrix}$</p>
</li>
<li><p>$R(w_0,w_1)$를 각 $w_0, w_1$로 편미분</p>
<p>  <img src="https://velog.velcdn.com/images/mios_leo/post/67b8c216-2920-4bc7-bb2c-b8a5ace3581a/image.png" alt=""></p>
<ul>
<li>$\partial R(w)/\partial w_1 = \frac{2}{N} \sum_{i=1}^{N}-x_i * (y_i(-w_0+w_1x_i)) = -\frac{2}{N}\sum_{i=1}^{N}x_i*(실제값_i-예측값_i)$</li>
<li>$\partial R(w)/\partial w_0 = \frac{2}{N} \sum_{i=1}^{N}-(y_i-(w_0+w_1x_i)) = -\frac{2}{N}\sum_{i=1}^{N}(실제값_i-예측값_i)$</li>
</ul>
</li>
<li><p>$w_1, w_0$의 편미분 결괏값인 $-\frac{2}{N}\sum_{i=1}^{N}x_i*(실제값<em>i-예측값_i)$,  $-\frac{2}{N}\sum</em>{i=1}^{N}(실제값_i-예측값_i)$ 을 반복적으로 보정하면서, $w_1, w_0$ 값을 업데이트 하면서 비용 함수 $R(w)$를 최소가 되는 $w_0, w_1$ 을 구할 수 있음</p>
<ul>
<li>이때, 편미분 값이 너무 클 수 있기 때문에 보정계수 $\eta$를 곱하는데, 이를 학습률(learning_rate)이라고 한다.</li>
<li>업데이트는 편미분 결괏값을 마이너스(-)하면서 적용</li>
<li>$새로운;w_1 = 이전;w_1 - (&gt;-\eta\frac{2}{N} \sum_{i=1}^{N}x_i(실제값_i-예측값_i)&gt;)$</li>
<li>$새로운;w_0 = 이전;w_0 - (&gt;- \eta \frac{2}{N} \sum_{i=1}^{N} (실제값_i-예측값_i)&gt;)$</li>
<li>이 과정을 반복적으로 적용하면서, 비용함수가 최소가 되는 값을 찾는 것</li>
</ul>
</li>
<li><p>경사 하강법의 일반적인 프로세스</p>
<ul>
<li>[Step 1] : $w_1, w_0$을 임의의 값으로 설정하고 첫 비용 함수의 값을 계산</li>
<li>[Step 2] : $w_1$을 $w_1 + \eta\frac{2}{N} \sum_{i=1}^{N}x_i(실제값<em>i-예측값_i)$ 으로, $w_0$을 $w_0 + \eta \frac{2}{N} \sum</em>{i=1}^{N} (실제값_i-예측값_i)$ 으로 업데이트한 후, 다시 비용 함수의 값을 계산</li>
<li>[Step 3] : 비용 함수의 값이 감소했으면, 다시 [Step 2]를 반복, 더 이상 비용 함수 값이 감소하지 않으면 그때의 $w_1,w_0$를 구하고 반복 중지</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="language-python">    import numpy as np
    import matplotlib.pyplot as plt
    %matplotlib inline

    ### --- 실제값을 Y=4X+6 시뮬레이션하는 데이터 값 생성 ----------------------------

    np.random.seed(0)
    # y = 4X + 6 식을 근사(w1=4, w0=6). random 값은 Noise를 위해 만듬
    X = 2 * np.random.rand(100,1)
    y = 6 +4 * X+ np.random.randn(100,1)
    print(type(X))

    ### --- w0과 w1의 값을 최소화 할 수 있도록 업데이트 수행하는 함수 생성 ---------------------

    # w1 과 w0 를 업데이트 할 w1_update, w0_update를 반환. 
    def get_weight_updates(w1, w0, X, y, learning_rate=0.01):
        N = len(y)

        # 먼저 w1_update, w0_update를 각각 w1, w0의 shape와 동일한 크기를 가진 0 값으로 초기화
        w1_update = np.zeros_like(w1)
        w0_update = np.zeros_like(w0)

        # 예측 배열 계산하고 예측과 실제 값의 차이 계산
        y_pred = np.dot(X, w1.T) + w0 # 예측값
        diff = y - y_pred # 실제값 - 예측값
        # diff == error

        # w0_update를 dot 행렬 연산으로 구하기 위해 모두 1값을 가진 행렬 생성 
        w0_factors = np.ones((N,1))

        # w1과 w0을 업데이트할 w1_update와 w0_update 계산
        w1_update = -(2/N)*learning_rate*(np.dot(X.T, diff)) # w1의 편미분 값
        w0_update = -(2/N)*learning_rate*(np.dot(w0_factors.T, diff)) # w0의 편미분 값

        return w1_update, w0_update

    ### --- 반복적으로 경사 하강법을 이용하여 get_weigth_updates()를 호출하여 w1과 w0를 업데이트 하는 함수 생성 ---

    # 입력 인자 iters로 주어진 횟수만큼 반복적으로 w1과 w0를 업데이트 적용함. 
    def gradient_descent_steps(X, y, iters=10000):
        # w0와 w1을 모두 0으로 초기화. 
        w0 = np.zeros((1,1))
        w1 = np.zeros((1,1))

        # 인자로 주어진 iters 만큼 반복적으로 get_weight_updates() 호출하여 w1, w0 업데이트 수행. 
        for ind in range(iters):
            w1_update, w0_update = get_weight_updates(w1, w0, X, y, learning_rate=0.01) # w1, w0 편미분값 return
            w1 = w1 - w1_update # 새로운 w1
            w0 = w0 - w0_update # 새로운 w0

        return w1, w0

    ### --- 예측 오차 비용을 계산을 수행하는 함수 생성 및 경사 하강법 수행 ---------------------

    def get_cost(y, y_pred):
        N = len(y) 
        cost = np.sum(np.square(y - y_pred))/N # 평균( (실제값 - 예측값)^2 ) = RMSE
        return cost

    w1, w0 = gradient_descent_steps(X, y, iters=1000)
    print(&quot;w1:{0:.3f} w0:{1:.3f}&quot;.format(w1[0,0], w0[0,0]))
    y_pred = w1[0,0] * X + w0
    print(&#39;Gradient Descent Total Cost:{0:.4f}&#39;.format(get_cost(y, y_pred)))</code></pre>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/98e86c36-f64a-41ef-aca5-c0147faa86c8/image.png" alt=""></p>
<ul>
<li><p>경사하강법은 모든 학습 데이터에 반복적으로 업데이트 하기에 시간이 매우 오래 걸린다는 단점 ⇒ 확률적 경사하강법을 대신 사용</p>
</li>
<li><p>(미니배치) 확률적 경사하강법(Stochastic_통계학의/확률적인_ Gradient Desent): 일부 데이터만을 이용해 w가 없데이트되는 값 계산 ⇒ SGD</p>
<ul>
<li><p>전반적으로 경사하강법과 비슷하지만, 전체 X, y 데이터에서 랜덤하게 batch_size만큼 데이터를 추출해서 w1, w0을 업데이트 함</p>
<pre><code class="language-python">def stochastic_gradient_descent_steps(X, y, batch_size=10, iters=1000):
  w0 = np.zeros((1,1))
  w1 = np.zeros((1,1))
  prev_cost = 100000
  iter_index =0

  for ind in range(iters):
      np.random.seed(ind)
      # 전체 X, y 데이터에서 랜덤하게 batch_size만큼 데이터 추출하여 sample_X, sample_y로 저장
      stochastic_random_index = np.random.permutation(X.shape[0]) # permutation : array를 복사해서 shuffle
      sample_X = X[stochastic_random_index[0:batch_size]]
      sample_y = y[stochastic_random_index[0:batch_size]]
      # 랜덤하게 batch_size만큼 추출된 데이터 기반으로 w1_update, w0_update 계산 후 업데이트
      w1_update, w0_update = get_weight_updates(w1, w0, sample_X, sample_y, learning_rate=0.01)
      w1 = w1 - w1_update
      w0 = w0 - w0_update

  return w1, w0

w1, w0 = stochastic_gradient_descent_steps(X, y, iters=1000)
print(&quot;w1:&quot;,round(w1[0,0],3),&quot;w0:&quot;,round(w0[0,0],3))
y_pred = w1[0,0] * X + w0
print(&#39;Stochastic Gradient Descent Total Cost:{0:.4f}&#39;.format(get_cost(y, y_pred)))</code></pre>
</li>
</ul>
</li>
<li><p>피처가 여러개인 경우 어떻게 회귀 계수 도출할 수 있을까? (↔ 지금까지는 피처 1개, 독립변수 1개인 단순 선형 회귀의 경사하강법)</p>
<ul>
<li>피처 1개인 경우 : $\hat{Y} = w_0 + w_1 * X$ 로</li>
<li>피처가 M개($X_1, X_2, \cdots, X_m$) 인 경우 : $\hat{Y} = w_0 + w_1 * X_1 + w_2 * X_2 + \cdots + w_{100}*X_{100}$<ul>
<li>회귀 계수도는 M+1개 (1개는 $w_0$)</li>
</ul>
</li>
<li>데이터가 N개이고 피처가 M개인 입력 행렬을 $X_{mat}$, 회귀 계수 $w_1, w_1, \cdots, w_{100}$을 W 배열로 표기하면
⇒ $\hat{Y} = np.dot(X_{mat}, W^T) + w_0$</li>
<li>$w_0$을 W배열에 포함시키기 위해서, $X_{mat}$의 맨 처음 열에 모든 데이터 값이 1인 피처 Feat 0을 추가 하면
⇒ $\hat{Y} = X_{mat} * W^T$</li>
</ul>
</li>
</ul>
<h1 id="2-회귀-평가지표">2. 회귀 평가지표</h1>
<ul>
<li><p>보스턴 주택 가격 예측 예시</p>
<ul>
<li>LinearRegression 클래스는 RSS를 최소화해 OLS(Ordinary Least Squares) 추정 방식으로 구현됨<ul>
<li><code>fit()</code> 메서드로 X, y 배열 받으면, 회귀 계수(Coefficients)인 W를 <code>coef_</code> 속성에 저장</li>
<li>입력 파라미터에서, $nomalize=True$ 로 설정하면 회귀 수행 전, 입력 데이터 세트를 정규화함 $*default = False$</li>
</ul>
</li>
<li>OLS 기반 회귀 계수 계산은 입력 피처의 독립성에 많은 영향을 받아, 피처 상관관계가 높은 경우 분산이 매우 커져 오류에 매우 민감해짐<ul>
<li>다중회귀(비선형) ⇒ 다중 공선성 문제 (multi-collinearity)</li>
<li>그래서 일반적으로 상관 관계가 높은 피처가 많은 경우 독립적인 중요한 피처만 남기고 제거 or 규제 및 PCA로 차원 축소 수행하기도 함</li>
</ul>
</li>
</ul>
</li>
<li><p>MAE(Mean Absolute Error)</p>
<ul>
<li>$1/N \sum_{i=1}^{N}|Y_i - \hat Y_i|$</li>
<li>실제값과 예측값의 차이를 절대값으로 변환해 평균한 것</li>
<li>사이킷런 평가지표: <code>metrics.mean_absolute_error</code></li>
<li>Scoring 함수 적용값 : ‘neg_mean_absolute_error’<ul>
<li>‘neg_’ ⇒ -1을 곱해서 반환 (scoring함수는 값이 클수록 좋은 평가 결과로 보기 때문)</li>
<li>10 &gt; 1 ⇒ -10 &lt; -1  == neg_mean_absolute_error ⇒ -1 * metrics.mean_absolute_error</li>
</ul>
</li>
</ul>
</li>
<li><p>MSE(Mean Squared Error)</p>
<ul>
<li>$MSE = 1/N\sum_{i=1}^{N}(Y_i-\hat Y_i)^2$</li>
<li>실제값과 예측값의 차이를 제곱해 평균한 것</li>
<li><code>metrics.mean_squared_error</code></li>
<li>Scoring 함수 적용값 : ‘neg_mean_squared_error’</li>
</ul>
</li>
<li><p>RMSE(Root MSE)</p>
<ul>
<li>$RMSE = \sqrt{1/N\sum_{i=1}^{N}(Y_i-\hat Y_i)^2}$</li>
<li>MSE는 실제 오류 평균보다 커지므로 보정한 것</li>
<li>사이킷런은 RMSE를 제공하지 않음</li>
</ul>
</li>
<li><p>$R^2$</p>
<ul>
<li>$R^2 = \frac{예측분산}{실제분산}$</li>
<li>$R^2 = 1 - \frac { \sum ( y - \hat{y} )^2 } { \sum ( y - 평균 )^2 } = 1 - \frac { \sum ( 오차 )^2 } { \sum ( 편차 )^2 }$</li>
<li>1에 가까워질 수록 예측 정확도가 좋은 것<ul>
<li>$R^2 = 1 = (&gt;1 - \color{yellow}0\color{d}&gt;)$  <strong>⇒</strong>  $\frac { \color{yellow}\sum ( 오차 )^2 } { \sum ( 편차 )^2 } = \frac {\color{yellow} \sum ( y - \hat{y} )^2 } { \sum ( y - 평균 )^2 }$   <strong>⇒</strong>   $\color{yellow}{(y - \hat{y}) = 0}$  <strong>⇒  $\color{yellow} y = \hat{y}$   ⇒   예측값이 실제값과 같다</strong></li>
<li>$R^2 = 0 = (&gt;1 - \color{red}1\color{d}&gt;)$  <strong>⇒</strong>  $\frac { \color{red}\sum ( 오차 )^2 } { \color{red} \sum ( 편차 )^2 } = \frac {\color{red} \sum ( y - \hat{y} )^2 } {\color{red} \sum ( y - 평균 )^2 }$   <strong>⇒</strong>   $\color{red}{(y - \hat{y}) = (y - 평균)}$  <strong>⇒  $\color{red} 평균 = \hat{y}$   ⇒   예측값이 평균값과 같다 (예측하나마나다)</strong></li>
</ul>
</li>
<li><code>metrics.r2_score</code></li>
<li>Scoring 함수 적용값 : ‘r2’</li>
</ul>
</li>
</ul>
<h1 id="3-선형-회귀-linear-regression">3. 선형 회귀 Linear Regression</h1>
<p>: 예측값과 실제값의 RSS를 최소화해 OLS(Ordinary Least Squares) 추정방식으로 구현한 클래스</p>
<ol>
<li>입력 파라미터</li>
</ol>
<pre><code>| 파라미터 | 디폴트 | 설명 |
| --- | --- | --- |
| fit_intercept | Ture | Boolean, intercept(절편)값을 계산할 것인지 결정 |
| normalize | False | Boolean, True면 회귀를 수행하기 전에 입력 데이터 세트 정규화, fit_intercept=False 인 경우 이 파라미터는 무시됨 |</code></pre><ol start="2">
<li>속성<ul>
<li>coef_: fit() 메서드를 수행했을 때, 회귀 계수가 배열 형태로 저장되는 속성, shape = (Target 개수, 피처 개수)</li>
<li>intercept_: 절편 값</li>
</ul>
</li>
</ol>
<ul>
<li>Seaborn의 regplot(): x, y축 값의 산점도와 선형 회귀 직선을 그려준다.</li>
</ul>
<h1 id="4-다항-회귀-polynomial-regression">4. 다항 회귀 Polynomial Regression</h1>
<p>: 회귀가 독립변수의 단항식이 아닌 2차, 3차 방정식과 같은 다항식으로 표현되는 것(하지만 선형회귀다!)</p>
<p>예) $y = w_0 + w_1x_1 + w_2x_2 + w_3x_1x_2 + w_4x_1^2 + w_5x_2^2$</p>
<ul>
<li>선형회귀 / 비선형 회귀를 나누는 기준 : 회귀 계수가 선형/비선형인지에 따른 것(독립변수의 선형/비선형은 X)</li>
<li>사이킷런은 다항회귀를 위한 클래스를 명시적으로 제공 X</li>
</ul>
<pre><code class="language-python">from sklearn.preprocessing import PolynomialFeatures
import numpy as np

# 다항식으로 변환한 단항식 생성, [[0,1],[2,3]]의 2X2 행렬 생성
X = np.arange(4).reshape(2,2)
print(&#39;일차 단항식 계수 feature:\n&#39;,X )

# degree = 2 인 2차 다항식으로 변환하기 위해 PolynomialFeatures를 이용하여 변환
poly = PolynomialFeatures(degree=2) # 2차 다항값을 만들겠다는 것
poly.fit(X)
poly_ftr = poly.transform(X)
print(&#39;변환된 2차 다항식 계수 feature:\n&#39;, poly_ftr)

------------------------------------------
&gt; 일차 단항식 계수 feature:
&gt; [[0 1]
&gt; [2 3]]
&gt; 변환된 2차 다항식 계수 feature:
&gt; [[1. 0. 1. 0. 0. 1.]
&gt; [1. 2. 3. 4. 6. 9.]]</code></pre>
<ul>
<li>3차 다항식 계수의 피처값과 3차 다항식 결정값으로 학습</li>
</ul>
<pre><code class="language-python"># 3 차 다항식 변환 
poly_ftr = PolynomialFeatures(degree=3).fit_transform(X)
print(&#39;3차 다항식 계수 feature: \n&#39;,poly_ftr)

# Linear Regression에 3차 다항식 계수 feature와 3차 다항식 결정값으로 학습 후 회귀 계수 확인
model = LinearRegression()
model.fit(poly_ftr,y)
print(&#39;Polynomial 회귀 계수\n&#39; , np.round(model.coef_, 2))
print(&#39;Polynomial 회귀 Shape :&#39;, model.coef_.shape)

------------------------------------------------
&gt; 3차 다항식 계수 feature: 
&gt;  [[ 1.  0.  1.  0.  0.  1.  0.  0.  0.  1.]
&gt;  [ 1.  2.  3.  4.  6.  9.  8. 12. 18. 27.]]
&gt; Polynomial 회귀 계수
&gt;  [0.   0.18 0.18 0.36 0.54 0.72 0.72 1.08 1.62 2.34]
&gt; Polynomial 회귀 Shape : (10,)</code></pre>
<ul>
<li>Polynomial Features로 변환 후 LinearRegression 사용 (Pipeline) (fit_transform 없이)</li>
</ul>
<pre><code class="language-python">from sklearn.pipeline import Pipeline

def polynomial_func(X):
    y = 1 + 2*X[:,0] + 3*X[:,0]**2 + 4*X[:,1]**3 
    return y

# Pipeline 객체로 Streamline 하게 Polynomial Feature변환과 Linear Regression을 연결
model = Pipeline([(&#39;poly&#39;, PolynomialFeatures(degree=3)),
                  (&#39;linear&#39;, LinearRegression())])
X = np.arange(4).reshape(2,2)
y = polynomial_func(X)

model = model.fit(X, y)
print(&#39;Polynomial 회귀 계수\n&#39;, np.round(model.named_steps[&#39;linear&#39;].coef_, 2))

------------------------------------------------
&gt; Polynomial 회귀 계수
&gt; [0.   0.18 0.18 0.36 0.54 0.72 0.72 1.08 1.62 2.34]</code></pre>
<ul>
<li><p>차수가 높아질 수록 과적합의 문제가 발생한다.</p>
</li>
<li><p>편향-분산 트레이드 오프(Bias-Variance Trade off)</p>
<ul>
<li>고편향: 매우 단순화된 모델</li>
<li>고분산: 매우 복잡한 모델, 지나치게 높은 변동성</li>
</ul>
</li>
<li><p>최적 모델을 위한 비용함수 구성요소: 학습 데이터 잔차 오류 최소화 + 회귀 계수 크기 제어</p>
<p>  ⇒ 비용함수 목표: $Min(RSS(w) + alphaX||w||_2^2)$</p>
<ul>
<li>alpha : 학습 데이터 적합정도와 회귀 계수 값의 크기 제어를 수행하는 튜닝 파라미터</li>
<li>alpha를 크게하면 w를 작게, alpha를 작게하면 w이 어느정도 크게하여(커져도) 상쇄함 $for$ 과적합 개선</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 5. Classification(3) (예제 및 스태킹)]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-5.-Classification3-%EC%98%88%EC%8B%9C%EC%8A%A4%ED%83%9C%ED%82%B9</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-5.-Classification3-%EC%98%88%EC%8B%9C%EC%8A%A4%ED%83%9C%ED%82%B9</guid>
            <pubDate>Tue, 04 Oct 2022 11:12:39 GMT</pubDate>
            <description><![CDATA[<h1 id="4-실전-예시">4. 실전 예시</h1>
<h2 id="a-santander-예시">A. Santander 예시</h2>
<ol>
<li>EDA 중, head, info, describe 사용</li>
<li>이상치 발생 ⇒ 제일 많은 걸로 대체하는 방법론도 있음</li>
</ol>
<h2 id="b-신용카드-사기-검출-예시">B. 신용카드 사기 검출 예시</h2>
<ul>
<li><code>LGBMClassifier( . . . boost_from_average=False)</code> : 레이블값 매우 불균형한 경우 False, if True ⇒ 재현률 및 ROC-AUC 성능 매우 저하 
( : 왜인지는 아직 모름)</li>
</ul>
<ol>
<li>언더 샘플링과 오버 샘플링의 이해 : 지도 학습시 극도로 불균형한 레이블 값 분포로 인한 문제점을, 적절한 학습 데이터를 확보로 해결 방법들
(주로 오버 샘플링 방식이 예측 성능상 더 유리한 경우가 많아 주로 사용됨)</li>
</ol>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/fbba4bfc-f772-442e-ad1b-147f2a368736/image.png" alt=""></p>
<pre><code>- 언더 샘플링 : 많은 데이터 세트를 적은 데이터 세트 수준으로 감소시키는 방식 ⇒ 너무 많은 정상 레이블 데이터를 감소시켜서, 오히려 학습이 잘 안될 수 있음
- 오버 샘플링 : 적은 데이터 세트를 많은 데이터 세트 수준으로 증식시키는 방식 ⇒ 동일한 데이터를 단순 증식하는 건 과적합 되기에 의미 X ⇒ 원본 피처 값들을 아주 약간만 변경하여 증식함
    1. 대표적으로 SMOTE(Synthetic Minority Over-sampling Technique) 방법이 있음
    2. SMOTE는 적은 제이터 세트에 있는 개별 데이터들의 K 최근접 이웃을 찾아서 이 데이터와 K개 이웃들의 차이를 일정 값으로 만들어거 기존 데이터와 약간 차이가 나는 새로운 데이터들을 생성하는 방식
    3. SMOTE를 구현하는 파이썬 패키지 == imbalanced-learn</code></pre><p><img src="https://velog.velcdn.com/images/mios_leo/post/a25e2411-7e88-409e-9c3a-a525c89fff03/image.png" alt=""></p>
<ol start="2">
<li><p>(전처리) 데이터 분포도 변환</p>
<ol>
<li><p>StandardScaler : 로지스틱 회귀 같은 선형 회귀 경우, 중요 피처값들이 정규분포 유지하는 것을 선호함.</p>
<ol>
<li><p>중요한 피처인 Amount를 sns.distplot 해보니 긴 꼬리 형태 ⇒ 정규분포형태로 전처리 (StandarScaler)</p>
</li>
<li><p>별로 큰 효과는 없었음</p>
<pre><code class="language-python">from sklearn.preprocessing import StandardScaler
# 사이킷런의 StandardScaler를 이용하여 정규분포 형태로 Amount 피처값 변환하는 로직으로 수정. 
def get_preprocessed_df(df=None):
 df_copy = df.copy()
 scaler = StandardScaler()
 print(df_copy[&#39;Amount&#39;].values)
 amount_n = scaler.fit_transform(df_copy[&#39;Amount&#39;].values.reshape(-1, 1))
 # 변환된 Amount를 Amount_Scaled로 피처명 변경후 DataFrame맨 앞 컬럼으로 입력
 df_copy.insert(0, &#39;Amount_Scaled&#39;, amount_n)
 # 기존 Time, Amount 피처 삭제
 df_copy.drop([&#39;Time&#39;,&#39;Amount&#39;], axis=1, inplace=True)
 return df_copy</code></pre>
</li>
</ol>
</li>
<li><p>로그 변환 :  데이터 분포도가 심하게 왜곡돼있을 때 사용하면 좋음</p>
<ol>
<li><p>원래 값을 log 값으로 변환해, 원래 큰 값을 상대적으로 작은 값으로 변환해주기에 데이터 분포도의 왜곡을 상당 수준 개선해 줌</p>
</li>
<li><p>약간식 개선됨</p>
<pre><code class="language-python">def get_preprocessed_df(df=None):
 df_copy = df.copy()
 # 넘파이의 log1p( )를 이용하여 Amount를 로그 변환 
 amount_n = np.log1p(df_copy[&#39;Amount&#39;])
 df_copy.insert(0, &#39;Amount_Scaled&#39;, amount_n)
 df_copy.drop([&#39;Time&#39;,&#39;Amount&#39;], axis=1, inplace=True)
 return df_copy</code></pre>
</li>
</ol>
</li>
</ol>
</li>
<li><p>(전처리) 이상치 데이터 제거</p>
<ol>
<li><p>IQR (Inter Quantile Range) : 사분위 값의 편차를 이용하는 기법 → Q1(25%) ~ Q3(75%) 범위를 IQR이라고 부름 (중앙값에서 퍼져나간 정도)
⇒ IQR = Q3 - Q1
⇒ Box Plot으로 시각화</p>
</li>
<li><p>IQR 이용해 이상치 데이터 검출하는 방식 : IQR * 1.5 하여 생성된 범위를 이용해, 최댓/최솟값을 결정한 뒤, 여기를 벗어나는 데이터를 이상치로 간주 ⇒ 경우에 따라 1.5가 변경될 수 있음
⇒ Q3(3/4분위수)에,  IQR<em>1.5를 더함 == 최댓값
⇒ Q2(1/2분위수) == 중앙값
⇒ Q1(1/4분위수)에, IQR</em>1.5를 뻄 == 최솟값</p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/29a91b2c-4334-43b7-9c0c-4db3738478fb/image.png" alt=""></p>
</li>
</ol>
</li>
</ol>
<pre><code>3. 매우 많은 피처가 있을 경우, 이들 중 결정값(레이블)과 가장 상관성이 높은 피처 위주로 이상치를 검출해야 시간/성능에 유리함

    ```python
    import seaborn as sns

    plt.figure(figsize=(9, 9))
    corr = card_df.corr()
    sns.heatmap(corr, cmap=&#39;RdBu&#39;)
    ```

4. IQR을 이용해, 이상치를 검출하는 함수 생성 ⇒ IQR 계산 ⇒ 최댓/최솟값 아웃라이어 찾기

    ```python
    import numpy as np

    def get_outlier(df=None, column=None, weight=1.5):
        # fraud에 해당하는 column 데이터만 추출, 1/4 분위와 3/4 분위 지점을 np.percentile로 구함. 
        fraud = df[df[&#39;Class&#39;]==1][column] # column = &#39;V14&#39;
        quantile_25 = np.percentile(fraud.values, 25)
        quantile_75 = np.percentile(fraud.values, 75)
        # IQR을 구하고, IQR에 1.5를 곱하여 최대값과 최소값 지점 구함. 
        iqr = quantile_75 - quantile_25
        iqr_weight = iqr * weight
        lowest_val = quantile_25 - iqr_weight
        highest_val = quantile_75 + iqr_weight
        # 최대값 보다 크거나, 최소값 보다 작은 값을 아웃라이어로 설정하고 DataFrame index 반환. 
        outlier_index = fraud[(fraud &lt; lowest_val) | (fraud &gt; highest_val)].index
        return outlier_index

    outlier_index = get_outlier(df=card_df, column=&#39;V14&#39;, weight=1.5)
    print(&#39;이상치 데이터 인덱스:&#39;, outlier_index)
    ```</code></pre><ol start="4">
<li><p>(전처리) SMOTE 오버 샘플링 적용</p>
<ol>
<li><p>SMOTE 적용시에는 반드시 train(학습) 데이터 세트만 오버 샘플링 해야함 → eval(검증), test(테스트) 데이터 세트 하면 올바른 검증/테스트 불가</p>
<pre><code class="language-python"> from imblearn.over_sampling import SMOTE

 smote = SMOTE(random_state=0)
 X_train_over, y_train_over = smote.fit_resample(X_train, y_train) #fit_sample 없어지고 -&gt; fit_resample로 바뀜
 print(&#39;SMOTE 적용 전 학습용 피처/레이블 데이터 세트: &#39;, X_train.shape, y_train.shape)
 print(&#39;SMOTE 적용 후 학습용 피처/레이블 데이터 세트: &#39;, X_train_over.shape, y_train_over.shape)
 print(&#39;SMOTE 적용 후 레이블 값 분포: \n&#39;, pd.Series(y_train_over).value_counts())

 lr_clf = LogisticRegression()
 # ftr_train과 tgt_train 인자값이 SMOTE 증식된 X_train_over와 y_train_over로 변경됨에 유의
 get_model_train_eval(lr_clf, ftr_train=X_train_over, ftr_test=X_test, tgt_train=y_train_over, tgt_test=y_test)</code></pre>
<ol>
<li>재현율/AUC는 엄청 올라가지만, 정밀도, 정밀도/F1은 급격히 내려감 ⇒ 실무에 적용할 수 없음</li>
<li>실제 원본 데이터의 유형보다 너무나 많은 Class=1 데이터가 학습되어, 테스트 데이터 세트 예측에서 Class=1 예측이 너무 많아짐</li>
</ol>
</li>
<li><p><code>precision_recall_curve_plot()</code> 으로 확인해보자 (추후 threshold를 변경하려나…?)</p>
<pre><code class="language-python"> import matplotlib.pyplot as plt
 import matplotlib.ticker as ticker
 from sklearn.metrics import precision_recall_curve
 %matplotlib inline

 def precision_recall_curve_plot(y_test , pred_proba_c1):
     # threshold ndarray와 이 threshold에 따른 정밀도, 재현율 ndarray 추출. 
     precisions, recalls, thresholds = precision_recall_curve( y_test, pred_proba_c1)

     # X축을 threshold값으로, Y축은 정밀도, 재현율 값으로 각각 Plot 수행. 정밀도는 점선으로 표시
     plt.figure(figsize=(8,6))
     threshold_boundary = thresholds.shape[0]
     plt.plot(thresholds, precisions[0:threshold_boundary], linestyle=&#39;--&#39;, label=&#39;precision&#39;)
     plt.plot(thresholds, recalls[0:threshold_boundary],label=&#39;recall&#39;)

     # threshold 값 X 축의 Scale을 0.1 단위로 변경
     start, end = plt.xlim()
     plt.xticks(np.round(np.arange(start, end, 0.1),2))

     # x축, y축 label과 legend, 그리고 grid 설정
     plt.xlabel(&#39;Threshold value&#39;); plt.ylabel(&#39;Precision and Recall value&#39;)
     plt.legend(); plt.grid()
     plt.show()

 precision_recall_curve_plot( y_test, lr_clf.predict_proba(X_test)[:, 1] )</code></pre>
<ol>
<li>실제로 그려보니, 임계값이 0.99이하에서는 재현율이 매우 좋고/정밀도가 극단적으로 낮다가, 0.99에는 급격히 서로 cross 됨</li>
<li>이건, threshold 바꿔도 성능을 얻을 수 없으므로, 이번 사례에서 로지스틱 회귀의 경우에는 SMOTE 적용하면 안된다는 결론</li>
</ol>
</li>
<li><p>LightGBM의 경우에는 SMOTE 활용하면, 이상치만 제거한 것에 비해 재현율은 높아지나, 정밀도는 낮아짐</p>
<ol>
<li>일반적으로 SMOTE를 쓰면 재현율은 높아지나, 정밀도는 낮아짐</li>
</ol>
</li>
</ol>
</li>
</ol>
<h1 id="5-스태킹-stacking">5. 스태킹 Stacking</h1>
<ol>
<li><p>스태킹 앙상블 : 개별 알고리즘의 예측 결과 데이터 세트를 “최종적인 메타 데이터 세트”로 만들어 별도의 ML 알고리즘으로 최종학습을 수행하고 테스트 데이터를 기반으로 다시 최종 예측을 수행하는 방식</p>
<ul>
<li><p>메타 모델: 개별 모델의 예측된 데이터 세트를 다시 기반으로 하여 학습하고 예측하는 방식</p>
</li>
<li><p>필요한 모델</p>
<ol>
<li><p>개별적인 기반 모델</p>
</li>
<li><p>개별 기반 모델의 예측 데이터를 학습 데이터로 만들어서 학습하는 “최종 메타 모델”</p>
<p> <img src="https://velog.velcdn.com/images/mios_leo/post/58349f05-b910-46fd-9080-1584e4eb7b54/image.png" alt=""></p>
</li>
</ol>
</li>
</ul>
</li>
</ol>
<pre><code>        ```python
        # 개별 모델들을 학습/예측

        knn_pred = knn_clf.predict(X_test)
        rf_pred = rf_clf.predict(X_test)
        dt_pred = dt_clf.predict(X_test)
        ada_pred = ada_clf.predict(X_test)

        pred = np.array([knn_pred, rf_pred, dt_pred, ada_pred])
        print(pred.shape)

        # transpose를 이용해 행과 열의 위치 교환. 컬럼 레벨로 각 알고리즘의 예측 결과를 피처로 만듦. 
        pred = np.transpose(pred)
        print(pred.shape)

        lr_final.fit(pred, y_test)
        final = lr_final.predict(pred)

        print(&#39;최종 메타 모델의 예측 정확도: {0:.4f}&#39;.format(accuracy_score(y_test , final)))
        ```</code></pre><ol start="2">
<li><p>CV 세트 기반의 스태킹 : 과적합 개선 위해, 최종 메타 모델을 위한 데이터 세트를 만들 때, 교차 검증 기반으로 예측된 결과 데이터 세트를 이용한다.</p>
<ol>
<li><p>위 스태킹 코드에서, 로지스틱 회귀 메타모델 최종 학습시, 학습 데이터가 아닌 테스트용 데이터 기반으로 학습했기에 과적합이 발생할 수 있음</p>
<ol>
<li>각 모델을 train data로 학습시킨 후</li>
<li>개별모델_pred = 개별모델.predict(X_test) ⇒ X_test 즉, 테스트용 데이터로 학습 시키고</li>
<li>최종 메타 모델때 y_test로 예측했으니 과적합 가능성 존재</li>
</ol>
</li>
<li><p>CV 세트 기반의 스태킹은 개별 모델들이, 각각 교차 검증으로,
[메타 모델을 위한 “학습용 스태킹 데이터 생성”] / [예측을 위한 “테스트용 스태킹 데이터”를 생성]한 뒤,
이를 기반으로 모델이 학습과 예측을 수행
⇒ 2단계의 스텝으로 구분</p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/320f6e7e-1bed-474d-ae1c-599ddec59865/image.png" alt=""></p>
</li>
</ol>
</li>
</ol>
<ol start="3">
<li><p>CV 기반의 스태킹 모델 Step</p>
<ol>
<li><p>각 모델 별로 원본 학습/테스트 데이터를 예측한 결과 값을 기반으로 메타 모델을 위한 학습/테스트용 데이터 생성</p>
<ol>
<li>원본 학습 데이터 n(폴드)-1개로 학습된 개별 모델을 만듦</li>
<li>개별 모델로 원본 학습 데이터 폴드 1개를 Val 예측으로 [메타 학습 데이터] 칸 순차적으로 채우기</li>
<li>개별 모델로 원본 테스트 데이터 예측해서 결괏값 순차적으로 나열(?)하기</li>
<li>위 3개의 작업을 cv=n, n번 반복하면 ⇒ [메타 학습 데이터] 완성</li>
<li>그리고 n개의 원본 테스트 데이터에 대한 결괏값에 대한 AVG 구해서 [메타 테스트 데이터] 만들기</li>
</ol>
</li>
<li><p>[메타 학습/테스트 데이터] 완성 됐으니 그 다음부턴 그냥 fit, predict하면 됨</p>
<pre><code class="language-python"># Step 1

from sklearn.model_selection import KFold
from sklearn.metrics import mean_absolute_error

# 개별 기반 모델에서 최종 메타 모델이 사용할 학습 및 테스트용 데이터를 생성하기 위한 함수. 
def get_stacking_base_datasets(model, X_train_n, y_train_n, X_test_n, n_folds ):
 # 지정된 n_folds값으로 KFold 생성.
 kf = KFold(n_splits=n_folds, shuffle=False) #, random_state=0)
 #추후에 메타 모델이 사용할 학습 데이터 반환을 위한 넘파이 배열 초기화 
 train_fold_pred = np.zeros((X_train_n.shape[0] ,1 ))
 test_pred = np.zeros((X_test_n.shape[0],n_folds))
 print(model.__class__.__name__ , &#39; model 시작 &#39;)

 for folder_counter , (train_index, valid_index) in enumerate(kf.split(X_train_n)):
     #입력된 학습 데이터에서 기반 모델이 학습/예측할 폴드 데이터 셋 추출 
     print(&#39;\t 폴드 세트: &#39;,folder_counter,&#39; 시작 &#39;)
     X_tr = X_train_n[train_index] 
     y_tr = y_train_n[train_index] 
     X_te = X_train_n[valid_index]  

     #폴드 세트 내부에서 다시 만들어진 학습 데이터로 기반 모델의 학습 수행.
     model.fit(X_tr , y_tr)       
     #폴드 세트 내부에서 다시 만들어진 검증 데이터로 기반 모델 예측 후 데이터 저장.
     train_fold_pred[valid_index, :] = model.predict(X_te).reshape(-1,1)
     #입력된 원본 테스트 데이터를 폴드 세트내 학습된 기반 모델에서 예측 후 데이터 저장. 
     test_pred[:, folder_counter] = model.predict(X_test_n)

 # 폴드 세트 내에서 원본 테스트 데이터를 예측한 데이터를 평균하여 테스트 데이터로 생성 
 test_pred_mean = np.mean(test_pred, axis=1).reshape(-1,1)    

 #train_fold_pred는 최종 메타 모델이 사용하는 학습 데이터, test_pred_mean은 테스트 데이터
 return train_fold_pred , test_pred_mean

knn_train, knn_test = get_stacking_base_datasets(knn_clf, X_train, y_train, X_test, 7)
rf_train, rf_test = get_stacking_base_datasets(rf_clf, X_train, y_train, X_test, 7)
dt_train, dt_test = get_stacking_base_datasets(dt_clf, X_train, y_train, X_test,  7)    
ada_train, ada_test = get_stacking_base_datasets(ada_clf, X_train, y_train, X_test, 7)

# 각 모델별 학습/테스트 데이터 합치기
Stack_final_X_train = np.concatenate((knn_train, rf_train, dt_train, ada_train), axis=1)
Stack_final_X_test = np.concatenate((knn_test, rf_test, dt_test, ada_test), axis=1)
print(&#39;원본 학습 피처 데이터 Shape:&#39;,X_train.shape, &#39;원본 테스트 피처 Shape:&#39;,X_test.shape)
print(&#39;스태킹 학습 피처 데이터 Shape:&#39;, Stack_final_X_train.shape,
   &#39;스태킹 테스트 피처 데이터 Shape:&#39;,Stack_final_X_test.shape)

# 최종 메타 모델 돌리기
lr_final.fit(Stack_final_X_train, y_train) # 최종 메타 모델 돌릴 때, 원본 학습 라벨 y_train 가져야 써야함
stack_final = lr_final.predict(Stack_final_X_test)

print(&#39;최종 메타 모델의 예측 정확도: {0:.4f}&#39;.format(accuracy_score(y_test, stack_final)))</code></pre>
</li>
</ol>
</li>
</ol>
<h1 id="6-정리">6. 정리</h1>
<ul>
<li>분류 Classification<ul>
<li>결정 트리 Decision Tree</li>
<li>Voting</li>
<li>Bagging<ul>
<li>RandomForestClassifier</li>
</ul>
</li>
<li>Boosting<ul>
<li>GBM</li>
<li>XGBoost</li>
<li>LightGBM</li>
</ul>
</li>
<li>Stacking</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 5. Classification(2) (앙상블)]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-5.-Classification-%EC%95%99%EC%83%81%EB%B8%94</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-5.-Classification-%EC%95%99%EC%83%81%EB%B8%94</guid>
            <pubDate>Thu, 29 Sep 2022 07:46:40 GMT</pubDate>
            <description><![CDATA[<h1 id="3-앙상블-ensemble">3. 앙상블 Ensemble</h1>
<p>: 여러 개의 분류기(classifier)를 생성하고 그 예측을 결합함으로써 보다 정확한 최종 예측을 도출하는 기법</p>
<p>→ 보팅Voting, 배깅Bagging, 부스팅Boosting + 스태킹Stacking</p>
<ul>
<li>보팅 : 서로 다른 알고리즘을 가진 분류기 결합</li>
<li>배깅 : 같은 유형의 알고리즘을 가진 분류기를 사용하지만, 데이터 샘플링을 다르게 가져감<ul>
<li>부트스트래핑 Bootstrapping: 개별 분류기에게 데이터를 샘플링해서 추출하는 방식</li>
<li>데이터 세트 간의 중첩 허용 (cf. 교차검증은 중복 불허)<ul>
<li>ex) 10,000개의 데이터를 10개의 분류기가 배깅 방식으로 나눠도, 각 1,000개의 데이터 내에서 중복된 데이터가 있을 수 있음</li>
</ul>
</li>
</ul>
</li>
<li>부스팅 : 여러 개의 분류기가 순차적으로 학습을 수행하되, 앞의 분류기의 틀린 예측에 대해서 다음 분류기에는 가중치를 부여하면서 학습과 예측을 진행하는 방식<ul>
<li>대표적인 모듈: 그래디언트 부스트, XGBoost, LightGBM</li>
</ul>
</li>
<li>스태킹 : 여러 가지 다른 모델의 예측 결과값을 “다시 학습 데이터로 만들어서” 다른 모델(메타 모델)로 재학습, 예측하는 방법</li>
</ul>
<h2 id="a-보팅">A. 보팅</h2>
<ol>
<li>유형
 <img src="https://velog.velcdn.com/images/mios_leo/post/94351c03-0fd0-41f7-a834-5ecf5864764c/image.png" alt=""></li>
</ol>
<pre><code>1. 하드 보팅 Hard Voting:  다수결원칙. 예측 결과값들 중 다수의 분류기가 결정한 예측값을 최종 보팅 결과값으로 선정
2. 소프트 보팅 Soft Voting : 분류기들의 레이블 값 결정 확률을 모두 더하고 이를 평균해서, 이들 중 확률이 가장 높은 레이블 값을 최종 보팅 결과값으로 선정(일반적으로 소프트 보팅 사용)</code></pre><ol start="2">
<li><p>사용 (보팅 분류기)</p>
<pre><code class="language-python"> from sklearn.ensemble import VotingClassifier
 # 로지스틱 회귀, KNN 기반 소프트 보팅 방식 분류기 만들기
 vo_clf = VotingClassigier(estimator = [(&#39;LR&#39;, lr_clf), (&#39;KNN&#39;, knn_clf)], voting=&#39;soft&#39;)</code></pre>
</li>
</ol>
<h2 id="b-배깅---대표적-알고리즘-랜덤-포레스트-random-forest">B. 배깅 - 대표적 알고리즘 랜덤 포레스트 Random Forest</h2>
<p>(Bagging = Bootstrap Aggregating)</p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/d43c5a49-b826-4c99-a28b-32b0604d6974/image.png" alt=""></p>
<p>→ 서브 트리의 데이터 건수 = 전체 데이터 건수 (중첩되어 갖고 있다.)</p>
<ol>
<li><p>사용</p>
<pre><code class="language-python"> from sklearn.ensemble import RandomForestClassifier
 from sklearn.metrics import accuracy_score
 import pandas as pd
 import warnings

 # 결정 트리에서 사용한 get_human_dataset( )을 이용해 학습/테스트용 DataFrame 반환
 X_train, X_test, y_train, y_test = get_human_dataset()

 # 랜덤 포레스트 학습 및 별도의 테스트 셋으로 예측 성능 평가
 rf_clf = RandomForestClassifier(random_state=0)
 rf_clf.fit(X_train , y_train)
 pred = rf_clf.predict(X_test)
 accuracy = accuracy_score(y_test , pred)
 print(&#39;랜덤 포레스트 정확도: {0:.4f}&#39;.format(accuracy))</code></pre>
</li>
<li><p>파라미터</p>
<ul>
<li><p><code>n_estimator</code> : 결정 트리 개수, 디폴트 = 10</p>
</li>
<li><p><code>max_features</code> : 최적의 분할을 위해 고려할 피처 개수, 디폴트 = ‘auto’ (= ‘sqrt’) ↔ 결정트리에서는 ‘None’</p>
</li>
<li><p><code>max_depth</code> :  트리의 최대 깊이</p>
</li>
<li><p><code>min_samples_leaf</code> : 말단 노드가 되기 위한 최소한의 샘플 데이터 수</p>
</li>
<li><ul>
<li><p><code>feature_importances_</code> : DecisionTreeClassifier와 같이 알고리즘이 선택한 피처의 중요도 파악 가능</p>
<pre><code class="language-python">import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline

ftr_importances_values = rf_clf1.feature_importances_
ftr_importances = pd.Series(ftr_importances_values,index=X_train.columns  )
ftr_top20 = ftr_importances.sort_values(ascending=False)[:20]

plt.figure(figsize=(8,6))
plt.title(&#39;Feature importances Top 20&#39;)
sns.barplot(x=ftr_top20 , y = ftr_top20.index)
plt.show()</code></pre>
</li>
</ul>
</li>
</ul>
</li>
<li><p>with GridSearch</p>
<pre><code class="language-python"> from sklearn.model_selection import GridSearchCV

 params = {
     &#39;n_estimators&#39;:[100],
     &#39;max_depth&#39; : [6, 8, 10, 12], 
     &#39;min_samples_leaf&#39; : [8, 12, 18 ],
     &#39;min_samples_split&#39; : [8, 16, 20]
 }
 # RandomForestClassifier 객체 생성 후 GridSearchCV 수행
 rf_clf = RandomForestClassifier(random_state=0, n_jobs=-1)
 grid_cv = GridSearchCV(rf_clf , param_grid=params , cv=2, n_jobs=-1 )
 grid_cv.fit(X_train , y_train)

 print(&#39;최적 하이퍼 파라미터:\n&#39;, grid_cv.best_params_)
 print(&#39;최고 예측 정확도: {0:.4f}&#39;.format(grid_cv.best_score_))</code></pre>
</li>
</ol>
<h2 id="c-부스팅-알고리즘">C. 부스팅 알고리즘</h2>
<p>: 여러 개의 약한 학습기를 순차적으로 학습-예측하면서 잘못 예측한 데이터에 가중치를 부여해 개선하는 방식</p>
<p>( AdaBoost_Adaptive boosting_에이다부스팅 )</p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/239cec3a-3c31-4049-bad8-1122e681b20a/image.png" alt=""></p>
<h3 id="1-gbmgradient-boosting-machine">1. GBM(Gradient Boosting Machine)</h3>
<ul>
<li><p>경사하강법(Gradient Descent) : ‘오류 값 = 실제 값 - 예측 값&#39;을 최소화하는 방향성을 갖고 반복적으로 가중치 업데이트</p>
<ul>
<li>이때 가중치 업데이트에 경사하강법을 이용하는 것이, 에이다와 큰 차이점</li>
<li>반복수행을 통해 오류를 최소화할 수 있도록 가중치의 업데이트 값을 도출하는 과정</li>
</ul>
</li>
<li><p>일반적으로 GBM이 랜덤 포레스트보다는 예측 성능이 조금 뛰어난 경우가 많지만, 수행 시간이 오래 걸리고 하이퍼 파라미터 튜닝 노력이 더 필요함</p>
<pre><code class="language-python">  import time
  import warnings
  from sklearn.ensemble import GradientBoostingClassifier
  from sklearn.model_selection import GridSearchCV
  warnings.filterwarnings(&#39;ignore&#39;)

  X_train, X_test, y_train, y_test = get_human_dataset()

  # GBM 수행 시간 측정을 위함. 시작 시간 설정.
  start_time = time.time()

  gb_clf = GradientBoostingClassifier(random_state=0)
  gb_clf.fit(X_train , y_train)
  gb_pred = gb_clf.predict(X_test)
  gb_accuracy = accuracy_score(y_test, gb_pred)

  print(&#39;GBM 정확도: {0:.4f}&#39;.format(gb_accuracy))
  print(&quot;GBM 수행 시간: {0:.1f} 초 &quot;.format(time.time() - start_time))

  # ------------------------------------------------------------------- #
  params = {
      &#39;n_estimators&#39;:[100, 500],
      &#39;learning_rate&#39; : [ 0.05, 0.1]
  }
  grid_cv = GridSearchCV(gb_clf , param_grid=params , cv=2 ,verbose=1)
  grid_cv.fit(X_train , y_train)
  print(&#39;최적 하이퍼 파라미터:\n&#39;, grid_cv.best_params_)
  print(&#39;최고 예측 정확도: {0:.4f}&#39;.format(grid_cv.best_score_))

  # ------------------------------------------------------------------- #

  # GridSearchCV를 이용하여 최적으로 학습된 estimator로 predict 수행. 
  gb_pred = grid_cv.best_estimator_.predict(X_test)
  gb_accuracy = accuracy_score(y_test, gb_pred)
  print(&#39;GBM 정확도: {0:.4f}&#39;.format(gb_accuracy))</code></pre>
</li>
<li><p>하이퍼 파라미터</p>
<ul>
<li><code>n_estimators, max_depth, max_features</code> 등 트리 기반 자체의 파라미터 포함</li>
<li><code>loss</code> : 경사하강법에서 사용할 비용 함수, 디폴트 = deviance</li>
<li><code>learning_rate</code> : 학습을 진행할 때마다 적용하는 학습률, weak learner가 순차적으로 오류값을 보정해 나가는데 적용하는 계수<ul>
<li>0~1 사이 값 지정 가능, 디폴트 = 0.1</li>
<li>너무 작은 값은 업데이트 되는 값이 작아져 최소 오류값을 찾아 예측 성능이 높아질 수 있지만, 수행시간이 증가하고 너무 작으면 반복이 완료되어도 최소 오류값을 못 찾을 수 있음</li>
<li>반대로 큰 값은 최소 오류값을 지나쳐 예측 성능이 떨어질 수 있지만, 빠른 수행이 가능</li>
<li>위 이유들로 <code>n_estimator</code>와 상호 보완적으로 사용<ul>
<li><code>learning_rate</code> 를 작게 하고 <code>n_estimator</code>를 크게 하면 더 이상 성능이 좋아지지 않는 한계점까지는 예측 성능이 조금씩 좋아질 수 있음</li>
<li>하지만 수행시간이 너무 오래 걸리는 단점이 있으며, 예측 성능 역시 현격히 좋아지지는 않음</li>
</ul>
</li>
</ul>
</li>
<li><code>n_estimator</code> : weak learner의 개수, 디폴트 = 100<ul>
<li>weak learner가 순차적으로 오류를 보정하므로 갯수가 많을 수록 예측 성능이 일정수준 이상까지는 좋아질 수 있으나, 시간 오래 걸림</li>
</ul>
</li>
<li><code>subsample</code> : weak learner가 “학습에 사용하는” 데이터의 “샘플링 비율”<ul>
<li>0~1 사이 값 지정 가능, 디폴트 = 1 (학습 데이터 전체를 기반으로 학습, if 0.5 == 학습 데이터의 50% 사용)</li>
<li>과적합이 염려되는 경우 1보다 작은 값으로 설정</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="2-xgboostextra-gradient-boost">2. XGBoost(eXtra Gradient Boost)</h3>
<ul>
<li>장점<ul>
<li>뛰어난 예측 성능</li>
<li>GBM 대비 빠른 수행 시간</li>
<li>자체에 과적합 규제 기능</li>
<li>Tree pruning(나무 가지치기): 더 이상 긍정 이득이 없는 분할을 가지치기해서 분할 수를 줄임</li>
<li>자체 내장된 교차 검증</li>
<li>결손값 자체 처리</li>
</ul>
</li>
<li>패키지<ul>
<li>파이썬 래퍼 XGBoost 모듈: 초기의 독자적인 XGBoost 프레임워크 기반의 XGBoost</li>
<li>사이킷런 래퍼 XGBoost 모듈: 사이킷런과 연동되는 모듈</li>
</ul>
</li>
</ul>
<ol>
<li>파이썬 래퍼 XGBoost<ol>
<li>하이퍼 파라미터<ul>
<li>일반 파라미터(디폴트 파라미터 값을 바꾸는 경우 거의 없음)</li>
</ul>
</li>
</ol>
</li>
</ol>
<pre><code>        | 파라미터 | 디폴트 | 설명 |
        | --- | --- | --- |
        | booster | gbtree | gbtree(tree based model) or gblinear(linear model) 선택 |
        | silent | 0 | 출력 메세지를 나타내고 싶지 않은 경우 1로 설정 |
        | nthread | cpu의 전체 스레드 다 사용 | cpu의 실행 스레드 개수 조정 |

    - 부스터 파라미터


        | 파라미터 | 디폴트 | 설명 |
        | --- | --- | --- |
        | eta***alias: learning_rate | 0.3 | 학습률. weak learner가 순차적으로 오류값을 보정하는데 적용하는 계수, 0~1 사이 값, 보통은 0.01~0.2 값 선호 |
        | num_boost_rounds |  | weak learner의 개수,
        | min_child_weight | 1 | 추가적으로 가지를 나눌지 결정하기 위해 필요한 데이터들의 가중치 총합, 클수록 분할을 자제함, 과적합 조절 역할 |
        | gamma alias: min_split_loss | 0 | 리프노드를 추가적으로 나눌지 결정할 최소 손실 감소 값, 해당값보다 큰 손실(loss)이 감소된 경우??? 리프 노드 분할, 값이 클수록 과적합 감소 효과 |
        | max_depth | 6 | 트리의 최대 깊이, 0으로 설정하면 깊이 제한 없음, 3~10 사이 값 적용 |
        | sub_sample | 1 | 데이터를 샘플링하는 비율 지정, 0.5~1 사이값 사용 |
        | colsample_bytree | 1 | 트리 생성에 필요한 피처를 임의로 샘플링하는데 사용, 매우 많은 피처가 있는 경우 과적합을 조정하는데 사용 |
        | lambda alias: reg_lambda | 1 | L2 Regularization 적용값, 피처가 많을 수록 적용을 검토, 값이 클수록 과적합 감소 효과 |
        | alpha alias: reg_alpha *** 확인 | 0 | L1 Regularization 적용값, 피처가 많을 수록 적용을 검토, 값이 클수록 과적합 감소 효과 |
        | scale_pos_weight | 1 | 특정값으로 치우친 비대칭한 클래스로 구성된 데이터 세트의 균형을 유지하기 위한 값 |
    - 학습 테스크 파라미터


        | 파라미터 | 디폴트 | 설명 |
        | --- | --- | --- |
        | objective |  | 최소값을 가져야할 손실 함수 정의 |
        | binary : logistic |  | 이진 분류일 때 적용 |
        | multi : softmax |  | 다중 분류일 때 적용 |
        | multi : softprob |  | 개별 레이블 클래스에 해당되는 예측 확률 반환 |
        | eval_metrics | rmse : Root Mean Square Error, mae : Mean Absolute Error, logloss : Negative log-likelihood, error : Binary classification error rate, merror : Multiclass classification error rate, mlogloss : Multiclass logloss, auc : Area under the curve | 검증에 사용되는 함수 정의 |
        - 과적합 문제가 심각할 경우
            - eta(학습률) 값을 낮춤(0.01~0.1) ⇒ 그럴 경우, num_round(n_estimators)는 반대로 높여줘야 함
            - max_depth 값을 낮춤
            - min_child_weight 값을 높임
            - gamma(min_split_loss) 값을 높임
            - sub_sample(subsample)과 colsample_bytree(max_features)를 조정하는 것도 트리가 너무 복잡하게 생성되는 것을 막아, 과적합에 도움이 될 수 있음
    - XGBoost 는 자체적으로 교차검증, 성능평가, 피처중요도 등의 시각화 기능과 조기중단 기능을 가지고 있음
    - 조기 중단 early stopping: 파라미터 값만큼 학습하는 동안 예측 오류가 감소하지 않으면 중단

    ```python
    from xgboost import plot_importance # 피처의 중요도를 시각화해주는 모듈

    plot_importance(xgb_model, ax=ax)
    ```

2. DMatrix: 파이썬 래퍼 XGBoost는 학습용/테스트용 데이터 세트를 위해 별도의 DMatrix를 생성한다.
    - `xgb.DMatirx()` : 넘파이 입력 파라미터를 받아서 만들어지는, XGBoost 만의 전용 데이터 세트

    ```python
    dtrain = xgb.DMatrix(data=피처 데이터 세트, label=분류:레이블 데이터 세트 | 회귀: 숫자형인 종속값 데이터 세트)
    ```

    - DMatrix는 넘파이, libsvm txt 포맷 파일, xgboost 이진 버퍼 파일, 판다스의 df.values를 이용해 적용 가능
    - 학습 수행전, 하이퍼 파라미터(딕셔너리)로 입력해야 함

        ```python
        params = { &#39;max_depth&#39;:3,
                   &#39;eta&#39;: 0.1,
                   &#39;objective&#39;:&#39;binary:logistic&#39;,
                   &#39;eval_metric&#39;:&#39;logloss&#39;,
                   &#39;early_stopping&#39; : 100
                }
        num_rounds = 400
        ```

    - XGBoost 모델 학습시엔, 모듈의 train() 함수에 파라미터 전달 (사이킷런의 경우 Estimator의 생성자를 하이퍼 파라미터로 전달하는 데 반해 차이가 있음)
    - 조기중단시, params 외에 XGB 모델에 early_stopping_rounds 파라미터를 설정해야 하고, 반드시 eval_set 과 eval_metric이 함께 설정되어야 함.
        - (eval == test 라고 생각하면 편함)
        - eval_set : 성능 평가를 수행할 평가용 데이터 세트 설정
        - eval_metric : 평가 세트에 적용할 성능 평가 방법 ⇒ 분류일 경우 주로 ‘error’, ‘logloss’를 적용
        - XGBoost는 반복마다 eval_set으로 지정된 데이터 세트에서 eval_metric의 지정된 평가 지표로 오류를 측정 ⇒ 얘네가 조기중단 적용

    ```python

    import xgboost as xgb

    # train 데이터 셋은 ‘train’ , evaluation(test) 데이터 셋은 ‘eval’ 로 명기합니다. 
    wlist = [(dtrain,&#39;train&#39;),(dtest,&#39;eval&#39;) ]

    # 하이퍼 파라미터와 early stopping 파라미터를 train( ) 함수의 파라미터로 전달
    xgb_model = xgb.train(params=params,
                                                dtrain=dtrain,
                                                num_boost_round=num_rounds,
                          early_stopping_rounds=100,
                                                evals=wlist)
    # xgb.train은 학습이 완료된 모델을 객체로 반환

    xgb_model = xgb.train(params=파라미터 딕셔너리(성능평가 방법 포함되어 있음),
                                                dtrain=XGBoost전용 데이터 세트,
                                                numboost_round=숫자,
                                                early_stopping_rounds=숫자,
                                                evals=평가용 데이터 세트)

    ```

    - 모델 객체의 예측을 위해서는 `predict()` 메서드를 사용하는데, 예측 결괏값이 아닌, 예측 결과를 추정할 수 있는 확률 값을 반환함

    ```python
    pred_probs = xgb_model.predict(dtest)
    print(&#39;predict( ) 수행 결과값을 10개만 표시, 예측 확률 값으로 표시됨&#39;)
    print(np.round(pred_probs[:10],3))

    # 예측 확률이 0.5 보다 크면 1 , 그렇지 않으면 0 으로 예측값 결정하여 List 객체인 preds에 저장 
    preds = [ 1 if x &gt; 0.5 else 0 for x in pred_probs ]
    print(&#39;예측값 10개만 표시:&#39;,preds[:10])
    ```

    - 내장된 시각화 기능 (↔ 사이킷런은 Estimator 객체에 feature_importances_ 속성을 이용해 직접 시각화 코드를 해야함)
        - XGBoost 넘파이 기반의 피처 데이터를 학습시에는 피처명을 제대로 알 수 없으므로, f0, f1와 같이 피처 순서별 f자 뒤에 순서를 붙여서 X축에 피처들로 나열해야함 (즉 f0은 첫 번째 피처, f1는 두 번째 피처를 의미)

    ```python
    import matplotlib.pyplot as plt
    %matplotlib inline

    fig, ax = plt.subplots(figsize=(10, 12))
    plot_importance(xgb_model, ax=ax)
    ```

3. cv(): 데이터 세트에 대한 교차 검증 수행 후 최적 파라미터를 구할 수 있는 방법 제공. 반환값은 DataFrame (사이킷런의 GridSearchCV 기능)                                          

    ```python
    xgboost.cv(params, # (dict) 부스터 파라미터
                         dtrain, # (DMatrix) 학습 데이터
                         num_boost_round=10, # (int) 부스팅 반복 횟수
                         nfold=3, # (int) CV 폴드 갯수
                         stratified=False, # (bool) CV 수행시 층화 표본 추출 수행 여부
                         folds=None,
                         metrics=(), # (string or list of strings) CV 수행시 모니터링할 선능 평가 지표
                         obj=None,
                         feval=None,
                         maximize=False,
                         early_stopping_rounds=None, # (int) 조기 중단을 활성화시킴. 반복 횟수 지정.
                         fpreproc=None,
                         as_pandas=True,
                         verbose_eval=None,
                         show_stdv=True,
                         seed=0,
                         callbacks=None,
                         shuffle=True)
    ```

    - params: dict, 부스터 파라미터
    - dtrain: DMatrix, 학습데이터
    - num_boost_round: int, 부스팅 반복 횟수
    - n_fold: int, cv 폴드 개수
    - stratified: string or list of strings, cv 수행 시 모니터링할 성능지표
    - early_stopping_rounds: int, 조기중단 활성화, 반복횟수 지정</code></pre><ol start="2">
<li><p>사이킷런 래퍼 XGBoost: fit(), predict()로 학습 및 예측</p>
<ol>
<li><p>하이퍼 파라미터: 파이썬 래퍼 XGBoost 보기!</p>
<ul>
<li><p>eat → learning_rate</p>
</li>
<li><p>sub_sample → subsample</p>
</li>
<li><p>lambda → reg_lambda</p>
</li>
<li><p>alpah → reg_alpha</p>
<pre><code class="language-python"># 사이킷런 래퍼 XGBoost 클래스인 XGBClassifier 임포트
from xgboost import XGBClassifier

xgb_wrapper = XGBClassifier(n_estimators=400, learning_rate=0.1, max_depth=3)
xgb_wrapper.fit(X_train, y_train)
w_preds = xgb_wrapper.predict(X_test)
w_pred_proba = xgb_wrapper.predict_proba(X_test)[:, 1]</code></pre>
</li>
</ul>
</li>
<li><p>조기 중단</p>
<ul>
<li><p>fit() 에 입력</p>
</li>
<li><p>early_stopping_rounds: 반복 횟수 정의</p>
</li>
<li><p>eval_metrics: 조기 중단을 위한 평가 지표  예) logloss</p>
</li>
<li><p>eval_set: 성능평가를 수행할 데이터 세트</p>
<pre><code class="language-python">from xgboost import XGBClassifier

xgb_wrapper = XGBClassifier(n_estimators=400, learning_rate=0.1, max_depth=3)
evals = [(X_test, y_test)]
xgb_wrapper.fit(X_train, y_train, early_stopping_rounds=100, eval_metric=&quot;logloss&quot;, 
              eval_set=evals, verbose=True)

ws100_preds = xgb_wrapper.predict(X_test) # 원래는 X_test가 evals에 들어가 있으니, 사용하면 안됨
ws100_pred_proba = xgb_wrapper.predict_proba(X_test)[:, 1]</code></pre>
</li>
</ul>
</li>
<li><p><code>plot_importance()</code>: 피처의 중요도를 시각화하는 모듈</p>
<ul>
<li><p>파이썬 래퍼 때처럼 그대로 사용해도 무방</p>
<pre><code class="language-python">from xgboost import plot_importance
import matplotlib.pyplot as plt
%matplotlib inline

fig, ax = plt.subplots(figsize=(10, 12))
# 사이킷런 래퍼 클래스를 입력해도 무방. 
plot_importance(xgb_wrapper, ax=ax)</code></pre>
</li>
</ul>
</li>
</ol>
</li>
</ol>
<h3 id="3-lightgbm">3. LightGBM</h3>
<ul>
<li><p>XGBoost 대비 장단점</p>
<ul>
<li>장점 : 더 빠른 학습과 예측 수행 시간, 더 작은 메모리 사용량, 카테고리형 피처의 자동변환과 최적 분할(원핫 인코딩 안써도 카테고리형 피처를 최적으로 변환하에 이에 따른 노드 분할 수행)</li>
<li>단점 : 적은 데이터 세트에 적용할 경우 과적합이 발생하기 쉬움 (일반적으로 10,000건 이하의 데이터 세트 정도)</li>
<li>주의점 : XGBoost와 대부분이 유사하지만, 리프 노드가 계속 분할 → 트리 깊어짐, 이러한 트리 특성에 맞는 하이퍼 파라미터 설정이 필요함<ul>
<li>ex) max_depth를 매우 크게 가짐</li>
</ul>
</li>
</ul>
</li>
<li><p>트리 분할 방법 : 리프 중심 트리 분할(Leaf Wise) ↔ GBM 계열 트리 분할 방법 : 균형 트리 분할 (Level Wise)</p>
<p>  <img src="https://velog.velcdn.com/images/mios_leo/post/a0a8953f-2150-42a0-89bf-7b82f0993be0/image.png" alt=""></p>
</li>
</ul>
<pre><code>- Level Wise : 최대한 균형 잡힌 트리 유지하면서 분할 → 트리의 깊이가 최소화 → 오버피팅에 보다 더 강한 구조를 가질 수 있음 ← 시간 오래 걸림
- Leaf Wise : 트리 균형 보다, 최대 손실 값 (max delta loss)을 가지는 리프 노드를 지속적 분할 → 트리 깊이 깊어지고 비대칭 ← 반복 학습하면, 결국 Level Wise 방식 보다 예측 오류 손실을 최소화할 수 있다는 것이 LightGBM의 구현 사상

```python
# LightGBM의 파이썬 패키지인 lightgbm에서 LGBMClassifier 임포트
from lightgbm import LGBMClassifier

import pandas as pd
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

dataset = load_breast_cancer()
ftr = dataset.data
target = dataset.target

# 전체 데이터 중 80%는 학습용 데이터, 20%는 테스트용 데이터 추출
X_train, X_test, y_train, y_test=train_test_split(ftr, target, test_size=0.2, random_state=156 )

# 앞서 XGBoost와 동일하게 n_estimators는 400 설정. 
lgbm_wrapper = LGBMClassifier(n_estimators=400)

# LightGBM도 XGBoost와 동일하게 조기 중단 수행 가능. 
evals = [(X_test, y_test)]
lgbm_wrapper.fit(X_train, y_train, early_stopping_rounds=100, eval_metric=&quot;logloss&quot;, 
                 eval_set=evals, verbose=True)
preds = lgbm_wrapper.predict(X_test)
pred_proba = lgbm_wrapper.predict_proba(X_test)[:, 1]
```</code></pre><ol>
<li>하이퍼 파라미터</li>
</ol>
<pre><code>| 파라미터 (뒤에는 사이킷런 호환 클래스) | 디폴트 | 설명 |
| --- | --- | --- |
| num_iterations | n_estimators | 100 | 반복수행하려는 트리의 개수
크게 지정할 수록 예측성능이 올라가지만 과적합 가능성도 높아진다. |
| learning_rate | 0.1 | 부스팅 스텝을 반복적으로 수행할 때 업데이트되는 학습률. 0~1 사이 값 |
| max_depth | -1 | 트리의 최대 깊이. 0보다 작은 값을 지정하면 깊이 제한 X |
| min_data_in_leaf | min_child_samples | 20 | 리프노드가 되기 위해 최소한으로 필요한 레코드 수 |
| num_leaves | 31 | 하나의 트리가 가질 수 있는 최대 리프 개수 |
| boosting | gbdt | 부스팅의 트리를 생성하는 알고리즘 기술, - gbdt : 일반적인 그래디언트 부스팅 결정 트리, - rf : 랜덤 포레스트 |
| bagging_fraction (subsample) | 1.0 | 데이터를 샘플링하는 비율 |
| feature_fraction (colsample_bytree) | 1.0 | 개별 트리를 학습할 때마다 무작위로 선택하는 피처의 비율율 |
| lambda_l2 (reg_lambda) | 0.0 | L2 Regularizaton 제어를 위한 값 : 피처 개수가 많을 수록 적용 검토, 값이 클수록 과적합 감소 효과 |
| lambda_l1 (reg_alpha) | 0.0 | L1 Regularization 제어를 위한 값 : 피처 개수가 많을 수록 적용 검토, 값이 클수록 과적합 감소 효과 |
| objective |  | 최소값을 가져야할 손실함수 지정 : 회귀, 다중 클래스 분류, 이진 분류에 따라서 손실함수가 지정됨 |
- plot_importance(): 피처 중요도 시각화</code></pre><ol start="2">
<li>하이퍼 파라미터 튜닝 방안<ul>
<li>num_leaves의 개수를 중심으로 min_child_samples(min_data_in_leaf), max_depth를 함께 조정하면서 모델의 복잡도를 줄인다.<ul>
<li>num_leaves는 개별 트리가 가질 수 있는 최대 리프 갯수이고, LightGBM 모델 복잡도 제어하는 주요 파라미터
(일반적으로, num_leaves의 갯수를 높이면 정확도가 높아지지만, 트리가 깊어지고 복잡도가 커져 과적합 영향도 커짐)</li>
<li>min_child_samples는 보통, 큰 값으로 설정하면 트리 깊이가 깊어지는 걸 방지함</li>
<li>max_depth는 깊이의 크기 제한</li>
</ul>
</li>
<li>learning_rate를 작게 하면서 n_estimators를 크게 하는 것 (n_estimators를 너무 크게 하면 과적합으로 성능이 저하될 수 있다.)</li>
<li>reg_lambda, reg_alpha와 같은 regularization을 적용</li>
<li>colsample_bytree, subsample을 적용하여 학습 데이터에 사용할 피처의 개수, 데이터 샘플링 레코드 수를 줄임</li>
</ul>
</li>
<li>하이퍼 파라미터 비교</li>
</ol>
<pre><code>| 파이썬 래퍼 LightGBM | 사이킷런 래퍼 LightGBM | 사이킷런 래퍼 XGBoost |
| --- | --- | --- |
| num_iterations | n_estimators | n_estimators |
| learning_rate | learning_rate | learning_rate |
| max_depth | max_depth | max_depth |
| min_data_in_leaf | min_child_samples | N/A |
| bagging_fraction | colsample_bytree | colsample_bytree |
| lambda_l2 | reg_lambda | reg_lambda |
| lambda_l1 | reg_alpha | reg_alpha |
| early_stopping_round | early_stopping_rounds | early_stopping_rounds |
| num_leaves | num_leaves | N/A |
| min_sum_hessian_in_leaf | min_child_weight | min_child_weight |</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 5. Classification(1) (결정트리)]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-5.-Classification-%EA%B2%B0%EC%A0%95%ED%8A%B8%EB%A6%AC</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-5.-Classification-%EA%B2%B0%EC%A0%95%ED%8A%B8%EB%A6%AC</guid>
            <pubDate>Thu, 29 Sep 2022 02:09:47 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/mios_leo/post/e7cde298-3c3d-4ece-a24f-a51d51193740/image.jpg" alt=""></p>
<h1 id="classification-분류">Classification 분류</h1>
<hr>
<p>: 학습 데이터로 주어진 데이터의 피처와 레이블 값(결정 값, 클래스 값)을 머신러닝 알고리즘으로 학습해 모델을 생성하고, 이렇게 생성된 모델에 새로운 데이터 값이 주어졌을 때 미지의 레이블 값을 예측하는 것</p>
<p>&lt;분류를 구현할 수 있는 머신러닝 알고리즘&gt;</p>
<ul>
<li>나이브 베이즈 Naive Bayes: 베이즈 통계와 생성 모델에 기반</li>
<li>로지스틱 회귀 Logistic Regression: 독립변수와 종속변수의 선형관계에 기반</li>
<li>결정 트리 Decision Tree: 데이터 균일도에 따름</li>
<li>서포트 벡터 머신 Support Vector Machine: 개별 클래스 간의 최대 분류 마진을 찾아줌</li>
<li>최소 근접 알고리즘 Nearest Neighbor: 근접 거리 기준</li>
<li>신경망 Neural Network: 심층 연결 기반</li>
<li>앙상블 Ensemble: 서로 같은(또는 다른) 머신러닝 알고리즘 결합</li>
</ul>
<pre><code class="language-python">from sklearn.base import BaseEstimator
# : customized 형태의 Estimator를 개발자가 생성할 수 있다.</code></pre>
<hr>
<h1 id="2-결정-트리-decision-tree">2. 결정 트리 Decision Tree</h1>
<p>: 데이터에 있는 규칙을 학습을 통해 자동으로 찾아내 트리 기반의 분류 규칙을 만든다.</p>
<p>→ (조건문) 따라서, 데이터의 어떤 기준을 바탕으로 규칙을 만들어야 가장 효율적인 분류가 될 것인가가 알고리즘 성능을 좌우한다.</p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/10f1781b-bb42-4f36-8574-491d1d93c309/image.png" alt=""></p>
<ul>
<li><p>깊이(depth)가 깊어질 수록 예측 성능이 저하될 가능성이 커진다.</p>
<ul>
<li>많은 규칙 존재 → 분류를 결정하는 방식이 복잡해진 것 → 과적합될 가능성 높음</li>
</ul>
</li>
<li><p>데이터를 분류할 때 최대한 많은 데이터가 해당 분류에 속할 수 있도록 결정 노드의 규칙이 정해져야 한다. 
(최대한 균일한 데이터세트를 구성할 수 있도록 분할 필요)</p>
</li>
<li><p>결정 노드는 정보 균일도가 높은 데이터 세트를 먼저 선택할 수 있도록 규칙 조건을 만듦</p>
</li>
<li><p>정보 균일도를 측정하는 방법</p>
<ol>
<li><p>정보이득 Information Gain</p>
<ul>
<li>엔트로피 기반 : 주어진 데이터 집합의 혼잡도. 서로 다른 값이 섞여있으면 엔트로피 값 증가</li>
<li>정보이득 지수 = 1 - 엔트로피 지수</li>
<li>결정트리는 정보이득 지수로 분할. 즉, 정보이득이 높은 속성을 기준으로 분할</li>
<li>$정보이득 = 부모의 불순도 - (\frac{왼쪽 노드 샘플수}{부모의 샘플수} * 왼쪽 노드 불순도)  -  (\frac{오른쪽 노드 샘플수}{부모의 샘플수} * 오른쪽 노드 불순도)$</li>
</ul>
</li>
<li><p>지니계수</p>
<ul>
<li><p>0이 가장 평등하고 1로 갈수록 불평등</p>
</li>
<li><p>지니계수가 낮을수록 데이터터 균일도가 높은 것으로 해석. 지니계수가 낮은 속성을 기준으로 분할</p>
<ul>
<li>그러면 정보이득 지수 같은 지표를 만들자면 = 1 - 지니계수 (?)</li>
</ul>
</li>
<li><p>$지니불순도 = 1 - 음성클래스비율^2 + 음성클래스비율^2$</p>
</li>
<li><p>사이킷런 DecisionTreeClassifier은 기본으로 지니계수를 이용해 데이터 분할</p>
<pre><code class="language-python">  from sklearn.tree import DecisionTreeClassifier</code></pre>
</li>
</ul>
</li>
</ol>
</li>
</ul>
<h2 id="결정-트리-모델의-특징">결정 트리 모델의 특징</h2>
<ul>
<li>장점 : 정보의 ‘균일도’ 라는 룰을 기반으로 하고 있어 알고리즘이 직관적, 균일도만 신경쓰면 되므로 각 피처의 스케일링과 정규화 같은전처리 작업이 (일반적인 경우) 필요 없음</li>
<li>단점 : 과적합으로 (테스트) 정확도가 떨어짐 (트리가 계속 깊어질수록)<ul>
<li>(학습) 모델의 정확도를 높이기 위해 계속 조건을 추가하며 트리 깊이가 깊어지면, 테스트 정확도가 떨어질 것임</li>
<li>오히려 완벽한 규칙을 만들 수 없다고 먼저 인정하고, 트리의 크기를 사전에 제한하는 것이 오히려 성능 튜닝에 더 도움이 될 것</li>
</ul>
</li>
</ul>
<h2 id="결정-트리의-파라미터">결정 트리의 파라미터</h2>
<ul>
<li>사이킷런 결정 트리 = DesicionTreeClassifier (for 분류) , DisicionTreeRegressor (for 회귀)<ul>
<li>결정 트리 구현은 CART ( Classfication And Regression Trees ) 알고리즘 기반 ⇒ 분류뿐 아니라 회귀에서도 사용될 수 있음</li>
<li>하위의 파라미터는 동일함</li>
</ul>
</li>
<li><code>min_samples_split</code><ul>
<li>노드를 분할하기 위한 최소한의 샘플 데이터 수</li>
<li>디폴트 = 2</li>
<li>작게 설정할 수록 분할되는 노드가 많아진다. (과적합 가능성 증가)</li>
</ul>
</li>
<li><code>min_samples_leaf</code><ul>
<li>말단 노드(leaf)가 되기 위한 최소한의 샘플 데이터 수</li>
<li>비대칭적 데이터의 경우 특정 클래스의 데이터가 극도로 작을 수 있으므로 이 경우는 작게 설정 필요</li>
</ul>
</li>
<li><code>max_features</code><ul>
<li>최적의 분할을 위해 고려할 최대 피처 개수</li>
<li>디폴트 = None : 전체 피처 선정</li>
<li>int 형으로 지정 : 대상 피처의 개수</li>
<li>float 형으로 지정: 전체 피처 중 대상 피처의 퍼센트</li>
<li>‘sqrt’ :  $\sqrt{전체피처 개수}$ 만큼 선정 (=’auto’)</li>
<li>‘log’ :  $log_2(전체 피처개수)$ 만큼 선정</li>
<li>‘None’ : 전체 피처 선정</li>
</ul>
</li>
<li><code>max_depth</code><ul>
<li>트리의 최대 깊이 규정</li>
<li>디폴트 = None : 완벽하게 클래스 결정 값이 될 때까지 깊이를 계속 키우며 분할하거나, 노드가 가지는 데이터 갯수가 min_samples_split보다 작아질 대까지 계속 깊이를 증가시킴</li>
<li>깊이가 깊어지면 min_samples_split 설정대로 초대분할하여 과적합할 수 있으므로 적절한 값으로 제어 필요</li>
</ul>
</li>
<li><code>max_leaf_nodes</code><ul>
<li>말단 노드의 최대 개수</li>
</ul>
</li>
</ul>
<h2 id="결정-트리-모델의-시각화">결정 트리 모델의 시각화</h2>
<pre><code class="language-python">from sklearn.tree import export_graphviz

export_graphviz(estimator, out_file=&#39;파일명&#39;, class_names=클래스 명칭,
                                feature_names=피처명칭, impurity=True, filled=True)</code></pre>
<pre><code class="language-python"># 위에서 생성한 파일을 graphviz가 읽어서 주피터 노트북 상에서 시각화
import graphviz

with open (&#39;파일명&#39;) as f: dot_graph = f.read()</code></pre>
<pre><code class="language-python">graphviz.Source(dot_graph)</code></pre>
<ul>
<li><p>시각화 결과의 구성들 :</p>
<ul>
<li>조건 : 피처 조건이 있는 것은 자식 노드를 만들기 위한 조건 규칙, 이게 없으면 리프 노드</li>
<li>gini(지니계수) : value=[ ] 로 주어진 데이터 분포에서의 지니 계수</li>
<li>samples : 현 규칙에 해당하는(적용되는) 데이터 건수</li>
<li>value=[ ] : 클래스 값 기반의 데이터 건수</li>
<li>색상 : 레이블 값, 선명도가 높을 수록 지니계수 낮음</li>
</ul>
</li>
<li><p><code>feautre_importance_ 속성</code>: ndarray로 반환, 피처 순서대로 값 할당, 값이 높을 수록 중요도 높음 : <code>estimator.feature_importance_</code></p>
<pre><code class="language-python">  import seaborn as sns
  import numpy as np
  %matplotlib inline

  # feature importance 추출 
  print(&quot;Feature importances:\n{0}&quot;.format(np.round(dt_clf.feature_importances_, 3)))

  # feature별 importance 매핑
  for name, value in zip(iris_data.feature_names , dt_clf.feature_importances_):
      print(&#39;{0} : {1:.3f}&#39;.format(name, value))

  # feature importance를 column 별로 시각화 하기 
  sns.barplot(x=dt_clf.feature_importances_ , y=iris_data.feature_names)</code></pre>
</li>
</ul>
<ul>
<li><p>make_classification(): 분류를 위한 테스트용 데이터를 쉽게 만들 수 있다.</p>
<pre><code class="language-python">  from sklearn.datasets import make_classification
  import matplotlib.pyplot as plt
  %matplotlib inline

  plt.title(&quot;3 Class values with 2 Features Sample data creation&quot;)

  # 2차원 시각화를 위해서 feature는 2개, 결정값 클래스는 3가지 유형의 classification 샘플 데이터 생성. 
  X_features, y_labels = make_classification(n_features=2, n_redundant=0, n_informative=2,
                               n_classes=3, n_clusters_per_class=1,random_state=0)

  # plot 형태로 2개의 feature로 2차원 좌표 시각화, 각 클래스값은 다른 색깔로 표시됨. 
  plt.scatter(X_features[:, 0], X_features[:, 1], marker=&#39;o&#39;, c=y_labels, s=25, cmap=&#39;rainbow&#39;, edgecolor=&#39;k&#39;)</code></pre>
</li>
<li><p>반환되는 객체: 피처 데이터 세트, 클래스 레이블 데이터 세트</p>
</li>
<li><p>예시: 피처 2개, 클래스 3가지 유형의 분류 샘플 데이터 생성</p>
<pre><code class="language-python">  X_features, y_labels = make_classification(n_features=2, n_redundant=0, n_informative=2, n_classes=3, n_clusters_per_class=1, random_state=0)</code></pre>
</li>
</ul>
<ul>
<li>visualize_boundary(): 머신러닝 모델이 만든 결정 기준을 색상과 경계로 나타낸다.</li>
</ul>
<pre><code class="language-python">visualize_boundary(estimator, X_features, y_labels)</code></pre>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 4. Evaluation]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-4.-Evaluation</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-4.-Evaluation</guid>
            <pubDate>Wed, 28 Sep 2022 03:15:40 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/mios_leo/post/98a29c49-4e99-4131-812b-92e310bdc896/image.jpeg" alt=""></p>
<h1 id="evaluation-평가--in-분류">Evaluation 평가 ( in 분류)</h1>
<h1 id="1-평가-지표">1. 평가 지표</h1>
<h2 id="1-정확도-accuracy">1. 정확도 Accuracy</h2>
<ul>
<li>실제 데이터에서 예측 데이터가 얼마나 같은지 판단하는 지표</li>
</ul>
<ul>
<li>특히 정확도는 불균형한 레이블 값 분포에서는, 적합한 평가 지표가 아님</li>
<li>ex) MNIST 데이터 셋을 다중분류에서 이진분류로 바꾸면 (7을 True, 나머지를 False) ⇒ 0과 1중 0을 찍으면 90%의 정확도가 나오게 됌</li>
<li></li>
</ul>
<p>$$
정확도(Accuracy) = \frac{TN+TP}{TN+FP+FN+TP} 
$$</p>
<h2 id="2-오차-행렬-confusion-matrix">2. 오차 행렬 Confusion Matrix</h2>
<ul>
<li>T/F : ‘같은가 틀린가&#39;  &amp;  N/P :  $\widehat{y}$ 이 ‘neg 0 인가 pos 1 인가’</li>
</ul>
<pre><code>|  |    $$\hat{y}$$ = 0 |    $$\hat{y}$$ = 1 |
| --- | --- | --- |
|    y = 0 |    TN |    FP |
|    y = 1 |    FN |    TP |</code></pre><pre><code class="language-python">from sklearn.metrics import confusion_matirx</code></pre>
<ul>
<li>불균형한 이진분류 데이터 세트에서는 positive 데이터 건수가 작아, negative로 예측 정확도가 높아지는 경향이 발생한다.<ul>
<li>보통 사기 행위나 암 검진 예측 이진분류 등에서는, Positive 데이터 건수가 작게 됨
⇒ TN는 매우 커지고, TP, FN, FP 모두 낮아지게 됨 (그냥 neg로 예측하면 정확도 자체가 올라가므로)</li>
</ul>
</li>
</ul>
<h2 id="3-정밀도와-재현율">3. 정밀도와 재현율</h2>
<h3 id="31-정밀도-precision">3.1. 정밀도 Precision</h3>
<p>$$
\frac{TP}{FP+TP} = \frac{실제 양성}{ 실제 음성(잘못판단)+실제양성}
$$</p>
<ul>
<li>양성으로 예측한 값 중에서 실제 양성인 값<ul>
<li><em>“P야!” 라고 말한 것들 중에, &lt;실제 P&gt;이 있는 확률</em></li>
</ul>
</li>
<li>[실제 음성인 데이터 예측을 양성으로 잘못 판단하면 안되는 경우]에 [정밀도]가 중요하다.<ul>
<li>스팸 메일 판단 모델 ⇒ FN 오류의 댓가는 불편한 정도, FP 경우 업무의 차질이 생김</li>
</ul>
</li>
<li>precision_score()</li>
</ul>
<h3 id="32-재현율-recall--민감도-sensitivity--tpr-true-positive-rate">3.2. <strong>재현율 Recall == 민감도 Sensitivity == TPR True Positive Rate</strong></h3>
<p>$$
\frac{TP}{FN+TP} = \frac{실제 양성}{실제 양성(잘못 판단)+실제 양성}
$$</p>
<ul>
<li>실제 양성인 대상 중에 양성으로 예측한 값<ul>
<li>*&lt;실제 P들&gt; 중에 “P야!” 라고 말한 게 있는 확률*</li>
</ul>
</li>
<li>[실제 양성인 데이터 예측을 음성으로 잘못 판단하면 안되는 경우]에 [재현율]이 중요하다.<ul>
<li>암 판단 모델 ⇒ FN 오류의 댓가가 생명이기에, 양성을 음성으로 잘못 판단하면 안되는 경우 ↔ FP 경우, 재검사를 하는 수준의 비용</li>
<li>금융 사기 모델 ⇒ FN 오류의 댓가가 어마어마한 금액 ↔ FP 경우, 사기인지 재확인 하는 수준의 비용</li>
<li>통상적으로도, 정밀도보다는 재현율이 더 중요한 업무가 많긴 함</li>
</ul>
</li>
<li>recall_score()</li>
</ul>
<blockquote>
<p><em>정밀도와 재현율 모두 TP를 높이는데 동일하게 촛점을 맞추지만,
정밀도는 FP를 낮추는데 촛점을 맞추고
재현율을 FN을 낮추는데 촛점을 맞춘다.
그러므로 서로 보완적인 지표로 분류의 성능을 평가하는데 도움이 되며,
가장 좋은 성능 평가는 재현율과 정밀도 모두 높은 수치를 얻는 것이며,
어느 한 평가 지표만 매우 높고 반대는 매우 낮은 경우는 바람직하지 않음</em></p>
</blockquote>
<h3 id="33-정밀도재현율-트레이드-오프-trade-off">3.3. <strong>정밀도/재현율 트레이드 오프 trade-off</strong></h3>
<ul>
<li><p>정밀도와 재현율은 상호보완적 지표이다.</p>
</li>
<li><p><code>predict_proba()</code>: 개별 데이터별로 예측 확률을 반환하는 메서드</p>
<ul>
<li><code>predict()</code> 가 위 메서드를 참고, 정제하여 보여주는 개념이라 생각하면 편함</li>
</ul>
</li>
<li><p><code>predict()</code>의 의사(pseudo) 코드 만들기</p>
<pre><code class="language-python">  from sklearn.preprocessing import Binarizer

  #Binarizer의 threshold 설정값. 분류 결정 임곗값임.  
  custom_threshold = 0.5

  # predict_proba( ) 반환값의 두번째 컬럼 , 즉 Positive 클래스 컬럼 하나만 추출하여 Binarizer를 적용
  pred_proba_1 = pred_proba[:,1].reshape(-1,1)

  binarizer = Binarizer(threshold=custom_threshold).fit(pred_proba_1) 
  custom_predict = binarizer.transform(pred_proba_1)

  get_clf_eval(y_test, custom_predict)</code></pre>
<ul>
<li>임곗값 threshold 보다 같거나 작으면 0을, 크면 1로 변환하고 반환한다.<ul>
<li>분류 결정 임곗값은 양성 예측값을 결정하는 확률의 기준이 된다.<ul>
<li>임곗값이 낮을 수록 True값이 많아진다. (양성증가)</li>
<li>양성 예측값이 많아지면 상대적으로 재현율이 높아진다. 정밀도는 떨어진다.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p>threshold 임곗값에 따른 재현률/정밀도 변화</p>
</li>
<li><p><code>precision_recall_curve()</code> : 임곗값 변화에 따른 정밀도와 재현율 값 나타내주는 API</p>
<ul>
<li><p>입력 파라미터</p>
<ul>
<li>y_true : 실제 클래스값 배열 (배열 크기 = [데이터 건수])</li>
<li>probas_pred : pos 칼럼의 예측 확률 배열 (배열 크기 = [데이터 건수])</li>
</ul>
</li>
<li><p>반환 값</p>
<ul>
<li>정밀도 : 임곗값별 정밀도 값을 ndarray로 반환</li>
<li>재현율 : 임곗값별 재현율 값을 ndarray로 반환</li>
<li>임곗값 : 일반적으로 0.11~0.95 정도의 임곗값들을 ndarray로 반환</li>
</ul>
<pre><code class="language-python">from sklearn.metrics import precision_recall_curve

precision, recalls, threshold = precision_recall_curve(y_test, \
                                                              *X_test의 predict_proba() 의 양성 예측 확률 배열* ) *# == [:,1]*</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="4-f1-score">4. F1 Score</h2>
<ul>
<li>정밀도와 재현율을 결합한 지표. 정밀도와 재현율이 어느 쪽으로 치우치지 않을 때 상대적으로 높은 값을 가짐</li>
</ul>
<p>$$
F1 = 2<em>\frac{prcision</em>recall}{precision+recall}
$$</p>
<pre><code class="language-python">from sklearn.metrics import f1_score</code></pre>
<h2 id="5-roc-곡선과-auc">5. ROC 곡선과 AUC</h2>
<p>: 머신러닝 이진분류 모델의 예측 성능을 판단하는 중요한 평가지표</p>
<ul>
<li><p>ROC 곡선: FPR(False Positive Rate)이 변할 때 [X축], TPR(True Positive Rate)이 변하는지 [Y축] 나타내는 곡선</p>
<ul>
<li><p>TPR (재현율) = TP/(FN+TP) = 실제 양성이 정확히 예측되어야 하는 수준(민감도)</p>
<ul>
<li>질병이 있는 사람은 질병이 있는 것으로 양성 판정</li>
</ul>
<p>$$
TPR(재현율, 민감도) = \frac{TP}{FN+TP}
$$</p>
</li>
<li><p>TNR (특이성) = TN/(FP+TN) = 실제 음성이 정확히 예측되어야 하는 수준 (특이성 ↔ 민감도에 대응하는 지표)</p>
<ul>
<li><p>질병이 없는 사람은 질병이 없는 것으로 음성 판정</p>
<p>$$
TNR(특이성) = \frac{TN}{FP+TN}
$$</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>ROC 곡선의 X축 기준인 FRP = FP/(FN+TP) = 1 - TNR (pos 틀린 비율?)</p>
</li>
</ul>
<p>$$
FPR = \frac{FP}{FP+TN} = 1-TNR(특이성) = 1 - \frac{TN}{FP+TN}
$$</p>
<ul>
<li><p>ROC 곡선이 중앙 직선에 가까울수록 성능이 떨어지는 것이며, 멀어질수록 성능이 뛰어난 것</p>
<ul>
<li>ROC 곡선은 FPR을 0부터 1까지 변경하면서 TPR의 변화 값을 구함 [HOW?] ⇒ 분류 결정 임곗값(thresholds)을 변경하면 됨</li>
<li>thresholds는 Positive 예측값을 결정하는 확률이기에, FPR을 0으로 만들려면 임곗값을 1로 지정하면 됨</li>
</ul>
</li>
<li><p><code>roc_curve()</code></p>
<ul>
<li>입력 파라미터<ul>
<li>y_true : 실제 클래스 값 array ( array shape = [데이터 건수] )</li>
<li>y_score : <code>predict_proba()</code>의 반환 값 array에서 Positive 칼럼의 예측 확률이 보통 사용 됨 (array shape = [n_samples] )</li>
</ul>
</li>
<li>반환 값<ul>
<li>FPR : FPR 값을 array로 반환</li>
<li>TPR : TPR 값을 array로 반환</li>
<li>Thresholds : Thresholds 값 array</li>
</ul>
</li>
</ul>
</li>
<li><p>AUC (Area Under Curve) : ROC 곡선 밑의면적을 구한 것으로, 일반적으로 1에 가까울 수록 좋은 수치</p>
<ul>
<li><p>AUC 수치가 커지려면, FPR이 작은 상태에서 알마나 큰 TPR을 얻을 수 있느냐가 관건</p>
<pre><code class="language-python">  from sklearn.metrics import roc_auc_score

  ### roc_auc_score(y_test, y_score)로 y_score는 predict_proba()로 호출된 예측 확률
  ### ndarray중 Positive 열에 해당하는 ndarray입니다. 

  pred_proba = lr_clf.predict_proba(X_test)[:, 1]
  roc_score = roc_auc_score(y_test, pred_proba)
  print(&#39;ROC AUC 값: {0:.4f}&#39;.format(roc_score))</code></pre>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 3. Scikit-Learn]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-3.-Scikit-Learn</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-3.-Scikit-Learn</guid>
            <pubDate>Wed, 28 Sep 2022 03:05:16 GMT</pubDate>
            <description><![CDATA[<h1 id="scikit-learn-사이킷런">Scikit-Learn 사이킷런</h1>
<hr>
<h1 id="1-estimator">1. Estimator</h1>
<ol>
<li><p>Classifier 분류</p>
<p> : DecisionTreeClassifier, RandomForestClassifier, GradientBoostingClassifier, GaussianNB, SVC</p>
</li>
<li><p>Regressor 회귀</p>
<p> : LinearRegression, Ridge, Lasso, RandomForestRegressor, GradientBoostingRegressor</p>
</li>
<li><p>비지도학습/피처추출(전처리) 에서의 fit(), transform()
: fit()이 학습이 아니라, 입력 데이터 형태에 맞춰 데이터를 변환하기 위한 사전 구조를 맞추는 작업
: transform()은 fit으로 변환된 사전 구조를 가지고 차원변환/클러스터링/피처추출 등을 하는 작업</p>
</li>
</ol>
<h1 id="2-module">2. Module</h1>
<ul>
<li><p>sklearn.model_selection 의 
<code>train_test_split(features, labels, test_size)</code></p>
</li>
<li><p>교차 검증: 데이터 편중을 막기 위해 별도의 여러 세트로 구성된 학습 데이터 세트와 검증 데이터 세트에서 학습, 평가를 수행하는 것</p>
<ul>
<li><p>KFold : K개의 데이터 폴드 세트를 만들어서, K번만큼 각 폴드 세트에 학습과 검증 평가를 반복적으로 수행하는 방법</p>
<ul>
<li><code>KFold(n_splits = 폴드 개수)</code></li>
<li><code>split()</code>: 학습용/검증용 데이터로 분할할 수 있는, 각각의 인덱스를 반환</li>
</ul>
<ol>
<li>객체 생성</li>
<li>인덱스 얻기</li>
<li>인덱스 활용해 데이터 추출</li>
<li>학습</li>
<li>예측</li>
<li>정확도 측정</li>
<li>평균 정확도</li>
</ol>
<ul>
<li><p>Kfold 사용 예시 코드</p>
<pre><code class="language-python">  kfold = KFold(n_splits=5)
  cv_accuracy = []

  n_iter = 0

  # KFold객체의 split( ) 호출하면 폴드 별 학습용, 검증용 테스트의 로우 인덱스를 array로 반환  
  for train_index, test_index  in kfold.split(features):
      # kfold.split( )으로 반환된 인덱스를 이용하여 학습용, 검증용 테스트 데이터 추출
      X_train, X_test = features[train_index], features[test_index]
      y_train, y_test = label[train_index], label[test_index]
      #학습 및 예측 
      dt_clf.fit(X_train , y_train)    
      pred = dt_clf.predict(X_test)
      n_iter += 1
      # 반복 시 마다 정확도 측정 
      accuracy = np.round(accuracy_score(y_test,pred), 4)
      train_size = X_train.shape[0]
      test_size = X_test.shape[0]
      print(&#39;\n#{0} 교차 검증 정확도 :{1}, 학습 데이터 크기: {2}, 검증 데이터 크기: {3}&#39;
            .format(n_iter, accuracy, train_size, test_size))
      print(&#39;#{0} 검증 세트 인덱스:{1}&#39;.format(n_iter,test_index))
      cv_accuracy.append(accuracy)

  # 개별 iteration별 정확도를 합하여 평균 정확도 계산 
  print(&#39;\n## 평균 검증 정확도:&#39;, np.mean(cv_accuracy))</code></pre>
</li>
<li><p>Kfold 사용 예시 코드 결과</p>
<blockquote>
<p>#1 교차 검증 정확도 :1.0, 학습 데이터 크기: 120, 검증 데이터 크기: 30
  #1 검증 세트 인덱스:[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29]</p>
</blockquote>
<p>  #2 교차 검증 정확도 :0.9667, 학습 데이터 크기: 120, 검증 데이터 크기: 30
  #2 검증 세트 인덱스:[30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59]</p>
<p>  #3 교차 검증 정확도 :0.8667, 학습 데이터 크기: 120, 검증 데이터 크기: 30
  #3 검증 세트 인덱스:[60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89]</p>
<p>  #4 교차 검증 정확도 :0.9333, 학습 데이터 크기: 120, 검증 데이터 크기: 30
  #4 검증 세트 인덱스:[ 90  91  92  93  94  95  96  97  98  99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119]</p>
<p>  #5 교차 검증 정확도 :0.7333, 학습 데이터 크기: 120, 검증 데이터 크기: 30
  #5 검증 세트 인덱스:[120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149]</p>
<h2 id="평균-검증-정확도-09">평균 검증 정확도: 0.9</h2>
<blockquote>
</blockquote>
</li>
</ul>
</li>
<li><p>Stratified KFold : 레이블 데이터 분포도에 따라 학습/검증 데이터를 나눔
⇒ 회귀에서는 연속형 데이터라 (not 이산형) Stratify가 의미가 없음</p>
<ul>
<li><p><code>split(features, labels)</code>: split에 피처, 레이블 데이터 모두를 입력해야 한다.</p>
</li>
<li><p>Stratified Kfold 사용 예시 코드</p>
<pre><code class="language-python">  iris = load_iris()
  features = iris.data
  label = iris.target

  dt_clf = DecisionTreeClassifier(random_state=156)

  skfold = StratifiedKFold(n_splits=3)
  n_iter=0
  cv_accuracy=[]

  # StratifiedKFold의 split( ) 호출시 반드시 레이블 데이터 셋도 추가 입력 필요  
  for train_index, test_index  in skfold.split(features, label):
      # split( )으로 반환된 인덱스를 이용하여 학습용, 검증용 테스트 데이터 추출
      X_train, X_test = features[train_index], features[test_index]
      y_train, y_test = label[train_index], label[test_index]
      #학습 및 예측 
      dt_clf.fit(X_train , y_train)    
      pred = dt_clf.predict(X_test)

      # 반복 시 마다 정확도 측정 
      n_iter += 1
      accuracy = np.round(accuracy_score(y_test,pred), 4)
      train_size = X_train.shape[0]
      test_size = X_test.shape[0]
      print(&#39;\n#{0} 교차 검증 정확도 :{1}, 학습 데이터 크기: {2}, 검증 데이터 크기: {3}&#39;
            .format(n_iter, accuracy, train_size, test_size))
      print(&#39;#{0} 검증 세트 인덱스:{1}&#39;.format(n_iter,test_index))
      cv_accuracy.append(accuracy)

  # 교차 검증별 정확도 및 평균 정확도 계산 
  print(&#39;\n## 교차 검증별 정확도:&#39;, np.round(cv_accuracy, 4))
  print(&#39;## 평균 검증 정확도:&#39;, np.mean(cv_accuracy))</code></pre>
</li>
<li><p>Stratified Kfold 사용 예시 코드 결과</p>
<blockquote>
<p>#1 교차 검증 정확도 :0.98, 학습 데이터 크기: 100, 검증 데이터 크기: 50
  #1 검증 세트 인덱스:[  0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  50
  51  52  53  54  55  56  57  58  59  60  61  62  63  64  65  66 100 101
  102 103 104 105 106 107 108 109 110 111 112 113 114 115]</p>
</blockquote>
<p>  #2 교차 검증 정확도 :0.94, 학습 데이터 크기: 100, 검증 데이터 크기: 50
  #2 검증 세트 인덱스:[ 17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  67
  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82 116 117 118
  119 120 121 122 123 124 125 126 127 128 129 130 131 132]</p>
<p>  #3 교차 검증 정확도 :0.98, 학습 데이터 크기: 100, 검증 데이터 크기: 50
  #3 검증 세트 인덱스:[ 34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  83  84
  85  86  87  88  89  90  91  92  93  94  95  96  97  98  99 133 134 135
  136 137 138 139 140 141 142 143 144 145 146 147 148 149]</p>
<h2 id="교차-검증별-정확도-098-094-098">교차 검증별 정확도: [0.98 0.94 0.98]</h2>
<h2 id="평균-검증-정확도-09666666666666667">평균 검증 정확도: 0.9666666666666667</h2>
<blockquote>
</blockquote>
</li>
</ul>
</li>
<li><p><code>cross_val_score(estimator, feartures, labels, scoring=단일_예측성능_평가지표, cv=교차검증_폴드수)</code> : 교차 검증 편하게 used Stratified KFold</p>
</li>
<li><p><code>cross_validation(estimator, feartures, labels, scoring=[복수_예측성능_평가지표], cv=교차검증_폴드수)</code>: 여러 개의 평가지표를 반환</p>
</li>
</ul>
</li>
<li><p><code>GridSearchCV(estimator, param_grid=파라미터 값 딕셔너리, scoring=평가지표, cv=분할되는 학습/테스트 세트 개수, refit=True)</code> : 교차 검증 + 최적 파라미터 튜닝을 한 번에</p>
<ul>
<li><p><code>refit</code> : 최적 하이퍼 파라미터로 재학습한다. ⇒ default가 True임</p>
</li>
<li><p>cf) 평가지표들</p>
<pre><code class="language-python">  from sklearn.metrics import SCORERS
  SCORERS.keys()</code></pre>
</li>
<li><p>GridSearchCV 사용 예시 코드</p>
<pre><code class="language-python">
  dtree = DecisionTreeClassifier()

  # parameter 들을 dictionary 형태로 설정
  parameters = {&#39;max_depth&#39;:[1,2,3], &#39;min_samples_split&#39;:[2,3]}

  grid_dtree = GridSearchCV(dtree, param_grid=parameters, scoring=&#39;accuracy&#39; , cv=3, refit=True)
  # 이렇게 multi-metric 줄 수도 있음 =&gt; refit을 어떤 metric으로 할지 설정해줘야함
  grid_dtree = GridSearchCV(dtree, param_grid=parameters, scoring=[&#39;accuracy&#39;, &#39;r2&#39;] , cv=3, refit=&#39;accuracy&#39;)

  # 붓꽃 Train 데이터로 param_grid의 하이퍼 파라미터들을 순차적으로 학습/평가 .
  grid_dtree.fit(X_train, y_train)

  # GridSearchCV 결과 추출하여 DataFrame으로 변환
  scores_df = pd.DataFrame(grid_dtree.cv_results_)
  scores_df[[&#39;params&#39;, &#39;mean_test_score&#39;, &#39;rank_test_score&#39;, \
             &#39;split0_test_score&#39;, &#39;split1_test_score&#39;, &#39;split2_test_score&#39;]]

  print(&#39;GridSearchCV 최적 파라미터:&#39;, grid_dtree.best_params_)
  print(&#39;GridSearchCV 최고 정확도: {0:.4f}&#39;.format(grid_dtree.best_score_))

  # GridSearchCV의 refit으로 이미 학습이 된 estimator 반환
  estimator = grid_dtree.best_estimator_

  # GridSearchCV의 best_estimator_는 이미 최적 하이퍼 파라미터로 학습이 됨
  pred = estimator.predict(X_test)
  print(&#39;테스트 데이터 세트 정확도: {0:.4f}&#39;.format(accuracy_score(y_test,pred)))</code></pre>
</li>
</ul>
</li>
</ul>
<h1 id="3-데이터-전처리">3. 데이터 전처리</h1>
<p>: 사이킷런 머신러닝에서 문자열과 NaN은, 입력값이 될 수 없다 → 숫자형이어야만 함 → 인코딩이 필수적</p>
<h3 id="31레이블-인코딩-label-encoding--카테고리-피처를-코드형-숫자값으로-변환">3.1.레이블 인코딩 (Label encoding) : 카테고리 피처를 코드형 숫자값으로 변환</h3>
<ul>
<li><p><code>LabelEncoder()</code> : 객체생성 → <code>fit_transform()</code>  ← <code>inverse_transform()</code> : 디코딩</p>
</li>
<li><p>레이블 인코딩 과정</p>
<pre><code class="language-python">  from sklearn.preprocessing import LabelEncoder

  items=[&#39;TV&#39;,&#39;냉장고&#39;,&#39;전자렌지&#39;,&#39;컴퓨터&#39;,&#39;선풍기&#39;,&#39;선풍기&#39;,&#39;믹서&#39;,&#39;믹서&#39;]

  # LabelEncoder를 객체로 생성한 후 , fit( ) 과 transform( ) 으로 label 인코딩 수행. 
  encoder = LabelEncoder()
  encoder.fit(items)
  labels = encoder.transform(items)

  print(&#39;인코딩 변환값:&#39;,labels)
  print(&#39;인코딩 클래스:&#39;,encoder.classes_)
  print(&#39;디코딩 원본 값:&#39;,encoder.inverse_transform([4, 5, 2, 0, 1, 1, 3, 3]))</code></pre>
<blockquote>
<p>인코딩 변환값: [0 1 4 5 3 3 2 2]
  인코딩 클래스: [&#39;TV&#39; &#39;냉장고&#39; &#39;믹서&#39; &#39;선풍기&#39; &#39;전자렌지&#39; &#39;컴퓨터&#39;]
  디코딩 원본 값: [&#39;전자렌지&#39; &#39;컴퓨터&#39; &#39;믹서&#39; &#39;TV&#39; &#39;냉장고&#39; &#39;냉장고&#39; &#39;선풍기&#39; &#39;선풍기&#39;]</p>
</blockquote>
</li>
<li><p><code>inverse_transform()</code>: 디코딩</p>
</li>
<li><p>Label Encoding은 숫자의 크기에 따라 순서나, 중요도 등의 가중치로 반영될 수 있으므로, 선형회귀와 같은 ML 알고리즘에는 적용되지 않아야 함</p>
</li>
<li><p>트리 계열의 ML 알고리즘은 숫자의 이러한 특성을 반영하지 않으므로, 레이블 인코딩도 별 문제가 없음</p>
</li>
</ul>
<h3 id="32-원-핫-인코딩-one-hot-encoding--피처-값의-유형에-따라-고유-값에-해당-칼럼만-1-표시--나머지는-0">3.2. 원-핫 인코딩 (One-Hot encoding) : 피처 값의 유형에 따라 고유 값에 해당 칼럼만 1 표시 / 나머지는 0</h3>
<ul>
<li><p>원-핫 인코더로 변환하기 전, 모든 문자열 값이 숫자형 값으로 변환 돼야 한다 (used by <code>LabelEncoder()</code>)</p>
<ul>
<li>== 원-핫 인코더의 input으로 숫자형이 와야한다</li>
</ul>
</li>
<li><p>입력값으로 2차원 데이터가 필요하다는 것 (used by <code>reshape(-1, 1)</code>)</p>
</li>
<li><p><code>LabelEncoder()</code> : 객체생성 → <code>fit_transform()</code> → <code>labels.reshape(-1, 1)</code> → <code>OneHotEncoder()</code> → <code>fit_transform()</code>← <code>inverse_transform()</code> : 디코딩</p>
</li>
<li><p>원-핫 인코딩 과정</p>
<pre><code class="language-python">  items=[&#39;TV&#39;,&#39;냉장고&#39;,&#39;전자렌지&#39;,&#39;컴퓨터&#39;,&#39;선풍기&#39;,&#39;선풍기&#39;,&#39;믹서&#39;,&#39;믹서&#39;]

  # 먼저 숫자값으로 변환을 위해 LabelEncoder로 변환합니다. 
  encoder = LabelEncoder()
  encoder.fit(items)
  labels = encoder.transform(items)

  # 2차원 데이터로 변환합니다. 
  labels = labels.reshape(-1,1)
  print(labels.transpose())

  # 원-핫 인코딩을 적용합니다. 
  oh_encoder = OneHotEncoder()
  oh_encoder.fit(labels)
  oh_labels = oh_encoder.transform(labels)

  print(&#39;원-핫 인코딩 데이터&#39;)
  print(oh_labels) # 1이 있는 좌표를 표시하는 matrix로 반환하는 구나
  print(type(oh_labels))
  print(oh_labels.toarray())

  print(&#39;원-핫 인코딩 데이터 차원&#39;)
  print(oh_labels.shape)</code></pre>
<blockquote>
<p>[[0 1 4 5 3 3 2 2]]</p>
<p>원-핫 인코딩 데이터
(0, 0)    1.0
(1, 1)    1.0
(2, 4)    1.0
(3, 5)    1.0
(4, 3)    1.0
(5, 3)    1.0
(6, 2)    1.0
(7, 2)    1.0
&lt;class &#39;scipy.sparse.csr.csr_matrix&#39;&gt;
[[1. 0. 0. 0. 0. 0.]
[0. 1. 0. 0. 0. 0.]
[0. 0. 0. 0. 1. 0.]
[0. 0. 0. 0. 0. 1.]
[0. 0. 0. 1. 0. 0.]
[0. 0. 0. 1. 0. 0.]
[0. 0. 1. 0. 0. 0.]
[0. 0. 1. 0. 0. 0.]]</p>
<p>원-핫 인코딩 데이터 차원
(8, 6)</p>
</blockquote>
<ul>
<li>원본 데이터 : <code>8개의 레코드와 1개의 칼럼</code>을 가진 원본 데이터 (index=각 상품명들, col=상품분류)가</li>
<li>원핫 인코딩으로 : <code>8개의 레코드와 6개의 칼럼</code>을 가진 데이터로 최종 변환</li>
</ul>
</li>
</ul>
<h3 id="33-판다스의-get_dummies-로-원-핫-인코딩-바로-하기">3.3. 판다스의 <code>get_dummies()</code> 로 원-핫 인코딩 바로 하기</h3>
<ul>
<li><p>사이킷런의 원핫인코더와 다르게, <code>문자열 카테고리 값을 숫자형으로 변환할 필요 없이</code> 바로 변환 가능</p>
<pre><code class="language-python">  import pandas as pd

  df = pd.DataFrame({&#39;item&#39;:[&#39;TV&#39;,&#39;냉장고&#39;,&#39;전자렌지&#39;,&#39;컴퓨터&#39;,&#39;선풍기&#39;,&#39;선풍기&#39;,&#39;믹서&#39;,&#39;믹서&#39;] })
  pd_oh = pd.get_dummies(df)
  print(type(pd_oh))
  pd_oh.astype(&#39;float64&#39;).values.tolist()</code></pre>
<blockquote>
<p>&lt;class &#39;pandas.core.frame.DataFrame&#39;&gt;
  [[1.0, 0.0, 0.0, 0.0, 0.0, 0.0],
  [0.0, 1.0, 0.0, 0.0, 0.0, 0.0],
  [0.0, 0.0, 0.0, 0.0, 1.0, 0.0],
  [0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
  [0.0, 0.0, 0.0, 1.0, 0.0, 0.0],
  [0.0, 0.0, 0.0, 1.0, 0.0, 0.0],
  [0.0, 0.0, 1.0, 0.0, 0.0, 0.0],
  [0.0, 0.0, 1.0, 0.0, 0.0, 0.0]]</p>
</blockquote>
</li>
</ul>
<h3 id="34-피처-스케일링과-정규화">3.4. 피처 스케일링과 정규화</h3>
<p>3.4.1. Standardization 표준화: 가우시안 정규분포로 변환 (평균 0, 분산 1)</p>
<ul>
<li><p>$x_i$_new $= \frac{x_i-mean(x)}{std(x)} = \frac{x-평균}{표준편차}$</p>
</li>
<li><p><code>StandarScaler()</code> 객체 생성 → <code>fit()</code> → <code>transform()</code></p>
<pre><code class="language-python">  from sklearn.preprocessing import StandardScaler

  # StandardScaler객체 생성
  scaler = StandardScaler()
  # StandardScaler 로 데이터 셋 변환. fit( ) 과 transform( ) 호출.  
  scaler.fit(iris_df)
  iris_scaled = scaler.transform(iris_df)

  #transform( )시 scale 변환된 데이터 셋이 numpy ndarry로 반환되어 이를 DataFrame으로 변환
  iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
  print(&#39;feature 들의 평균 값&#39;)
  print(iris_df_scaled.mean())
  print(&#39;\nfeature 들의 분산 값&#39;)
  print(iris_df_scaled.var())</code></pre>
<blockquote>
<p>feature 들의 평균 값
  sepal length (cm)   -1.690315e-15 # == 0에 수렴
  sepal width (cm)    -1.637024e-15
  petal length (cm)   -1.482518e-15
  petal width (cm)    -1.623146e-15
  dtype: float64</p>
<p>feature 들의 분산 값
sepal length (cm)    1.006711 == 1에 수렴
sepal width (cm)     1.006711
petal length (cm)    1.006711
petal width (cm)     1.006711
dtype: float64</p>
</blockquote>
</li>
</ul>
<p>3.4.2. Normalization 정규화: 피처 크기를 동일구간으로 변환 (0<del>1 사이값, 음수가 있으면 -1</del>1)</p>
<ul>
<li>$x_i$_new $= \frac{x_i-min(x)}{max(x)-min(x)} = \frac{x-최솟값}{최댓값-최솟값}$  : 일반적인 정규화 식</li>
</ul>
<p>$x_i$_new $= \frac{x_i}{\sqrt{x_i^2 + y_i^2 + z_i^2}}$ : 사이킷런 Normalizer 모듈의 정규화 식</p>
<ul>
<li><p><code>MinMaxScaler()</code> 객체 생성 → <code>fit()</code> → <code>transform()</code></p>
<pre><code class="language-python">  from sklearn.preprocessing import MinMaxScaler

  # MinMaxScaler객체 생성
  scaler = MinMaxScaler()
  # MinMaxScaler 로 데이터 셋 변환. fit() 과 transform() 호출.  
  scaler.fit(iris_df)
  iris_scaled = scaler.transform(iris_df)

  # transform()시 scale 변환된 데이터 셋이 numpy ndarry로 반환되어 이를 DataFrame으로 변환
  iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
  print(&#39;feature들의 최소 값&#39;)
  print(iris_df_scaled.min())
  print(&#39;\nfeature들의 최대 값&#39;)
  print(iris_df_scaled.max())</code></pre>
<blockquote>
<p>feature들의 최소 값
  sepal length (cm)    0.0
  sepal width (cm)     0.0
  petal length (cm)    0.0
  petal width (cm)     0.0
  dtype: float64</p>
<p>feature들의 최대 값
sepal length (cm)    1.0
sepal width (cm)     1.0
petal length (cm)    1.0
petal width (cm)     1.0
dtype: float64</p>
</blockquote>
</li>
<li><p>데이터의 분포가 가우시안이 아닐 경우에, MinMaxScaler를 적용해볼 수 있음</p>
</li>
</ul>
<pre><code>![](https://velog.velcdn.com/images/mios_leo/post/ca0052b0-e41e-426c-a35c-b353baf9bc7a/image.png)</code></pre><h1 id="4-정리">4. 정리</h1>
<ol>
<li>데이터 가공 및 변환(전처리)<ul>
<li>데이터 클렌징</li>
<li>인코딩</li>
<li>스케일링, 정규화</li>
</ul>
</li>
<li>데이터세트 분리<ul>
<li>교차검층 수행</li>
<li>KFold<ul>
<li>kfold = KFold(estimator,</li>
</ul>
</li>
<li>StratifiedKFold</li>
<li>cross_val_score<ul>
<li><code>cross_val_score(estimator, X_data, y_label, cv=n )</code><ul>
<li>최적의 하이퍼 파라미터를 위해 GridSearchCV</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>학습</li>
<li>예측</li>
<li>평가</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 2. Pandas]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-2.-Pandas</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-2.-Pandas</guid>
            <pubDate>Mon, 26 Sep 2022 02:46:41 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/mios_leo/post/5734f3bb-c891-47fb-970d-b59969a2e8c6/image.jpeg" alt=""></p>
<h1 id="🗂-pandas-판다스">🗂 Pandas 판다스</h1>
<h2 id="1-데이터-읽기-및-확인">1. 데이터 읽기 및 확인</h2>
<ul>
<li><code>read_csv() : ,</code>, <code>read_table() : \t</code>, <code>read_fwf() : 고정길이 파일</code></li>
<li><code>value_counts()</code>: 해당 칼럼 값의 유형과 건수 확인 (Series 객체에만 정의)</li>
<li><code>describe()</code>  : agg류 연산 보여줌</li>
</ul>
<h2 id="2-데이터-변환">2. 데이터 변환</h2>
<h3 id="21-list-ndarray-dictionary를-dataframe으로-변환하기">2.1. list, ndarray, dictionary를 DataFrame으로 변환하기</h3>
<ul>
<li>2차원 이하의 데이터들만 변환 가능</li>
<li>생성인자로 list, ndarray, dictionary 입력<ul>
<li>list, ndarray는 컬러명 지정해줘야 함 ⇒ 안해줘도 defalut로 만들어지긴 함</li>
</ul>
</li>
</ul>
<h3 id="22-dataframe-⇒-list-ndarray-dictionary-로-변환하기">2.2. DataFrame ⇒ list, ndarray, dictionary 로 변환하기</h3>
<ul>
<li>list 로 변환하기<ul>
<li><code>values()</code>로 얻은 ndarray에 또 다시 <code>tolist()</code> 호출</li>
<li>DataFrame → ndarray → list 과정</li>
</ul>
</li>
<li>ndarray로 변환하기<ul>
<li><code>values()</code></li>
<li>머신러닝 패키지의 입력인자로 적용하기 위해 다시 ndarray로 변환하는 경우 빈번</li>
</ul>
</li>
<li>dictionary 로 변환하기<ul>
<li>DataFrame 객체에 <code>to_dict()</code> 호출 ⇒ dict의 value 값이 또다시 idx:val인 이중 dict으로 나옴</li>
<li>to_dict(’list’)로 호출하면 ⇒ dict의 value 값이 리스트( <code>[]</code> )로 나옴</li>
</ul>
</li>
</ul>
<h2 id="3-데이터-수정-인덱싱-정렬-groupby">3. 데이터 수정, 인덱싱, 정렬, groupby()</h2>
<h3 id="31-데이터-삭제">3.1. 데이터 삭제</h3>
<ul>
<li><code>drop(&#39;삭제할 칼럼명&#39;, axis=0, inplace=False)</code><ul>
<li>삭제할 축 설정: axis=0은 row, axis=1은 column</li>
<li>inplace: False는 자기 자신의 데이터를 삭제하지 않고, 삭제된 결과를 반환. True는 자기 자신의 데이터를 삭제하고 None을 반환</li>
<li>axis = 0 으로 row drop : <code>df.drop([0,1,2], axis=0)</code></li>
</ul>
</li>
</ul>
<h3 id="32-index-객체">3.2 Index 객체</h3>
<ul>
<li><code>df.index</code>: index 추출<ul>
<li><code>print(type(indexes))
print(type(indexes.values))
print(indexes.values.shape)
print(indexes[:5].values)
print(indexes.values[:5])
print(indexes[6])</code></li>
<li><blockquote>
<blockquote>
<blockquote>
<p>&lt;class &#39;pandas.core.indexes.range.RangeIndex&#39;&gt;</p>
<pre><code>   &lt;class &#39;numpy.ndarray&#39;&gt;
    (891,)
    [0 1 2 3 4]
    [0 1 2 3 4]
    6*</code></pre></blockquote>
</blockquote>
</blockquote>
</li>
<li><code>indexes[0] = 5</code> : error ⇒ 한번 만들어진 Index 객체는 함부로 변경할 수 없음</li>
<li>Series 객체는 Index 객체를 포함하지만, 연산 함수를 적용할 때는 Index는 연산에서 제외되고, Index 객체는 오직 식별용으로만 사용 됨</li>
</ul>
</li>
<li><code>reset_index()</code><ul>
<li>새로운 연속 숫자형 인덱스 생성. 기존 인덱스는 index 칼럼명으로 추가됨</li>
<li>drop=True로 설정하면 기존 인덱스는 추가되지 않고 삭제됨</li>
<li>Series에 <code>rest_index()</code> 를 적용하면, Series가 아닌, DataFrame으로 반환됨 ⇒ 기존 인덱스가 칼럼으로 추가 되어, 칼럼이 2개가 됨<ul>
<li>drop=True로 하면 기존 인덱스 칼럼이 날아가서, Series로 반환 됨</li>
</ul>
</li>
<li><code>df.index = df.index+1</code> 으로 새로운 index값 생성해서, index 재할당이 가능</li>
</ul>
</li>
</ul>
<h3 id="33-데이터-셀렉션-및-필터링">3.3. 데이터 셀렉션 및 필터링</h3>
<p>3.3.1. <code>[ ]</code> 연산자 ⇒ 단일 컬럼 데이터 추출 : <code>df[&#39;col&#39;]</code>, 여러 컬럼 데이터 추출 : <code>df[[&#39;col_1&#39;, ‘col_2’]]</code></p>
<ul>
<li><input disabled="" type="checkbox"> 안에 숫자 index는 KeyError 오류 발생 ⇒ <code>df[0]</code></li>
<li>단, 숫자 index가 pandas default index 형태면 가능 ⇒ <code>df[0:2]</code></li>
</ul>
<p>3.3.2. <strong>column [명칭] 기반 인덱싱과 column [위치] 기반 인덱싱의 구분</strong></p>
<p>3.3.2.1. column [명칭] 기반 인덱싱  : <code>df.loc[시작점:종료점]</code> ⇒ 여기서 인덱싱 시작점과 종료점 모두 (-1 없이) 다 포함(명칭 기반이기에)</p>
<ul>
<li><code>loc[]</code>: 명칭 기반 인덱싱으로 행은 index값, 열은 column명 입력<ul>
<li><code>df.loc[&#39;one&#39;, &#39;Year&#39;]</code></li>
</ul>
</li>
<li><em>index*가 *pandas default index</em> 형태면 <em>df.loc[ ]에 숫자형을 줘도 됨</em><ul>
<li><code>df.loc[1, &#39;Year&#39;]</code></li>
<li>이때, index=0은 없음 ⇒ (0, 0)의 빈자리임</li>
</ul>
</li>
<li><code>loc[&#39;A&#39;:&#39;Z&#39;, &#39;Name&#39;]</code> : 명칭의 슬라이싱도 가능</li>
<li>궁극적으로 아래의 세 가지가 모두 가능 ⇒ index가 default여서 숫자가 가능한거고, 명칭으로도 가능<ul>
<li><code>df.loc[1:2, &#39;Name&#39; : &#39;Year&#39;]</code></li>
<li><code>df.loc[1:2, [&#39;Name&#39;, &#39;Year&#39;]]</code></li>
<li><code>df.loc[[1,2], [&#39;Name&#39;, &#39;Year&#39;]]</code></li>
</ul>
</li>
</ul>
<p>3.3.2.2. column [위치] 기반 인덱싱 : <code>df.iloc[행, 렬]</code> ⇒ 여기서는 일반적인 슬라이싱 처럼 (시작, 종료) ⇒ (시작, 종료-1)</p>
<ul>
<li><code>iloc[ 0, 1:3]</code> : 처럼 슬라이싱도 가능<ul>
<li><code>iloc[]</code>:  위치 기반 인덱싱으로 index, column 의 위치를 입력<ul>
<li><code>df.iloc[0,1]</code> 만약 <code>df.iloc[&#39;A&#39;, 0]</code> or <code>df.iloc[0, &#39;A&#39;]</code> 등 명칭을 입력하면 error</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>3.3.3. 불린 인덱싱 , 예시) (row조건) ‘Age’가 60 초과인 row에서, (컬럼) ‘Name’ 과 ‘Age’ 인덱싱</p>
<ul>
<li><code>titanic_df[titanic_df[’Age’] &gt; 60][[&#39;Name&#39;, &#39;Age&#39;]]</code> : “<em>인덱싱</em> ”  <code>df[조건(에맞는row)][칼럼명]</code></li>
<li><code>titanic_df.loc[titanic_df[&#39;Age&#39;] &gt; 60.0 , [&#39;Name&#39;,&#39;Age&#39;]]</code> : “<em>명칭 loc</em>“  <code>df.loc[조건(에 맞는row)[칼럼명]</code></li>
<li>불린 인덱싱 종류 ( and &amp; , or | , not ~ )<ul>
<li><code>titanic_df[ (titanic_df[&#39;Age&#39;] &gt; 60) &amp; (titanic_df[&#39;Pclass&#39;]==1) &amp; (titanic_df[&#39;Sex&#39;]==&#39;female&#39;) ]</code> : 불린으로 row 조건걸기<ul>
<li><code>titanic_df[ (titanic_df[&#39;Age&#39;] &gt; 60) &amp; (titanic_df[&#39;Pclass&#39;]==1) &amp; (titanic_df[&#39;Sex&#39;]==&#39;female&#39;) ] [&#39;Name&#39;]</code> : col 명 인덱싱</li>
</ul>
</li>
<li><code>titanic_df.loc[ (titanic_df[&#39;Age&#39;] &gt; 60) &amp; (titanic_df[&#39;Pclass&#39;]==1) &amp; (titanic_df[&#39;Sex&#39;]==&#39;female&#39;) ]</code> : loc로 row에 조건걸기<ul>
<li><code>titanic_df.loc[ (titanic_df[&#39;Age&#39;] &gt; 60) &amp; (titanic_df[&#39;Pclass&#39;]==1) &amp; (titanic_df[&#39;Sex&#39;]==&#39;female&#39;) ]</code> <code>[&#39;Name]</code> : col 명 인덱싱</li>
</ul>
</li>
<li>조건을 할당해서 적용할 수도 있음<ul>
<li><code>cond1 = titanic_df[&#39;Age&#39;] &gt; 60
cond2 = titanic_df[&#39;Pclass&#39;]==1
cond3 = titanic_df[&#39;Sex&#39;]==&#39;female&#39;
titanic_df[ cond1 &amp; cond2 &amp; cond3]</code></li>
</ul>
</li>
</ul>
</li>
<li><strong><em>자주 쓸 것을 요점정리 하자면</em></strong><ul>
<li><code>df.loc[조건 , [cols]]</code></li>
<li><code>df[조건][[cols]]</code></li>
</ul>
</li>
</ul>
<p>3.3.4. 정렬, Aggregation함수, GroupBy 적용</p>
<ul>
<li>DataFrame, Series의 정렬 ⇒ <code>sort_values()</code><ul>
<li><code>sort_values(by=[&#39;칼럼명&#39;], ascending=True, inplace=False)</code></li>
</ul>
</li>
<li>DataFrame에서 Aggregation 호출하면 ⇒ 모든 칼럼에 해당 aggregation이 적용됨<ul>
<li><code>df.count()</code></li>
<li><code>df[[&#39;Age&#39;, &#39;Fare&#39;]].mean()</code></li>
<li><code>df[&#39;Age&#39;].mean()</code> : Series에 mean 적용</li>
</ul>
</li>
<li>GroupBy + Agg 호출하면 ⇒ groupby( ) 대상 칼럼 제외한 모든 칼럼에 해당 agg 함수 적용됨<ul>
<li><code>titanic_df.groupby(by=&#39;Pclass&#39;)</code> : 타입은 DataFrameGroupBy로 객체만 반환</li>
<li><code>titanic_df.groupby(&#39;Pclass&#39;)[&#39;Age&#39;].count()</code> : 이 객체에 다음과 같이 agg 함수를 적용해야함<ul>
<li>단독으로 위의 예시처럼도 사용 가능하고</li>
<li><code>titanic_df.groupby(&#39;Pclass&#39;)[&#39;Age&#39;].agg([max, min])</code> :  agg를 호출해서 여러개 적용도 가능</li>
</ul>
</li>
</ul>
</li>
<li>서로 다른 column에, 서로 다른 agg 함수 넣기 ← dict으로 지정해서 넣어야 함
: groupby에서 호출하려면 SQL에 비해 조금 복잡함<ul>
<li>SQL ⇒ <code>Select max(Age), sum(SibSP), avg(Fare) From titanic_table group by Pclass</code></li>
<li>Pandas ⇒ `agg_format={&#39;Age&#39;:&#39;max&#39;, &#39;SibSp&#39;:&#39;sum&#39;, &#39;Fare&#39;:&#39;mean&#39;}<pre><code>     titanic_df.groupby(&#39;Pclass&#39;).agg(agg_format)`
                                   OR
           `titanic_df.groupby(&#39;Pclass&#39;).agg({&#39;Age&#39;:&#39;max&#39;, &#39;SibSp&#39;:&#39;sum&#39;, &#39;Fare&#39;:&#39;mean&#39;})`</code></pre></li>
</ul>
</li>
</ul>
<h2 id="4-결손-데이터-처리">4. 결손 데이터 처리</h2>
<ul>
<li><code>isna()</code>: NaN 결손 데이터 여부 확인 (boolean)<ul>
<li><code>isna().sum()</code> : 각 col별로 결손 데이터 확인하기</li>
</ul>
</li>
<li><code>fillna(&#39;대체할 값&#39;)</code>: NaN 값을 대체하여 Missing 데이터 처리<ul>
<li><code>titanic_df[&#39;Age&#39;] = titanic_df[&#39;Age&#39;].fillna(titanic_df[&#39;Age&#39;].mean())
titanic_df[&#39;Embarked&#39;] = titanic_df[&#39;Embarked&#39;].fillna(&#39;S&#39;)
titanic_df.isna().sum()</code></li>
</ul>
</li>
<li><code>apply(lambda x: 식)</code> : apply lambda식으로 데이터 가공<ul>
<li>pandas에서 lambda를 쓰려면 .apply() 를 써야함<ul>
<li><code>titanic_df[&#39;Name_len&#39;]= titanic_df[&#39;Name&#39;].apply(lambda x : len(x))</code></li>
</ul>
</li>
<li>lambda에서 if else 조건식 쓰기<ul>
<li><code>titanic_df[&#39;Child_Adult&#39;] = titanic_df[&#39;Age&#39;].apply(lambda x : &#39;Child&#39; if x &lt;=15 else &#39;Adult&#39; )</code></li>
</ul>
</li>
<li>lambda에서 if else (if else) 이중 쓰기<ul>
<li><code>titanic_df[&#39;Age_cat&#39;] = titanic_df[&#39;Age&#39;].apply(lambda x : &#39;Child&#39; if x&lt;=15 else (&#39;Adult&#39; if x &lt;= 60 else &#39;Elderly&#39;))</code></li>
</ul>
</li>
<li>너무 많으면 그냥 함수를 따로 만들어라</li>
</ul>
</li>
</ul>
<h2 id="99-dataframe-크기-조정">99. DataFrame 크기 조정</h2>
<ul>
<li><code>pd.options.display.max_rows = None</code> : 전체 보기, None 대신 숫자 지정</li>
<li><code>pd.options.display.max_columns = None</code> : 전체 보기, None 대신 숫자 지정</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 머신러닝 완벽 가이드 - 1. Numpy]]></title>
            <link>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-1.-Numpy</link>
            <guid>https://velog.io/@mios_leo/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C-1.-Numpy</guid>
            <pubDate>Mon, 26 Sep 2022 02:24:44 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/mios_leo/post/f88a35d6-3d11-4a57-9515-effef0d5014f/image.jpeg" alt=""></p>
<h1 id="🧮--numpy-넘파이">🧮  Numpy 넘파이</h1>
<h2 id="1-데이터-생성-및-수정">1. 데이터 생성 및 수정</h2>
<ul>
<li><p>데이터 타입: ndarray</p>
</li>
<li><p><code>array()</code>: 인자를 받아 ndarray로 변환</p>
</li>
<li><p><code>arange()</code>: 연속된 숫자(정수)를 ndarray로 변환</p>
<p>  예) np.arange(10): 0~9의 숫자를 ndarray로 만듦</p>
</li>
<li><p><code>zeros()</code>: shape 값을 입력하면 0으로 채운 뒤 해당 shape를 가진 ndarray를 반환
예) np.zeros((3,2))</p>
</li>
<li><p><code>ones()</code>: shape 값을 입력하면 1로 채운 뒤 해당 shape를 가진 ndarray를 반환</p>
</li>
<li><p><code>reshape()</code>: 차원, 크기 변환
예) array1.reshape(2, 5)</p>
</li>
</ul>
<h2 id="2-인덱싱-indexing">2. 인덱싱 indexing</h2>
<ul>
<li>단일값</li>
<li>슬라이싱<ul>
<li><code>array2d[ :2, 0 ]</code> : 한 쪽은 슬라이싱, 한쪽은 단일을 적용해도 된다.</li>
</ul>
</li>
<li>팬시 인덱싱 : 리스트나 ndarray로 인덱스 집합을 지정하면, 해당 위치의 인덱스에 해당하는 ndarray를<ul>
<li><code>array2d[ [0, 1], 0:2 ]</code> 반환하는 인덱싱 방식</li>
</ul>
</li>
<li>불린 인덱싱: [ ] 안에 array1d &gt; 5 Boolean indexing을 적용<ul>
<li><code>array3 = array1d[ array1d &gt; 5 ]</code> : [ ] 안에 조건 넣기</li>
<li><code>boolean_indexes = np.array([False, False, False, False, False,  True,  True,  True,  True])</code>
<code>array3 = array1d[boolean_indexes]</code> : 위의 거랑 같음</li>
<li><code>indexes = np.array([5,6,7,8])</code>
<code>array4 = array1d[ indexes ]</code> : 위의 거랑 같음</li>
</ul>
</li>
</ul>
<h2 id="3-데이터-정렬---sort-와-argsort-">3. 데이터 정렬 - sort( )와 argsort( )</h2>
<ul>
<li><p>행렬 정렬(기본적으로 list와 비슷)</p>
<ul>
<li><code>np.sort(ndarray)</code> : 원행렬은 유지, 정렬된 행렬 반환 ⇒ 기본 오름차순, [::-1]로 내림차순<ul>
<li><code>np.sort( )[::-1]</code> : 내림 차순 정렬시 슬라이싱 사용</li>
</ul>
</li>
<li><code>ndarray.sort( )</code> : 원행렬을 정렬, None 반환(원행렬을 sort하여 inplace 됨)<ul>
<li><code>ndarray[::-1].sort( )</code> : 사실상 슬라이싱으로 순서를 바꾸는 거</li>
</ul>
</li>
</ul>
</li>
<li><p>2차원 이상 행렬 정렬 : axis값 이용해서 row 방향, col 방향 정렬</p>
<ul>
<li><code>sort_array2d_axis0 = np.sort(array2d, axis=0)</code> : row 방향 정렬 (axis=0)</li>
<li><code>sort_array2d_axis1 = np.sort(array2d, axis=1)</code> : col 방향 정렬 (axis=1)</li>
</ul>
</li>
<li><p>정렬  행렬의 인덱스 반환 : 원본 행렬이 정렬 됐을 때, 기존 행렬 원소에 대한 인덱스가 피요할 때</p>
<ul>
<li><p><code>np.argsort(ndarray)</code>: 원본 행렬 정렬 시, 행렬 인덱스 값 반환</p>
<ul>
<li><code>org_array = np.array([ 3, 1, 9, 5]) 
sort_indices = np.argsort(org_array)
print(type(sort_indices))
print(&#39;행렬 정렬 시 원본 행렬의 인덱스:&#39;, sort_indices)</code></li>
<li><blockquote>
<blockquote>
<p> &lt;class &#39;numpy.ndarray&#39;&gt;</p>
<pre><code> 행렬 정렬 시 원본 행렬의 인덱스: [1 0 3 2]*</code></pre></blockquote>
</blockquote>
</li>
</ul>
</li>
<li><p><code>np.argsort(ndarray)[: : -1]</code> : 원본 행렬 내림차순 정렬시, 행렬 인덱스 값 반환</p>
<ul>
<li><code>org_array = np.array([ 3, 1, 9, 5]) 
sort_indices_desc = np.argsort(org_array)[::-1]
print(&#39;행렬 내림차순 정렬 시 원본 행렬의 인덱스:&#39;, sort_indices_desc)</code></li>
<li><blockquote>
<blockquote>
<p> 행렬 내림차순 정렬 시 원본 행렬의 인덱스: [2 3 0 1]*</p>
</blockquote>
</blockquote>
</li>
</ul>
</li>
<li><p>RDBMS의 TABLE 칼럼이나 Pandas의 DataFrame 칼럼과 같은 메타 데이터 갖기 어려우므로,
[실제 값]과 [그 값이 뜻하는 메타 데이터]를 별도의 ndarray로 각각 가져야 함</p>
<ul>
<li><p><code># [그 값이 뜻하는 메타 데이터]
name_array = np.array([&#39;John&#39;, &#39;Mike&#39;, &#39;Sarah&#39;, &#39;Kate&#39;, &#39;Samuel&#39;])</code>
<code># [실제 값]
score_array= np.array([78, 95, 84, 98, 88])</code></p>
<p><code>sort_indices_asc = np.argsort(score_array)
print(&#39;성적 오름차순 정렬 시 score_array의 인덱스:&#39;, sort_indices_asc)
print(&#39;성적 오름차순으로 name_array의 이름 출력:&#39;, name_array[sort_indices_asc])</code></p>
</li>
<li><blockquote>
<blockquote>
<p> 성적 오름차순 정렬 시 score_array의 인덱스: [0 2 4 1 3]</p>
<pre><code>  성적 오름차순으로 name_array의 이름 출력: [&#39;John&#39; &#39;Sarah&#39; &#39;Samuel&#39; &#39;Mike&#39; &#39;Kate&#39;]*</code></pre></blockquote>
</blockquote>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="4-선형대수-연산">4. 선형대수 연산</h2>
<ul>
<li><code>np.dot( A, B )</code>: 행렬 곱(내적)</li>
<li><code>np.transpose(A)</code>: 전치 행렬</li>
</ul>
]]></description>
        </item>
        <item>
            <link>https://velog.io/@mios_leo/5nygl7jj</link>
            <guid>https://velog.io/@mios_leo/5nygl7jj</guid>
            <pubDate>Mon, 22 Aug 2022 06:20:37 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/mios_leo/post/df7c3d01-d7ae-4aaf-985b-3e451b054d58/image.png" alt=""></p>
<h1 id="제-1장-상대에게-전달한다는-것">제 1장 상대에게 전달한다는 것</h1>
</br>

<h2 id="📍-중요한-것은-내가-말하고-싶은-것이-아니라">📍 중요한 것은 (내가 말하고 싶은 것이 아니라)</h2>
<h2 id="과제에-대해-상대에게-전달할-메시지"><strong>과제에 대해 상대에게 전달할 메시지</strong></h2>
</br>

<h2 id="📍-메시지의-3요소">📍 메시지의 3요소</h2>
<ol>
<li>[명쾌한 과제] : 내가 답변해야 하는 것</li>
<li>[상대의 기대 반응]</li>
<li>과제에 대한 나의 [답변]</li>
</ol>
</br>

<h2 id="📍-상대-기대-반응의-3분류">📍 상대 기대 반응의 3분류</h2>
<ol>
<li>이해시키기 : 전달 내용을 상대에게 정확하게 이해시킨다</li>
<li>피드백 받기 : 판단, 조언, 감상 등</li>
<li>행동 유도</li>
</ol>
</br>

<h2 id="📍-답변의-3요소--핵심은-상대도-명쾌하게-납득이-되어야-한다는-점">📍 답변의 3요소 : 핵심은 상대도 명쾌하게 납득이 되어야 한다는 점</h2>
<ol>
<li>결론 : 작성자의 명확한 의견(요약)<ol>
<li>함정 1 : 하고 싶은 말 요약 X, 과제의 요약이어야 함<br>→ 어떤 결론에 이르렀다면, 한 번 더 과제를 확인하라<br>→ if ‘그래서 결론이 뭐야? ⇒ 실패</li>
<li>함정 2 : 애매하고 주관적인 부대조건은 안됨<br>→ 명확히 설명할 수 없다면 문제 자체를 제대로 해결하지 못했다는 뜻<br>→ ex) ~에 따라서’ 와 같은 것들은 안됨</br></li>
</ol>
</li>
<li>근거 : 결론의 타당성<ol>
<li>함정 1 : 인과 관계를 잘 파악해라<br>→ ex) ‘A가 필요하다. 왜냐하면 A가 없기 때문이다’</li>
<li>함정 2 : 수치로 말하라 (객관성을 유지하라) (수치화가 어렵다면, 개념의 조작적 정의를 해라)<br>→ if ‘그것은 사실인가? 아니면 당신의 판단/가설 인가?’ ⇒ 실패</li>
<li>함정 3 : 당연한 건 없다<br>→ 나만 당연하게 여기는 것일 확률이 높다<br>→ ex) ‘말할 것도 없고&#39;, ‘당연하다’</br></li>
</ol>
</li>
<li>방법 : 결론이 행동으로 옮겨야 하는 경우의 구체성<ol>
<li>함정 1 : 타사 및 10년전에도 통할 공리는 방법이 아니다.<br>→ 방법은 기업에 적용할 때, 구체적으로 무엇을 해야하는지 전달해야 의미가 있음<br>→ ‘타사에도 통용될까?’ , ‘10년 전/후에도 통용될까?’ 자문자답하고 yes면 방법이 아니다.</li>
<li>함정 2 : 수식어로는 구체적으로 되지 않는다.<br>→ 내용이 구체적이지 않으면, 여러 수식어를 붙여 내용을 부풀리고 싶은 충동에 사로잡힘<br>→ 답변이 구체적이지 않으면, 그 원인은 과제를 충분히 이해/분석하지 못함에 있다.<br>→ [Five Whys] [5W1H] 같은 방법론을 적용해보아 원인을 분석해보는 것도 방법</li>
</ol>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[배민, 지난해 허위리뷰 11만건 차단…AI 시스템 도입]]></title>
            <link>https://velog.io/@mios_leo/%EB%B0%B0%EB%AF%BC-%EC%A7%80%EB%82%9C%ED%95%B4-%ED%97%88%EC%9C%84%EB%A6%AC%EB%B7%B0-11%EB%A7%8C%EA%B1%B4-%EC%B0%A8%EB%8B%A8AI-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%8F%84%EC%9E%85</link>
            <guid>https://velog.io/@mios_leo/%EB%B0%B0%EB%AF%BC-%EC%A7%80%EB%82%9C%ED%95%B4-%ED%97%88%EC%9C%84%EB%A6%AC%EB%B7%B0-11%EB%A7%8C%EA%B1%B4-%EC%B0%A8%EB%8B%A8AI-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EB%8F%84%EC%9E%85</guid>
            <pubDate>Tue, 02 Aug 2022 09:16:24 GMT</pubDate>
            <description><![CDATA[<h2 id="📰--본문"><strong>📰  본문</strong></h2>
<p><strong>배달의민족(이하 배민) 운영사 우아한형제들은 지난해 11만4054건의 허위리뷰를 차단했다고 밝혔다. 허위리뷰는 음식의 배달 및 취식 없이 거짓으로 작성한 리뷰를 뜻한다.</strong>  </p>
<p><strong>배민은 허위리뷰 근절을 위해 ‘실시간 모니터링 시스템’부터 ‘자전거래 탐지’, ‘인공지능(AI)를 활용한 고도화 모델’ 등 기술적 수단을 동원해왔다. 그 결과 허위 의심 리뷰 제보건수는 지난해 연 최고점 대비 60% 이상 줄었다는 설명이다.</strong>  </p>
<p><strong>배민은 2020년까지만 해도 업주 및 이용자의 제보와 전담인력 검수 등에 의존해 허위리뷰를 차단했다. 회사는 2020년 11월 허위 의심 리뷰 실시간 모니터링 시스템 도입을 통해 허위 의심 리뷰 적발 속도와 정확도를 높였다. 이 시스템은 배민 앱에 등록되는 리뷰를 실시간으로 탐지해 24시간 이내 분석 및 조치를 취하는 시스템이다. 허위리뷰로 의심될 경우 자동으로 노출을 일시 제한시킨다.</strong></p>
<p><img src="https://velog.velcdn.com/images/mios_leo/post/7b4ddf57-c70d-4349-84cd-0977b799d9d6/image.png" alt=""></p>
<p><strong>배민은 실시간 모니터링 활성화 외에도 허위리뷰 근절을 위한 다양한 시스템을 가동했다. 2021년 6월부터 리뷰조작이 의심되는 업주의 데이터를 분석해 차단하는 조치를 취하고, 12월엔 AI를 활용한 고도화 모델을 탑재했다. 허위리뷰의 주문 수법이 다양해지고 복잡해짐에 따라 AI가 그간의 다양한 허위리뷰 사례를 학습, 허위 의심 리뷰를 빠르게 적발하도록 했다</strong></p>
<p><strong>배민은 리뷰 조작이 불법임을 알리고자 악성 리뷰조작 업체에 대한 고소 및 경고 작업을 진행했다. 현재까지 6건에 대한 수사가 진행 중이며, 34개 업체를 대상으로 경고 및 내용 증명을 발송했다. 지난해 5월에는 법적 대응 끝에 허위리뷰 조작 업체가 실형을 선고받기도 했다. 더불어 최근에는 리뷰 조작 업체에 대한 모니터링을 강화했다. 또 경고를 했음에도 지속적으로 유사한 행위를 하는 리뷰조작업체 대상으로 고소를 해나갈 예정이다.</strong></p>
<p><strong>이원재 우아한형제들 서비스위험관리실장은 &quot;이용자가 믿고 볼 수 있는 리뷰 환경을 만들고자 실시간 모니터링 시스템부터 법적 대응까지 허위리뷰에 대해 강경 대응을 취하고 있다&quot;며 &quot;지난해말 탑재한 AI 고도화 모델을 통해 앞으로 더 빠르게 효과적으로 허위리뷰에 대응해 나갈 것이다&quot;고 말했다.</strong></p>
<hr>
<h2 id="🔎--본문-선정-이유"><strong>🔎  본문 선정 이유</strong></h2>
<p><strong>**📍</strong>  배민에서 허위 리뷰를 AI를 활용해 어떤 식으로 판별하는지 궁금**</p>
<hr>
<h2 id="📝--핵심-요약"><strong>📝  핵심 요약</strong></h2>
<p><strong>📍</strong> <strong><strong>지난해 11만4054건의 허위리뷰를 차단했다고 밝혔고, **</strong></strong>허위 의심 리뷰 제보건수는 지난해 연 최고점 대비 60% 이상 줄었다는 설명이다.<strong><strong>**</strong></strong></p>
<ul>
<li><strong>****</strong>현재까지 6건에 대한 수사가 진행 중이며, 34개 업체를 대상으로 경고 및 내용 증명 발송 및 허위리뷰 조작 업체가 실형을 선고받기도 함<strong>****</strong></li>
<li><strong>****</strong>최근에는 리뷰조작업체에 대한 모니터링을 강화했하여 리뷰조작업체 대상으로 고소 해나갈 예정<strong>****</strong></li>
</ul>
<p><strong>📍</strong> <strong>**</strong>허위리뷰 근절을 위해 ‘실시간 모니터링 시스템’부터 ‘자전거래 탐지’, ‘인공지능(AI)를 활용한 고도화 모델’ 등 기술적 수단을 동원해왔다.<strong>**</strong> </p>
<ul>
<li><strong><strong>**</strong></strong>배민은 실시간 모니터링 활성화 외에도 허위리뷰 근절을 위한 다양한 시스템을 가동했다.<strong><strong>**</strong></strong></li>
<li><strong><strong>**</strong></strong>2021년 6월부터 리뷰조작이 의심되는 업주의 데이터를 분석해 차단하는 조치를 취하고,<strong><strong>**</strong></strong></li>
<li><strong><strong>**</strong></strong>12월엔 AI를 활용한 고도화 모델을 탑재했다.<strong><strong>**</strong></strong> </li>
</ul>
<hr>
<h2 id="📚--추가-조사할-내용"><strong>📚  추가 조사할 내용</strong></h2>
<p><strong>📍</strong> <strong>어떤 알고리즘 혹은 기준으로 허위 리뷰를 구별할까?</strong></p>
<p> [못 믿을 음식 리뷰...배민, 가짜 리뷰 어떻게 적발하나</p>
<p>배달 애플리케이션(앱)으로 음식을 주문할 때 눈여겨보게 되는 리뷰. 맛이 없다거나 위생이나 응대 서비스가 좋지 않았다는 리뷰를 보게 되면 그 식당에서는 당연히 주문을 하기 꺼려진다. 반면</p>
<p><a href="http://www.edaily.co.kr%5D(https://www.edaily.co.kr/news/read?newsId=03968806625864368&amp;mediaCodeNo=257)">www.edaily.co.kr](https://www.edaily.co.kr/news/read?newsId=03968806625864368&amp;mediaCodeNo=257)</a></p>
<blockquote>
<p>&quot; 결국 배민은 ‘부정거래감시팀’이라는 전담조직을 두고 리뷰를 지속적으로 모니터링 했다. 인공지능(AI) 기술을 활용한 리뷰 검수 기능도 도입했다. 리뷰 자동 탐지 시스템으로 주문대비 리뷰 작성률이 지나치게 높거나 단기간에 리뷰가 급증한 음식점을 골라낸 후 검수 전담 인력이 직접 리뷰를 세밀하게 살피는 방법이다. &quot;</p>
</blockquote>
<p> [배달의민족, 허위 리뷰 사전 차단 시스템 도입 - 디지털투데이 (DigitalToday)</p>
<p>[디지털투데이 정유림 기자] 배달앱 배달의민족을 운영하는 우아한형제들(대표 김범준)이 허위로 의심되는 리뷰(후기)를 사전에 자동 탐지하는 실시간 모니터링 시스템을 도입한다고 24일 밝혔</p>
<p><a href="http://www.digitaltoday.co.kr%5D(https://www.digitaltoday.co.kr/news/articleView.html?idxno=254065)">www.digitaltoday.co.kr](https://www.digitaltoday.co.kr/news/articleView.html?idxno=254065)</a></p>
<blockquote>
<p>&quot; 기존에는 거짓 주문을 발생시켜 지어낸 후기, 대행 업체가 쓴 리뷰 등이 앱에 등록된 다음에야 이를 찾아내 차단할 수 있었다. 그러나 이제는 이용자가 리뷰 작성 완료 버튼을 누르는 순간, 시스템이 허위 여부를 실시간으로 판별하도록 했다. 허위가 의심되면 아예 등록되지 않도록 조치했으며 이를 위해 주문 기록, 이용 현황 등을 분석한다는 설명이다 &quot;</p>
</blockquote>
<p><strong>📍</strong> <strong>허위 리뷰 업체는 어떤 정보의 처벌을 받았을까?</strong></p>
<p> [‘허위리뷰 실형 판결’ 받아낸 배달의민족, 클린리뷰 문화 정착 선도 - 업다운뉴스</p>
<p>[업다운뉴스 김민주 기자] 음식점의 의뢰를 받아 300차례 넘게 허위 리뷰를 작성한 혐의로 재판에 넘겨진 업자 A씨에게 최근 실형이 확정된 사실이 유통업계에서 주목을 받는다. 국내 배달앱 시</p>
<p><a href="http://www.updownnews.co.kr%5D(http://www.updownnews.co.kr/news/articleView.html?idxno=231930)">www.updownnews.co.kr](http://www.updownnews.co.kr/news/articleView.html?idxno=231930)</a></p>
<blockquote>
<p>&quot; 배달의민족 운영사인 우아한형제들은 지난해 11월 서울동부지방법원에서 징역 10월형을 선고받은 A씨가 항소했지만 법원은 최근 이를 기각하면서 원심이 최종 확정됐다고 지난 25일 밝혔다. &quot;</p>
</blockquote>
<p><strong>📍</strong> <strong>실형을 받을 정도로 심각해진 **</strong>리뷰, 다른 업체들은 어떻게 대처해나가고 있을까?<strong>**</strong></p>
<p> [‘인공지능’으로 &lt;가짜 리뷰와의 전쟁&gt; 나선 5개 IT스타트업</p>
<p>가짜, 허위를 근절해 세상을 건강하게 바꾸려는 기업들이 있다. ‘진짜 제품’, ‘진짜 리뷰’. 이를 골라내는 일은 바로 인공지능(AI)이 한다. 인공지능 기술을 활용해 ‘가짜와의 전쟁’을 펼</p>
<p><a href="http://www.top3.kr%5D(https://www.top3.kr/entry/%E2%80%98%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5%E2%80%99%EC%9C%BC%EB%A1%9C-%EA%B0%80%EC%A7%9C-%EB%A6%AC%EB%B7%B0%EC%99%80%EC%9D%98-%EC%A0%84%EC%9F%81-%EB%82%98%EC%84%A0-5%EA%B0%9C-IT%EC%8A%A4%ED%83%80%ED%8A%B8%EC%97%85)">www.top3.kr](https://www.top3.kr/entry/%E2%80%98%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5%E2%80%99%EC%9C%BC%EB%A1%9C-%EA%B0%80%EC%A7%9C-%EB%A6%AC%EB%B7%B0%EC%99%80%EC%9D%98-%EC%A0%84%EC%9F%81-%EB%82%98%EC%84%A0-5%EA%B0%9C-IT%EC%8A%A4%ED%83%80%ED%8A%B8%EC%97%85)</a></p>
<blockquote>
<p>&quot; 인공지능 기술을 활용해 ‘가짜와의 전쟁’을 펼치는 대표적인 IT회사로 마크비전, 당근마켓, 인덴트코퍼레이션과 같은 스타트업부터, 배달의민족, 카카오 등 규모급 기업에 이르기까지 다양한 곳에서 건전한 생태계와 시장 환경 조성에 발벗고 나서며 이용자 보호에 힘을 쏟고 있다. &quot;</p>
</blockquote>
<p> [거짓, 가짜, 그리고 AI</p>
<p>거짓리뷰와 제한된 게시글을 탐지하고 가짜를 신고하는 인공지능 | #17. 인공지능이 활용되는 분야별로 대표성을 띈 사례들을 차근차근, 꾸준히 정리해보려 한다. 이번 글에서는 인공지능을 활</p>
<p>brunch.co.kr](<a href="https://brunch.co.kr/@monglec/64">https://brunch.co.kr/@monglec/64</a>)</p>
<p>[##<em>Image|kage@b2jPIn/btrzDu1DayA/KlkOkITuD1AMuFHJlXKoY0/img.png|CDM|1.3|{&quot;originWidth&quot;:1432,&quot;originHeight&quot;:1162,&quot;style&quot;:&quot;widthContent&quot;,&quot;caption&quot;:&quot;출처 : 마크비전 사이트&quot;}</em>##]</p>
<hr>
<h2 id="📰--기사-원문"><strong>📰  기사 원문</strong></h2>
<p> [배민, 지난해 허위리뷰 11만건 차단…AI 시스템 도입</p>
<p>배달의민족(이하 배민) 운영사 우아한형제들은 지난해 11만4054건의 허위리뷰를 차단했다고 밝혔다. 허위리뷰는 음식의 배달 및 취식 없이 거짓으..</p>
<p>it.chosun.com](<a href="http://it.chosun.com/m/svc/article.html?contid=2022041101577&amp;utm_source=undefined&amp;utm_medium=unknown&amp;utm_campaign=itchosun">http://it.chosun.com/m/svc/article.html?contid=2022041101577&amp;utm_source=undefined&amp;utm_medium=unknown&amp;utm_campaign=itchosun</a>)</p>
]]></description>
        </item>
    </channel>
</rss>