<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Tulip in Paris 🌷</title>
        <link>https://velog.io/</link>
        <description>납작복숭아 먹고 싶어요</description>
        <lastBuildDate>Sun, 08 Sep 2024 11:18:59 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Tulip in Paris 🌷</title>
            <url>https://velog.velcdn.com/images/tulip_0206/profile/dfe3f6dd-f911-46cc-8b87-f39620eafbb3/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Tulip in Paris 🌷. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/tulip_0206" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Reviewed Paper] 비정형 데이터 분석을 통한 금융 소비자 유형화 및 그에 따른 금융상품 추천 방법]]></title>
            <link>https://velog.io/@tulip_0206/Reviewed-Paper-2</link>
            <guid>https://velog.io/@tulip_0206/Reviewed-Paper-2</guid>
            <pubDate>Sun, 08 Sep 2024 11:18:59 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.kci.go.kr/kciportal/ci/sereArticleSearch/ciSereArtiView.kci?sereArticleSearchBean.artiId=ART002184266">비정형 데이터 분석을 통한 금융 소비자 유형화 및 그에 따른 금융상품 추천 방법 (Financial Instruments Recommendation based on Classification Financial Consumer by Text Mining Techniques)</a></p>
<ul>
<li>이재웅 (경희대학교 일반대학원 경영학과)</li>
<li>김영식 /Kim Young Sik (경희대학교 경영대학 경영연구원 연구원)</li>
<li>권오병 /KWON OHBYUNG (경희대학교 경영대학, 교신저자)
<br></br></li>
</ul>
<blockquote>
<p><strong>주요 용어</strong></p>
</blockquote>
<ul>
<li><strong>비정형 데이터</strong>
텍스트와 같이 고정된 형식이 없는 데이터. 금융 상담 기록, 온라인 댓글, 리뷰 등이 이에 해당하며, 이 데이터로부터 소비자의 성향을 분석.<blockquote>
</blockquote>
</li>
<li><strong>로보 어드바이저</strong>
알고리즘을 통해 투자 성향을 분석하고 맞춤형 금융상품을 추천하는 자동화된 금융 서비스.<blockquote>
</blockquote>
</li>
<li><strong>텍스트 마이닝</strong>
비정형 데이터를 분석하여 유의미한 정보를 추출하는 기법. 여기서는 금융 소비자의 성향 파악에 사용됨.<blockquote>
</blockquote>
</li>
<li><strong>투자 성향</strong>
금융 소비자의 위험 선호도, 투자 안정성, 수익률 기대치 등을 포함하는 개인별 투자 특성.<blockquote>
</blockquote>
</li>
<li><strong>분류 알고리즘</strong>
데이터를 기반으로 특정 결과를 예측하는 모델. 여기서는 의사결정트리(Decision Tree), 랜덤 포레스트(Random Forest) 등이 사용됨.</li>
</ul>
<p><br></br></p>
<h2 id="연구-배경">연구 배경</h2>
<p>최근 금융 산업에서는 비정형 데이터를 활용한 고객 맞춤형 서비스에 대한 필요성이 대두되고 있다. 기존 로보 어드바이저 시스템은 정형화된 데이터를 주로 활용하여 설문이나 기본 정보만으로 고객의 투자 성향을 파악하는 데 한계가 있다. 하지만 상담 기록, 리뷰, 온라인 댓글과 같은 비정형 데이터는 고객이 자신의 금융 성향을 자발적으로 표현한 중요한 정보원이 될 수 있다. 이를 분석하면 고객의 투자 성향을 더 깊이 이해할 수 있으며, 맞춤형 금융상품을 추천하는 데 유용할 수 있다.
<br></br></p>
<h2 id="연구-목적">연구 목적</h2>
<p>이 논문의 목적은 비정형 데이터를 분석하여 금융 소비자의 성향을 유형화하고, 이를 바탕으로 고객에게 적합한 금융상품을 추천하는 시스템을 개발하는 것이다. 이를 통해 금융 소비자의 투자 성향을 더 정교하게 파악하고, 고객의 요구에 맞는 맞춤형 금융상품을 추천하는 방법론을 제시하고자 한다.
<br></br></p>
<h2 id="연구-방법론">연구 방법론</h2>
<p>본 연구는 비정형 데이터를 수집하고, 이를 텍스트 마이닝 기법을 통해 분석하여 고객의 투자 성향을 파악하는 방식을 채택했다. 수집된 데이터는 고객 상담 기록, 고객 의견, 금융 상품 리뷰 등에서 얻은 비정형 텍스트로, 이를 통해 금융 소비자의 투자 성향을 도출할 수 있었다.</p>
<h4 id="1-데이터-수집-및-처리">1. 데이터 수집 및 처리</h4>
<p>연구에서는 금융 소비자의 비정형 데이터를 수집하였으며, 이 데이터를 전처리 과정을 거쳐 분석 가능한 형태로 변환했다. 이 과정에서 텍스트 마이닝 기법을 활용하여 주요 키워드를 추출하고, 이 키워드들을 바탕으로 소비자의 투자 성향을 유형화했다.</p>
<h4 id="2-투자-성향-분석-및-유형화">2. 투자 성향 분석 및 유형화</h4>
<p>고객의 투자 성향을 분석하기 위해 SVM(서포트 벡터 머신), 의사결정트리, 랜덤 포레스트 등 다양한 분류 알고리즘을 사용했다. 이 과정에서 가장 효과적인 알고리즘을 찾아내고, 고객의 텍스트 데이터에서 투자 성향을 예측하는 모델을 개발했다. 실험 결과, 랜덤 포레스트 알고리즘이 가장 우수한 성능을 보였으며, 이를 통해 금융 소비자의 투자 성향을 분류하는 데 성공했다.</p>
<h4 id="3-맞춤형-금융상품-추천">3. 맞춤형 금융상품 추천</h4>
<p>고객의 투자 성향을 분석한 이후, 분석된 성향에 맞는 금융상품을 추천하는 모델을 개발했다. 고객의 성향을 반영한 금융상품을 추천함으로써, 고객의 만족도와 금융상품에 대한 적합성을 크게 향상시킬 수 있음을 확인했다.
<br></br></p>
<h2 id="실험-결과">실험 결과</h2>
<p>실험에서는 비정형 데이터를 분석하여 고객의 투자 성향을 정확히 예측하고, 이 성향에 맞는 금융상품을 추천하는 시스템이 높은 성능을 보였음을 입증했다. 특히, 랜덤 포레스트 알고리즘이 다른 분류 알고리즘에 비해 우수한 성능을 보였으며, 이를 통해 금융 소비자의 투자 성향을 예측하는 데 있어서 높은 정확도를 달성했다.</p>
<p>추천된 금융상품은 고객의 성향에 잘 맞는 상품들이었으며, 이를 통해 금융 소비자가 실제로 추천된 상품을 선택하는 비율이 높아졌다. 이는 맞춤형 추천 시스템이 금융 소비자의 투자 결정을 돕고, 금융 서비스의 효율성을 높일 수 있음을 보여준다.
<br></br></p>
<h2 id="연구의-시사점">연구의 시사점</h2>
<p>본 연구는 비정형 데이터를 활용하여 금융 소비자의 투자 성향을 더 깊이 이해할 수 있는 가능성을 열었다. 고객의 비정형 텍스트 데이터를 분석함으로써, 기존의 정형화된 설문이나 인구통계학적 데이터에만 의존하던 방식을 넘어서 고객의 실제 투자 성향을 반영한 맞춤형 금융상품 추천이 가능해졌다.</p>
<p>이러한 연구는 로보 어드바이저의 기능을 강화하고, 고객 맞춤형 금융상품 추천의 정확도를 높이는 데 중요한 역할을 할 수 있다. 금융기관은 이 시스템을 활용해 고객의 요구를 더 잘 이해하고, 보다 나은 금융 서비스를 제공할 수 있을 것이다.
<br></br></p>
<h2 id="한계-및-향후-연구-방향">한계 및 향후 연구 방향</h2>
<p>본 연구는 비정형 데이터를 활용한 고객 성향 분석에 중점을 두었으나, 텍스트 외의 다른 유형의 비정형 데이터(예: 음성 데이터)를 포함하지 않은 점은 한계로 작용할 수 있다. 향후 연구에서는 다양한 비정형 데이터를 활용한 연구를 확장하고, 고객의 투자 성향을 더 다각도로 분석하여 금융상품 추천 시스템의 성능을 더욱 향상시킬 수 있을 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Reviewed Paper] 고객의 투자상품 선호도를 활용한 금융상품 추천시스템 개발]]></title>
            <link>https://velog.io/@tulip_0206/Reviewed-Paper-1</link>
            <guid>https://velog.io/@tulip_0206/Reviewed-Paper-1</guid>
            <pubDate>Sun, 08 Sep 2024 11:00:28 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.kci.go.kr/kciportal/ci/sereArticleSearch/ciSereArtiView.kci?sereArticleSearchBean.artiId=ART002939414">고객의 투자상품 선호도를 활용한 금융상품 추천시스템 개발
