<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>chanhee-kang.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Mon, 06 Feb 2023 02:17:52 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>chanhee-kang.log</title>
            <url>https://velog.velcdn.com/images/chanhee-kang/profile/7697e377-6fe6-41b1-a584-08de95794a8b/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. chanhee-kang.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/chanhee-kang" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Process Mining(프로세스 마이닝) 에 대해서]]></title>
            <link>https://velog.io/@chanhee-kang/Process-Mining%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EB%A7%88%EC%9D%B4%EB%8B%9D-%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C</link>
            <guid>https://velog.io/@chanhee-kang/Process-Mining%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EB%A7%88%EC%9D%B4%EB%8B%9D-%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C</guid>
            <pubDate>Mon, 06 Feb 2023 02:17:52 GMT</pubDate>
            <description><![CDATA[<p>이번 포스팅에서는 프로세스마이닝에 대해 진행해 보도록 하겠습니다. </p>
<h2 id="📌-프로세스-마이닝이란">📌 프로세스 마이닝이란?</h2>
<p>프로세스마이닝은 데이터마이닝의 한 분야로 프로세스 자체에 집중하는 방법이라고 할 수 있을것 같습니다. 예를 들어 환자가 감기에 걸려서 병원에서 진단을 받아보고자 합니다. </p>
<p>환자가 병원에가서 진료를 받기까지 진료예약, 외래각과접수, 외래진료실 검사예약, 원무수납, 처방전발급과 같은 다양한과정을 거치게 됩니다. 데이터 마이닝이 이러한 과정에서 결과적으로 무엇이 일어났는가와 무엇이 일어날까에 집중을 한다면, 프로세스 마이닝은 공정 과정 전체를 분석하고 분석결과를 시각화해서 해당 프로세스를 더 효율적으로 개선하고 발전시키는 방법론이라고 할 수 있습니다.</p>
<p>즉, <strong>어떠한 프로세스에서 가장 일이 많이 몰리는 곳이나 가장 시간이 많이 소요되는 병목지점등과 같은 질문에 답을 주기 위해 프로세스 마이닝을 진행 할 수 있습니다</strong>. </p>
<p>프로세스 마이닝의 기본적인 개념은 정보시스템에 기록 되어 있는 이벤트 로그에서 지식을 추출함으로써, 사람들이 머리 속에서 추정하고 있는 프로세스가 아닌 실제 업무 프로세스를 도출하고, 모니터링하며, 개선하는 것입니다.</p>
<h2 id="📌-event-log이벤트-로그">📌 Event Log(이벤트 로그)</h2>
<p>프로세스 마이닝에서는 이번트 로그라는 데이터를 사용하여 분석을 합니다. </p>
<p>이벤트로그는 케이스 아이디(case id), 액티비티(activity), 그리고 타임스탬프(timestamp)의 3가지 요소가 포함되어야 합니다. 먼저 아래의 이벤트 로그를 살펴보도록 합시다. 
<img src="https://velog.velcdn.com/images/chanhee-kang/post/80f3ffa0-6c0c-47ed-b55b-31acaf48f831/image.png" alt=""></p>
<p>위의 차트는 병원에서 환자들에 대한 프로세스 입니다. Patient 컬럼은 환자의 번호를 의미하며 이는 환자의 고유 번호로 환자 가각을 구별해 줄 수 있기 때문에 케이스 아이디가 됩니다. </p>
<p>그리고 activity는 어떠한 활동을 하였는지, timestamp는 activity가 발생된 시간, doctor는 주치의, cost는 activity의 비용을 의미합니다. </p>
<h2 id="📌-프로세스-디스커버리process-discovery">📌 프로세스 디스커버리(Process Discovery)</h2>
<p>프로세스 디스커버리는 아무런 사전정보 없이 이벤트 로그로부터 모델을 도출하는 것을 의미 합니다. 이러한 프로세스 디스커버리는 pm4py 패키지를 통해 진행할 수 있으며 주요 알고리즘으로는 alpha miner, heuristc miner, inductive miner 등이 존재 합니다.</p>
<h2 id="알파마이너-alpha-miner">알파마이너 (Alpha Miner)</h2>
<p>알파마이너는 이벤트 로그의 요소중 액티비티의 순서에 집중한 알고리즘입니다. </p>
<p>즉 하나의 케이스에 대해 액티비티가 어떤 순서대로 일어났는지를 확인 할 수 있습니다. 간단한 집수리 데이터를 통해 알파마이너를 통해 프로세스 디스커버리를 진행해 보도록하겠습니다. 아래는 집수리 이력데이터의 일부이며 dataframe 형태로 구성되었습니다.
<img src="https://velog.velcdn.com/images/chanhee-kang/post/e4591924-cba1-4c36-aba7-e6d281bfbb81/image.png" alt="">
상단의 데이터프레임을 먼저 이벤트로그 형태로 변경시켜주어야하는데, 이는 <code>pm4py</code> 패키지를 통해 아래와 같이 변경시켜 줄수 있습니다.</p>
<pre><code class="language-python">from pm4py.objects.conversion.log import converter as log_converter

eventlog = df.copy()
eventlog.rename(columns={&#39;Start Timestamp&#39;: &#39;time:timestamp&#39;, 
                         &#39;CaseID&#39;: &#39;case:concept:name&#39;, 
                         &#39;TaskID&#39;: &#39;concept:name&#39;, 
                         &#39;Originator&#39;: &#39;org:resource&#39;}, inplace=True)

log = log_converter.apply(eventlog)</code></pre>
<p>그후, Event log를 기반으로 프로세스 모델을 도출하는 process discovery와 해당 모델에 대해 시각화를 진행해보았습니다. </p>
<p>먼저 각 task들에 대한 빈도를 고려하지 않고 모든 activity를 프로세스에 도출할 수 있는 <strong>Alpha Miner 알고리즘</strong>을 통해 모델을 구축하여 보았습니다.</p>
<pre><code>from pm4py.algo.discovery.alpha import algorithm as alpha_miner
from pm4py.visualization.petrinet import visualizer as pn_visualizer

net, initial_marking, final_marking = alpha_miner.apply(log)
gviz = pn_visualizer.apply(net, initial_marking, final_marking) 
pn_visualizer.view(gviz)</code></pre><p><img src="https://velog.velcdn.com/images/chanhee-kang/post/276d2599-9058-418b-aa5a-6d92fe2991e8/image.png" alt=""></p>
<h2 id="dircetly-follwed-graph">Dircetly follwed graph</h2>
<p>Dircetly follwed graph는 각 activity간의 directly follwed 관계를 나타낸 그래프입니다.</p>
<pre><code class="language-python">from pm4py.algo.discovery.dfg import algorithm as dfg_discovery
from pm4py.visualization.dfg import visualizer as dfg_visualization

dfg = dfg_discovery.apply(log)
gviz = dfg_visualization.apply(dfg, log=log, variant=dfg_visualization.Variants.FREQUENCY)
dfg_visualization.view(gviz)</code></pre>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/06f6e9a0-b068-407e-a6f0-11fd1c964fe8/image.png" alt="">
또한, Dircetly follwd graph를 통해 프로세스를 진행하면서 걸리는 시간을 알아 볼 수도 있습니다.</p>
<pre><code class="language-python">dfg = dfg_discovery.apply(log, variant=dfg_discovery.Variants.PERFORMANCE)
gviz = dfg_visualization.apply(dfg, log=log, variant=dfg_visualization.Variants.PERFORMANCE)
dfg_visualization.view(gviz)</code></pre>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/04727d24-9db2-4748-b4d7-08d450d8fd51/image.png" alt="">
Dircetly follwed graph를 통한 집수리의 과정에 대해 프로디스커버리 과정을 거치면 알수있는 현상은 다음과 같습니다.</p>
<ol>
<li>FirstContact → MakeTicket → ArrangeSurvey → InformClient → Survey → ImmediateRepair or InternRepair or ExternRepair → RepairReady → SendTicektToFinAdmin → ReadyInformClient → TicketReady로 이루어 짐을 확인할 수 있습니다.</li>
<li>ReadyInfromClient 와 SendTicketToFinAdmin 사이의 문제가 있어보임. 해당 문제에 대한 원인파악이 필요해 보입니다.</li>
<li>InformClientSurvey가 진행된이후 Survey가 진행되기까지 Bottleneck현상이 발생되는것으로 파악되어집니다.</li>
<li>InternRepair에서의 수리과정을 확인해 봐야할 필요성이 존재합니다.</li>
<li>Survey → InternReapir로 넘어가는 처리시간에 대해 원인 파악이 필요해 보입니다.</li>
</ol>
<h2 id="📌-마무리">📌 마무리</h2>
<p>이런식으로 프로세스마이닝을 진행하게 되면 프로세스에서 가장 일이 많이 몰리는 곳이나 가장 시간이 많이 소요되는 병목지점등과 같은 질문에 답을 얻을 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[RoBERTa 논문리뷰]]></title>
            <link>https://velog.io/@chanhee-kang/RoBERTa-%EB%85%BC%EB%AC%B8%EB%A6%AC%EB%B7%B0</link>
            <guid>https://velog.io/@chanhee-kang/RoBERTa-%EB%85%BC%EB%AC%B8%EB%A6%AC%EB%B7%B0</guid>
            <pubDate>Sun, 05 Feb 2023 08:48:11 GMT</pubDate>
            <description><![CDATA[<p>본 포스팅에서는 RoBERTa : A Robustly Optimized BERT Pretraing Model에 대해 소개해드리겠습니다. RoBERTa의 경우 BERT의 후속 모델로 유명합니다.</p>
<h2 id="📌-bert란">📌 BERT란?</h2>
<p>BERT는 Bidirectional Encoder Representations from Transformers의 약자로 2018년 구글에서 발표한 언어모델중 한 개 입니다. BERT는 여러가지 자연어 task중 최고 성능을 기록하면서 모델이 처음 발표되었을때부터 지금까지 자연어처리분야에서 큰 화제를 불러왔던 모델입니다. 그리고 RoBERTa는 이러한 BERT의 몇가지 한계점에 대해 개선한 모델중 하나 입니다.</p>
<h2 id="📌-roberta에-대해서">📌 RoBERTa에 대해서</h2>
<p>RoBERTa의 경우 기존의 BERT가 underfitting되어있음일 지적하면서 등장한 모델입니다. 즉, underfitting의 문제점등을 해결하면서 성능을 좀더 끌어올릴수 있다고 주장한 논문입니다. 성능을 끌어 올리기위해 본 논문에서는 3가지 방법을 제시하였습니다. </p>
<p>첫번째로 dynamic masking 방법을 사용합니다. 두번째로는 더 많은 데이터와 더큰 batch 사이즈를 사용하였습니다. 마지막으로는 기존의 BERT학습에 사용되었던 NSP(Next Sentence Prediction)을 제거 하였습니다. </p>
<h3 id="dynamic-masking">Dynamic masking</h3>
<p>BERT는 학습을 위해 2가지의 task를 수행합니다 첫번째로는 Masked languaged model이라 불리는 MLM task이며, 두번째는 NSP task 입니다.
<img src="https://velog.velcdn.com/images/chanhee-kang/post/07609190-cfec-44e3-b9ec-c63a2627da29/image.png" alt=""></p>
<p>MLM task는 BERT 모델이 입력이 들어올때, 그중 일부를 mask 처리합니다. 즉 가려진 token에 대해 맞추는 task라고 할 수 있습니다. 따라서 BERT는 가려진 token을 예측하기위해 문맥정보를 최대한 활용하는 방향으로 학습이 수행됩니다. 이때 기존의 BERT는 masking하는 토큰을 static하게 선정하는 반면, RoBERTa의 경우 토큰을 dynamic한 방법을 사용하여 masking 합니다.
<img src="https://velog.velcdn.com/images/chanhee-kang/post/1b1ba784-5483-4353-a47f-a35cc0f366e1/image.png" alt=""></p>
<p>위의 그림은 BERT에서 사용된 static 방법과 RoBERTa에서 사용된 dynamic한 방법에 대한 그림입니다. </p>
<p>먼저 왼쪽그림은 기존 BERT에서 사용된 static한 방식인데, 예를 들어 &#39;I am a boy&#39;라는 문장이 주어졌을 때, BERT는 전처리 단계에서 일부 토큰을 masking하여 모델의 입력값으로 넣습니다. </p>
<p>즉, 입력값이 모델에 들어갈때 부터 가려진 토큰이 결정되므로 왼쪽 그림에서 확인 할 수 있듯이 epoch에 관계없이 같은 입력에 대해서 항상 동일한 위치에 토큰이 가려지게 됩니다. </p>
<p>반면 RoBERTa의 경우 dynamic한 masking 방식으로 마스킹 처리하게되는데, 따라서 매 epoch마다 다른 토큰이 마스킹 되게 됩니다. 이를 통해 오버피팅을 방지 할수 있음과 더불어 task의 난이도 상승으로 인해 학습후에 모델이 더 어려운 task에 대해서도 잘 해결 할 수 있게 학습을 수행합니다. </p>
<p>아래 지표에서 확인 할 수 있듯이, dynamic한 방식이 모든 task에 대해 높은 성능을 보인것은 아니지만, SQuAD와 SST와 같은 task에서 저자들의 컨트리뷰션이 유효했음을 알수 있습니다.
<img src="https://velog.velcdn.com/images/chanhee-kang/post/ddad36b7-6a3a-4b9a-858c-35547c39e45e/image.png" alt=""></p>
<h3 id="more-datasets-and-batch-size">More datasets and Batch size</h3>
<p>RoBERTa는 모델의 성능 향상을 위해 더 많은 데이터와 더 큰 배치사이즈를 사용하였습니다. 
<img src="https://velog.velcdn.com/images/chanhee-kang/post/6f944059-34b6-4217-aa46-251059697d38/image.png" alt="">
위의 지표를 보면 batch 사이즈를 높인다고해서 무조건 모델의 성능이 향상되는것은 아니지만, 이전 BERT 모델과 비교해서 더 큰 batch 사이즈를 사용하였을때, 모델의 성능이 높아지는것을 확인할수 있습니다. </p>
<h3 id="next-sentence-prediction">Next Sentence Prediction</h3>
<p>RoBERTa는 모델의 성능을 높이기위해 Next Sentence Prediction(NSP)을 제거하였습니다. 
<img src="https://velog.velcdn.com/images/chanhee-kang/post/c6317dce-8a03-44bf-b7cd-b9be36819106/image.png" alt="">
NSP는 위에서 설명드렸던 것과 같이 BERT의 학습에 이용되는 task 중 하나로써, NSP는 입력값으로 들어간 두 문장이 이어지는 문장인지, 아니면 관계없는 문장인지를 예측하는 이진분류(binary classification) task 입니다. </p>
<p>즉, 두 문장의 일관성에 대해 학습하는것으로도 볼 수 있습니다. NSP는 처음 BERT가 등장한 이후로 자연어처리 분야에서는 꾸준히 의문이 제기되어왔는데, 예를들어 XLNet의 경우 RoBERTa와 같이 NSP를 제거하여 Pre-training하는 방법을 제안하였습니다. 아래 지표의 경우 NSP를 제거하였을 때와 제거하지 않았을때의 각 데이터셋에 대한 성능을 나타내었습니다.</p>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/4443aa22-270e-49ea-9bbf-89446eb3f9cd/image.png" alt=""></p>
<p>지표를 살펴보면 NSP를 제거하였을때의 성능이 NSP를 사용하였을때의 성능보다 높은것을 확인 할 수 있습니다. 하지만, BERT논문의 경우 NSP를 사용하였을 떄 성능이 높아진것을 보여준 결과, NSP의 경우 모델의 성능을 사용하는 사용자가 각자의 task에 맞게 NSP를 조절해서 사용하는게 맞다고 생각이 듭니다.</p>
<h2 id="📌-결과">📌 결과</h2>
<p>RoBERTa의 경우 BERT 모델의 성능을 끌어 올리기위해  첫번째로 dynamic masking 방법, 두번째로는 더 많은 데이터와 더큰 batch 사이즈를 사용, 그리고 마지막으로는 기존의 BERT학습에 사용되었던 NSP(Next Sentence Prediction)을 제거 하는 방식에 대해 제안하였습니다. 
<img src="https://velog.velcdn.com/images/chanhee-kang/post/8f37c869-dbd9-4cae-be99-e6c1b68e20ad/image.png" alt="">
위의 결과에서 확인할수 있듯이 3가지 방법 모두 모델의 성능을 높이는데 유의미한 결과를 보여주었음을 확인 할 수 있습니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[QANet 논문리뷰]]></title>
            <link>https://velog.io/@chanhee-kang/QANet-%EB%85%BC%EB%AC%B8%EB%A6%AC%EB%B7%B0</link>
            <guid>https://velog.io/@chanhee-kang/QANet-%EB%85%BC%EB%AC%B8%EB%A6%AC%EB%B7%B0</guid>
            <pubDate>Sun, 05 Feb 2023 08:42:15 GMT</pubDate>
            <description><![CDATA[<p>본 포스팅에서는 <strong>reading comprehension task</strong>에 대해 새로운 모델을 제시한 <strong>QANet: Combining Local Convolution with Global Self-Attention for Reading Comprehension</strong>에 대해 진행해보도록하겠습니다.</p>
<h2 id="📌-서론">📌 서론</h2>
<p>본 논문이 나오기 이전의 QA모델의 경우 RNN과 Attention이 결합된 모델이 있었으며, 이는 학습과 추론에 오랜 시간이 걸린다는 단점이 있었습니다. 따라서 본 논문은 RNN 대신 convolution과 self-attention을 결합한 모델을 제시하였으며, 성능은 비슷하면서 SQuAD 데이터셋에서 성능은 유지하면서 학습속도는 3~13배 빠르고 추론이 4 ~ 9배 빠른 결과를 보여주었습니다. 본 논문에서 활용된 데이터셋은 위키피디아에서 모은 데이터셋으로 span-base 데이터셋이라는 특징을 가지고 있습니다. 또한 sigle model을 기준으로 해당 데이터셋에서 84.6 F1 스코어를 기록하였습니다.</p>
<h2 id="📌-qaquestion-answering가-뭘까">📌 QA(Question Answering)가 뭘까?</h2>
<p>QA는 질문이 주어졌을때 정답을 예측하는 테스크 입니다.  본 논문 이전의 QA모델은 아래의 그림과 같은 구조를 가지고 있습니다.
<img src="https://velog.velcdn.com/images/chanhee-kang/post/cc9f7d57-8b65-430c-a084-58bc43b3c138/image.png" alt="">
주어진 paragraph와 question을 임베딩하여 encoding하고 피쳐를 뽑아낸 이후 서로간의 attention을 계산합니다. 그리고 추가적인 인코더를 통과하여 정답을 예측하는 구조입니다. 여기서 인코더 레이어가 대부분 RNN으로 이루어져있는데, RNN의 경우 크게 2가지 문제가 존재합니다. </p>
<p>첫번째로 문단과 같은 긴 문맥을 처리하는 과정에서 시간이 지날 수록 앞의 정보가 점차 희미해지는 경향이 있습니다. 두번째로는 학습과 추론에 시간이 오래 걸린다는 단점이 있습니다. 학습의 경우 experimentation에 걸리는 시간이 오래걸려서 큰 데이터셋을 사용하는데 cost가 너무 많이 들며 추론의 경우 QA모델의 추론이 실시간 수준으로 빠르지 않기 때문에 실제 산업에 적용되는데 어렵다는 단점이 존재합니다. 따라서 본 논문에서는 QANet이라는 새로운 모델을 제시하였습니다.</p>
<h2 id="📌-qanet이란">📌 QANet이란?</h2>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/36168d7a-e396-4282-8f9f-89dbb2528d2d/image.png" alt="">
위의 사진은 QANet에 대한 전체적인 모델 구조입니다. Encoder block인 하늘색 부분이 RNN이 아닌 convolution과 self-attention을 사용하는 transformer block을 사용하였습니다. 해당 QANet의 모델 구조를 각 layer별로 살펴보면 다음과 같습니다.</p>
<h3 id="input-embedding-layer">Input Embedding Layer</h3>
<p>해당 레이어는 처음 context와 question을 임베딩하는데 사용되는 레이어 입니다. Word embedding과 character embedding으로 이루어져 있으며, word embedding의 경우 pretraind GloVe를 사용하였습니다. Embedding layer에서 look-up한 후에는 2개의 highway network로 이루어진 convolution layer를 통과해서 아웃풋을 만들어냅니다. </p>
<h3 id="embedding-encoder-layer">Embedding Encoder Layer</h3>
<p>해당 레이어는 기존의 모델과는 다르게 RNN을 사용하지 않았으며, convolution과 self-attention을 사용한 transformer모델을 사용하였습니다. Convolution은 depthwise separable convolution을 사용하였으며, self-attention의 multi-head attention을 적용하였습니다. 그리고 각 convolution, self-attention, feed-forward 부분 모두 layer normalization 및 residual block으로 이루어져있습니다. </p>
<h3 id="context-query-attention-layer">Context-Query Attention Layer</h3>
<p>해당 레이어는 context 피쳐와 query 피쳐간의 유사도를 계산하여 어텐션을 계산하는 레이어 입니다. 먼저 유사 행렬 S를 만들고 행으로 정교한것이 context의 어텐션이며 열로 정교한것이 query의 어텐션 입니다. Query to context 어텐션의 경우 context to query 어텐션과 식이 다른데 이는 좀더 좋은 성능을 보이는 tcm 모델의 쿼리 투 컨텍스트 계산 방식을 가져왔습니다</p>
<h3 id="model-encoder-layer">Model Encoder Layer</h3>
<p>해당 레이어의 구조는 Embedding Encoder Layer와 동일하며, convolution layer의 갯수 및 block의 갯수의 차이만 존재합니다.</p>
<h3 id="output-layer">Output Layer</h3>
<p>해당 레이어는 정답을 예측하기 위한 레이어이고, 어떠한 task에냐에 따라 다르게 구성될 가능성이 있습니다. 본논문의 QANet의 경우 span-based 데이터셋에 대한 예시를 들고있기 때문에, start-index와 end-index를 예측하는 부분으로 output layer가 2개로 나누어져있습니다. </p>
<h3 id="back-translation">Back Translation</h3>
<p>Back Translation은 본 논문에서 추가 학습을 위해 사용되었으며, 구글에서 발표된 NMT모델(=번역모델)을 사용하여 하나의 데이터를 늘리는 데이터 agmentation 기법을 사용하였습니다. 
<img src="https://velog.velcdn.com/images/chanhee-kang/post/4930a683-1cd0-4eef-b019-9da6d7c542fc/image.png" alt="">
해당 기법은 위의 그림에서처럼 영어를 불어로 번역후 생성된 번역본을 다시 영어로 번역하는 방식입니다. 즉, 다시 번역한다는 의미를 담아서 back translation이라고도 부릅니다. 본 논문에서는 해당 방식을 사용하여 기존 데이터 대비 더 많은 학습을 진행하였으며, 기존 데이터 학습 성능보다 1.1 포인트의 F1 score 향상되었습니다.</p>
<h2 id="📌-결과">📌 결과</h2>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/87853a06-9b4f-4670-8b08-3054c91c9af6/image.png" alt="">
SQuAD 데이터셋의 공식 테스트셋에서 완전 일치를 나타내는 지표에서 76.2를 기록하였으며 F-1 스코어의 경우 84.6을 기록 하였습니다. 이는 본 논문이 출시되었을시 SOTA로 지정되었습니다.
<img src="https://velog.velcdn.com/images/chanhee-kang/post/5dd41894-c15a-4480-8c93-e563596a9e16/image.png" alt="">
위의 지표는 RNN모델과의 성능 차이를 기록한 지표입니다.
<img src="https://velog.velcdn.com/images/chanhee-kang/post/4a63a6c4-d669-436a-b2ae-1634b5e011e7/image.png" alt="">
위의 지표의 경우 BiDAF모델과의 비교 지표입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Neural Probabilistic Language Model 논문리뷰]]></title>
            <link>https://velog.io/@chanhee-kang/Neural-Probabilistic-Language-Model-%EB%85%BC%EB%AC%B8%EB%A6%AC%EB%B7%B0</link>
            <guid>https://velog.io/@chanhee-kang/Neural-Probabilistic-Language-Model-%EB%85%BC%EB%AC%B8%EB%A6%AC%EB%B7%B0</guid>
            <pubDate>Sun, 05 Feb 2023 08:34:23 GMT</pubDate>
            <description><![CDATA[<p>본 포스팅에서는 <strong>Neural Probabilistic Language Model(NPLM)</strong>의 논문에 대해 리뷰를 해보도록 하겠습니다.</p>
<p>Statical language model은 단어의 시퀀스(Sequence)의 probability function을 찾는데 의의를 둡니다. 하지만 본 논문에서는 이러한 경우 <strong>curse of dimensionality</strong>라는 차원의 저주가 발생한다고 하였습니다. </p>
<p>Curse of dimensionality는 단어와 같은 sequential한 데이터를 학습 시킬때, 차원이 증가함에 따라 학습데이터의 수가 생성된 차원의 수보다 적어지면서 모델의 성능이 저하되는 현상을 의미합니다.</p>
<h2 id="📌-curse-of-dimensionality">📌 Curse of dimensionality</h2>
<p>기계에게 단어를 인식시키기 위해서는 단어를 숫자로 변환해주어야 합니다. 이러한 방법중 <strong>one-hot-encoding</strong>이 존재하는데, 이는 $n$개의 단어를 각각 $n$차원의 벡터로 표현해주는 방식입니다.</p>
<p>즉, 단어가 포함되는 자리에 1을 넣은후 나머지는 0을 넣는다고 이해하면된다. 하디만 이러한 방식은 단어의 의미와 개념의 차이를 담아내기 어렵습니다. </p>
<p>One-hot vector는 1개의 요소만 1이고 나머지는 0 인 희소 벡터 형태를 띄기 떄문입니다.이때 단어의 내적은 0을 띄우며 직교형식을 이루며, 사전 내의 단어가 무수히 많다면, 예를들어 a라는 자연어가 10만개 존재한다면 a를 표현하기위해서는 10만개의 차원을 형성해내는 curse of dimensionality에 빠질 가능성이 존재합니다.이러한 Curse of dimensionality는 모델의 테스트를 위한 단어의 시퀀스가 트레이닝시 등장할 단어의 시퀸스와 다른 현상이 발생될 가능성이 존재합니다. </p>
<p>따라서 본 논문은 이러한 <strong>curse of dimensionality의 문제를 distributed representation(분산표상)</strong>을 통해 해결하고자 하였습니다. 즉, probability function에 대해 neural netwrok를 사용하는 단어에 distributed representation을 학습시켜 curse of dimensionality를 해결하는 방법을 제시하였습니다.</p>
<h3 id="distributed-representation분산표상">Distributed Representation(분산표상)</h3>
<p>Distributed Representation은 curse of dimensionality의 문제를 해결하기 위한 방법 중 하나입니다. One hot vector에서의 차원 의 수는 전체 단어의 수가 되는데 이를 더작은 $n$차원 벡터로 바꿉니다. </p>
<p>Distributed Representation으로 표현된 단어의 벡터는 연속형의 실수값이되며 이는 비슷한 분포를 가진 단어의 주변 단어들도 비슷한 의미를 가진다는것을 의미합니다. 또한 내의 각각의 차원은 정보를 내포하고있어 벡터연산을 통해 벡터간 similarity를 구할 수 있습니다.</p>
<h2 id="📌-neural-probabilistic-language-modelnplm">📌 Neural Probabilistic Language Model(NPLM)</h2>
<p>Neural Probabilistic Language Model(NPLM)은 curse of dimensionality를 해결하기 위해 효과적이면서 효율적인 확률 모델링 기법을 제시합니다. 그리고 모델의 단어의 시퀀스가 서로 달라지는 현상에 대한 해결방법 역시 제시 하였습니다. </p>
<p><strong>Neural Probabilistic Language Model(NPLM)은 어휘 내 각 단어들을 분산된 단어 백터와 연관시키고 시퀀스에서 이 단어들의 벡터로 단어 시퀀스의 결합 함수를 표현하고, 단어 벡터와 파라미터를 동시에 학습 하는 모델입니다.</strong> 또한 단어에 대한 확률함수는 문맥상 단어에 대한 벡터의 입력 시퀀스를 다음 단어에 대한 조건부 확률 분포에 mapping을 합니다. </p>
<p>즉, Neural Probabilistic Language Model(NPLM)은 각 단어의  distributed representation과  distributed representation에 대한 함수로써, 시퀀스의 확률함수를 학습합니다. 또한, Neural Probabilistic Language Model(NPLM)의 신경망에는 tanh화 되어있는 hidden layer와 output의 경우 softmax 함수로 이루어져있습니다.</p>
<p>본 논문의 경우 총 2가지의 데이터로 실험을 진행 하였습니다. 먼저 brawn campus의 경우 1,101,401개의 단어로 구성되었으며 이중 대략 8:2의 비율로 학습을 진행 하였습니다. 또한 AP Nese Corpus의 경우 14million 개의 단어로 학습을 진행하였으며, 이중 1million개의 단어를 각각 test 및 validation 데이터로 사용하였습니다. </p>
<p>그리고 Neural Probabilistic Language Model(NPLM)와의 비교를 위해 Smoothed trigram model과 back-off-n-gram model를 사용 하였습니다. Neural Probabilistic Language Model(NPLM)의 결과로는 neural network를 사용할때 좋은 결과를 얻을 수 있었으며, MLP(Multi-layer perceptron)을 적용 시켰을 때 Brown corpus의 경우 대략 24% 그리고 AP Nese Corpus 8%의 차이가 존재 하였습니다.</p>
<h2 id="nplm의-동작-과정">NPLM의 동작 과정</h2>
<p>Neural Probabilistic Language Model(NPLM)은 단어의 시퀀스가 제공되었을 때, 다음단어가 무엇인지 맞추는 과정에서 학습을 진행한다고 합니다. 즉 $n-1$개의 단어로 다음단어를 예측하는한다고 합니다. 즉 아래의 수식과 같이 나타낼수 있습니다.</p>
<p>$$
P\left(w_t \mid w_{t-1}, \ldots, w_{t-n+1}\right)=\frac{\exp \left(y_{w_{\mathrm{t}}}\right)}{\sum_i \exp \left(y_i\right)}
$$</p>
<p>수식을 살펴보면, NPLM은 위의 조건부 확률을 최대화 하려고 합니다.
그리고 NPLM의 밑부분 출력은 $|v|$ 차원의 score vector $y_{w}$에 softmax 함수를 적용한 $|v|$ 차원의 확률 벡터라고 합니다. 이때 $y_{wt}$는 다음과 같이 정의 됩니다.
$$
y_{w_t}=b+U \cdot \tanh \left(d+H \cdot x_t\right)
$$
즉 NPLM은 $y_{wx}$에 softmax를 적용시킨후 <strong>backpropogation</strong> 하는 방식으로 학습합니다. NPLM의 입력은 문장의 n번째 단어$w_t$에 대응하는 단어 백터 $x_t$를 만드는 과정입니다. 이러한 Nueral Probabilistic Language Model의 구조를 살펴보면 다음과 같습니다.
<img src="https://velog.velcdn.com/images/chanhee-kang/post/a9eb1eca-c873-4954-a7bb-dde9d056d088/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Subword model은 무엇일까?(ft. FastText)]]></title>
            <link>https://velog.io/@chanhee-kang/Subword-model%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8Cft.-FastText</link>
            <guid>https://velog.io/@chanhee-kang/Subword-model%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8Cft.-FastText</guid>
            <pubDate>Sun, 05 Feb 2023 08:22:22 GMT</pubDate>
            <description><![CDATA[<p>본 포스팅에서는 <strong>FastText(Enriching Word Vectors with Subword Information)</strong> 논문에서 말하는 <strong>Subword model</strong>에 대해 리뷰해 보도록 하겠습니다.</p>
<h2 id="📌-서론">📌 서론</h2>
<p>FastText는 2017년 ACL에서 발표되었으며, 오늘날 워드임베딩의 개념인 <strong>word vectors representation</strong>을 학습시키는 방법에 대한 논문입니다. 본 논문이 등장 할 때 까지만 해도 워드 임베딩(word embedding)이라는 단어 대신 distributed 혹은 continious word represnetation이라는 단어가 주로 사용되었습니다. FastText은 Word2vec을 타겟 논문으로 잡았으며, word2vec의 몇가지 한계점에 대해 언급했습니다.</p>
<h2 id="📌-word2vec의-한계점">📌 Word2Vec의 한계점</h2>
<p>Word2Vec의 한계는 하나의 단어에 고유한 벡터를 할당 하기 때문에 단어의 형태학적 특징을 반영할수 없습니다. 예를 들어 go와 going이 라는 단어가 있다고 가정해 봅시다. Word2vec은 2개의 단어인 go 와 going에 대해 각각 고유한 벡터를 할당합니다.</p>
<p>이 두 단어는 근본적으로 &#39;go&#39;라는 같은 의미를 가짐에도 불구하고 서로다른 벡터를 할당받게 됩니다. 벡터 a가 go에 할당되고 b가 going에 할당되는 의미입니다. 이런식으로 같은 의미를 가진 단어들에 서로 다른 벡터를 할당하게 되면, 단어의 수가 기하급수적으로 많은 경우의 학습이 제대로 이루어지지 않을 가능성이 존재합니다</p>
<h3 id="word2vec의-학습방법continuous-skip-gram">Word2Vec의 학습방법(Continuous Skip-gram)</h3>
<p>word2vec모델의 학습방법은 총 <em>w</em>개의 단어가 있을때 각 단어들의 단어들에 대해 백터를 할당해주고 주변에 있는 단어들에 대해 어떠한 단어들이 올지 잘 예측할수 있게 학습 진행하게 됩니다.
$$
\sum_{t=1}^T \sum_{c \in C_t} \log p\left(w_c \mid w_t\right)
$$</p>
<p>먼저 수식을 통해 간략하게 살펴보며는 $w_{1}...w_{n}$개의 단어 시퀀스가 있다고 가정했을 때, $w_{t}$라는 주변의 문맥단어인 $w_{c}$를 잘 맞추는 방식으로 학습이 진행 됩니다. 즉 $w_{c}$가 어떤 단어들이 왔을때, 확률값이 가장 높은 지를 최적화하는 방법으로 학습이 진행됩니다. 또한 $w_{c}$와 $w_{t}$는 서로다른 벡터를 지니게 됩니다. 즉 위의 2개의 벡터를 가지고 확률값을 만들어야 합니다.
$$
p\left(w_c \mid w_t\right)=\frac{e^{s\left(w_t, w_c\right)}}{\sum_{j=1}^W e^{s\left(w_t, j\right)}}
$$
Training focus에있는 모든 vocabulary에 대해서 $w_{t}$가 주어졌을때  다른 모든단어들이 등장할 확률을 더한 것 분의 $w_{t}$가 주어졌을때 실제 정답인 문맥 단어 $w_{c}$가 등장할 확률을 분자로가면 확률값을 구할 수 있습니다.</p>
<p>대표적으로 이러한 경우 우리는 대표적으로 <strong>softmax</strong>를 사용하게 됩니다. 하지만 word2vec은 softmax를 사용하지 않는데, 이는 주변 문맥단어 한개에 대해 잘맞출수 있지만, 주위 다른단어들에 대해서는 예측이 어려운 상황이 생깁니다. 예를들어 5개의 단어가 있고 가운데에 $w_{t}$라는 단어가 주어졌을 떄 가운데 $w_{t}$를 보고 주위 단어를 맞춰야하는데, 1번째 단어가 잘 맞춰지도록 학습이 되면 2,4,5번째 단어들을 맞추기 어렵습니다.
$$
\log \left(1+e^{-s\left(w_t, w_c\right)}\right)+\sum_{n \in N_{t, c}} \log \left(1+e^{s\left(w_t, n\right)}\right)
$$</p>
<p>따라서 word2vec은 softmax대신 <strong>네게티브샘플링(Negative Sampling)</strong>을 진행하게 됩니다. 간략하게 네거티브샘플링에 대해 설명드리면, 학습과정에서 전체 단어집합이 아니라 일부 단어 집합에만 집중하도록 하는 방법입니다.</p>
<h2 id="📌-subword-model">📌 Subword Model</h2>
<p>FasText논문에서는 <strong>subword model</strong>에 대한 중요성을 강조합니다. Subword model은 기존의 word2vec에서는 하나의 단어에서 주변단어들의 정보만을 가지고 지금현재 단어의 백터를 만들기 때문에 go와 going에서 둘이 동일하다는 내재적 정보를 반영하지 못하는 단점이 있습니다. Subword model의 경우 이를 다음과 같이 해결 합니다.
$$
\left.\left.\mathcal{G}<em>{\text {where }}={&lt;w h, \text { whe, her, ere, re }\rangle, \quad&lt;\text { where }\right\rangle\right}
$$
위의 그림과 같이 where 이라는 단어를 예를들면 where에 대해 각각을 나눌수 있는 모든 n-gram으로 나누게 합니다. 예를들면 $n=3$ 이면, $&lt;wh, whe, her, ere, re&gt;$경우로 나눕니다.  모든 <strong>n-gram으로 나눌수 있는 모든 경우의 수들의 단어들의 벡터를 더한값을 where의 백터로 나타나는게</strong> subword model 입니다. 이것을 다시 수식으로 살펴보면 다음과 같습니다.
$$
s(w, c)=\sum</em>{g \in \mathcal{G}_w} z_g^T v_c
$$
여기서 $g$의 경우는 n-gram의 dictionary의 사이즈를 의미하고, $g_w$는 단어 $w$에서 나올 수 있는 모든 n-gram의 경우의 세트이며, $z$는 n-gram의 각각 vector representaiton입니다.
<img src="https://velog.velcdn.com/images/chanhee-kang/post/cb666343-6322-442e-b3f6-422c55348887/image.png" alt=""></p>
<p>위의 그림을 살펴보면 Orange라는 단어가 주어졌을때 orange에 대해 n-gram에 대한 모든 경우의 수로 나타내면 총  n=2 부터 5까지로 나타나게 됩니다. 여기서 n이 2~5일때 까지의 n-gram의 경우의 수를 모두 더한값을 orange에 대한 하나의 백터로 사용하게 됩니다.
<img src="https://velog.velcdn.com/images/chanhee-kang/post/f09dbf23-7149-4324-8572-9e8d2c292efa/image.png" alt="">
Subword modeld은 이렇게 모든 n-gram에 대한 경우의 수들의 합을 사용하므로써, 모르는 단어(Out Of Vocabulary, OOV)에 대해서도 다른 단어와의 유사도를 계산할 수 있어 위의 그림과 같이 oranges 라는 모르는 단어가 발생됬을때 해당 문제를 해결할수 있습니다.</p>
<h3 id="subword-model의-성능">Subword Model의 성능</h3>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/d80a8f8c-af5e-4cac-9c4a-474ab5d7c463/image.png" alt="">
위의 그림은 FastText를 De-GUR350데이터와 EN-RW의 데이터를 가지고 학습을 했을때 성능에 대한 지표입니다. 
<strong>sisg</strong> : FastText 모델
<strong>sigs- *<em>: OOV문제를 해결하지 않은 FastText 모델
*</em>cbow</strong> : Word2Vec의 CBOW 모델
<img src="https://velog.velcdn.com/images/chanhee-kang/post/f5179471-08aa-48d2-be91-d4d55cf8e8c7/image.png" alt="">
더나아가, young 과 preadolescent가 주어졌을때, 위의 차트를 보면 dole과 young의 유사도가 높은걸을 확인 할 수 있습니다. 여기서 preadolescef를 학습할때 young을 일부 반영하여 학습이 진행되는 점 역시 확인 할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Confusion matrix(혼동 행렬) 및 평가지표]]></title>
            <link>https://velog.io/@chanhee-kang/Confusion-matrix%ED%98%BC%EB%8F%99-%ED%96%89%EB%A0%AC</link>
            <guid>https://velog.io/@chanhee-kang/Confusion-matrix%ED%98%BC%EB%8F%99-%ED%96%89%EB%A0%AC</guid>
            <pubDate>Sun, 05 Feb 2023 07:32:39 GMT</pubDate>
            <description><![CDATA[<p>이번 포스팅에서는 ML모델의 평가 지표중 하나인 <strong>Confusion Matrix</strong>랑 이를통한 평가지표(accuracy, precision, recall, f-1 score) 대해 진행해 볼려구 합니다.</p>
<p>모델에 대한 성능 평가를 위해서 일반적으로는 정확도(accuracy)라는 기준을 주로 사용하는데, 정확도만을 이용하여 모델을 평가하기에는 충분하지 않을 수 있습니다. 예를 들어 이번 코로나 감염에 대해 머신러닝을 통해서 분류한다고 가정해 봅시다. 코로나의 발병률은 일반적으로 극히 낮기에 ‘코로나에 걸리지 않았다’라고 학습하게 되면 모델의 예측 정확도가 거의 100%에 수렴할 수 있습니다. 하지만 이 모델에서는 코로나에 진짜 걸렸는지를 잘 판별하고 싶었던 것이지, 코로나에 안 걸렸다는 사실을 판별하고 싶었던 것은 아닐 것입니다. 이러한 상황을 불균형 데이터(skewed class)문제라고 합니다.</p>
<h2 id="📌-confusion-matrix">📌 Confusion matrix</h2>
<p>정확도만으로는 모델의 성능평가가 힘든데, 이때 주로 <strong>confusion matrix</strong>를 활용하기도 합니다. Confusion matrix는 데이터의 예측 범주와 실제 범주를 교차 표의 형태로 정리한 행렬을 의미하는데, 가설 검정시에 <strong>1종 오류(type 1 error)</strong> 와 <strong>2종 오류(type 2 error)</strong>의 개념을 분류하기 위해 주로 언급되기도 합니다.</p>
<p>머신러닝에서도 confusion matrix는 예측데이터와 실제 데이터를 비교해서 분류가 얼마나 잘 되었는지를 보는 방법으로, 비유하자면 기계가 푼 시험지를 정답을 두고 채점하는 방식이기 때문에 <strong>지도학습(supervised learning)</strong> 에서 쓰이는 개념이라고 할 수 있습니다. </p>
<p>Confusion matrix는 ‘코로나에 걸렸는가’라는 명제를 가지고 2진법(binary) 기계학습을 한다고 가정해봅시다. 2진법은 ‘Yes or No’이므로, 머신러닝을 통해 분류를 하면 코로나에 걸렸다고 예측한 긍정(positive) 데이터와 코로나에 걸리지 않았다고 예측한 부정(negative) 데이터 얻을 수 있을 것입니다. 이 데이터들을 참인가(True) 거짓인가(False)로 판별하여 2x2의 모형을 만드는 것이 바로 Confusion matrix입니다.</p>
<p>따라서 Confusion matrix에는 총 4개의 분류기준(parameters)이 있습니다. 참인데 참이라고 분류한 경우(true positive, TP), 거짓인데 참으로 분류한 경우(false positive, FP), 거짓인데 거짓으로 분류한 경우(true negative, TN) 및 참인데 거짓으로 분류한 경우(false negative, FN)로 나누어집니다. 이를 보기쉽게 표로 표현하면 아래와 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/ab09251d-06d0-42c7-a29c-0c3ff203848f/image.png" alt=""></p>
<h2 id="📌-평가지표">📌 평가지표</h2>
<h3 id="정확도accuracy">정확도(Accuracy)</h3>
<p>정확도는 모델의 성능을 가장 직관적으로 보여주는 지표로써 실제 분류 범주를 올바르게 예측한 비율을 의미합니다. 전체 데이터인 TP, FN, FP, TN 중 기계가 정확히 분류해낸 TP와 TN이 전체에서 얼마나 비율을 차지하는지를 보고 모델의
정확도를 평가하는 척도입니다.</p>
<h3 id="정밀도precision">정밀도(Precision)</h3>
<p>정밀도는 참이라고 예측된 데이터인 TP와 FP 중에서 실제로 참인 데이터인 TP의 비율을 측정하는 방법입니다. 즉, 1종 오류(실제로는 틀렸지만 옳다고 판단하는 경우)와의 비율을 통해 모델의 신뢰도를 측정하는 방법이라고 할 수 있습니다.</p>
<h3 id="재현도recall">재현도(Recall)</h3>
<p>재현도는 정밀도와 비교되는 척도이며, 실제로 참인 TP와 FN 데이터 중에서 기계가 올바르게 예측한 TP의 비율을 측정하는 방법입니다. 2종 오류(실제로는 맞지만 틀렸다고 하는 경우)와의 비율을 통해 모델의 실용성을 측정하는 방법으로 민감도(sensitivity)라고 불리기도 합니다.</p>
<h3 id="f-1-score">F-1 Score</h3>
<p>F-1 score는 정밀도와 재현도의 조화평균(harmonic mean)으로 정밀도와 재현도의 밸런스를 고려하여 모델을 평가하는 방법입니다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[랜덤포레스트(Random Forest)]]></title>
            <link>https://velog.io/@chanhee-kang/%EB%9E%9C%EB%8D%A4%ED%8F%AC%EB%A0%88%EC%8A%A4%ED%8A%B8Random-Forest</link>
            <guid>https://velog.io/@chanhee-kang/%EB%9E%9C%EB%8D%A4%ED%8F%AC%EB%A0%88%EC%8A%A4%ED%8A%B8Random-Forest</guid>
            <pubDate>Sun, 05 Feb 2023 07:27:06 GMT</pubDate>
            <description><![CDATA[<p>이번 포스팅에서는 tree 구조의 앙상블 학습방법인** 랜덤포레스트(Random Forest)** 에 대해 써보겠습니다. 랜덤포레스트는 기계학습의 일종으로, 분류, 회귀 분석 등 의 문제에 활용되며 훈련 과정에서 구성한 다수의 결정 트리로부터 분류 또는 평균 예측등에 주로 사용됩니다.</p>
<h2 id="📌-decision-tree의사결정나무">📌 Decision Tree(의사결정나무)</h2>
<p>먼저, 랜덤 포레스트를 이해하기 위해서는 랜덤 포레스트를 구성하는 <strong>decision tree</strong>에 대한 사전 지식이 요구됩니다. Decision tree는 의사 결정에 필요한 경로와 결과를 나무 구조로 시각화하여 분류와 예측을 수행하는 분석방법 입니다. Decision tree의 핵심은 노드(node) 로, 각 노드가 yes or no를 선택하는 하나의 분기점이라고 볼 수 있습니다. 이 개념은 분류(classfication) 혹은 예측을 나무 형태로 visualizing 된 추론 규칙에 따라 표현할 수 있기 때문에, 다른 방법들과 비교했을 때 그 과정을 쉽게 이해할 수 있습니다.
<img src="https://velog.velcdn.com/images/chanhee-kang/post/6b05ad57-a819-4403-bf2b-f2344904f1cf/image.png" alt="">
위의 그림에서 제일 처음 시작되는 질문인 뿌리 <strong>노드(root node)</strong> 가 있고 제일 끝에 형성되는 <strong>끝노드(terminal node)</strong> 가 있으며 그사이에 <strong>중간 노드(intermediate)</strong> 들이 있습니다. 뿌리 노드에서 그 아래 노드로 갈수록 데이터의 개수는 점점 줄어들게 되고 끝노드에 속하는 데이터의 개수를 합하면 뿌리 노드의 데이터 수와 일치하 게 된다. 즉, 끝노드 간의 교집합이 없으며 끝노드의 개수가 분리된 데이터의 수 만큼 나타나게 된다. 위의 그림 상황에 적용해보면, 끝마디가 7개라면 전체 데이터가 7개의 부분집합으로 나누어진 것으로 볼 수 있습니다.</p>
<h3 id="타이타닉-데이터셋을-통한-decision-tree-설명">타이타닉 데이터셋을 통한 Decision Tree 설명</h3>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/3c4f71c1-bb50-43d8-9daf-3cd4ed5ab9a6/image.png" alt="">
위의 그림은 Kaggle의 머신러닝 입문 데이터셋중 하나인 타이타닉 생존자를 찾는 것에 대한 decision tree입니다. 각 노드당 질문을 보면 조건들이 있고 뿌리 노드를 시작으로 질 문에 질문이 꼬리에 꼬리를 무는 형식이다. 뿌리 노드를 보면 ‘성별 &lt;= 0.5’ 라고 되어 있는 데 이것은 남자인가? 여자인가? 라고 질문하는 것과 같고, 결과적으로 전체 승객에 대한 분류를 통해 생존 확률을 예측할 수 있습니다.</p>
<p>이처럼, 숫자형 결과 가 나오는 것을 <strong>회귀나무(regression tree)</strong> 라 하고, 범주형 결과가 나오는 것을 <strong>분류나무(classification tree)</strong> 라고 합니다. 의사 결정 나무를 만들기 위해서는 우선 어떤 질문을 어떤 순서로 할 것인지를 결정해야 한다. 질문을 고르는 가장 좋은 방법은 예측하려는 대상에 대한 가장 많 은 정보를 담고 있는 질문을 고르는 것이 좋습니다. 이렇듯 ‘정보를 얼마나 담고 있는가’의 정도를 <strong>엔트로피(entropy)</strong> 라고 표현이 됩니다. 이러한 엔트로피는 데이터의 불확실성 정도 를 나타내고 엔트로피가 클수록 데이터의 분포 정도가 커지기 때문에 엔트로피가 높은 값을 좋은 지표로 볼 수 있습니다.</p>
<p>Decision tree는 이해하기 쉽고 해석이 용이하다는 장점이 있으며 숫자형 및 범주형 데이터를 둘 다 처리할 수 있습니다. 하지만 decision tree는 overfitting될 위험이 높다라는 치명적인 단점이 존재합니다. Overfitting 이란 이전의 학습한 데이터에 대해서는 예측을 잘하지만, 새로운 데이터에 대해서는 예측 성능이 떨어지는 경우를 말하는데 이러한 과적합의 문제를 해결하기 위해 랜덤포레스트(Random Forest)가 등장한 계기가 됩니다.</p>
<h2 id="📌-random-forest랜덤-포레스트">📌 Random Forest(랜덤 포레스트)</h2>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/e5b7b5fb-6da8-4d71-947c-62af9652be8c/image.png" alt="">
랜덤 포레스트는 위에서 설명한 의사 결정 나무를 이용해 만든 알고리즘으로, 분류와 회귀 분석 등에서 자주 활용되는 앙상블학습 기법 중 하나입니다. 랜덤 포레스트에서의 랜덤(random)은 임의성을 뜻하며, 포레스트 (Forest)는 문자 그대로 숲을 의미하며 숲은 decision tree의 트리(Tree)가 모여 형성된것으로 이해할 수 있습니다.</p>
<p>Decision tree의 단점으로 주어진 데이터에만 학습이 잘되고, 새로운 데이터에 대해서는 학습 성능이 떨어지는 overfitting의 위험도가 높다는게 있는데, 이는 주어진 데이터에 대해서만 최적화되어 있어 normalize가 어렵다는 것을 의미합니다. 따라서 이러한 문제점을 해결하기 위해 랜덤포레스트는 임의대로 tree를 여러개 만들어 overfitting의 문제를 해결할려고 합니다. 임의대로 tree를 만들면 기존 decision tree에서 주어진 학습 데이터에 따라서 의사 결정 트리가 달라져서 일반화하여 사용하기 어렵다는 단점을 극복할 수 있기 때문입니다.</p>
<p>그리고 이렇게 임의대로 데이터를 중복을 허용하여 선택하는 방식을 <strong>부트스트랩(bootstrap)</strong> 이라고 합니다. 또한 임의로 선택하여 여러 개의 의사 결정 트리를 만들어 다수의 예측 결과를 활용하는 방식을 <strong>앙상블(ensemble)</strong> 기법이라고 합니다. 부트스트랩을 이용해 무작위성을 가진 의사 결정 트리의 집합인 랜덤 포레스트를 구성하고, 다양한 의사 결정 트리에 앙상블 기법을 적용하여 다수의 예측 결과를 내놓고, 이를 최종 하나로 합치는 것을 <strong>배깅(bagging)</strong> 이라고 합니다. 배깅은 부트스트랩(bootstrap)과 어그리게이팅(aggregating)을 합친 단어인데, 여러 개의 데이터를 임의로 선택해서 결과들을 모으고 다시 합치는 것을 의미한다.</p>
<p>예를 들어, 고려해야할 요소(Feature)들이 20개 있다고 합시다. 20개의 요 소를 기반으로 하나의 결정 트리를 만들 때, 트리의 가짓수가 많아지게 될 것이고, 이는 overfitting의 문제를 야기하게 될 것입니다. 그러나 20개의 요소들 중에서 임의로 5개의 요소만 선택해서 하나의 결정트리를 만들고, 또 20개 중 임의로 5개의 요소를 선택해서 또 다른 결정 트리를 만들고(이때 선택할 5개의 요소들은 중복을 허락하여 뽑는다.) 이렇게 수차례 반복해서 여러개의 decision tree를 만들 수 있게 됩니다. 각 결정 트리에서 예측 값을 내놓게 되고, 이러한 여러 예측 값들 중에서 가장 많이 나온 값을 최종 값으로 정하게 됩니다 이렇듯 하나의 크고 가짓수가 많은 결정 트리를 만드는 것이 아닌 여러 개의 작은 결정 트리를 이용해 값을 분류하는 방식인 것입니다.</p>
<h2 id="📌-마무리">📌 마무리</h2>
<p>실상활의 예를들어 쉽게 decision tree와 랜덤포레스트를 설명해보면, decision tree는 내가 회식메뉴를 고르는 과정이라고 설명할 수 있을꺼 같습니다. 반면, 랜덤포레스트의 경우는 나 뿐만 아니라 내팀 혹은 부서원들이 각자 회식 메뉴를 골라서 투표를 통해 과반수 이상의 투표를 받은 메뉴가 회식 메뉴로 정해지는 의사결정하는 방법이라 할 수 있을 꺼 같습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CNN(Convolutional neural network)의 배경]]></title>
            <link>https://velog.io/@chanhee-kang/CNNConvolutional-neural-network%EC%9D%98-%EB%B0%B0%EA%B2%BD</link>
            <guid>https://velog.io/@chanhee-kang/CNNConvolutional-neural-network%EC%9D%98-%EB%B0%B0%EA%B2%BD</guid>
            <pubDate>Sun, 05 Feb 2023 07:14:30 GMT</pubDate>
            <description><![CDATA[<p>본 포스팅에서는 대략적인 CNN이라고 불리는 Convolutional neural network의 역사에 대해 진행해보려구합니다. </p>
<p>최근 뉴스에서 인공지능이 하나의 주요 이슈로 부상하면서 우리는 머신러닝, 딥러닝이라는 말을 많이 들어보았을겁니다. 그럼 왜 인공지능이 주요이슈로 부상했을까요? 제가 생각하는 이유로는 인간이 생성하는 <code>sequential data</code>가 비로소 기계가 잘 처리할수 있게 되었기 떄문일거라 생각합니다. </p>
<h2 id="📌-sequential-data">📌 sequential data</h2>
<p>여기서 <code>sequential data</code>는 <strong>데이터 집합 내의 객체들이 어떤 순서를 가진 데이터</strong>로 그 순서가 변경될시, 데이터의 고유 특성을 잃어버릴 수 있습니다. 예를 AAPL의 2022년 1월 31일 부터 2월 3일까지의 데이터를 확인해 보겠습니다.</p>
<pre><code class="language-python">import yfinance
df = yfinance.download(&#39;AAPL&#39;,start = &#39;2022-01-31&#39;, 
                        end = &#39;2022-02-03&#39;)[&#39;Open&#39;]

print(df)
Out[01]: 
Date          Open
2022-01-31    170.160004
2022-02-01    174.009995
2022-02-02    174.750000
2022-02-03    174.479996
Name: Open, dtype: float64</code></pre>
<p>AAPL의 시가를 살펴보면 <code>170.160004</code>, <code>174.009995</code>, <code>174.750000</code>, <code>174.479996</code> 로 이루어진것을 확인해 볼 수 있습니다. 만일 여기서, 시가가 <code>174.479996</code>, <code>174.750000</code>, <code>174.009995</code>, <code>170.160004</code>의 inverse된 형태로 바뀐다면, 이는 앞선데이터와 같은 데이터 일까요? </p>
<p>둘은 완전히 다른 데이터 입니다. 즉, <strong>sequential data</strong>는 데이터의 값 뿐만 아니라 데이터의 위치까지 중요한 요소로 포함됩니다. 주식뿐만아니라, 이미지도 마찬가지입니다. 만일 너구리의 사진이 주어졌을때, 우리가 생각하는 너구리의 사진이 아닌 눈,코,입,팔,다리가 각 픽셀별로 뒤바껴있는 사진은 우리에게 온전한 너구리사진으로 인식되지 않을겁니다. </p>
<p>이처럼 <strong>sequential data</strong>는 값이 온전히 존재하냐 뿐만 아니라, 해당 값이 어느위치, 몇번째에 존자하는가도 중요한 데이터를 의미합니다. 그리고 본 포스팅에서 이루어질 CNN(Convolutional neural network)은 여러 sequentail data 중 이미지를 잘 처리하는 뉴럴넷 모델이라고 생각합니다.</p>
<h2 id="📌-cnn의-배경">📌 CNN의 배경</h2>
<p>만일 아래과 같은 손글씨 데이터셋이 주어졌다고 합시다.
<img src="https://velog.velcdn.com/images/chanhee-kang/post/4df80555-7741-4142-864a-de28ce057f29/image.png" alt="">
해당 손글씨 데이터를 구분하기위해, 뉴럴넷을 사용하지 않고 순수 코딩으로 프로그래밍을 한다고 가정하면, 우리는 <strong>IF문</strong>을 통해 <strong>pixel-pixel</strong>의 형태를 일일히 비교해가면서 주어진그림이 어떤숫자인지 classify 할 것입니다. </p>
<p>만약 각 숫자의 대한 변형이 5가지라면, 어찌저찌 IF문을 통해 classify 할 수있겠지만 숫자의 변형이 많아질 수록 코드를 짜는 시간은 기하급수적으로 늘어날 것 입니다.</p>
<p>하지만 이를 pixel-pixel 이 아닌 <strong>local feature</strong>로 비교하는건 어떨까요? 사람은 사진을 비교할때 각 pixel 별로 비교하지 않고 각 그림의 local feature를 찾아내고 local feature를 추출하고 각 local feature와 다른 local feature를 비교해서 두 사진이 같은지 다른지를 판단합니다. </p>
<p>그리고 이런식으로 프로그래밍을 한게 convolution이며 이를 뉴럴넷 형태로 발전 시킨것이 <strong>CNN(Convolution neural network)</strong> 라고 생각이 듭니다. CNN이 sequential data 중 이미지에 좋은 성능을 보이는 이유도 이미지를 비교할때 local feature를 찾아내고 그 local feature 끼리 비교하자라는 아이디어에서 시작된게 바로 CNN 이기 때문입니다.</p>
<p>보다 정확하게 CNN의 기원을 살펴 보자면 David Hubel과 Torseten Wiesel은 1958년과 59년에 진행된 시각 피질의 구조에 대한 결정적 통찰을 제공한 고양이 실험에서의 고수준의 뉴런이 저수준의 뉴런의 출력에 기반한다는 아이디어로 출발하게 되었다. 그리고 이러한 아이디어는 <strong>Backpropagation applied to handwritten zip code recognition</strong>이 나오면서 CNN의 처음 소개되는 계기가 됬으며, 1998년 Yann Lecn et al.의<strong>Gradient-based learning applied to document recognition</strong>의 <strong>LeNet</strong>이 나오면서 CNN의 본격적인 구조가 탄생되었습니다.</p>
<h2 id="📌-cnn의-발전과정">📌 CNN의 발전과정</h2>
<h3 id="lenet---gradient-based-learning-applied-to-document-recognition1998">LeNet - Gradient-based learning applied to document recognition(1998)</h3>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/4bdf0009-9655-4514-86f0-cf425aa64a4d/image.png" alt="">
LeNet은 CNN의 기반을 구성했으며 input layer, convolution layer, subsampling layer, fully connected layer, output layer로 구성되는 것을 확인 할 수 있습니다. LeNet은 LeNet1을 시작으로 input의 크기 및 convolution kernal의 크기 LeNet5까지 발표되었으며, CNN 이전의 fully connected neural network의 topology 나 noise에 대한 이슈에 잘 대응하는것으로 확인되었습니다.</p>
<h3 id="alexnet---imagenet-classification-with-deep-convolutional-neural-networks2012">AlexNet - ImageNet Classification with Deep Convolutional Neural Networks(2012)</h3>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/2c036ee1-aaae-454f-b524-8b2ef4222ed7/image.png" alt="">
AlexNet은 CNN의 구조를 담고있는 뉴럴넷으로 LeNet-5와 유사하지만 병렬적인 구조로 설계되었습니다. 실제 위의 그림에서 확인 할 수 있듯이 AlexNet은 병렬적 구조를 제외하고는 LeNet-5와 유사한 형태로 나타납니다. AlexNet은 총 8개의 layer로 구성되었으며 8개의 layer는 5개의 convolution layer와 3개의 fully connected layer로 구성되었습니다.</p>
<p>그리고 마지막 fully connected layer의 경우 category 분류를 위해 softmax 함수로 설계된것을 확인 할 수 있습니다. AlexNet의 경우 성능 향상을 위해 2개의 GPU 사용을위한 병렬구조, activation function 으로 Relu를 사용하였으며, polling의 경우 현재도 많이 사용되는 max pooling을 사용하였습니다. 또한 ML 혹은 DL 모델 개발시 발생되는 오버피팅 문제를 해결하기위해 dropout 기법을 사용하였습니다.</p>
<h3 id="zfnet---adaptive-deconvolutional-network-for-mid-and-high-level-feature-learning">ZFNet - Adaptive Deconvolutional Network for Mid and High-level Feature Learning</h3>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/60b63d43-17f3-4fc9-842e-6e8cb7cd5ced/image.png" alt="">
Layer가 많이 생길수록(=deep neural network) 하이퍼파라미터 튜닝은 중요한 문제입니다. ZFNet은 새로운 CNN의 모델구조를 제시했다기  보단 visualizing 기법을 통해 이러한 문제를 해결하려고 시도하였습니다.</p>
<h3 id="vggnet---very-deep-convolutional-networks-for-large-scale-image-recognition-2014">VGGNet - Very Deep Convolutional Networks for Large-Scale Image Recognition (2014)</h3>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/afb32fac-c7af-4993-9348-7b36cec6b0ea/image.png" alt="">
CNN기반인 AlexNet이 좋은 성과를 내면서 더욱 발전된 후속 모델들이 나왔습니다. VGGNet는 모델의 제목에서 유추할수 있듯이 모델의 lyaer를 많이 쌓을 수록 CNN 모델의 성능에 어떠한 영향을 미치는지에 대해 집중하여 ILSVRC에서 준우승을 차지한 모델입니다.</p>
<p>VGGNet은 모델의 깊이가 어떠한 영향을 끼치는지 알기위해 3x3크기의 layer를 겹쳐서 사용하였습니다. ILSVRC의 데이터의 경우 16개의 layer이후 부터는 성능에 별다른 소득을 주지 못한것을 확인 하였습니다. 또한, VGGNet은 3x3 convolution layer 2개와 5x5 convolution layer 1개의 성능 차이를 비교하였는데, 3x3 convolution layer 2개를 사용하는 편이 모델을 deep하게 만들고 파라미터 수 를 줄일 뿐만아니라 non-linearity activation function을 통해 feature추출 특성이 좋아짐을 확인 하였습니다.</p>
<h3 id="googlenet---2014">GoogLeNet - (2014)</h3>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/df1a00bc-8778-49df-a09b-0bee083b91da/image.png" alt="">
앞서 말한 VGGNet이 ILSVTC에서 준우승을 차지했다면, GoogLeNet의 경우 동일 대회에서 우승을 차지한 모델로써 VGGNet과 유사하게 22개의 layer를 쌓음으로써 CNN을 좀더 deep하게 만들었습니다.</p>
<p>GoogLeNet은 기계의 자원을 효율적으로 이용하면서 학습 능력을 극대화 할 수 있는 deep 한 CNN모델을 설계하는 것에 초점을 맞추었습니다. 이에GoogLeNet 에는 총 9 개의 Inception이라는 기본 모듈을 중첩시키는 구조를 사용하였습니다. 또한 local field에서 다양한 feature들을 추출하기 위해서 여러개의 convolution을 병렬적으로 확용하였습니다.</p>
<p>처음에는 1x1 convolution, 3x3 convolution, 3x3 max pooling로 구성하려고 했으나 3x3과 5x5의 convolution 연산량은 부담이 되어 망의 깊이와 넖이가 커질수록 GoogLeNet에 악영향을 끼칠수도 있었습니다. 이에 3x3과 5x5 convolution layer 앞에 1x1 convolution을 cascade 구조로 두면서 feature map의 차원을 줄이면서, 다양한 scale을 확보하면서 연산량의 균형을 맞출수 있게 되었습니다.</p>
<p>GoogLeNet은 이런식의 inception을 구축하고 NIN(Network In Network; CNN의 convolution layer의 local field에서 feature을 찾는 성능은 우수하지만 filter가 linear하기 때문에 non-linear한 feature를 찾는데 어려움이 존재하여, feature map의 수를 늘리는 형식으로 non-liner한 상황을 지원하는 filter를 설계하여 한계를 극복하며[= MLP convolutional layer], global average pooling을 사용) 구조로 사용된 모델입니다. 하지만 이러한 성능 및 구조에도 불구하고 ResNet의 단순성, 확장성 및 성능으로 후퇴하게 되었습니다.</p>
<h3 id="resnet-2015">ResNet (2015)</h3>
<p><img src="https://velog.velcdn.com/images/chanhee-kang/post/1831abe8-2de1-4244-accd-74ab894cf306/image.png" alt="">
위에서 말한 내용처럼 2014년에는 CNN의 layer가 깊게 설계된 모델이 주목을 받았습니다. ResNet은 residual learning, shortcut, identity mapping 과 같이 이전의 CNN 구조에서 찾기 힘든 용어들이 사용되며, 152의 layer의 구조를 갖고있는 모델입니다.</p>
<p>VGGNet에서는 16개의 layer이후 추가적으로 layer를 생성해도 성능 향상을 이루기 힘듬을 보여주었으며, 추가적으로 ResNet의 실험팀에서 VGGNet의 20 layer와 56 layer에 대해 CIFAR-10의 학습데이터로 실험한 결과, 56 layer의 구조를 가진 CNN 모델이 20 layer의 구조를 가진 모델보다 성능이 낮아진것을 확인하였습니다. 이는 단순히 layer를 깊게 설계하는 것만으로 좋은 결과를 기대하기 어렵다고 해석할 수 있습니다. 이에 ResNet 실험팀은 layer를 deep하게 설계하면서 학습성능을 높을수 있는 방법을 고민한 결과 residual learning을 발표하게되었습니다.</p>
<p>ResNet의 경우 residual learning과 shortcut 연결을 통해 layer의 optimization을 잘 수행할수 있는 기초를 마련한 모델이라고 할 수 있습니다. 또한 ResNet에 나온 shortcut의 경우 현재의 CNN 구조에서 역시 흔하게 찾아볼수 있게 되었습니다. 또한 성능적 측면에서인간의 인지 능력을 웃도는 수준을 보여주며 후속 연구에서 새로운 CNN 구조를 연구 혹은 비교할때도 ResNet을 우선적으로 검토하게 되었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[DBSCAN - 밀도 기반 클러스터링]]></title>
            <link>https://velog.io/@chanhee-kang/DBSCAN-%EB%B0%80%EB%8F%84-%EA%B8%B0%EB%B0%98-%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0%EB%A7%81-szvbgsk9</link>
            <guid>https://velog.io/@chanhee-kang/DBSCAN-%EB%B0%80%EB%8F%84-%EA%B8%B0%EB%B0%98-%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0%EB%A7%81-szvbgsk9</guid>
            <pubDate>Sun, 05 Feb 2023 06:52:00 GMT</pubDate>
            <description><![CDATA[<p>본 포스팅에서는 밀도기반 클러스터링이라고도 불리는 <strong>DBSCAN(Density based spatial clustring of applications with noise)</strong>에 대해서 진행해 보도록 하겠습니다. </p>
<h2 id="📌-dbscan-이란">📌 DBSCAN 이란?</h2>
<p>DBSCAN은 19996년도의 A density-based algorithm for discovering clusters in large spatial database with noise 라는 논문에서 제시된 클러스터링 기법입니다. </p>
<p>DBSCAN은 K-means와 같이 군집간의 거리나 중심을 이용한 클러스터링이 아닌 <strong>밀도</strong>를 통해 군집화를 하는 방법에 대해 제시를 하였는데, 이는 &#39;동일한 클래스에 속하는 데이터는 서로 근접하게 분포할것이다&#39; 라는 가정으로 동작하는 클러스터링이라 이해하면 될것 같습니다.</p>
<p>이러한 밀도기반 클러스터링과 중심기반 클러스터링에 대한 예시는 아래의 그림과 같습니다. 먼저 왼쪽그림의 경우 DBSCAN과 같이 밀도를 기반으로 클러스터링을 진행한 결과이며 오른쪽 그림의 경우 K-means와 같이 중심기반으로 클러스터링을 진행한 결과 입니다.
<img src="https://velog.velcdn.com/images/chanhee-kang/post/3cfb7d97-18ff-4ccd-a2e4-5e00f427f47d/image.png" alt=""></p>
<p>위의 그림과 같이 DBSCAN은 가깝게 모여있고 연결되어있는 데이터들에 대해 클러스터링을 진행할때 유용하게 사용될 수 있습니다. 또한 DBSCAN의 경우 클러스터의 갯수를 미리 정할 필요가없으며 노이즈에 대해 효과적으로 제외할 수 있다고 합니다.</p>
<h2 id="📌-dbscan의-작동방식">📌 DBSCAN의 작동방식</h2>
<p>DBSCAN의 작동방식은 반경의 크기와 최소 군집의 크기 두가지를 정해 준다음 클러스터링을 진행합니다. 반경의 크기는 데이터간의 거리가 얼마나 가까워야 서로 연결되어 하나의 군집으로 볼수 있는지를 의미하며 최소 근집의 크기는 몇개의 데이터가 서로 연결되어있어야 군집으로 볼건지를 의미합니다. 예를들어서 최소 군집의 크기인 MinPts가 5라면 4개의 데이터가 고르게 모여져있다고 해도 이를 노이즈로 간주하겠다는 의미입니다. 이러한 DBSCAN은 아래와 같이 작동한다고 볼 수 있습니다.</p>
<pre><code>DBSCAN(DB, distFunc, eps, minPts) {
    C := 0
    for each point P in database DB {
        if label(P) ≠ undefined then continue              
        Neighbors N := RangeQuery(DB, distFunc, P, eps)
        if |N| &amp;lt; minPts then {                            
            label(P) := Noise
            continue
        }
        C := C + 1                                         
        label(P) := C                    
        SeedSet S := N \ {P}                               
        for each point Q in S {                             
            if label(Q) = Noise then label(Q) := C       
            if label(Q) ≠ undefined then continue        
            label(Q) := C                                  
            Neighbors N := RangeQuery(DB, distFunc, Q, eps)
            if |N| ≥ minPts then {                  
                S := S ∪ N                    
            }
        }
    }
}</code></pre><p>위의 수도코드를 간단하게 살펴보면, 먼저 랜덤하게 데이터포인트를 탐색합니다. 데이터 포인트를 탐색할때 마다 해당 포인트에서 다른 모든 데이터포인트까지의 거리를 계산하고, 미리 정한 반경의 크기(eps)보다 작은 데이터포인트가 MinPts - 1 이상만큼 존재한다면 해당 포인트는 core point 가 됩니다. 만일 아닐 경우 해당 포인트는 노이즈로 처리를 합니다. 그 후 모든 데이터포인트가 군집이거나 노이즈로 판단될때 까지 반복하는 과정이라 보면 될것 같습니다.</p>
<h2 id="📌-dbscan-in-python">📌 DBSCAN in Python</h2>
<p>이러한 DBSCAN은 Python의 <a href="https://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html">Scikit-learn</a> 패키지를 통해 쉽게 사용할수있습니다. 간단하게 코드를 살펴보겠습니다.</p>
<pre><code class="language-python">from sklearn.cluster import DBSCAN
import numpy as np

X = np.array([[1, 2], [2, 2], [2, 3],
              [8, 7], [8, 8], [25, 80]])
clustering = DBSCAN(eps=3, min_samples=2).fit(X)
</code></pre>
<p>Scikit-learn에서 제공하는 DBSCAN의 파라미터는 eps인 반경의 크기와 최소 군집의 크기인 min_samples를 필수적으로 설정해주어야하며 다른 파라미터의 경우 필수적으로 지정해 줄 필요는 없습니다. 먼저 제공해주는 파라미터에 대해 살펴보도록 하겠습니다</p>
<pre><code class="language-python">class sklearn.cluster.DBSCAN(eps=0.5, *, 
                             min_samples=5, metric=&#39;euclidean&#39;, 
                             metric_params=None, algorithm=&#39;auto&#39;, 
                             leaf_size=30, 
                             p=None, n_jobs=None)</code></pre>
<h3 id="파리미터parameters설명">파리미터(Parameters)설명</h3>
<p><strong>eps</strong>
하나의 샘플에 대한 두 샘플 간의 최대 거리가 다른 샘플의 이웃으로 간주됩니다. 이것은 클러스터 내의 포인트 거리에 대한 최대 경계가 아닙니다. 이것은 데이터 세트 및 거리 기능에 대해 적절하게 선택하는 가장 중요한 DBSCAN 매개변수입니다.</p>
<p><strong>min_sample</strong>
핵심 포인트로 간주할 포인트에 대한 이웃의 샘플 수(또는 총 가중치)입니다.</p>
<p><strong>metric</strong>
피쳐 배열에서 인스턴스 간의 거리를 계산할 때 사용할 메트릭입니다. metric이 문자열이거나 호출 가능한 경우 해당 metric 매개변수에 대해 sklearn.metrics.pairwise_distances에서 허용하는 옵션 중 하나여야 합니다. metric이 &quot;미리 계산된&quot; 경우 X는 거리 행렬로 간주되며 정사각형이어야 합니다. X는 희소 그래프일 수 있으며, 이 경우 &quot;0이 아닌&quot; 요소만 DBSCAN의 이웃으로 간주될 수 있습니다.</p>
<p><strong>metric_params</strong>
메트릭 함수에 대한 추가 키워드 인수입니다. </p>
<p><strong>algorithm</strong>
NearestNeighbors 모듈에서 포인트별 거리를 계산하고 가장 가까운 이웃을 찾는 데 사용할 알고리즘입니다</p>
<p><strong>leaf_size</strong><br>BallTree 또는 cKDTree에 전달된 리프 크기입니다. 이는 트리를 저장하는 데 필요한 메모리는 물론 구성 및 쿼리 속도에 영향을 줄 수 있습니다. 최적의 값은 문제의 특성에 따라 다릅니다.</p>
<p><strong>p</strong>
점 사이의 거리를 계산하는 데 사용되는 Minkowski 메트릭의 거듭제곱입니다. None이면 p=2(유클리드 거리와 동일)입니다.</p>
<p><strong>n_jobs</strong>    실행할 병렬 작업의 수입니다. None으로 설정할 경우 joblib.parallel_backend 컨텍스트가 아닌 한 1을 의미합니다. -1은 모든 프로세서를 사용함을 의미합니다. 자세한 내용은 용어집을 참조하십시오.</p>
<h2 id="📌-마무리">📌 마무리</h2>
<p>DBSCAN은 군집의 갯수(=클러스터의 갯수)를 지정해 줄 필요가 없다는 점에서 장점을 가집니다. 하지만 여전히 eps와 같이 미리 설정해 주어야 하는 파라미터들이 존재합니다. 예를들어 eps를 너무 크게 설정해 버리면 모든 데이터들이 연결되어 버릴수 있으며, 작게 설정을 하면 모든 데이터들이 노이즈 처리가 될수 있습니다. 이러한 문제로 인해 DBSCAN을 사용할때 여러 값의 eps로 테스트를 해보면서 확인해 주어야 합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Reusing Logic with Custom Hooks]]></title>
            <link>https://velog.io/@chanhee-kang/React-Reusing-Logic-with-Custom-Hooks</link>
            <guid>https://velog.io/@chanhee-kang/React-Reusing-Logic-with-Custom-Hooks</guid>
            <pubDate>Thu, 10 Nov 2022 05:05:56 GMT</pubDate>
            <description><![CDATA[<p>본 포스팅은 React Beta문서, Reusing Logic with Custom Hooks를 일부 번역하였습니다. </p>
<p>React에는 <code>useState</code>, <code>useContext</code>, <code>useEffect</code>와 같은 몇 가지 내장 Hook이 존재합니다. 데이터를 가져오거나, 사용자가 온라인 상태인지 확인 하거나, 채팅방에 연결하는 등의 좀 더 구체적인 목적을 위해 Hook이 있었으면 하는 경우가 있습니다. React에서 이러한 Hook을 찾지 못할 수도 있지만 애플리케이션의 필요에 따라 커스텀 Hook을 만들 수 있습니다.</p>
<h3 id="custom-hooks-sharing-logic-between-component">Custom Hooks: Sharing logic between component</h3>
<p>대부분의 application이 그렇듯이 네트워크에 크게 의존하는 앱을 개발한다고 상상해보겠습니다. App을 사용하는 동안 네트워크 연결이 실수로 끊어진 경우 사용자에게 경고를 해야할 경우에는 크게 두 가지가 컴포넌트 안에 필요한 것 같습니다.</p>
<ol>
<li>네트워크가 온라인인지 여부를 추적하는 상태입니다.</li>
<li>전역 온라인 및 오프라인 이벤트를 구독하고 해당 상태를 업데이트하는 Effect입니다.</li>
</ol>
<p>이렇게 하면 컴포넌트가 네트워크 상태와 동기화된 상태를 유지합니다. 아래의 코드와 같이 시작할 수 있습니다. 네트워크를 켜고 끄고, 이 상태 표시줄이 사용자의 행동에 따라 어떻게 업데이트되는지 확인할 수 있습니다.</p>
<pre><code class="language-jsx">import { useState, useEffect } from &#39;react&#39;;

export default function StatusBar() {
  const [isOnline, setIsOnline] = useState(true);
  useEffect(() =&gt; {
    function handleOnline() {
      setIsOnline(true);
    }
    function handleOffline() {
      setIsOnline(false);
    }
    window.addEventListener(&#39;online&#39;, handleOnline);
    window.addEventListener(&#39;offline&#39;, handleOffline);
    return () =&gt; {
      window.removeEventListener(&#39;online&#39;, handleOnline);
      window.removeEventListener(&#39;offline&#39;, handleOffline);
    };
  }, []);

  return &lt;h1&gt;{isOnline ? &#39;✅ Oline&#39; : &#39;❌ Disconnected&#39;}&lt;/h1&gt;;
}</code></pre>
<p>이제 다른 컴포넌트에서 동일한 로직을 사용해 보려고 합니다. 네트워크가 꺼져 있는 동안 비활성화되고 &quot;저장&quot; 대신 &quot;다시 연결 중...&quot;이 표시되는 저장 버튼을 구현하려고 합니다. 이를 구현하기 위해, 먼저 isOnline state와 effect를 복사하여 SaveButton에 붙여넣을 수 있습니다.</p>
<pre><code class="language-jsx">import { useState, useEffect } from &#39;react&#39;;

export default function SaveButton() {
  const [isOnline, setIsOnline] = useState(true);
  useEffect(() =&gt; {
    function handleOnline() {
      setIsOnline(true);
    }
    function handleOffline() {
      setIsOnline(false);
    }
    window.addEventListener(&#39;online&#39;, handleOnline);
    window.addEventListener(&#39;offline&#39;, handleOffline);
    return () =&gt; {
      window.removeEventListener(&#39;online&#39;, handleOnline);
      window.removeEventListener(&#39;offline&#39;, handleOffline);
    };
  }, []);

  function handleSaveClick() {
    console.log(&#39;✅ Progress saved&#39;);
  }

  return (
    &lt;button disabled={!isOnline} onClick={handleSaveClick}&gt;
      {isOnline ? &#39;Save progress&#39; : &#39;Reconnecting...&#39;}
    &lt;/button&gt;
  );
}</code></pre>
<p>네트워크를 끄면 버튼의 모양이 변경되는지 확인하십시오. 코드 내 두개 컴포넌트는 잘 작동하지만 이들 간의 로직상 중복이 존재합니다. 시각적으로 다른 모양을 하고 있어도 둘 사이의 로직을 재사용하고 싶은 것 같습니다.</p>
<h3 id="extracting-your-own-custom-hook-from-a-component">Extracting your own custom Hook from a component</h3>
<p><code>useState</code> 및 <code>useEffect</code>와 유사하게 내장된 <code>useOnlineStatus</code> Hook이 있다고 가정해 봅시다. 그러면 이 두가지 컴포넌트를 모두 단순화하고 둘 사이의 중복을 제거할 수 있을겁니다. 비록 이러한 내장 Hook은 없지만 직접 작성할 수 있습니다. <code>useOnlineStatus</code>라는 함수를 선언하고 이전에 작성한 컴포넌트의 코드를 해당 함수로 복사합니다.</p>
<pre><code class="language-jsx">function StatusBar() {
  const isOnline = useOnlineStatus();
  return &lt;h1&gt;{isOnline ? &#39;✅ Online&#39; : &#39;❌ Disconnected&#39;}&lt;/h1&gt;;
}

function SaveButton() {
  const isOnline = useOnlineStatus();

  function handleSaveClick() {
    console.log(&#39;✅ Progress saved&#39;);
  }

  return (
    &lt;button disabled={!isOnline} onClick={handleSaveClick}&gt;
      {isOnline ? &#39;Save progress&#39; : &#39;Reconnecting...&#39;}
    &lt;/button&gt;
  );
}</code></pre>
<p>함수가 끝나면 isOnline을 반환합니다. 이렇게 하면 구성 요소에서 해당 값을 읽을 수 있습니다.</p>
<pre><code class="language-jsx">// App.js
import { useOnlineStatus } from &#39;./useOnlineStatus.js&#39;;

function StatusBar() {
  const isOnline = useOnlineStatus();
  return &lt;h1&gt;{isOnline ? &#39;✅ Online&#39; : &#39;❌ Disconnected&#39;}&lt;/h1&gt;;
}

function SaveButton() {
  const isOnline = useOnlineStatus();

  function handleSaveClick() {
    console.log(&#39;✅ Progress saved&#39;);
  }

  return (
    &lt;button disabled={!isOnline} onClick={handleSaveClick}&gt;
      {isOnline ? &#39;Save progress&#39; : &#39;Reconnecting...&#39;}
    &lt;/button&gt;
  );
}

export default function App() {
  return (
    &lt;&gt;
      &lt;SaveButton /&gt;
      &lt;StatusBar /&gt;
    &lt;/&gt;
  );
}</code></pre>
<pre><code class="language-jsx">// useOnlineStatus.js
import { useState, useEffect } from &#39;react&#39;;

export function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(true);
  useEffect(() =&gt; {
    function handleOnline() {
      setIsOnline(true);
    }
    function handleOffline() {
      setIsOnline(false);
    }
    window.addEventListener(&#39;online&#39;, handleOnline);
    window.addEventListener(&#39;offline&#39;, handleOffline);
    return () =&gt; {
      window.removeEventListener(&#39;online&#39;, handleOnline);
      window.removeEventListener(&#39;offline&#39;, handleOffline);
    };
  }, []);
  return isOnline;
}</code></pre>
<p>이제 네트워크를 켜고 끄면 두 구성 요소가 모두 업데이트되는지 확인해봅시다. 이제 컴포넌트 안에 반복적인 로직이 많지 않습니다. 더 중요한 것은 내부의 코드가 수행하는 방법보다 수행하려는 작업을 설명한다는 것입니다. 커스텀 Hooks을 통해 로직을 추출할 때 외부 시스템이나 브라우저 API를 처리하는 방법에 대한 복잡한 세부 사항을 숨길 수도 있습니다. </p>
<h3 id="hook-names-always-start-with-use">Hook names always start with <code>use</code></h3>
<p>React 애플리케이션은 컴포넌트로 구축됩니다. 컴포넌트는 내장 또는 사용자 지정 여부에 관계없이 Hook에서 빌드됩니다. 다른 사람이 만든 사용자 정의 Hook을 자주 사용하지만 때로는 직접 작성할 수도 있으며, 다음 규칙을 따라야 합니다.</p>
<ol>
<li>React 구성 요소 이름은 StatusBar 및 SaveButton과 같이 대문자로 시작해야 합니다. 또한 React 구성 요소는 JSX와 같이 React가 표시하는 방법을 알고 있는 것을 반환해야 합니다.</li>
<li>Hook의 이름은 useState나 useOnlineStatus와 같이 대문자가 뒤에 와야 합니다. Hook은 임의의 값을 반환할 수 있습니다. </li>
</ol>
<p>해당 컨밴션을 사용하면 컴포넌트를 통해 state, effect, 혹은 기타 React 기능이 &quot;숨길&quot; 수 있는 위치를 알 수 있습니다. 예를 들어, 컴포넌트 내부에서 <code>getColor()</code> 함수 호출을 본다면 이름이 use로 시작하지 않기 때문에 내부에 React 상태를 포함할 수 없다는 것을 확신할 수 있습니다. 그러나 <code>useOnlineStatus()</code>와 같은 함수 호출에는 내부에 다른 Hooks에 대한 호출이 포함될 가능성이 존재함을 확인 할수 있습니다.</p>
<p>그럼 렌더링 중에 호출되는 모든 함수는 use로 시작해야 할까요? react beta 문서에 따르면 아니라고 합니다. Hooks를 호출하지 않는 함수는 Hooks일 필요가 없습니다. 함수가 Hook을 호출하지 않는 경우 <code>use</code>를 사용하지 말고, 접두사 없이 일반 함수로 작성하는것을 권장하고 있습니다. 예를 들어 아래의 useSorted는 Hooks를 호출하지 않으므로 대신 getSorted라고 합니다.</p>
<pre><code class="language-jsx">// 🔴 Avoid: A Hook that doesn&#39;t use Hooks
function useSorted(items) {
  return items.slice().sort();
}

// ✅ Good: A regular function that doesn&#39;t use Hooks
function getSorted(items) {
  return items.slice().sort();
}</code></pre>
<p>이렇게 하면 코드가 다음 조건을 포함하여 어디에서나 이 일반 함수를 호출할 수 있습니다.</p>
<pre><code class="language-jsx">function List({ items, shouldSort }) {
  let displayedItems = items;
  if (shouldSort) {
    // ✅ It&#39;s ok to call getSorted() conditionally because it&#39;s not a Hook
    displayedItems = getSorted(items);
  }
  // ...
}</code></pre>
<p>함수 내부에 하나 이상의 Hook을 사용하는 경우 함수에 앞에 use를 써주어야 합니다.</p>
<pre><code class="language-jsx">// ✅ Good: A Hook that uses other Hooks
function useAuth() {
  return useContext(Auth);
}</code></pre>
<p>앞에 use를 붙인다 하여 React에 의한 기술적 변화는 가져오지 않습니다. 원칙적으로 다른 Hook을 호출하지 않는 Hook을 만들 수도 있기는 하지만 소스코드가 혼란스러워 지고 제한적이므로 해당 패턴을 피하는 것이 가장 좋습니다. 그러나 드물게 도움이 되는 경우가 있습니다. 예를 들어, 함수가 지금은 Hooks를 사용하지 않지만 앞으로 Hook 호출을 추가할 계획입니다. 그런 다음 use 접두사로 이름을 지정하는 것이 좋습니다.</p>
<pre><code class="language-jsx">// ✅ Good: A Hook that will likely some other Hooks later
function useAuth() {
  // TODO: Replace with this line when authentication is implemented:
  // return useContext(Auth);
  return TEST_USER;
}</code></pre>
<p>이렇게되면 state가 조건부로 호출할 수 없습니다. 이것은 실제로 내부에 Hook을 추가할 때 중요해집니다. 내부에 Hooks를 사용하지 않을 계획이라면 Hook으로 만들지 않는것을 권장합니다.</p>
<h3 id="custom-hooks-let-you-share-stateful-logic-not-state-itself">Custom Hooks let you share stateful logic, not state itself</h3>
<p>앞의 예에서 네트워크를 켜고 끌 때 두 구성 요소가 함께 업데이트되었습니다. 그러나 단일 isOnline 상태 변수가 그들 사이에 공유된다고 생각하는 것은 잘못입니다. 이 코드를 보세요.</p>
<pre><code class="language-jsx">function StatusBar() {
  const isOnline = useOnlineStatus();
  // ...
}

function SaveButton() {
  const isOnline = useOnlineStatus();
  // ...
}</code></pre>
<p>중복을 extract 하기 전과 같은 방식으로 작동합니다.</p>
<pre><code class="language-jsx">function StatusBar() {
  const [isOnline, setIsOnline] = useState(true);
  useEffect(() =&gt; {
    // ...
  }, []);
  // ...
}

function SaveButton() {
  const [isOnline, setIsOnline] = useState(true);
  useEffect(() =&gt; {
    // ...
  }, []);
  // ...
}</code></pre>
<p>이들은 완전히 독립적인 두 가지 상태 변수와 효과입니다! 동일한 외부 값(네트워크가 켜져 있는지 여부)으로 동기화했기 때문에 동시에 동일한 값을 가졌을 뿐입니다.</p>
<p>이것을 더 잘 설명하려면 다른 예가 필요합니다. 다음 <code>Form</code> 구성 요소를 고려하십시오.</p>
<pre><code class="language-jsx">import { useState } from &#39;react&#39;;

export default function Form() {
  const [firstName, setFirstName] = useState(&#39;Mary&#39;);
  const [lastName, setLastName] = useState(&#39;Poppins&#39;);

  function handleFirstNameChange(e) {
    setFirstName(e.target.value);
  }

  function handleLastNameChange(e) {
    setLastName(e.target.value);
  }

  return (
    &lt;&gt;
      &lt;label&gt;
        First name:
        &lt;input value={firstName} onChange={handleFirstNameChange} /&gt;
      &lt;/label&gt;
      &lt;label&gt;
        Last name:
        &lt;input value={lastName} onChange={handleLastNameChange} /&gt;
      &lt;/label&gt;
      &lt;p&gt;&lt;b&gt;Good morning, {firstName} {lastName}.&lt;/b&gt;&lt;/p&gt;
    &lt;/&gt;
  );
}</code></pre>
<p>각 양식 필드에 대해 몇 가지 반복적인 논리가 있습니다.</p>
<ol>
<li>상태(firstName 및 lastName)가 있습니다.</li>
<li>변경 핸들러(handleFirstNameChange 및 handleLastNameChange)가 있습니다.</li>
</ol>
<p>해당 입력에 대한 값과 <code>onChange</code> 속성을 지정하는 JSX가 있습니다. <code>useFormInput</code> 커스텀 훅으로 반복적인 로직을 추출할 수 있습니다:</p>
<pre><code class="language-jsx">// App.js
import { useFormInput } from &#39;./useFormInput.js&#39;;

export default function Form() {
  const firstNameProps = useFormInput(&#39;Mary&#39;);
  const lastNameProps = useFormInput(&#39;Poppins&#39;);

  return (
    &lt;&gt;
      &lt;label&gt;
        First name:
        &lt;input {...firstNameProps} /&gt;
      &lt;/label&gt;
      &lt;label&gt;
        Last name:
        &lt;input {...lastNameProps} /&gt;
      &lt;/label&gt;
      &lt;p&gt;&lt;b&gt;Good morning, {firstNameProps.value} {lastNameProps.value}.&lt;/b&gt;&lt;/p&gt;
    &lt;/&gt;
  );
}</code></pre>
<pre><code class="language-jsx">//useFormInput.js
import { useState } from &#39;react&#39;;

export function useFormInput(initialValue) {
  const [value, setValue] = useState(initialValue);

  function handleChange(e) {
    setValue(e.target.value);
  }

  const inputProps = {
    value: value,
    onChange: handleChange
  };

  return inputProps;
}</code></pre>
<p>value라는 하나의 상태 변수만 선언합니다. 그러나 Form 구성 요소는 useFormInput을 두 번 호출합니다.</p>
<pre><code class="language-jsx">function Form() {
  const firstNameProps = useFormInput(&#39;Mary&#39;);
  const lastNameProps = useFormInput(&#39;Poppins&#39;);
  // ...</code></pre>
<p>이것이 두 개의 개별 상태 변수를 선언하는 것처럼 작동하는 이유입니다. Custom Hooks를 사용하면 상태 저장 논리를 공유할 수 있지만 상태 자체는 공유할 수 없습니다. Hook에 대한 각 호출은 동일한 Hook에 대한 다른 모든 호출과 완전히 독립적입니다. 이것이 위의 두 샌드박스가 완전히 동일한 이유입니다. 원하는 경우 위로 스크롤하여 비교하십시오. 사용자 정의 Hook을 추출하기 전과 후의 동작은 동일합니다. 여러 구성 요소 간에 상태 자체를 공유해야 하는 경우 대신 들어 올리고 아래로 전달합니다.</p>
<h3 id="passing-reactive-values-between-hooks">Passing reactive values between Hooks</h3>
<p>커스텀 Hooks 내부의 코드는 구성 요소를 다시 렌더링할 때마다 다시 실행됩니다. 이것이 컴포넌트와 마찬가지로 사용자 정의 Hook이 순수해야 하는 이유입니다. 사용자 정의 Hooks의 코드를 구성 요소 본문의 일부로 생각하면 됩니다.</p>
<p>커스텀 Hook은 컴포넌트와 함께 다시 렌더링되기 때문에 항상 최신 props와 state를 받습니다. 이것이 의미하는 바를 보려면 이 대화방 예를 고려하십시오</p>
<h3 id="custom-hooks-help-you-migrate-to-better-patterns">Custom Hooks help you migrate to better patterns</h3>
<p>Effect는 &quot;escape hatch&quot;입니다.  “step outside React&quot; 할 필요가 있고 사용 사례에 더 나은 내장 솔루션이 없을 때 사용합니다. 시간이 지남에 따라 React 팀의 목표는 보다 구체적인 문제에 대한 보다 구체적인 솔루션을 제공하여 앱의 효과 수를 최소로 줄이는 것입니다. 사용자 정의 Hooks의 Wrapping Effects를 사용하면 이러한 솔루션을 사용할 수 있게 되면 코드를 더 쉽게 업그레이드할 수 있습니다. 이 예를 다시 살펴보겠습니다.</p>
<pre><code class="language-jsx">import { useOnlineStatus } from &#39;./useOnlineStatus.js&#39;;

function StatusBar() {
  const isOnline = useOnlineStatus();
  return &lt;h1&gt;{isOnline ? &#39;✅ Online&#39; : &#39;❌ Disconnected&#39;}&lt;/h1&gt;;
}

function SaveButton() {
  const isOnline = useOnlineStatus();

  function handleSaveClick() {
    console.log(&#39;✅ Progress saved&#39;);
  }

  return (
    &lt;button disabled={!isOnline} onClick={handleSaveClick}&gt;
      {isOnline ? &#39;Save progress&#39; : &#39;Reconnecting...&#39;}
    &lt;/button&gt;
  );
}

export default function App() {
  return (
    &lt;&gt;
      &lt;SaveButton /&gt;
      &lt;StatusBar /&gt;
    &lt;/&gt;
  );
}</code></pre>
<pre><code class="language-jsx">import { useState, useEffect } from &#39;react&#39;;

export function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(true);
  useEffect(() =&gt; {
    function handleOnline() {
      setIsOnline(true);
    }
    function handleOffline() {
      setIsOnline(false);
    }
    window.addEventListener(&#39;online&#39;, handleOnline);
    window.addEventListener(&#39;offline&#39;, handleOffline);
    return () =&gt; {
      window.removeEventListener(&#39;online&#39;, handleOnline);
      window.removeEventListener(&#39;offline&#39;, handleOffline);
    };
  }, []);
  return isOnline;
}</code></pre>
<p>위의 예에서 useOnlineStatus는 useState와 useEffect의 쌍으로 구현됩니다. 그러나 이것은 최상의 솔루션이 아닙니다. 고려하지 않는 많은 경우가 있습니다. 예를 들어 구성 요소가 탑재될 때 isOnline이 이미 true라고 가정하지만 네트워크가 이미 오프라인 상태가 된 경우 잘못된 것일 수 있습니다. 브라우저 navigator.onLine API를 사용하여 확인할 수 있지만 서버에서 React 앱을 실행하여 초기 HTML을 생성하면 직접 사용하면 중단됩니다. 요컨대 이 코드는 개선될 수 있습니다.</p>
<p>운 좋게도 React 18에는 이러한 모든 문제를 처리하는 useSyncExternalStore라는 전용 API가 포함되어 있습니다. 다음은 이 새로운 API를 활용하기 위해 재작성된 useOnlineStatus Hook입니다.</p>
<pre><code class="language-jsx">import { useSyncExternalStore } from &#39;react&#39;;

function subscribe(callback) {
  window.addEventListener(&#39;online&#39;, callback);
  window.addEventListener(&#39;offline&#39;, callback);
  return () =&gt; {
    window.removeEventListener(&#39;online&#39;, callback);
    window.removeEventListener(&#39;offline&#39;, callback);
  };
}

export function useOnlineStatus() {
  return useSyncExternalStore(
    subscribe,
    () =&gt; navigator.onLine, // How to get the value on the client
    () =&gt; true // How to get the value on the server
  );
}</code></pre>
<p>Custom Hooks를 사용하면 구성 요소 간에 논리를 공유할 수 있습니다. 또한, Custom Hooks의 이름은 use로 시작하고 그 뒤에 대문자가 와야 한다고 하며 state 자체가 아닌 상태 저장 논리만 공유합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Referencing Values with Refs]]></title>
            <link>https://velog.io/@chanhee-kang/Referencing-Values-with-Refs</link>
            <guid>https://velog.io/@chanhee-kang/Referencing-Values-with-Refs</guid>
            <pubDate>Thu, 10 Nov 2022 05:02:02 GMT</pubDate>
            <description><![CDATA[<p>React 베타버전의 문서를 일부 번역하여 작성하였습니다.</p>
<blockquote>
<p><a href="https://beta.reactjs.org/learn/referencing-values-with-refs">https://beta.reactjs.org/learn/referencing-values-with-refs</a></p>
</blockquote>
<p>어떤 정보를 기억해야하지만 컴포넌트의 새로운 렌더링을 원하지 않은때 <code>ref</code> 를 사용할 수 있다고합니다.</p>
<h3 id="adding-a-ref-to-your-component">Adding a ref to your component</h3>
<p><code>ref</code>를 사용하기 위해서는 <code>useRef</code> 훅을 import 하여 사용할 수 있으며, 컴포넌트 안에 <code>useRef</code> 를 호출 시킬수 있으며, 하나의 argument만을 사용하여야 합니다.</p>
<pre><code class="language-jsx">import { useRef } from &#39;react&#39;;</code></pre>
<p> <code>useRef</code> 는 아래 예시의 object와 같은 값을 리턴 시킬 수도 있습니다.</p>
<pre><code class="language-jsx">{
current : 0 //The value you passed to useRef
}</code></pre>
<p><code>ref.current</code> 프로퍼티를 통해 <strong>current value</strong>에 접근을 할 수 있으며, 해당 값은 변경이 가능하며 읽고 쓸 수 있습니다. 아래의 코드와 같이 <code>ref.current</code>를 통해 버튼클릭시 마다 카운트를 할 수도 있습니다.</p>
<pre><code class="language-jsx">import { useRef } from &#39;react&#39;;

export default function Counter() {
  let ref = useRef(0);

  function handleClick() {
    ref.current = ref.current + 1;
    alert(&#39;You clicked &#39; + ref.current + &#39; times!&#39;);
  }

  return (
    &lt;button onClick={handleClick}&gt;
      Click me!
    &lt;/button&gt;
  );
}</code></pre>
<p><code>ref</code>는 숫자를 가리키지만 <code>state</code>와 마찬가지로 문자열, 객체, 함수 역시 가리킬 수 있습니다. State와는 달리 ref는 읽고 수정할 수 있는 현재 속성이 있는 일반 JavaScript 객체입니다. 또한 구성 요소는 증가하거나 감소 할때 마다 다시 렌더링되지 않습니다.</p>
<h3 id="differences-between-refs-and-state">Differences between refs and state</h3>
<p>예를 들어 항상 상태 설정 기능을 사용하는 대신 ref를 변경할 수 있으나 대부분의 경우 state를 사용하게 되기는 합니다. <code>ref</code>는 자주 필요하지 않은 “esacpe hatch&quot;입니다. state와 ref의 차이는 아래와 같습니다.</p>
<p><code>state</code>를 사용하여 counter 버튼을 만들때는 아래와 같이 구성할 수 있습니다.</p>
<pre><code class="language-jsx">import { useState } from &#39;react&#39;;

export default function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    &lt;button onClick={handleClick}&gt;
      You clicked {count} times
    &lt;/button&gt;
  );
}</code></pre>
<p>count의 값이 표시되기 때문에 state 값을 사용하는 것이 좋습니다. count 값이 setCount()로 설정되면 React는 구성 요소를 다시 렌더링하고 화면은 다시 개수를 반영하도록 업데이트됩니다.</p>
<p>이것을 ref로 구현하려고 시도하면 React는 구성 요소를 다시 렌더링하지 않으므로 count 변경에 따른 값을 볼 수 없습니다. 렌더링 중에 ref.current를 읽으면 신뢰할 수 없는 코드로 이어지는 이유입니다. </p>
<p>useState와 useRef 모두 React에서 제공하지만 원칙적으로 useState 위에 useRef를 구현할 수 있습니다. React 내부에서 useRef가 다음과 같이 구현되어 있다고 상상할 수 있습니다.</p>
<pre><code class="language-jsx">// Inside of React
function useRef(initialValue) {
  const [ref, unused] = useState({ current: initialValue });
  return ref;
}</code></pre>
<p>첫 번째 렌더링 중에 <code>useRef</code>는 <code>{ current: initialValue }</code>를 반환합니다. 이 객체는 React에 의해 저장되므로 다음 렌더링 중에 동일한 객체가 반환됩니다. 위의 예제에서 상태 설정자가 사용되지 않는 방법에 유의하십시오. useRef는 항상 동일한 객체를 반환해야 하기 때문에 불필요합니다.</p>
<p>일반적으로 구성 요소가 React &quot;밖으로 나가서&quot; 외부 API(종종 구성 요소의 모양에 영향을 미치지 않는 브라우저 API)와 통신해야 할 때 ref를 사용합니다.</p>
<ul>
<li>Storing <a href="https://developer.mozilla.org/docs/Web/API/setTimeout">timeout IDs</a></li>
<li>Storing and manipulating <a href="https://developer.mozilla.org/docs/Web/API/Element">DOM elements</a>, which we cover on <a href="https://beta.reactjs.org/learn/manipulating-the-dom-with-refs">the next page</a></li>
<li>Storing other objects that aren’t necessary to calculate the JSX.</li>
</ul>
<h3 id="recap">Recap</h3>
<p><code>ref</code>는 렌더링에 사용되지 않는 값을 유지하기 위한 escape hatch로서 자주 사용되지는 않습니다. <code>ref</code>는 읽거나 설정할 수 있는 current라는 단일 속성이 있는 일반 JavaScript 객체이며, <code>useRef</code> Hook을 호출하여 React에 <code>ref</code>를 제공하도록 요청할 수 있습니다. 또한 <code>state</code>와 마찬가지로 <code>ref</code>를 사용하면 구성 요소를 다시 렌더링하는 사이에 정보를 유지할 수 있습니다. 반면 <code>state</code>와 달리 ref의 현재 값을 설정해도 다시 렌더링이 트리거되지 않습니다. 또한 렌더링하는 동안 <code>ref.current</code>를 읽거나 쓰게되면 구성 요소를 예측하기 어렵게 만듭니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] Text content does not match server-rendered HTML]]></title>
            <link>https://velog.io/@chanhee-kang/React-Text-content-does-not-match-server-rendered-HTML</link>
            <guid>https://velog.io/@chanhee-kang/React-Text-content-does-not-match-server-rendered-HTML</guid>
            <pubDate>Wed, 09 Nov 2022 01:07:20 GMT</pubDate>
            <description><![CDATA[<h3 id="발생이유"><strong>발생이유</strong></h3>
<p>navbarItems을 <code>map</code> 을 통해 보여주기 위해, 초기에 key값을 부여하지 않은 상태로 코드를 구현하였다가, 이후 console내 log를 확인후 key값을 {index}로 부여하게끔 코드 수정후 refersh를 하였을때 적용할때 발생하였음</p>
<p>아래블로그에 따르면, 렌더링된 HTML(SSR, ISR 등)이 업데이트되지만 페이지 로드 후 React 코드는 업데이트되지 않을 때 발생한다고 함.</p>
<p><a href="https://www.netlify.com/blog/fix-next-js-react-hydration-error/">관련 블로그 글</a></p>
<h3 id="해결-방법">해결 방법</h3>
<p>Next.js에선 이를 ‘React Hydration Error’라고 명시하였는데, 해당 문서를 살펴보면, 애플리케이션을 렌더링하는 동안 사전에 렌더링된 React 트리(SSR/SSG)와 브라우저에서 랜더링된 React 트리 간에 차이가 존재하여, React 트리가 DOM과 동기화되지 않고 예기치 않은 콘텐츠/속성이 나타날 수 있다고 합니다. </p>
<p>일반적으로 이 문제는 사전 렌더링과 브라우저 간에 다를 수 있는 것에 의존하는 특정 라이브러리 또는 애플리케이션 코드를 사용하기 때문에 컴포넌트의 렌더링에서 <code>window</code> 를 사용하여 해결 할수 있다고 합니다.</p>
<p>아래와 같은 예제의 경우,</p>
<pre><code class="language-jsx">function MyComponent() {
  // This condition depends on `window`. During the first render of the browser the `color` variable will be different
  const color = typeof window !== &#39;undefined&#39; ? &#39;red&#39; : &#39;blue&#39;
  // As color is passed as a prop there is a mismatch between what was rendered server-side vs what was rendered in the first render
  return &lt;h1 className={`title ${color}`}&gt;Hello World!&lt;/h1&gt;
}</code></pre>
<p>Next.js 에서는 아래와 같이 에러를 해결할 수 있다고 한다.</p>
<pre><code class="language-jsx">// In order to prevent the first render from being different you can use `useEffect` which is only executed in the browser and is executed during hydration
import { useEffect, useState } from &#39;react&#39;
function MyComponent() {
  // The default value is &#39;blue&#39;, it will be used during pre-rendering and the first render in the browser (hydration)
  const [color, setColor] = useState(&#39;blue&#39;)
  // During hydration `useEffect` is called. `window` is available in `useEffect`. In this case because we know we&#39;re in the browser checking for window is not needed. If you need to read something from window that is fine.
  // By calling `setColor` in `useEffect` a render is triggered after hydrating, this causes the &quot;browser specific&quot; value to be available. In this case &#39;red&#39;.
  useEffect(() =&gt; setColor(&#39;red&#39;), [])
  // As color is a state passed as a prop there is no mismatch between what was rendered server-side vs what was rendered in the first render. After useEffect runs the color is set to &#39;red&#39;
  return &lt;h1 className={`title ${color}`}&gt;Hello World!&lt;/h1&gt;
}</code></pre>
]]></description>
        </item>
    </channel>
</rss>