(Financial Products Recommendation System Using Customer Behavior Information)</a></p>
<ul>
<li>김 효 중 (Hyojoong Kim)연세대학교 정보시스템학 석사</li>
<li>김 성 범 (SeongBeom Kim)연세대학교 정보대학원 석박통합과정</li>
<li>김 희 웅 (Hee-Woong Kim)연세대학교 정보대학원 교수, 교신저자
<br></br></li>
</ul>
<blockquote>
<p><strong>주요 용어</strong></p>
</blockquote>
<ul>
<li><strong>개인화 추천시스템</strong>
고객의 데이터를 바탕으로 개별 사용자의 선호도에 맞춰 상품이나 콘텐츠를 추천하는 시스템. 금융상품 추천에서는 고객의 투자 성향, 위험 회피도 등을 기반으로 맞춤형 금융상품을 제안함.<blockquote>
</blockquote>
</li>
<li><strong>협업 필터링(Collaborative Filtering)</strong>
다수의 사용자와 상품 간의 상호작용 데이터를 기반으로 사용자와 비슷한 선호를 가진 다른 사용자들의 선택을 활용하여 추천하는 방식.<blockquote>
</blockquote>
</li>
<li><strong>콜드 스타트 문제(Cold Start Problem)</strong>
신규 사용자나 신규 아이템에 대해 과거 데이터가 부족하여 정확한 추천을 제공하지 못하는 문제.<blockquote>
</blockquote>
</li>
<li><strong>딥러닝 기반 협업 필터링(Deep Learning Collaborative Filtering)</strong>
사용자와 아이템 간의 복잡한 비선형 관계를 학습하기 위해 다층 신경망을 사용하는 협업 필터링 방식.<blockquote>
</blockquote>
</li>
<li><strong>임베딩(Embedding)</strong>
데이터를 고차원에서 저차원 벡터로 변환하는 방식. 사용자와 상품의 특성을 저차원 벡터로 표현하여 추천 모델의 입력값으로 사용함.</li>
</ul>
<p><br></br></p>
<h2 id="연구-배경">연구 배경</h2>
<p>이 논문은 최근 금융상품의 급증과 금융 거래의 복잡성 속에서 고객이 적합한 금융상품을 선택하기 어려워진 상황을 해결하고자 시작되었다. 금융상품은 고객의 투자 성향과 리스크 회피도에 따라 추천해야 하는데, 기존의 금융상품 추천시스템은 고객의 다양한 특성을 충분히 반영하지 못하는 한계를 가지고 있다. 또한, 새로운 고객이나 새로운 상품에 대한 데이터가 부족할 때 발생하는 콜드 스타트 문제로 인해 추천의 정확도도 떨어지는 문제가 있다.
<br></br></p>
<h2 id="연구-목적">연구 목적</h2>
<p>이 연구는 고객의 금융상품 선호도를 분석하고, 그에 따른 맞춤형 금융상품을 추천하는 시스템을 개발하는 것을 목표로 하고 있다. 특히, 고객의 다양한 행동 데이터(예: 거래 내역, 자산 정보, 보유 종목 정보 등)를 활용하여 고객의 투자 성향과 리스크 회피도를 반영한 추천 모델을 제안하고자 한다. 이를 통해 고객의 투자 탐색 비용을 줄이고, 금융 투자 결정을 보다 쉽게 할 수 있도록 돕는 시스템을 구축하는 것이 목적이다.
<br></br></p>
<h2 id="기존-연구의-한계">기존 연구의 한계</h2>
<p>기존 금융상품 추천 모델들은 주로 정형화된 고객 데이터를 바탕으로 하고 있으며, 복잡한 투자 성향이나 비선형적인 관계를 충분히 반영하지 못했다. 또한, 기존 협업 필터링 방식은 고객 간의 유사성을 계산하여 추천을 제공하지만, 새로운 고객이나 새로운 상품에 대해서는 적절한 추천을 제공하기 어려운 콜드 스타트 문제를 안고 있다.
<br></br></p>
<h2 id="연구-방법론">연구 방법론</h2>
<p>본 연구에서는 딥러닝 기반의 협업 필터링 모델을 도입하여, 고객의 투자 성향, 리스크 회피도, 거래 패턴 등 다양한 특성을 분석하고 이를 바탕으로 금융상품을 추천하는 시스템을 개발했다. 딥러닝을 통해 고객과 상품 간의 비선형적인 관계를 학습함으로써, 기존 협업 필터링의 한계를 극복하고 추천 성능을 향상시켰다.</p>
<h4 id="1-데이터-수집-및-전처리">1. 데이터 수집 및 전처리</h4>
<p>고객의 거래 내역, 자산 정보, 보유 종목 정보, 계좌 개설일, 연령, 성별, 투자 상품 등에 대한 데이터를 수집하였고, 이를 바탕으로 고객의 잠재 선호도를 계산했다. 딥러닝 모델의 입력으로 사용하기 위해 고객과 상품의 특성을 임베딩 벡터로 변환하였고, 이를 통해 비선형적인 관계를 학습할 수 있도록 설계했다.</p>
<h4 id="2-협업-필터링-모델-개발">2. 협업 필터링 모델 개발</h4>
<p>기존의 협업 필터링 방식과 달리, 본 연구에서는 딥러닝 기반의 협업 필터링을 활용하여 고객과 상품 간의 복잡한 상호작용을 모델링했다. 특히, 다층 신경망(Multi-Layer Perceptron, MLP)을 사용하여 고객과 상품 간의 비선형적인 관계를 학습하고, 이를 바탕으로 추천 성능을 향상시켰다. 이 과정에서 고객의 성별, 연령, 자산 정보, 거래 내역 등 다양한 특성 데이터를 함께 고려하여, 고객의 투자 성향과 금융상품에 대한 잠재 선호도를 예측했다.</p>
<h4 id="3-콜드-스타트-문제-해결">3. 콜드 스타트 문제 해결</h4>
<p>콜드 스타트 문제를 해결하기 위해, 새로운 고객이나 상품에 대해 기존 고객의 데이터를 활용하여 유사한 특성을 가진 고객 그룹을 찾아 추천을 제공하는 방식을 사용했다. 이를 통해 데이터가 부족한 상황에서도 정확한 추천을 제공할 수 있도록 했다.
<br></br></p>
<h2 id="실험-결과">실험 결과</h2>
<p>본 연구에서 제안한 딥러닝 기반 협업 필터링 모델은 기존의 행렬 분해 방식이나 단순 협업 필터링 방식에 비해 훨씬 우수한 성능을 보였다. 특히, 추천 시스템의 성능을 평가하는 지표(MAE, MSE)에서 우수한 결과를 나타냈으며, 콜드 스타트 문제를 효과적으로 해결하는 데 성공했다. 실험 결과, 고객의 투자 성향과 리스크 회피도를 반영한 추천 시스템이 고객 만족도와 추천 정확도를 크게 향상시켰다.
<br></br></p>
<h2 id="성능-비교">성능 비교</h2>
<p>딥러닝 협업 필터링 모델은 MAE(평균 절대 오차) 및 MSE(평균 제곱 오차) 지표에서 기존의 협업 필터링 모델에 비해 더 낮은 오차율을 보였으며, 특히 NDCG(정규화된 누적 이득)와 같은 지표에서도 탁월한 성능을 기록했다. 이는 고객의 다양한 특성과 금융상품 정보를 반영한 모델이 기존 방식에 비해 훨씬 더 효과적이라는 것을 입증한다.
<br></br></p>
<h2 id="연구의-시사점">연구의 시사점</h2>
<p>본 연구는 금융상품 추천 시스템에서 고객의 다양한 특성을 반영하는 것이 중요하다는 점을 강조하며, 특히 고객의 투자 성향과 리스크 회피도를 반영한 맞춤형 추천이 가능하다는 것을 실증적으로 보여주고 있다. 이를 통해 금융기관은 고객의 만족도를 높이고, 투자 결정을 돕는 서비스를 제공할 수 있으며, 금융상품 추천의 정확도를 높일 수 있다.</p>
<p>또한, 본 연구는 실무적으로 금융상품 추천 시스템의 성능을 향상시키기 위한 딥러닝 기술의 활용 가능성을 제시하고 있으며, 이를 통해 고객 맞춤형 금융상품 추천 서비스가 더욱 발전할 수 있음을 보여준다.
<br></br></p>
<h2 id="한계-및-향후-연구-방향">한계 및 향후 연구 방향</h2>
<p>본 연구의 한계로는, 추천 성능을 평가하는 기준이 상위 10개 또는 20개의 상품에 한정되었다는 점이다. 향후 연구에서는 다양한 추천 상품 개수에 따른 성능 변화를 분석하여 최적의 추천 시스템을 구축할 필요가 있다. 또한, 비정형 데이터(예: 고객 상담 기록, STT)와 같은 데이터를 추가적으로 분석하여 추천 시스템의 성능을 더욱 향상시킬 수 있는 가능성도 제시된다.</p>
<p>결론적으로, 본 연구는 딥러닝 기반 협업 필터링을 활용하여 금융상품 추천의 정확도를 높이고, 콜드 스타트 문제를 해결한 맞춤형 금융상품 추천 모델을 제안함으로써 금융 투자 분야에서의 추천 시스템 연구에 큰 기여를 했다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[행렬] SVD (Singular Value Decomposition, 특이값 분해)]]></title>
            <link>https://velog.io/@tulip_0206/data-1-SVD</link>
            <guid>https://velog.io/@tulip_0206/data-1-SVD</guid>
            <pubDate>Thu, 05 Sep 2024 06:37:46 GMT</pubDate>
            <description><![CDATA[<p>SVD(Singular Value Decomposition, 특이값 분해)는 다양한 데이터 분석, 이미지 처리, 정보 검색, 추천 시스템 등 많은 응용 분야에서 사용되고 있는 기법이다.</p>
<h2 id="1-svd">1. SVD</h2>
<p>임의의 행렬 $m×n$ 행렬 $A$를 세 개의 행렬 $U, Σ, V$로 분해하는 방법이다.</p>
<blockquote>
<p>$A=UΣV^T$</p>
</blockquote>
<ul>
<li>$U$ : $m×m$ 직교 행렬(Orthogonal Matrix)로    $A$의 열 공간(column space)을 설명하는 왼쪽 특이벡터들로 구성되어 있다.</li>
<li>$Σ$ : $m×n$ 대각 행렬(Digonal Matrix)로 $A$의 특이값들이 대각선에 위치한다.</li>
<li>$V^T$ : $n×n$ 직교 행렬(Orthogonal Matrix)로 $A$의 행 공간(row space)을 설명하는 오른쪽 특이벡터들로 구성되어 있다.</li>
</ul>
<p>세 행렬을 <strong>좌표 변환</strong>의 측면에서 해석하면, $U$와 $V^T$는 회전 및 대칭을 나타내고 $Σ$는 크기 조정을 나타낸다.</p>
<h2 id="2-변환과-pca">2. 변환과 PCA</h2>
<h3 id="21-행렬의-변환">2.1 행렬의 변환</h3>
<p>임의의 행렬 $A$는 벡터에 대해 <strong>스케일링, 회전</strong> 등의 선형 변환을 수행할 수 있다.
특이값 분해는 이 변환 과정을 세 가지 변환으로 나누어서 설명할 수 있다.</p>
<blockquote>
<p>$Ax = UΣV^Tx$</p>
</blockquote>
<ol>
<li>$V^T$ : 오른쪽 회전 or 반사<ul>
<li>데이터의 방향을 바꾼다.</li>
</ul>
</li>
<li>$Σ$ : 스케일링(크기 조정)<ul>
<li>각 특이값은 행렬 $A$가 각 특이값에 매칭되는 특정 축을 따라서 데이터를 얼마나 늘리거나 줄이는지를 설명한다.</li>
<li>이 단계에서 벡터의 길이(크기)가 변하면서 중요한 정보는 유지되고, 덜 중요한 정보는 탈락되는 선택의 기능을 보인다.</li>
</ul>
</li>
<li>$U$ : 왼쪽 회전 or 반사<ul>
<li>특이값에 의해 스케일링 된 벡터들을 새로운 공간으로 이동시킨다.</li>
</ul>
</li>
</ol>
<h3 id="22-주성분-분석pca-principal-component-analysis">2.2 주성분 분석(PCA, Principal Component Analysis)</h3>
<blockquote>
<p><strong>PCA의 목표</strong></p>
</blockquote>
<ul>
<li>PCA는 데이터의 분산을 최대한 유지하면서 차원을 줄이는 것</li>
<li>고차원 데이터를 저차원으로 투영해, 데이터의 중요한 패턴을 찾고 노이즈나 덜 중요한 정보를 제거하려는 것</li>
</ul>
<p>SVD는 <strong>주성분 분석(PCA)</strong>와 매우 밀접하게 연결된 차원 축소 기법이다. 고차원 데이터를 중요한 정보만 남기고 차원을 줄이는 기법으로, 데이터의 주요 패턴을 파악하는 데 사용된다. SVD는 PCA를 수행하는 수학적 방법 중 하나이다.</p>
<h4 id="svd와-pca의-관계">SVD와 PCA의 관계</h4>
<p>PCA는 다음과 같은 단계를 거쳐 수행한다.</p>
<blockquote>
</blockquote>
<ol>
<li><strong>데이터의 중심화 (Centering)</strong>
데이터가 원점 주변에 분포하게 하여 데이터의 패턴을 분석할 수 있도록 각 차원의 평균을 0으로 맞춰주는 과정<blockquote>
</blockquote>
</li>
<li><strong>공분산 행렬 계산</strong>
공분산 행렬은 데이터가 어떻게 서로 상관되어 있는지 설명한다.
공분산 행렬 : $A^TA$ 혹은 $AA^T$<blockquote>
</blockquote>
</li>
<li><strong>SVD 적용</strong>
이 공분산 행렬에 SVD를 적용하여 특이값과 특이벡터를 구한다.<ul>
<li>특이값은 각 주성분(Principal Component)이 설명하는 데이터의 분산 정도를 나타내며, 특이벡터는 주성분 방향을 나타낸다.</li>
<li>특이값이 큰 주성분이 데이터의 중요한 패턴을 설명하며, 특이값이 작은 주성분은 노이즈나 덜 중요한 정보일 가능성이 크다.<blockquote>
</blockquote>
</li>
</ul>
</li>
<li><strong>주성분 선택</strong>
특이값이 큰 몇 개의 주성분을 선택한다.
기존의 데이터가 m차원이었지만, 특이값이 큰 상위 n개의 주성분만을 선택하면 n차원으로 데이터의 차원을 줄일 수 있다.</li>
</ol>
<h4 id="직관적-이해">직관적 이해</h4>
<blockquote>
<p><strong>SVD의 역할</strong> : SVD는 데이터의 중요한 패턴(주성분)을 찾고, 이 정보를 사용하여 데이터의 차원을 줄이는데 도움을 준다.</p>
</blockquote>
<p><strong>차원 축소의 의미</strong> : 차원이 높은 데이터는 분석과 시각화가 어렵고, 계산 비용이 높기 때문에 SVD를 통해 데이터의 차원을 줄이면 더 간단하게 데이터를 다룰 수 있다.</p>
<blockquote>
</blockquote>
<p><strong>데이터 압축과 노이즈 제거</strong> : 특이값이 작은 주성분은 보통 데이터의 노이즈나 덜 중요한 정보를 나타낸다. 따라서 특이값이 작은 성분을 제거하면 데이터의 노이즈를 줄이면서 중요한 정보만 남길 수 있다.</p>
<h2 id="3-svd의-수학적-이해">3. SVD의 수학적 이해</h2>
<h3 id="31-행렬-a의-고유값과-고유벡터">3.1 행렬 $A$의 고유값과 고유벡터</h3>
<p>정방 행렬에만 적용이 가능한 고유값 분해와는 다르게, SVD는 모든 형태의 $m×n$ 행렬에 적용할 수 있다. 이 과정에서 행렬의 특이값(singular value)과 특이벡터(singular vector)가 도출된다.</p>
<h3 id="32-특이값-분해-계산-단계">3.2 특이값 분해 계산 단계</h3>
<blockquote>
<p><strong><em>Step 1</em></strong> : $A^TA$와 $AA^T$의 계산
SVD의 첫 번째 단계는 다음 두 행렬을 계산하는 것이다.</p>
</blockquote>
<ol>
<li>$A^TA$는 $n×n$ 대칭 행렬이다.</li>
<li>$AA^T$는 $m×m$ 대칭 행렬이다.<blockquote>
</blockquote>
이 두 행렬은 각각 $A$의 오른쪽 고유벡터와 왼쪽 고유벡터를 찾는 데 사용된다.</li>
</ol>
<blockquote>
<p><strong>* Step 2*</strong> : 고유값 문제 해결</p>
</blockquote>
<ul>
<li>$A^TA$의 고유값을 구한다. 이 고유값들은 특이값의 제곱이 된다.</li>
<li>$A^TA$의 고유벡터는 $V$의 열을 이루며, 이를 <strong>오른쪽 특이벡터</strong>라고 한다.</li>
<li>$AA^T$의 고유벡터는 $U$의 열을 이루며, 이를 <strong>왼쪽 특이벡터</strong>라고 한다.</li>
</ul>
<blockquote>
<p><strong>*Step 3 *</strong> : 특이값 계산
각 고유값의 제곱근이 $A$의 특이값이 되고, $Σ$행렬의 대각선에 배치된다.
특이값은 행렬 $A$의 중요한 정보, 즉 데이터의 분산과 크기를 나타낸다.</p>
</blockquote>
<blockquote>
<p><strong><em>Step 4</em></strong> : $U, Σ, V$ 행렬 구성</p>
</blockquote>
<ul>
<li>$U$ : $AA^T$의 고유벡터를 이용해 구성한다.</li>
<li>$Σ$ : 특이값을 대각선에 배치한 행렬이다.</li>
<li>$V$ : $A^TA$의 고유벡터를 이용해 구성한다.</li>
</ul>
<h2 id="4-svd의-응용">4. SVD의 응용</h2>
<h3 id="41-차원-축소">4.1 차원 축소</h3>
<p>SVD는 데이터의 차원을 축소하는 데 많이 사용된다. 예를 들어, 추천 시스템에서는 사용자와 아이템 간의 상호작용 행렬을 SVD로 분해하여 중요하지 않은 데이터를 제거하고, 중요한 패턴만을 남길 수 있다. 이렇게 하면 모델의 효율성과 성능을 개선할 수 있다.</p>
<h3 id="42-데이터-압축">4.2 데이터 압축</h3>
<p>이미지 처리에서는 SVD를 사용하여 이미지를 압축할 수 있다. 이미지 데이터는 보통 큰 행렬로 표현되는데, 이를 SVD로 분해하고 중요 특이값만을 사용하여 이미지를 재구성함으로써 원본 이미지와 유사한 품질을 유지하면서도 파일 크기를 줄일 수 있다.</p>
<h3 id="43-노이즈-제거">4.3 노이즈 제거</h3>
<p>SVD는 데이터를 노이즈와 신호로 분리하는 데 유용하다. 중요하지 않은 특이값(노이즈)을 제거하고 나머지 신호를 사용하여 더 깨끗한 데이터를 얻을 수 있다.</p>
<h2 id="5-svd의-장점과-한계">5. SVD의 장점과 한계</h2>
<blockquote>
<p><strong>장점</strong></p>
</blockquote>
<ul>
<li>모든 행렬에 적용 가능 : 정방 행렬뿐만 아니라 모든 차원의 행렬에 대해 SVD를 사용할 수 있다.</li>
<li>차원 축소와 압축 : 중요한 정보를 추출해 차원을 축소할 수 있다.</li>
<li>수치적 안정성 : SVD는 매우 안정적인 수치적 기법으로, 대부분의 경우 수치 계산에서 매우 정확한 결과를 제공한다.</li>
</ul>
<blockquote>
<p><strong>한계</strong></p>
</blockquote>
<ul>
<li>계산 복잡성 : 큰 행렬에 대해서는 SVD의 계산이 매우 복잡하고 시간이 오래 걸릴 수 있다.</li>
<li>실시간 응용의 제한: 실시간으로 대규모 데이터를 처리해야 하는 경우 SVD는 적합하지 않을 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[행렬] 고유값(Eigenvalue)과 고유벡터(Eigenvector), 그리고 주성분 분석(PCA)]]></title>
            <link>https://velog.io/@tulip_0206/math-3-Eigen-and-PCA</link>
            <guid>https://velog.io/@tulip_0206/math-3-Eigen-and-PCA</guid>
            <pubDate>Thu, 29 Aug 2024 10:28:29 GMT</pubDate>
            <description><![CDATA[<h2 id="1-행렬의-고유값eigenvalue과-고유벡터eigenvector">1. 행렬의 고유값(Eigenvalue)과 고유벡터(Eigenvector)</h2>
<h3 id="1-1-고유값과-고유벡터의-개념-및-기하학적-의미">1-1. 고유값과 고유벡터의 개념 및 기하학적 의미</h3>
<p>고유값(eigenvalue)과 고유벡터(eigenvector)는 행렬이 표현하는 선형 변환의 본질을 이해하는 데 핵심적인 역할을 하며, 다양한 응용 분야에서 활용된다.</p>
<p><strong>선형 변환</strong> : 벡터 공간에서 벡터를 다른 벡터로 변환하는 연산 예를 들어, 2차원 공간에서의 행렬</p>
<p>행렬 𝐴는 벡터 𝑥를 다른 벡터 𝐴𝑥로 변환한다. 이때 대부분의 벡터는 변환 과정에서 <strong>크기</strong>와 <strong>방향</strong>이 모두 변한다. 하지만 특정한 벡터는 이 변환을 거치더라도 방향은 그대로 유지되고 크기만 변화하는데, 이러한 벡터를 <strong>고유벡터</strong>라고 하며, 크기의 변화 비율을 나타내는 값을 <strong>고유값</strong>이라고 한다.</p>
<blockquote>
<p>선형 변환은 다음과 같은 수식으로 표현할 수 있다.</p>
</blockquote>
<p>$Av=λv$</p>
<blockquote>
</blockquote>
<p>𝐴 : $𝑛×𝑛$ 정방행렬
𝑣 : 고유벡터(Eigenvector) → 𝐴에 의해 변환되어도 방향이 변하지 않는 벡터
𝜆 : 고유값(Eigenvalue) → 고유벡터 𝑣의 크기 변화</p>
<p>양수의 고유값 𝜆 → 고유벡터의 크기는 변하지만 방향은 유지
음수의 고유값 𝜆 → 고유벡터의 크기는 변화하며 방향은 반대
고유값 𝜆 = 1 → 크기와 방향이 모두 변화 없다.
고유값 𝜆 = 0 → 고유벡터가 축소되어 사라진다.</p>
<p>이 개념은 선형 변환의 기하학적 특성을 이해하는 데 매우 중요하다.
고유벡터와 고유값은 벡터 공간의 구조를 분석하고, 변환의 고유한 특성을 파악하는 데 도움을 준다.
<br></br></p>
<h3 id="1-2-고유값-방정식과-고유값의-계산">1-2. 고유값 방정식과 고유값의 계산</h3>
<blockquote>
<p>고유값과 고유벡터를 구하는 과정은 행렬의 고유값 방정식을 푸는 것과 같다.</p>
</blockquote>
<p>$(A-λI)v=0$</p>
<blockquote>
</blockquote>
<p>$I$ : 단위행렬(identity matrix)
$λ$ : 고유값</p>
<p>이 방정식이 의미하는 바는, 행렬 $𝐴$에서 고유값 𝜆를 뺀 행렬 $A-λI$가 고유벡터 𝑣를 영벡터로 변환한다는 것이다. 이때, 고유벡터 𝑣가 자명하지(Trivial) 않은 해를 가지려면, 행렬 $A-λI$의 행렬식이 0이어야 한다.</p>
<p>$det(A-λI) = 0$</p>
<p>이 특성 방정식을 풀면 행렬 𝐴의 고유값 𝜆를 구할 수 있다. 각 고유값에 대해 대응하는 고유벡터는 행렬 $A-λI$의 영공간(null space)에 속하는 벡터이다.
<br></br></p>
<h3 id="1-3-고유값-분해-eigen-decomposition">1-3. 고유값 분해 (Eigen Decomposition)</h3>
<p>고유값 분해(Eigen Decomposition) : 행렬을 고유값과 고유벡터로 분해하여 표현하는 방법</p>
<blockquote>
<p>정방행렬 𝐴에 대해 𝑛개의 고유값 $λ_i$와 고유벡터 $𝑣_𝑖$가 존재하면, 𝐴를 다음과 같이 분해할 수 있다.</p>
</blockquote>
<p>$A=VΛV^{−1}$</p>
<blockquote>
</blockquote>
<p>$V$ : 고유벡터로 구성된 행렬 ($V$의 각 열벡터는 행렬 $A$의 고유벡터)
$Λ$ : 대각행렬 (대각선 요소로 행렬 $A$의 고유값들이 위치)
$V^{−1}$ : $V$의 역행렬</p>
<p>이 고유값 분해는 행렬을 보다 간단하게 분석하거나 계산하는 데 유용하다.</p>
<ul>
<li>행렬의 거듭제곱</li>
<li>행렬의 대각합(trace)</li>
</ul>
<blockquote>
<p>대칭행렬의 경우, 고유벡터들이 항상 서로 직교하므로 고유값 분해가 더 간단하다.
이때 $V$는 직교행렬(orthogonal matrix)이 되며, $𝑉^{−1} = 𝑉^𝑇$가 성립한다.</p>
</blockquote>
<p>따라서 대칭행렬 $A$는 다음과 같이 분해할 수 있다.</p>
<blockquote>
</blockquote>
<p>$A=VΛV^{T}$</p>
<blockquote>
</blockquote>
<p>이와 같은 <strong>대칭행렬의 고유값 분해</strong>는 <strong>데이터 분석</strong>, <strong>신호 처리</strong>, <strong>기계 학습</strong> 등의 다양한 분야에서 활용된다.</p>
<p><br></br></p>
<h2 id="2-주성분-분석pca">2. 주성분 분석(PCA)</h2>
<h3 id="2-1-pca">2-1. PCA</h3>
<blockquote>
<p><strong>주성분 분석(PCA, Principal Component Analysis)</strong> : 고차원 데이터를 간단한 저차원 공간으로 변환하면서도, 원래 데이터의 손실을 최소화하는 차원 축소 기법이다. 데이터의 변동성(variance)을 가장 잘 설명하는 축을 찾아내고, 이 축을 따라 데이터를 투영(projection)하여 차원을 축소한다.</p>
</blockquote>
<p>원 데이터가 위치한 공간에서, 데이터의 분산이 최대가 되는 새로운 좌표 축을 찾는다. 이 새로운 축은 데이터의 분산을 가장 잘 설명하는 방향이며, 첫 번째 주성분(Principal Component, <strong>PC1</strong>)이라고 불린다. PCA는 이 과정에서 상관성이 높은 변수들을 고려하여, 변수들 간의 상관성을 제거하고 데이터의 주요 패턴을 유지한다.</p>
<p><br></br></p>
<h3 id="2-2-pca의-수학적-원리">2-2. PCA의 수학적 원리</h3>
<p>PCA의 수학적 원리는 <strong>고유값 분해(Eigen Decomposition)</strong>에 기반을 두고 있다.
이 과정에서 공분산 행렬의 고유값과 고유벡터를 계산하여, 고유값이 큰 순서대로 고유벡터를 정렬하고, 이들을 새로운 좌표 축으로 사용한다.</p>
<blockquote>
<p><strong>데이터 중심화 (Mean Centering)</strong> :
원 데이터의 각 변수에서 평균을 빼서, 데이터가 원점을 중심으로 분포하도록 한다. 이를 데이터 중심화(mean centering)라고 하며, 데이터 행렬 𝑋를 중심화한 결과는 다음과 같이 나타낼 수 있다:</p>
</blockquote>
<p>$X_{centered} = X - \bar{X}$</p>
<blockquote>
</blockquote>
<p>여기서 $\bar{X} = \mu$로 $X$의 평균을 의미한다.</p>
<blockquote>
<p><strong>공분산 행렬 계산 (Covariance Matrix)</strong> :
중심화된 데이터를 바탕으로 공분산 행렬 $Σ$를 계산한다. 공분산 행렬은 데이터의 분산과 변수 간의 상관성을 나타내는 행렬로, 다음과 같이 정의된다:</p>
</blockquote>
<p>$Σ = {1\over n-1} ; X^T_{centered} ; X_{centered}$</p>
<blockquote>
</blockquote>
<p>여기서 n은 데이터 포인트의 수이다.</p>
<blockquote>
<p><strong>고유값과 고유벡터 계산 (Eigenvalues and Eigenvectors)</strong> :
공분산 행렬 $Σ$의 고유값과 고유벡터를 계산한다. 고유값은 새로운 축의 중요도를 나타내며, 고유벡터는 새로운 좌표 축의 방향을 나타낸다.</p>
</blockquote>
<p>$Σe=λe$</p>
<blockquote>
</blockquote>
<p>여기서 $λ$는 고유값, $e$는 고유벡터이다.</p>
<blockquote>
<p><strong>주성분 선택 (Selection of Principal Components)</strong> :
고유값의 크기 순서대로 고유벡터를 정렬하고, 가장 큰 고유값에 대응하는 고유벡터를 첫 번째 주성분(PC1)으로 선택한다. 두 번째로 큰 고유값에 대응하는 고유벡터는 두 번째 주성분(PC2)으로 선택한다. 이 과정을 반복하여 원하는 수의 주성분을 선택할 수 있다.</p>
</blockquote>
<blockquote>
<p><strong>데이터 투영 (Projection of Data)</strong> :
선택된 주성분 축에 데이터를 투영하여, 저차원 공간으로 변환한다. 투영된 데이터는 원래 데이터의 중요한 정보를 최대한 유지하면서, 차원이 축소된 형태로 나타납니다.</p>
</blockquote>
<p>$Z=XW$</p>
<blockquote>
</blockquote>
<p>$X$ : $n×p$ 크기의 데이터 행렬
$W$ : $p×k$ 크기의 주성분 벡터로 구성된 행렬 ($k$는 선택한 주성분의 수)
$Z$ : $n×k$ 크기의 축소된 데이터 행렬로 $p$차원의 데이터가 $k$차원으로 축소된 형태</p>
<p><br></br></p>
<h3 id="2-3-정보-보존과-차원-축소">2-3. 정보 보존과 차원 축소</h3>
<p>PCA는 기존 데이터의 정보를 최대한 보존하면서, 즉 차원 축소 과정에서 발생하는 정보의 손실을 최소화하며 데이터의 차원을 줄이는 것이다. 하지만 모든 주성분을 사용하지 않고 일부만 선택하면, 데이터의 변동성 중 일부는 손실될 수밖에 없다. 따라서 정보의 손실을 최소화하되 선택하는 주성분의 수를 최소화하기 위해서 <strong>적절한 주성분의 수</strong>를 결정해야한다.</p>
<p>주성분의 수를 결정하기 위해, <strong>스크리 플롯(Scree Plot)</strong>이나 <strong>분산 설명 비율(PVE, Proportion of Variance Explained)</strong>을 사용할 수 있다. </p>
<blockquote>
<p><strong>스크리 플롯(Scree Plot)</strong> : 각 주성분에 대응하는 고유값의 크기를 시각화한 그래프</p>
</blockquote>
<p>고유값의 크기가 급격히 줄어드는 지점인 <strong>엘보 포인트(Elbow Point)</strong>를 찾는 것이 일반적이다. 이 지점 이후의 주성분은 설명력이 낮으므로 제외할 수 있다.</p>
<blockquote>
<p><strong>분산 설명 비율(PVE, Proportion of Variance Explained)</strong> : 각 주성분이 데이터의 총 변동성에서 차지하는 비율</p>
</blockquote>
<p>$PVE = {\lambda_j \over \sum_{i=1}^p \lambda_i }$</p>
<blockquote>
<p>$\lambda_j$ : 선택된 주성분의 고유값
$\sum_{i=1}^p \lambda_i$ : 전체 고유값의 합</p>
</blockquote>
<p>원하는 수준의 변동성을 설명할 수 있는 최소한의 주성분 개수를 선택할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[python library] re 라이브러리와 정규 표현식]]></title>
            <link>https://velog.io/@tulip_0206/python-library-3-re</link>
            <guid>https://velog.io/@tulip_0206/python-library-3-re</guid>
            <pubDate>Wed, 14 Aug 2024 00:47:33 GMT</pubDate>
            <description><![CDATA[<h2 id="1-python의-re-라이브러리">1. Python의 re 라이브러리</h2>
<p>Python의 re 라이브러리는 정규 표현식을 사용하여 문자열을 검색하고 조작하는 강력한 도구입니다. 정규 표현식(정규식)은 특정한 규칙을 가진 문자열의 집합을 표현하는 형식 언어로, 복잡한 문자열 패턴을 간단하게 처리할 수 있습니다.</p>
<hr>
<h2 id="2-정규-표현식regular-expression-패턴-구성-요소">2. 정규 표현식(regular expression) 패턴 구성 요소</h2>
<ul>
<li>메타문자</li>
</ul>
<table>
<thead>
<tr>
<th align="left">메타문자</th>
<th align="left">설명</th>
<th align="left">예시</th>
</tr>
</thead>
<tbody><tr>
<td align="left">.</td>
<td align="left">임의의 한 문자</td>
<td align="left">a.b → acb , a1b , ...</td>
</tr>
<tr>
<td align="left">^</td>
<td align="left">문자열의 시작</td>
<td align="left">^ab → abc , abd , ...</td>
</tr>
<tr>
<td align="left">$</td>
<td align="left">문자열의 끝</td>
<td align="left">ab$ → 1ab , 2ab , 3ab , ...</td>
</tr>
<tr>
<td align="left">*</td>
<td align="left">바로 앞 문자열 0회 이상 반복</td>
<td align="left">ab*c → ac , abc , abbc , abbbc , ...</td>
</tr>
<tr>
<td align="left">+</td>
<td align="left">바로 앞 문자열 1회 이상 반복</td>
<td align="left">ab+c → abc , abbc , abbbc , ...</td>
</tr>
<tr>
<td align="left">?</td>
<td align="left">바로 앞 문자열 0회 또는 1회</td>
<td align="left">ab?c → ac , abc</td>
</tr>
<tr>
<td align="left">{n, m}</td>
<td align="left">바로 앞 문자열 n회부터 m회까지 반복</td>
<td align="left">a{1,3} → a , aa , aaa</td>
</tr>
<tr>
<td align="left">[ ]</td>
<td align="left">문자의 집합 또는 범위</td>
<td align="left">[a-z] → a , b , c , ... , x , y , z</td>
</tr>
<tr>
<td align="left">[^ ]</td>
<td align="left">(부정) 괄호 안에 있는 것 제외</td>
<td align="left">[^a-z] → 소문자 a부터 z를 제외한 문자열</td>
</tr>
</tbody></table>
<ul>
<li>특수 시퀀스</li>
</ul>
<table>
<thead>
<tr>
<th align="left">특수 시퀀스</th>
<th align="left">설명</th>
<th align="left">예시</th>
</tr>
</thead>
<tbody><tr>
<td align="left">\d</td>
<td align="left">숫자</td>
<td align="left">(= [0-9]) \d{3} → 123 , 456</td>
</tr>
<tr>
<td align="left">\D</td>
<td align="left">숫자가 아닌 문자</td>
<td align="left">(= [^0-9]) \D+ → abc, @#$</td>
</tr>
<tr>
<td align="left">\w</td>
<td align="left">단어 문자 (알파벳, 숫자, 밑줄)</td>
<td align="left">(= [a-zA-Z0-9_]) \w+ → abc , 123 , a_1</td>
</tr>
<tr>
<td align="left">\W</td>
<td align="left">단어 문자가 아닌 문자</td>
<td align="left">(= [^a-zA-Z0-9_]) \W+ → @#! , &quot; &quot;</td>
</tr>
<tr>
<td align="left">\s</td>
<td align="left">공백 문자</td>
<td align="left">(공백, \t, \n) \s+ → &quot; &quot; , \t , \n</td>
</tr>
<tr>
<td align="left">\S</td>
<td align="left">공백 문자가 아닌 문자</td>
<td align="left">(= [^ \t\n\r\f\v]) \S+ →abc , 123 , a_1</td>
</tr>
</tbody></table>
<hr>
<h2 id="3-re-라이브러리-기본-사용법">3. re 라이브러리 기본 사용법</h2>
<blockquote>
<p><em>re. search( &lt;<em>sub</em> string&gt; , &lt;<em>main</em> string&gt; )</em></p>
</blockquote>
<pre><code class="language-python">import re
&gt;
# &lt;sub string&gt;이 &lt;main string&gt;에 있을 경우
A = re.search(r&#39;abc&#39;, &#39;abcdef&#39;)
print(A.start())    # 0
print(A.end())        # 3
print(A.group())    # &#39;abc&#39;
&gt;
# &lt;sub string&gt;이 &lt;main string&gt;에 없을 경우
B = re.search(r&#39;abc&#39;, &#39;ab&#39;)
print(B)            # None
&gt;
# &lt;sub string&gt;이 &lt;main string&gt;에 두 번 이상 있을 경우 ▶ 제일 첫 &lt;sub string&gt; 반환
C = re.search(r&#39;abc&#39;, &#39;abcabc&#39;)
print(C)            # &lt;re.Match object; span=(0, 3), match=&#39;abc&#39;&gt;
&gt;
# 두 자리 숫자 찾기
D = re.search(r&#39;\d\d&#39;, &#39;a1ab12abc123&#39;)
print(D)            # &lt;re.Match object; span=(4, 6), match=&#39;12&#39;&gt;</code></pre>
<blockquote>
<p><em>re.match( &lt;<em>sub</em> string&gt; , &lt;<em>main</em> string&gt; )</em></p>
</blockquote>
<pre><code class="language-python">import re
&gt;
# &lt;sub string&gt;이 &lt;main string&gt;의 시작에 있을 경우
A = re.match(r&#39;abc&#39;, &#39;abcdef&#39;)
print(A.start())  # 0
print(A.end())    # 3
print(A.group())  # &#39;abc&#39;
&gt;
# &lt;sub string&gt;이 &lt;main string&gt;의 시작에 없을 경우
B = re.match(r&#39;abc&#39;, &#39;ab&#39;)
print(B)  # None
&gt;
# &lt;sub string&gt;이 &lt;main string&gt;의 시작에 두 번 이상 있을 경우 ▶ 제일 첫 &lt;sub string&gt; 반환
C = re.match(r&#39;abc&#39;, &#39;abcabc&#39;)
print(C)  # &lt;re.Match object; span=(0, 3), match=&#39;abc&#39;&gt;
&gt;
# 두 자리 숫자가 문자열의 시작에 있을 경우
D = re.match(r&#39;\d\d&#39;, &#39;12abc123&#39;)
print(D)  # &lt;re.Match object; span=(0, 2), match=&#39;12&#39;&gt;
&gt;
# 두 자리 숫자가 문자열의 시작에 없을 경우
E = re.match(r&#39;\d\d&#39;, &#39;a1ab12abc123&#39;)
print(E)  # None</code></pre>
<blockquote>
<p><em>re.compile( &lt;<em>pattern</em>&gt; , &lt;flags=0&gt; )</em></p>
</blockquote>
<pre><code class="language-python">  import re
&gt;
# 정규 표현식을 컴파일하여 패턴 객체 생성
pattern = re.compile(r&#39;\d+&#39;)
&gt;
# 패턴 객체를 사용하여 매칭 작업 수행
result = pattern.search(&#39;The year is 2024&#39;)
print(result.group())  # &#39;2024&#39;</code></pre>
<blockquote>
<p><em>re.fullmatch( &lt;<em>pattern</em>&gt; , &lt;<em>string</em>&gt; , &lt;flags=0&gt; )</em></p>
</blockquote>
<pre><code class="language-python">import re
&gt;
# 문자열 전체가 패턴과 일치하는지 확인
result = re.fullmatch(r&#39;\d+&#39;, &#39;123456&#39;)
print(result.group())  # &#39;123456&#39;
&gt;
# 문자열 전체가 패턴과 일치하지 않는 경우
result = re.fullmatch(r&#39;\d+&#39;, &#39;123abc&#39;)
print(result)  # None</code></pre>
<blockquote>
<p><em>re.split( &lt;<em>pattern</em>&gt; , &lt;<em>string</em>&gt; , &lt;maxsplit=0&gt; , &lt;flags=0&gt; )</em></p>
</blockquote>
<pre><code class="language-python">import re
&gt;
# 패턴을 기준으로 문자열을 분할하여 리스트로 반환
result = re.split(r&#39;\s+&#39;, &#39;This is a test string&#39;)
print(result)  # [&#39;This&#39;, &#39;is&#39;, &#39;a&#39;, &#39;test&#39;, &#39;string&#39;]
&gt;
# 최대 분할 횟수를 지정
result = re.split(r&#39;\s+&#39;, &#39;This is a test string&#39;, maxsplit=2)
print(result)  # [&#39;This&#39;, &#39;is&#39;, &#39;a test string&#39;]</code></pre>
<blockquote>
<p><em>re.findall( &lt;<em>pattern</em>&gt; , &lt;<em>string</em>&gt; , &lt;flags=0&gt; )</em></p>
</blockquote>
<pre><code class="language-python">import re
&gt;
# 문자열에서 패턴과 일치하는 모든 부분을 찾아 리스트로 반환
result = re.findall(r&#39;\d+&#39;, &#39;There are 123 apples and 456 oranges&#39;)
print(result)  # [&#39;123&#39;, &#39;456&#39;]</code></pre>
<blockquote>
<p><em>re.finditer( &lt;<em>pattern</em>&gt; , &lt;<em>string</em>&gt; , &lt;flags=0&gt; )</em></p>
</blockquote>
<pre><code class="language-python">import re
&gt;
# 문자열에서 패턴과 일치하는 모든 부분을 찾아 반복 가능한 객체로 반환
matches = re.finditer(r&#39;\d+&#39;, &#39;There are 123 apples and 456 oranges&#39;)
for match in matches:
    print(match.group())  # &#39;123&#39;, &#39;456&#39;</code></pre>
<blockquote>
<p><em>re.sub( &lt;<em>pattern</em>&gt; , &lt;<em>repl</em>&gt; , &lt;<em>string</em>&gt; , &lt;count=0&gt; , &lt;flags=0&gt; )</em></p>
</blockquote>
<pre><code class="language-python">import re
&gt;
# 패턴과 일치하는 부분을 다른 문자열로 대체
result = re.sub(r&#39;\d+&#39;, &#39;number&#39;, &#39;There are 123 apples and 456 oranges&#39;)
print(result)  # &#39;There are number apples and number oranges&#39;</code></pre>
<blockquote>
<p><em>re.subn( &lt;<em>pattern</em>&gt; , &lt;<em>repl</em>&gt; , &lt;<em>string</em>&gt; , &lt;count=0&gt; , &lt;flags=0&gt; )</em></p>
</blockquote>
<pre><code class="language-python">import re
&gt;
# 패턴과 일치하는 부분을 다른 문자열로 대체하며, 대체된 횟수도 함께 반환
result = re.subn(r&#39;\d+&#39;, &#39;number&#39;, &#39;There are 123 apples and 456 oranges&#39;)
print(result)  # (&#39;There are number apples and number oranges&#39;, 2)</code></pre>
<blockquote>
<p><em>re.escape( &lt;<em>string</em>&gt; )</em></p>
</blockquote>
<pre><code class="language-python">import re
&gt;
# 문자열에서 특수 문자를 이스케이프 처리
escaped_string = re.escape(&#39;This is a test. [Special characters: *?+|]&#39;)
print(escaped_string)  # &#39;This\\ is\\ a\\ test\\.\\ \\[Special\\ characters\\:\\ \\*\\?\\+\\|\\]&#39;
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[python library] 크롤링 with Selenium]]></title>
            <link>https://velog.io/@tulip_0206/python-library-2-selenium</link>
            <guid>https://velog.io/@tulip_0206/python-library-2-selenium</guid>
            <pubDate>Tue, 06 Aug 2024 06:55:24 GMT</pubDate>
            <description><![CDATA[<h2 id="1-requests과-selenium">1. requests과 selenium</h2>
<blockquote>
<p><strong>selenium</strong> : 웹 어플리케이션을 테스트하기 위해 고안된 프레임워크</p>
</blockquote>
<p>requests 라이브러리로 웹 정보를 받고 BeautifulSoup를 사용해서 파싱하는 방식도 있지만, 로그인이나 클릭, 혹은 스크롤과 같은 <em><strong>동적인 웹 컨트롤이 필요한 경우</strong></em> selenium을 사용한다.</p>
<p>하지만, selenium의 경우 시간과 비용이 많이 들기 때문에 동적인 웹 컨트롤이 필요하지 않은 경우에는 requests와 BeautifulSoup를 활용하는 것이 더 유리하다.</p>
<p>또한 selenium과 BeautifulSoup를 동시에 활용하는 것도 시간과 비용의 문제를 해결하기에 적합하다는 사실!</p>
<p><br></br></p>
<h2 id="2-selenium--chromedriver">2. selenium &amp; chromedriver</h2>
<blockquote>
<p>chromedriver : chrome 브라우저를 제어하기 위한 드라이버</p>
</blockquote>
<p>selenium을 사용하기 위해서는 chrome driver을 다운받아서 사용해야 한다. <a href="https://chromedriver.chromium.org/downloads">https://chromedriver.chromium.org/downloads</a> 에서 다운로드가 가능하지만 python 코드를 활용해서 이 과정을 자동화 할 수 있다.</p>
<pre><code class="language-python">!pip install selenium
!apt-get update
!apt install chromium-chromedriver
# !cp /usr/lib/chromium-browser/chromedriver &#39;/content/drive/MyDrive/Colab Notebooks&#39; # (최초 1회)
!pip install chromedriver-autoinstaller</code></pre>
<p><br></br></p>
<h2 id="3-selenium으로-chrome-browser-열기">3. selenium으로 Chrome browser 열기</h2>
<pre><code class="language-python">from selenium import webdriver
driver = webdriver.Chrome() # driver 경로를 파일경로와 같은 곳에 둘 경우
driver = webdriver.Chrome(&#39;driver path&#39;) # driver 경로를 파일경로와 다른 곳에 둘 경우
url = &#39;https://www.google.com&#39;
driver.get(url)</code></pre>
<p>위와 같이 chrome browser을 화면에 직접 띄우고 눈으로 과정을 확인하면서 작업하는 방법도 있지만, 지금부터 작성할 코드는 화면을 띄우지 않고 진행할 것이라는 점을 명심하길 바란다.</p>
<pre><code class="language-python">from selenium import webdriver
import chromedriver_autoinstaller
import sys

# chrome_path를 시스템 경로에 추가
chrome_path = &quot;/content/drive/MyDrive/Colab Notebooks/chromedriver&quot;
sys.path.insert(0,chrome_path)

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument(&#39;--headless&#39;) # 창을 띄우지 않는 Headless 모드
chrome_options.add_argument(&#39;--no-sandbox&#39;) # 샌드박스 모드 비활성화
chrome_options.add_argument(&#39;--disable-dev-shm-usage&#39;) # 메모리 문제 제거
chrome_options.add_argument(&#39;lang=ko_KR&#39;) # 한국어
chrome_options.add_experimental_option(&quot;excludeSwitches&quot;, [&quot;enable-logging&quot;]) # 불필요한 에러메시지 노출 방지
...

chromedriver_autoinstaller.install()  # Chromedriver 다운로드

driver = webdriver.Chrome(options=chrome_options)

url = &#39;https://www.google.com&#39;
driver.get(url)</code></pre>
<p><br></br></p>
<h2 id="4-웹-페이지-소스코드-읽기">4. 웹 페이지 소스코드 읽기</h2>
<p>위와 같이 chromedriver의 기본적인 설정 및 준비가 끝나면 기존에 requests를 활용했던 것과 동일하게 크롤링이 가능하다. BeautifulSoup를 활용한 파싱 이후로는 requests를 활용했던 것과 동일하지만, response.text 대신에 driver.page_source를 파싱해야 한다는 사실!</p>
<pre><code class="language-python">from bs4 import BeautifulSoup
import re

html = driver.page_source    # response.text와 같은 역할

soup = BeautifulSoup(html, &#39;html.parser&#39;)    # BeautifulSoup를 활용한 파싱
div_list = soup.find_all(&quot;div&quot;, attrs={&quot;class&quot; : re.compile(&quot;className&quot;)})
...
</code></pre>
<p><br></br></p>
<h2 id="5-동적-웹-컨트롤">5. 동적 웹 컨트롤</h2>
<p>버튼 클릭, 텍스트 입력, 로그인, 스크롤 등 다양한 동적 웹 컨트롤을 구현할 수 있다.</p>
<blockquote>
<p><em>Example 1 : 버튼 클릭</em></p>
</blockquote>
<pre><code class="language-python">from selenium.webdriver.common.by import By
&gt;
target = driver.find_element(By.XPATH, &#39;//*[@id=&quot;content&quot;]/div[2]/div/button&#39;)
target.click()</code></pre>
<blockquote>
<p><em>Example 2 : 텍스트 입력</em></p>
</blockquote>
<pre><code class="language-python">from selenium.webdriver.common.by import By
&gt;
target = driver.find_element(By.ID, &#39;loginForm&#39;)
target.send_keys(&quot;abc123!&quot;)</code></pre>
<blockquote>
<p><em>Example 3 : 로그인</em></p>
</blockquote>
<pre><code class="language-python">from selenium.webdriver.common.by import By
&gt;
url = &quot;https://nid.naver.com/nidlogin.login?mode=form&amp;url=https://www.naver.com/&quot;
driver.get(url)
&gt;
entry_ID = driver.find_element(By.XPATH, &#39;//*[@id=&quot;id&quot;]&#39;)
entry_ID.send_keys(&quot;ID123&quot;)
&gt;
entry_PW = driver.find_element(By.XPATH, &#39;//*[@id=&quot;pw&quot;]&#39;)
entry_PW.send_keys(&quot;pswd123!&quot;)
&gt;
btn = driver.find_element(By.XPATH, &#39;//*[@id=&quot;log.login&quot;]&#39;)
btn.click()</code></pre>
<blockquote>
<p><em>Example 4 : 스크롤 움직이기</em></p>
</blockquote>
<pre><code class="language-python">driver.execute_script(&quot;window.scrollTo(0, 700)&quot;)</code></pre>
<ul>
<li>execute_script() : 자바스크립트 동작</li>
</ul>
<p>그 외에 버튼 누르기, 특정 위치로 focus 이동하기 등 다양한 동적 웹 컨트롤이 가능하다.</p>
<blockquote>
<p>+ By 활용법</p>
</blockquote>
<pre><code class="language-python">from selenium.webdriver.common.by import By
&gt;
driver.find_element(By.XPATH, &#39;//button&#39;)
driver.find_element(By.ID, &#39;loginForm&#39;)
driver.find_element(By.LINK_TEXT, &#39;Continue&#39;)
driver.find_element(By.PARTIAL_LINK_TEXT, &#39;Conti&#39;)
driver.find_element(By.NAME, &#39;username&#39;)
driver.find_element(By.TAG_NAME, &#39;h1&#39;)
driver.find_element(By.CLASS_NAME, &#39;content&#39;)
driver.find_element(By.CSS_SELECTOR, &#39;p.content&#39;)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[python library] 크롤링 with requests & BeautifulSoup]]></title>
            <link>https://velog.io/@tulip_0206/python-library-1</link>
            <guid>https://velog.io/@tulip_0206/python-library-1</guid>
            <pubDate>Mon, 05 Aug 2024 16:29:58 GMT</pubDate>
            <description><![CDATA[<h2 id="1-크롤링crawling과-스크래핑scraping">1. 크롤링(Crawling)과 스크래핑(Scraping)</h2>
<p><img src="https://velog.velcdn.com/images/tulip_0206/post/a5ccada4-20bd-47e4-b68a-a086e06275fa/image.png" alt=""><a href="https://namu.wiki/w/%ED%81%AC%EB%A1%A4%EB%A7%81">▲ 나무위키 - 크롤링</a></p>
<hr>
<p><img src="https://velog.velcdn.com/images/tulip_0206/post/8ad2c358-26e1-4ef2-991a-f6c71b40e116/image.png" alt=""><a href="https://namu.wiki/w/%EC%8A%A4%ED%81%AC%EB%9E%98%ED%95%91">▲ 나무위키 - 스크래핑</a></p>
<hr>
<blockquote>
<p>구분 없이 용어를 사용하는 경우가 많다고 하지만 엄밀하게 말하자면 크롤링이 스크래핑보다 더 큰 개념의 용어이다.</p>
</blockquote>
<ul>
<li><strong>크롤링 (Crawling)</strong> : 웹 페이지<u><strong>의</strong></u> 정보를 가져오는 것</li>
<li><strong>스크래핑 (Scraping)</strong> : (크롤링한) 웹 페이지<u><strong>에서</strong></u> 데이터를 추출하는 것<blockquote>
</blockquote>
이번 글에서는 python의 <em><strong>BeautifulSoup</strong>_와 _<strong>requests</strong></em> 라이브러리를 사용한 크롤링을 다루고, 더 나아가 스크래핑까지 다룰 예정이다.</li>
</ul>
<p><br></br></p>
<h2 id="2-requests-라이브러리로-html-소스코드-불러오기">2. requests 라이브러리로 html 소스코드 불러오기</h2>
<p>우선 <em><strong>requests</strong></em> 에 대하여,  python에서 http를 다루기 위해 사용되는 라이브러리이다.</p>
<pre><code class="language-python">import requests

response = requests.get(&#39;url&#39;)</code></pre>
<p>사실 requests 라이브러리의 <strong>.get( &#39;url&#39; )</strong> 함수 하나면 해당 url의 html 소스코드를 불러올 수 있다.</p>
<pre><code class="language-python">print(response)
&gt;&gt;&gt; &lt;Response [200]&gt;

print(response.status_code)
&gt;&gt;&gt; 200

print(response.text)
&gt;&gt;&gt; &lt;!doctype html&gt; &lt;head&gt; &lt;meta charset=&quot;utf-8&quot;&gt; ... &lt;/body&gt;&lt;/html&gt;</code></pre>
<p>위와 같이 <strong>.status_code</strong>의 값이 200일 경우 해당 url에 정상적으로 접근했다는 걸 뜻하기에 앞으로 다음과 같이 사용하도록 하자.</p>
<pre><code class="language-python">import requests
import sys

response = requests.get(&#39;url&#39;)

# status_code가 200이 아니면 status_code를 출력하며 프로그램 종료
if response.status_code != 200:
    sys.exit(&quot;status code of response is &quot; + str(response.status_code))
</code></pre>
<p><br></br></p>
<h2 id="3-user---agent를-사용하여-안전하게-접근하기">3. User - Agent를 사용하여 안전하게 접근하기</h2>
<p>위 과정을 반복하다보면, 어느 순간 똑같은 url에 접근함에도 불구하고 status_code가 200이 나오지 않는 순간이 찾아온다. 반복된 비정상적인 접근을 서버가 탐지하고 차단한 것이라고 볼 수 있다. 따라서, 비정상적인 접근으로 간주되지 않기 위해서 <strong>User-Agent</strong>를 활용해서 정상적인 접근을 시도해보자.</p>
<pre><code class="language-python">headers = {&#39;User-Agent&#39; : &#39;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36&#39;}
response = requests.get(&#39;url&#39;, headers=headers)
</code></pre>
<p>이때 &#39;User-Agent&#39;의 값은 <a href="https://m.avalon.co.kr/check.html">m.avalon.co.kr</a>에서 확인할 수 있다.</p>
<p><br></br></p>
<h2 id="4-beautifulsoup를-이용한-html-소스코드-파싱">4. BeautifulSoup를 이용한 HTML 소스코드 파싱</h2>
<blockquote>
<p>파싱(Parsing)
: 언어의 구문을 분석하는 것</p>
</blockquote>
<p>따라서 <em><strong>BeautifulSoup</strong></em> 라이브러리를 활용해서 HTML 소스코드를 HTML 문법에 따라 분석하고 활용하자.</p>
<pre><code class="language-python">from bs4 import BeautifulSoup
soup = BeautifulSoup(response.text, &#39;html.parser&#39;)
# 혹은 BeautifulSoup(response.text, &#39;lxml&#39;)</code></pre>
<p>HTML은 <em><strong>태그(Tag)</strong>_와 _<strong>속성(Attribute)</strong></em>, 그리고 <em><strong>속성 정보</strong></em> 등으로 구성되어 있다. 따라서 특정 함수를 통해서 원하는 정보를 추출할 수 있다.</p>
<blockquote>
</blockquote>
<pre><code class="language-python">soup.find(&lt;Tag&gt;)        # HTML 문서의 위에서부터 첫 번째 &lt;Tag&gt;를 반환</code></pre>
<pre><code class="language-python">soup.find_all(&lt;Tag&gt;)    # HTML 문서의 모든 &lt;Tag&gt;를 반환</code></pre>
<pre><code class="language-python">soup.get(&lt;Attr&gt;)        # soup가 가리키는 첫 Tag의 속성(Attribute)들 중
                          # &lt;Attr&gt;에 해당하는 값을 반환</code></pre>
<pre><code class="language-python">soup.text                # soup가 가리키는 첫 Tag의 text를 반환</code></pre>
<pre><code class="language-python"># &lt;Tag&gt;와 &lt;Attr&gt;를 동시에 활용하여 검색하기
soup.find(&lt;Tag&gt;, attrs = {&lt;Attr&gt; : ... }
soup.find_all(&lt;Tag&gt;, attrs = {&lt;Attr&gt; : ... }</code></pre>
<blockquote>
<p><em>Example</em></p>
</blockquote>
<pre><code class="language-python">soup.find(&quot;div&quot;)        # body, div, span, a, li, ul, table, ...
soup.find_all(&quot;div&quot;, attrs = {&quot;class&quot; : &quot;Toastify&quot;})</code></pre>
<pre><code class="language-python">soup.find(&quot;a&quot;)
soup.get(&quot;href&quot;)
&gt;&gt;&gt;&gt; &quot;/write?id=fe2612d2-a18b-47c6-bcda-21715ee42316&quot;</code></pre>
<pre><code class="language-python">soup.find(&quot;span&quot;)
soup.text
&gt;&gt;&gt;&gt; &quot;동시대 미술이 선사하는\n극한의 깊이와 파격&quot;</code></pre>
<p><br></br></p>
<h2 id="5-re-정규식-연산-라이브러리">5. re 정규식 연산 라이브러리</h2>
<p>정규표현식(정규식) : 특정한 규칙을 가진 문자열의 집합을 표현하는 데 사용하는 형식 언어
find 혹은 find_all 함수를 사용하여 원하는 태그를 찾을 때 attrs을 사용하여 속성을 함께 검색할 수 있는데, 특정 단어를 포함한 모든 속성을 찾고 싶을 때 사용할 수 있다. 예를 들어서 설명해보겠다.</p>
<blockquote>
<pre><code class="language-python">soup.find_all(&quot;div&quot;, attrs = {&quot;class&quot; : &quot;language&quot;}</code></pre>
</blockquote>
<pre><code>
위 코드는 _**Tag**_가 _**div**_이며 속성 중 _**&quot;class&quot;**_의 값이 _**&quot;language&quot;**_인 태그가 반환된다.

하지만 만약 _**&quot;language_markdown&quot;**_과 _**&quot;language_null&quot;**_처럼 _**&quot;language&quot;**_라는 단어를 포함한 _**&quot;class&quot;**_ 속성 값을 가진 _**div**_ _**Tag**_를 반환받고 싶다면 다음과 같이 _**re**_ 라이브러리의 _**re.compile()**_ 함수를 활용할 수 있다.
&gt;```python
soup.find_all(&quot;div&quot;, attrs = {&quot;class&quot; : re.compile(&quot;language&quot;)})</code></pre><p><br></br></p>
<h2 id="결과물">결과물</h2>
<pre><code class="language-python">import requests
from bs4 import BeautifulSoup
import sys
import re

headers = {&#39;User-Agent&#39; : &#39;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36&#39;}
response = requests.get(&#39;url&#39;, headers=headers)

if response.status_code != 200:
    sys.exit(&quot;status code of response is &quot; + str(response.status_code))

soup = BeautifulSoup(response.text, &#39;html.parser&#39;)
td_list = soup.find_all(&quot;td&quot;, attrs = {&quot;class&quot; : re.compile(&quot;cell&quot;)})

text_list = []
for td in td_list:
    text_list.append(td.text)
# text_list = list(map(lambda x: x.text, td_list))</code></pre>
]]></description>
        </item>
    </channel>
</rss>