<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dev_dreamer.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sun, 21 Jan 2024 18:10:34 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. dev_dreamer.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dev_dreamer" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[컴퓨터 그래픽스] 블러링 기법]]></title>
            <link>https://velog.io/@dev_dreamer/%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B7%B8%EB%9E%98%ED%94%BD%EC%8A%A4-%EB%B8%94%EB%9F%AC%EB%A7%81-%EA%B8%B0%EB%B2%95</link>
            <guid>https://velog.io/@dev_dreamer/%EC%BB%B4%ED%93%A8%ED%84%B0-%EA%B7%B8%EB%9E%98%ED%94%BD%EC%8A%A4-%EB%B8%94%EB%9F%AC%EB%A7%81-%EA%B8%B0%EB%B2%95</guid>
            <pubDate>Sun, 21 Jan 2024 18:10:34 GMT</pubDate>
            <description><![CDATA[<h1 id="블러링이란">블러링이란?</h1>
<p>블러링(bluring)이란 초점이 맞지 않은 사진처럼 영상을 부드럽게 만드는 필터링 기법이다. 스무딩(smoothing)이라고 표현하기도 한다. 대표적인 블러링 기법에는 박스 블러, 가우시안 블러가 있다.</p>
<h1 id="커널이란">커널이란?</h1>
<p>커널(필터라고도 표현함)이란 주로 이미지를 변환하는데 사용되는 작은 행렬을 의미한다.</p>
<p>일반적으로 이미지에 커널을 적용할 때는 컨볼루션 연산을 수행한다.(아래의 사진 참고)
<img src="https://velog.velcdn.com/images/dev_dreamer/post/720379ab-ad64-416f-93f4-d7a1d1fc7191/image.png" alt=""></p>
<figcaption style="text-align:center; font-size:15px; color:#808080; margin-top:40px">
    "출처: https://en.wikipedia.org/wiki/Kernel_(image_processing)"
</figcaption>


<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/ea5f2f3b-1fca-4996-bfce-2d64ce0f0a3a/image.gif" alt=""></p>
<figcaption style="text-align:center; font-size:15px; color:#808080; margin-top:40px">
    "출처: https://commons.wikimedia.org/w/index.php?curid=24288958"
</figcaption>

<h1 id="separable-filter란">Separable filter란?</h1>
<p>2차원 필터는 두 개의 1차원 필터의 외적(outer product)으로 표현할 수 있다. 이렇게 나누어 진 1차원 필터를 Separable filter라고 한다. 모든 2차원 필터가 두 개의 일차원 필터로 표현 될 수 있는 것은 아님에 주의해야한다. 외적으로 표현하지 못하는 2차원 필터는 2개의 1차원 필터로 나눌 수 없다. 아래의 사진은 Separable filter의 예이다.</p>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/e462c9fa-d473-407d-9551-985224e4a34f/image.png" alt=""></p>
<figcaption style="text-align:center; font-size:15px; color:#808080; margin-top:40px">
    "출처: https://en.wikipedia.org/wiki/Separable_filter"
</figcaption>

<p>이렇게 나누어진 1차원 필터를 이미지 픽셀 값에 각각 컨볼루션하면 2차원 필터를 이미지 픽셀 값에 컨볼루션 연산한 것과 동일한 결과가 나온다.</p>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/be69b8f1-5688-4fad-9b7b-2bafa9dca9ff/image.png" alt=""></p>
<h1 id="separable-filter를-쓰는-이유">Separable filter를 쓰는 이유</h1>
<p>일반 2D filter를 컨볼루션해서 사용하는 것보다 연산량이 적기 때문에 속도면에서 우위를 가져갈 수 있다.</p>
<p>예를 들어 N X N 크기의 2D 필터가 있다고 하자.</p>
<p>이미지 픽셀 수가 M인 경우 2D필터를 그대로 적용하려면 총 $N^2 \times M$번 연산을 수행해야한다.</p>
<p>하지만 Separable filter를 사용하는 경우 $2 \times N \times M$이 된다.</p>
<p>필터의 크기가 커질수록 연산량의 차이는 점점 더 벌어진다는 것을 알 수 있다.</p>
<h1 id="박스-블러">박스 블러</h1>
<h2 id="개념">개념</h2>
<p>박스 블러(Box blur)는 이미지 내 특정한 픽셀을 포함한 주변 픽셀 값들을 모두 더해서 평균을 내는 방식으로 블러를 구현한다. 아래의 사진은 Box blur 커널의 예시이다.
<img src="https://velog.velcdn.com/images/dev_dreamer/post/7fecc774-b3a5-4773-940b-dfae3ebd1f52/image.png" alt=""></p>
<figcaption style="text-align:center; font-size:15px; color:#808080; margin-top:40px">
    "출처: https://en.wikipedia.org/wiki/Kernel_(image_processing)"
</figcaption>

<h2 id="구현방법">구현방법</h2>
<ol>
<li>박스 블러 필터를 1차원 필터 2개로 나눈다.(Separable filter)</li>
<li>원본 이미지 픽셀 값에 가로 방향 필터를 적용해 컨볼루션 연산을 시행한다.</li>
<li>가로 방향 필터를 적용한 픽셀 값들에 세로 방향 필터를 적용해 컨볼루션 연산을 시행한다.</li>
</ol>
<h2 id="결과">결과</h2>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/dev_dreamer/post/ae44c960-e533-45f9-b0f9-87cac712824f/image.jpg" alt=""> 이미지 원본</th>
<th><img src="https://velog.velcdn.com/images/dev_dreamer/post/2f4242ab-55d3-41d6-816a-a756e345acce/image.png" alt=""> 박스 블러 적용 후</th>
</tr>
</thead>
<tbody><tr>
<td># 가우시안 블러</td>
<td></td>
</tr>
</tbody></table>
<h2 id="개념-1">개념</h2>
<p>가우시안 블러(Gaussian Blur)는 이미지의 각 픽셀의 값을 해당 픽셀 주변의 다른 픽셀의 색상 값의 가중 평균으로 대체하여 블러를 구현하는 방법이다. 이 때 중심에 가까운 픽셀일수록 더 큰 가중치를 가진다.
<img src="https://velog.velcdn.com/images/dev_dreamer/post/0747b466-6405-4beb-9121-b632f203989a/image.png" alt=""></p>
<figcaption style="text-align:center; font-size:15px; color:#808080; margin-top:40px">
    "출처: https://en.wikipedia.org/wiki/Kernel_(image_processing)"
</figcaption>


<h2 id="구현방법-1">구현방법</h2>
<ol>
<li>가우시안 블러 필터를 1차원 필터 2개로 나눈다.(Separable filter)</li>
<li>원본 이미지 픽셀 값에 가로 방향 필터를 적용해 컨볼루션 연산을 시행한다.</li>
<li>가로 방향 필터를 적용한 픽셀 값들에 세로 방향 필터를 적용해 컨볼루션 연산을 시행한다.</li>
</ol>
<h2 id="결과-1">결과</h2>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/dev_dreamer/post/5af2b0aa-1104-47ce-b9b1-6fa6a91bfa5b/image.jpg" alt=""> 이미지 원본</th>
<th><img src="https://velog.velcdn.com/images/dev_dreamer/post/a76e003e-d000-4fd2-9c25-a535e4ad72e7/image.png" alt=""> 가우시안 블러 적용 후</th>
</tr>
</thead>
</table>
<h1 id="박스-블러-vs-가우시안-블러">박스 블러 VS 가우시안 블러</h1>
<table>
<thead>
<tr>
<th><img src="https://velog.velcdn.com/images/dev_dreamer/post/01b5c82b-1f3c-489c-970f-3439eb78a55c/image.png" alt=""> 박스 블러 적용 후</th>
<th><img src="https://velog.velcdn.com/images/dev_dreamer/post/fbb35fe0-de0d-467c-8703-0da422f450f0/image.png" alt=""> 가우시안 블러 적용 후</th>
</tr>
</thead>
</table>
<p>박스 블러</p>
<ul>
<li>주변 픽셀들의 값을 평균화하기 때문에 경계가 흐려지는 효과가 강하게 나타남</li>
<li>세부적인 텍스처 정보 손실 값이 큼</li>
<li>계산이 간단하기 때문에 실시간 이미지 처리에 유리함.</li>
</ul>
<p>가우시안 블러</p>
<ul>
<li>가우시안 분포를 따르는 블러링 방식이기 때문에 세부적인 텍스터 정보를 적절히 살리면서 블러 구현 가능</li>
<li>박스블러와 달리 필터 요소값마다 적용해야 할 값이 다르기 때문에 계산이 복잡하고 시간이 박스블러에 비해 좀 더 소요됨</li>
</ul>
</br>
</br>
이 포스팅은 홍정모 연구소의 그래픽스 새싹 코스를 듣고 정리한 것입니다.]]></description>
        </item>
        <item>
            <title><![CDATA[[주식 전략 백테스팅] 종합 듀얼 모멘텀 전략]]></title>
            <link>https://velog.io/@dev_dreamer/%EC%A3%BC%EC%8B%9D-%EC%A0%84%EB%9E%B5-%EB%B0%B1%ED%85%8C%EC%8A%A4%ED%8C%85-%EC%A2%85%ED%95%A9-%EB%93%80%EC%96%BC-%EB%AA%A8%EB%A9%98%ED%85%80-%EC%A0%84%EB%9E%B5</link>
            <guid>https://velog.io/@dev_dreamer/%EC%A3%BC%EC%8B%9D-%EC%A0%84%EB%9E%B5-%EB%B0%B1%ED%85%8C%EC%8A%A4%ED%8C%85-%EC%A2%85%ED%95%A9-%EB%93%80%EC%96%BC-%EB%AA%A8%EB%A9%98%ED%85%80-%EC%A0%84%EB%9E%B5</guid>
            <pubDate>Mon, 25 Dec 2023 15:11:49 GMT</pubDate>
            <description><![CDATA[<h1 id="종합-듀얼-모멘텀-전략이란">종합 듀얼 모멘텀 전략이란?</h1>
<p>게리 안토나치가 제안한 전략으로 오리지널 듀얼 모멘텀에서 채권, 부동산, 불경기 자산 등을 추가해서 크게 4가지 자산으로 나누고 모멘텀을 적용한 전략이다.</p>
<h1 id="전략-설명">전략 설명</h1>
<p>포함 자산</p>
<ul>
<li>포트폴리오를 4개 파트로 나눔(각 파트에 자산의 25% 배분)</li>
<li>파트 1: 주식 - 미국 주식 SPY 또는 해외 주식 EFA</li>
<li>파트 2: 채권 - 미국 회사채 LQD 또는 미국 하이일드 채권 HYG</li>
<li>파트 3: 부동산 - 부동산 리츠 VNQ 또는 모기지 리츠 REM</li>
<li>파트 4: 불경기 - 미국 장기채 TLT 또는 금 GLD</li>
</ul>
<p>매수 전략</p>
<ul>
<li>매월 말 각 파트 별 2개 자산의 최근 12개월 모멘텀을 계산</li>
<li>둘 중 수익이 더 높은 ETF에 투자 (상대 모멘텀)</li>
<li>두 ETF 수익 모두가 BIL(미국 초단기채)수익보다 낮으면 달러 현금에 투자 (절대 모멘텀)</li>
</ul>
<p>매도 전략</p>
<ul>
<li>월 1회 리밸러싱</li>
</ul>
<h1 id="구현-코드">구현 코드</h1>
<h2 id="필요한-패키지-임포트">필요한 패키지 임포트</h2>
<pre><code class="language-python">import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime</code></pre>
<h2 id="데이터-다운로드">데이터 다운로드</h2>
<pre><code class="language-python"># 데이터 다운로드
tickers = [&#39;SPY&#39;, &#39;EFA&#39;, &#39;LQD&#39;,&#39;HYG&#39;,  &#39;VNQ&#39;, &#39;REM&#39;, &#39;TLT&#39;, &#39;GLD&#39;, &#39;BIL&#39;]
start = &#39;2007-05-01&#39; # BIL은 2007년 5월 이전의 정보는 없음
end = &#39;2023-06-01&#39;
data = yf.download(tickers, start=start, end=end)[&#39;Adj Close&#39;]</code></pre>
<h2 id="월별-데이터셋으로-변환">월별 데이터셋으로 변환</h2>
<pre><code class="language-python"># 월별 데이터셋 변환
monthly_data = data.resample(&#39;M&#39;).last()

print(monthly_data)</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/d8148cb5-a53b-4dcb-9f90-46912e15fe7d/image.png" alt=""></p>
<h2 id="모멘텀-계산">모멘텀 계산</h2>
<pre><code class="language-python"># 모멘텀 계산
momentum_12m = monthly_data.pct_change(periods=12) # 12개월 기준으로 수익률 계산
momentum_1m = monthly_data.pct_change(periods=1) # 1개월 기준으로 수익률 계산(월 1회 리밸런싱을 하기때문에 미리 계산해둠)
returns = pd.DataFrame(columns=[&#39;월 단위 수익률&#39;]) # 월별 수익률 저장할 데이터 프레임
cumprod = pd.DataFrame(columns=[&#39;누적 수익률&#39;]) # 누적 수익률을 저장할 데이터 프레임
strategy = monthly_data.copy()# 백테스팅 결과를 담을 데이터프레임
print(&quot;1개월 모멘텀&quot;)
print(momentum_1m) # 인덱스 1 이전의 값들은 자신 이전의 1개월 이전의 데이터를 찾을 수 없으므로 nan이다.

print(&quot;12개월 모멘텀&quot;)
print(momentum_12m)</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/2d498fa4-9f2c-413a-a9a7-d0b24968f7f8/image.png" alt=""></p>
<h2 id="월별-수익률-계산-함수">월별 수익률 계산 함수</h2>
<pre><code class="language-python"># 월별 수익률 계산 함수
def calculate_momentum_1m(t,ticker):
  return float(momentum_1m[[ticker]].iloc[t+1])+1 # 나중에 누적곱을 해줘야하기 때문에 +1를 더해줌</code></pre>
<h2 id="종합-듀얼-모멘텀-로직">종합 듀얼 모멘텀 로직</h2>
<pre><code class="language-python"># 종합 듀얼 모멘텀 로직
# 달마다 투자하는 자산을 바꿔주기 때문에 리밸런싱이 되고 있다.
# t가 12부터 시작하는 이유는 12보다 작을 경우 return_12m의 값이 nan이기 때문
returns.loc[monthly_data.index[12], :] = 1 # 처음 시작 수익률은 1

for t in range(12,len(momentum_12m)-1):
  total = 0

  # 파트 1 로직, SPY와 EFA
  if momentum_12m[&#39;SPY&#39;].iloc[t] &gt; momentum_12m[&#39;BIL&#39;].iloc[t] or momentum_12m[&#39;EFA&#39;].iloc[t] &gt; momentum_12m[&#39;BIL&#39;].iloc[t]:
    # SPY가 클경우 SPY에 투자
    if momentum_12m[&#39;SPY&#39;].iloc[t] &gt;= momentum_12m[&#39;EFA&#39;].iloc[t]:
      total_1 = calculate_momentum_1m(t,&#39;SPY&#39;) # SPY의 1개월 수익률 할당
      strategy.loc[monthly_data.index[t], [&quot;파트 1&quot;]] = &#39;SPY&#39; # 구매한 종목 이름 저장
    # EFA가 클경우 EFA에 투자
    else:
      total_1 = calculate_momentum_1m(t,&#39;EFA&#39;) # EFA의 1개월 수익률 할당
      strategy.loc[monthly_data.index[t], [&quot;파트 1&quot;]] = &#39;EFA&#39; # 구매한 종목 이름 저장
  else:
    # SPY와 EFA 둘다 BIL보다 작으면 달러 현금에 투자 즉 수익률 변동이 없으므로 1할당
    total_1 = 1
    strategy.loc[monthly_data.index[t], [&quot;파트 1&quot;]] = &#39;달러 현금 투자&#39;

  # 파트 2 로직, LQD와 HYG, 파트1과 로직은 동일
  if momentum_12m[&#39;LQD&#39;].iloc[t] &gt; momentum_12m[&#39;BIL&#39;].iloc[t] or momentum_12m[&#39;HYG&#39;].iloc[t] &gt; momentum_12m[&#39;BIL&#39;].iloc[t]:
    # LQD가 클경우 LQD에 투자
    if momentum_12m[&#39;LQD&#39;].iloc[t] &gt;= momentum_12m[&#39;HYG&#39;].iloc[t]:
      total_2 = calculate_momentum_1m(t,&#39;LQD&#39;)
      strategy.loc[monthly_data.index[t], [&quot;파트 2&quot;]] = &#39;LQD&#39;
    # HYG가 클경우 HYG에 투자
    else:
      total_2 = calculate_momentum_1m(t,&#39;HYG&#39;)
      strategy.loc[monthly_data.index[t], [&quot;파트 2&quot;]] = &#39;HYG&#39;
  else:
    # LQD와 HYG 둘다 BIL보다 작으면 달러 현금에 투자 즉 수익률 변동이 없으므로 1할당
    total_2 = 1
    strategy.loc[monthly_data.index[t], [&quot;파트 2&quot;]] = &#39;달러 현금 투자&#39;

  # 파트 3 로직, VNQ와 REM, 파트1과 로직은 동일
  if momentum_12m[&#39;VNQ&#39;].iloc[t] &gt; momentum_12m[&#39;BIL&#39;].iloc[t] or momentum_12m[&#39;REM&#39;].iloc[t] &gt; momentum_12m[&#39;BIL&#39;].iloc[t]:
    # VNQ가 클경우 VNQ에 투자
    if momentum_12m[&#39;VNQ&#39;].iloc[t] &gt;= momentum_12m[&#39;REM&#39;].iloc[t]:
      total_3 = calculate_momentum_1m(t,&#39;VNQ&#39;)
      strategy.loc[monthly_data.index[t], [&quot;파트 3&quot;]] = &#39;VNQ&#39;
    # REM가 클경우 REM에 투자
    else:
      total_3 = calculate_momentum_1m(t,&#39;REM&#39;)
      strategy.loc[monthly_data.index[t], [&quot;파트 3&quot;]] = &#39;REM&#39;
  else:
    # VNQ와 REM 둘다 BIL보다 작으면 달러 현금에 투자 즉 수익률 변동이 없으므로 1할당
    total_3 = 1
    strategy.loc[monthly_data.index[t], [&quot;파트 3&quot;]] = &#39;달러 현금 투자&#39;

  # 파트 4 로직, TLT와 GLD, 파트1과 로직은 동일
  if momentum_12m[&#39;TLT&#39;].iloc[t] &gt; momentum_12m[&#39;BIL&#39;].iloc[t] or momentum_12m[&#39;GLD&#39;].iloc[t] &gt; momentum_12m[&#39;BIL&#39;].iloc[t]:
    # TLT가 클경우 TLT에 투자
    if momentum_12m[&#39;TLT&#39;].iloc[t] &gt;= momentum_12m[&#39;GLD&#39;].iloc[t]:
      total_4 = calculate_momentum_1m(t,&#39;TLT&#39;)
      strategy.loc[monthly_data.index[t], [&quot;파트 4&quot;]] = &#39;TLT&#39;
    # GLD가 클경우 GLD에 투자
    else:
      total_4 = calculate_momentum_1m(t,&#39;GLD&#39;)
      strategy.loc[monthly_data.index[t], [&quot;파트 4&quot;]] = &#39;GLD&#39;
  else:
    # TLT와 GLD 둘다 BIL보다 작으면 달러 현금에 투자 즉 수익률 변동이 없으므로 1할당
    total_4 = 1
    strategy.loc[monthly_data.index[t], [&quot;파트 4&quot;]] = &#39;달러 현금 투자&#39;

  #각 파트 별로 자산의 25% 배분
  total = 0.25*total_1 + 0.25*total_2 + 0.25*total_3 + 0.25*total_4
  returns.loc[monthly_data.index[t+1], :] = total

print(&quot;월단위 수익률&quot;)
print(returns)
print()
strategy[&quot;월단위 수익률&quot;] = returns[&#39;월 단위 수익률&#39;]

print(&quot;누적 수익률&quot;)
cumprod[&#39;누적 수익률&#39;] = (returns[&#39;월 단위 수익률&#39;]).cumprod(axis = 0) # 누적 수익률를 구하기 위함
print(cumprod)
strategy[&quot;누적 수익률&quot;] = cumprod[&#39;누적 수익률&#39;]</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/be1672b3-db9e-497d-887a-f355e281911f/image.png" alt=""></p>
<h2 id="누적-수익률-그래프">누적 수익률 그래프</h2>
<pre><code class="language-python"># 누적 수익률 그래프 출력
plt.figure(figsize=(10,5))
plt.plot(cumprod)
plt.title(&#39;Portfolio Value over Time&#39;)
plt.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/77977668-ee96-449f-8d8b-1839aed5d29f/image.png" alt=""></p>
<h2 id="롤링-맥스-그래프">롤링 맥스 그래프</h2>
<pre><code class="language-python">rolling_max = cumprod.cummax() # 월별로 누적 최대값을 저장
strategy[&quot;rolling max&quot;] = rolling_max
# 롤링 맥스 그래프 출력
plt.figure(figsize=(10,5))
plt.plot(rolling_max)
plt.title(&#39;Rolling max over Time&#39;)
plt.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/7a1825fb-3a37-4ad3-843f-718731df86e2/image.png" alt=""></p>
<h2 id="mdd-그래프">MDD 그래프</h2>
<pre><code class="language-python"># CAGR 계산
# len(monthly_data)에서 12를 빼준 이유는 우리가 투자를 시작한 지점은 처음 데이터가
# 나온 2007-05-31의 1년 뒤인 2008-05-31이기 때문이다.(실투자 기간으로 잡음)
# 1년 뒤에 투자를 시작한 이유는 우리가 12개월 모멘텀을 사용함으로
# 12개월 모멘텀을 구하기 위해서는 최초데이터에서 최소한 12개월이 지나야한다.
cagr = cumprod[&#39;누적 수익률&#39;].iloc[-1] ** (1 / ((len(monthly_data)-12) / 12)) - 1

# MDD 계산
daily_drawdown = cumprod/rolling_max - 1.0 # 누적 수익률에 롤링맥스 값 나누고 떨어진 값을 표현하기 위해 - 1.0을 더함
strategy[&quot;daily drawdown&quot;] = daily_drawdown
max_daily_drawdown = daily_drawdown.cummin()

print(&quot;Cumulative Return: &quot;, float(cumprod.iloc[-1]))
print(&quot;CAGR: &quot;, cagr)
print(&quot;MDD: &quot;, float(max_daily_drawdown.iloc[-1]))

# Plot MDD 그래프 출력
plt.figure(figsize=(10,5))
plt.plot(daily_drawdown)
plt.plot(max_daily_drawdown)
plt.title(&#39;Maximum Drawdown&#39;)
plt.show()

strategy[&quot;Cumulative Return&quot;] = float(cumprod.iloc[-1])
strategy[&quot;cagr&quot;] = cagr
strategy[&quot;MDD&quot;] = float(max_daily_drawdown.iloc[-1])</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/91c535e1-73cc-45a7-a159-05c02834576e/image.png" alt=""></p>
<h2 id="정규화된-etf-가격-그래프-출력기타-성능-평가-요인">정규화된 ETF 가격 그래프 출력(기타 성능 평가 요인)</h2>
<pre><code class="language-python"># 기타 부가 성능 평가 요인
# 정규화된 ETF 가격 그래프 출력
normalize_monthly_data = monthly_data/monthly_data.iloc[0]

plt.figure(figsize=(10,5))
plt.plot(normalize_monthly_data,label = normalize_monthly_data.columns)
plt.legend(loc = &quot;upper left&quot;)
plt.title(&#39;ETF Price&#39;)
plt.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/17aa12ee-a942-4529-9a35-45a729b6432b/image.png" alt=""></p>
<h2 id="엑셀-파일-다운로드">엑셀 파일 다운로드</h2>
<pre><code class="language-python"># 엑셀 파일 다운로드
from google.colab import files
strategy.to_excel(&#39;백테스팅 결과 값.xlsx&#39;,index = True)
files.download(&#39;백테스팅 결과 값.xlsx&#39;)

momentum_12m.to_excel(&#39;12개월 모멘텀 값.xlsx&#39;,index = True)
files.download(&#39;12개월 모멘텀 값.xlsx&#39;)

momentum_1m.to_excel(&#39;1개월 모멘텀 값.xlsx&#39;,index = True)
files.download(&#39;1개월 모멘텀 값.xlsx&#39;)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 플로이드 워셜]]></title>
            <link>https://velog.io/@dev_dreamer/%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%9B%8C%EC%85%9C</link>
            <guid>https://velog.io/@dev_dreamer/%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%9B%8C%EC%85%9C</guid>
            <pubDate>Sun, 13 Aug 2023 04:57:57 GMT</pubDate>
            <description><![CDATA[<h2 id="플로이드-워셜-알고리즘이란">플로이드 워셜 알고리즘이란?</h2>
<p>플로이드 워셜 알고리즘은 모든 노드에서 다른 모든 노드로 가는 최단 경로를 구하는 알고리즘이다.</p>
<p>즉, 다익스트라 알고리즘과 다르게 출발점이 정해져있지 않다는 것이다.</p>
<p>$$
D_{ab} = min(D_{ab},D_{ak}+D_{kb})
$$</p>
<p>플로이드 워셜 알고리즘의 핵심은 위의 점화식을 구현하는데 있다. </p>
<p>$D_{ab}$는 a노드에서 b노드까지 가는데 소요되는 비용을 의미한다. </p>
<p>여기서 a노드에서 b노드를 가는데 중간에 k노드를 거쳐서 간다고 생각해보자 </p>
<p>기존에 $D_{ab}$ 보다 $D_{ak}+D_{kb}$(k노드를 경유)의 값이 더 작은 경우가 있을 것이다.</p>
<p>우리는 최단거리를 찾는 것이므로 $D_{ab}$의 값을 $D_{ak}+D_{kb}$로 갱신해준다. </p>
<p>이것을 모든 노드에 대하여 반복한다면 결국에는 모든 노드에서 다른 모든 노드로 가는 최단경로를 구할 수 있다.</p>
<pre><code class="language-python">INF = int(1e9)

n,m = map(int,input().split())

graph = [[INF] * (n+1) for _ in range(n+1)]

# 자기 자신에서 자기 자신으로 가는 비용은 0으로 초기화
for i in range(1,n+1):
    for j in range(1,n+1):
        if i == j:
            graph[i][j] = 0

# 간선 정보를 2차원 행렬에 반영
for _ in range(m):
    a,b,c = map(int,input().split())
    graph[a][b] = c

# 플로이드 워셜 알고리즘 수행
for k in range(1,n+1): # 거쳐가는 노드
    for a in range(1,n+1): # 시작 노드
        for b in range(1,n+1): # 도착 노드
            graph[a][b] = min(graph[a][b], graph[a][k]+graph[k][b])

for i in range(1,n+1):
    for j in range(1,n+1):
        if graph[i][j] == INF:
            print(&#39;INF&#39;, end = &#39;  &#39;)
        else:
            print(graph[i][j], end = &#39;  &#39;)
    print()</code></pre>
<p>위에 코드에서 보다시피 인접 행렬을 기반으로 하며, 3중 for문을 이용해서 구현한다.</p>
<ol>
<li>첫 번째 for문은 거쳐가는 노드를 기준으로 한다.</li>
<li>두 번째 for문은 출발하는 노드를 기준으로 한다.</li>
<li>세 번째 for문은 도착하는 노드를 기준으로 한다.</li>
<li>graph[a][b], graph[a][k]+graph[k][b]를 비교해 더 작은 값으로 갱신한다.</li>
</ol>
<h2 id="시간-복잡도">시간 복잡도</h2>
<p>알고리즘의 시간 복잡도는 O($N^{3}$)이다.</p>
<p>N개의 노드가 있을 때 거쳐가는 노드 하나당 O($N^{2}$) 연산을 시행하기 때문이다.</p>
<h2 id="특징">특징</h2>
<ul>
<li>다익스트라 알고리즘과 달리 음의 간선이 있어도 정상 수행(하지만 음수 사이클이 있으면 안됨)</li>
<li>다이나믹 프로그래밍 기법을 사용한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[데이터 시각화] Plotly 사용법]]></title>
            <link>https://velog.io/@dev_dreamer/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%8B%9C%EA%B0%81%ED%99%94-Plotly-%EC%82%AC%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@dev_dreamer/%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%8B%9C%EA%B0%81%ED%99%94-Plotly-%EC%82%AC%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Mon, 17 Jul 2023 02:34:04 GMT</pubDate>
            <description><![CDATA[<h2 id="plotly란">Plotly란?</h2>
<blockquote>
<p>Plotly는 클릭에 반응하는 인터렉티브한 그래프(3D 그래프, 파이 차트 등등)를 만들 수 있고,
다양한 언어(Python, JavaScript, R 등등)를 지원하는 오픈소스 그래프 라이브러리이다.
<a href="https://plotly.com/python/">Plotly 공식 사이트(Python)</a></p>
</blockquote>
<hr>
<h2 id="plotly-기본이해">Plotly 기본이해</h2>
<ul>
<li><p>Plotly를 통해 그래프를 그리는 방법은 크게 2가지가 있다. </p>
<ul>
<li><code>plotly.graph_objects</code>를 사용하는 경우 그래프의 구성요소를 세부적으로 지정해주는 방식으로 그래프에 대한 디테일한 커스텀이 가능하다. (본 게시글에서 다루는 방법)</li>
<li><code>plotly.express</code>를 사용하는 경우 graph_objects를 API 형식으로 제공하는 방법으로 데이터만을 가공하여 API에 입력하면 그래프를 그릴 수 있다.</li>
</ul>
</li>
<li><p>Plotly의 기본구조
<img src="https://velog.velcdn.com/images/dev_dreamer/post/e9545db7-757a-42db-ba9a-f8fb23eca869/image.svg" alt=""></p>
<ul>
<li><p>Figure</p>
<ul>
<li>Plotly 작업의 기본 단위이며 graph_objects.Figure() 메소드를 통해 생성이 가능하다.</li>
<li>data와 layout를 입력으로 받고, 해당 정보를 기반으로 show() 메소드를 통해 그래프를 그려준다.</li>
</ul>
</li>
<li><p>data</p>
<ul>
<li>data는 figure가 표현할 데이터를 의미하는데 trace를 하나 또는 그이상을 파이썬 리스트로 감싸서 입력받는다.</li>
<li>trace란 그리고자 하는 그래프의 타입(ex. Bar, Scatter, Line, Box..)과 그 그래프에 시각화 하고자 하는 Raw 데이터를 품고있는 단위이다.</li>
</ul>
</li>
<li><p>layout</p>
<ul>
<li>그래프의 data와는 무관하고 그외 모든 부분을 편집 및 가공하는 부분이다.</li>
<li>Title, legend, Colors, Hover-label, Axes, Shape 등 시각화를 높히기 위한 다양한 도구들은 모두 layout을 통해 지정한다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="bar-chart">Bar Chart</h2>
<h3 id="일반적인-bar-chart">일반적인 Bar Chart</h3>
<pre><code class="language-python">from plotly import graph_objects as go
langs = [&#39;C&#39;, &#39;C++&#39;, &#39;Java&#39;, &#39;Python&#39;, &#39;PHP&#39;]
students = [23,17,35,29,12]

# x축과 y축에 해당하는 데이터를 각각 넣고 리스트로 감싸줌
data = [go.Bar(x = langs, y = students)]
# 만들어놓은 데이터 전달
fig = go.Figure(data = data)

# 그래프 출력
fig.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/de1a0d15-1219-448b-be5d-cbb4a520ef46/image.png" alt=""></p>
<h3 id="그룹화와-스택화">그룹화와 스택화</h3>
<pre><code class="language-python">from plotly import graph_objects as go

branches = [&#39;CSE&#39;, &#39;Mech&#39;, &#39;Electronics&#39;]

fy=[23,17,35]
sy=[20,23,30]
ty=[30,20,15]

# x는 동일하되 y의 값은 다른 3개의 Bar객체 생성
trace1=go.Bar(
    x = branches,
    y = fy,
    name = &#39;FY&#39;)

trace2=go.Bar(
    x = branches,
    y = sy,
    name = &#39;SY&#39;)

trace3=go.Bar(
    x = branches,
    y = ty,
    name = &#39;TY&#39;)

data = [trace1,trace2,trace3]

# 그룹화 된 막대 차트를 표시하려면 레이아웃 개체의 막대 모드 속성을 그룹으로 설정해야함
layout = go.Layout(barmode=&#39;group&#39;,title=&#39;Departments&#39;)
fig = go.Figure(data=data,layout=layout)
fig.show()

# 스택형 막대 차트를 표시하려면 레이아웃 개체의 막대 모드 속성을 그룹으로 설정해야함
layout=go.Layout(barmode=&#39;stack&#39;, title=&#39;Departments&#39;)
fig = go.Figure(data=data, layout=layout)
fig.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/420013e0-d249-4cd1-8c8e-696eabed9c2b/image.png" alt="">
<img src="https://velog.velcdn.com/images/dev_dreamer/post/bf929ce7-9e4a-4322-8a16-50d8eaa8cc9d/image.png" alt=""></p>
<h3 id="색상-커스터마이징">색상 커스터마이징</h3>
<pre><code class="language-python">from plotly import graph_objects as go

years = [1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012]
rest = [219, 146, 112, 127, 124, 180, 236, 207, 236, 263, 350, 430, 474, 526, 488, 537, 500, 439]
china = [16, 13, 10, 11, 28, 37, 43, 55, 56, 88, 105, 156, 270, 299, 340, 403, 549, 499]

trace1=go.Bar(
    x=years,
    y=rest,
    name=&#39;Rest of the World&#39;,
    # 색상 커스터마이징을 위한 정보를 딕셔너리에 담아서 marker에 전달
    marker=dict(
        # RGB값 설정
        color=&#39;rgb(49,130,189)&#39;,
        # 불투명도 설정
        opacity=0.7
    )
)

trace2=go.Bar(
    x=years,
    y=china,
    name=&#39;China&#39;,
    marker=dict(
        color=&#39;rgb(204,204,204)&#39;,
        opacity=0.5
    )
)

data=[trace1,trace2]
layout=go.Layout(barmode=&#39;group&#39;, title=&#39;Export of Plastic Scrap&#39;)
fig=go.Figure(data=data, layout=layout)
fig.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/152ae04d-94c1-4350-a31e-87726546d92c/image.png" alt=""></p>
<hr>
<h2 id="pie-chart">Pie Chart</h2>
<h3 id="일반적인-pie-chart">일반적인 Pie Chart</h3>
<pre><code class="language-python">from plotly import graph_objects as go

langs = [&#39;C&#39;,&#39;C++&#39;,&#39;Java&#39;,&#39;Python&#39;,&#39;PHP&#39;]
students = [23,17,35,29,12]

data = [go.Pie(
    labels = langs,
    values = students,
    # 각각의 인덱스에 배정된 조각을 원점을 기준으로 얼마나 당길건지 설정
    pull=[0.1,0,0,0,0]
)]

fig = go.Figure(data=data)
fig.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/66eb183b-95c2-4327-826c-1b970179cf47/image.png" alt=""></p>
<h3 id="pie-chart의-여러-옵션-및-subplots-활용">Pie Chart의 여러 옵션 및 subplots 활용</h3>
<pre><code class="language-python">from plotly import graph_objects as go
from plotly.subplots import make_subplots

countries = [&quot;US&quot;, &quot;China&quot;, &quot;European Union&quot;, &quot;Russian Federation&quot;, &quot;Brazil&quot;, &quot;India&quot;, &quot;Rest of World&quot;]
ghg = [16, 15, 12, 6, 5, 4, 42] 
co2 = [27, 11, 25, 8, 1, 3, 25]

fig = make_subplots(rows=1,cols=2, 
                    specs=[[{&#39;type&#39;:&#39;domain&#39;},{&#39;type&#39;:&#39;domain&#39;}]]) # 1x2형식의 subplot 생성
fig.add_trace(go.Pie(labels=countries,
                    values=ghg,
                    name=&quot;GHG Emissions&quot;),
             # 1행 1열에 위치
             row=1,col=1)

fig.add_trace(go.Pie(labels=countries,
                    values=co2,
                    name=&quot;CO2 Emissions&quot;),
             # 1행 2열에 위치
             row=1,col=2)

# hole은 파이차트 가운데 구멍의 크기를 설정
# hoverinfo는 마우스 커서를 갖다 댔을때 띄워질 정보 설정
fig.update_traces(hole=0.4, hoverinfo=&quot;label+percent+name&quot;)

fig.update_layout(
    title_text=&quot;Global Emissions 1990-2011&quot;, # 타이틀 설정
    # annotations은 주석에 대한 정보를 딕셔너리형태로 표현하고 리스트에 넣어서 전달 받음.
    # showarrow가 True면 해당좌표를 화살표로 가리킴.
    annotations=[dict(text=&#39;GHG&#39;,x=0.19, y=0.5, font_size=20, showarrow=False),
                 dict(text=&#39;CO2&#39;,x=0.8, y=0.5, font_size=20, showarrow=False)])

fig.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/85271de1-fb02-48b0-be76-6d29c1d4189c/image.png" alt=""></p>
<hr>
<h2 id="scatter-plot">Scatter Plot</h2>
<pre><code class="language-python">from plotly import graph_objects as go
import numpy as np

N = 100

# 0~1사이안에서 N개의 요소를 동일한 간격으로 나누어 놓은 1차원 넘파이 배열 반환
# 예를 들어 linspace(0,10,11)이면 [0,1,2,...,9,10]를 반환한다는 것
x_vals = np.linspace(0,1,N)

# 데이터 준비
# randn: 표준정규분포를 따르는 난수 발생
y1 = np.random.randn(N)+5
y2 = np.random.randn(N)
y3 = np.random.randn(N)-5

trace1 = go.Scatter(
    x=x_vals,
    y=y1,
    # mode는 데이터 포인트의 모양을 결정
    mode=&#39;markers&#39;,
    name=&#39;markers&#39;
)

trace2 = go.Scatter(
    x=x_vals,
    y=y2,
    mode=&#39;lines+markers&#39;,
    name=&#39;lines+markers&#39;
)

trace3 = go.Scatter(
    x=x_vals,
    y=y3,
    mode=&#39;lines&#39;,
    name=&#39;lines&#39;
)

data=[trace1,trace2,trace3]
fig=go.Figure(data=data)
fig.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/be39e09c-03e0-46eb-83a7-92703b3bd36f/image.png" alt=""></p>
<hr>
<h2 id="dot-plot">Dot plot</h2>
<pre><code class="language-python">from plotly import graph_objects as go

schools=[&quot;Brown&quot;, &quot;NYU&quot;, &quot;Notre Dame&quot;, &quot;Cornell&quot;, &quot;Tufts&quot;, &quot;Yale&quot;,
         &quot;Dartmouth&quot;, &quot;Chicago&quot;, &quot;Columbia&quot;, &quot;Duke&quot;, &quot;Georgetown&quot;,
         &quot;Princeton&quot;, &quot;U.Penn&quot;, &quot;Stanford&quot;, &quot;MIT&quot;, &quot;Harvard&quot;]

trace1=go.Scatter(
    x=[72, 67, 73, 80, 76, 79, 84, 78, 86, 93, 94, 90, 92, 96, 94, 112],
    y=schools,
    marker=dict(color=&#39;crimson&#39;, size=12),
    mode=&quot;markers&quot;,
    name=&quot;Women&quot;)

trace2=go.Scatter(
    x=[92, 94, 100, 107, 112, 114, 114, 118, 119, 124, 131, 137, 141, 151, 152, 165],
    y=schools, marker=dict(color=&quot;gold&quot;, size=12),
    mode=&quot;markers&quot;,
    name=&quot;Men&quot;)

data=[trace1,trace2]

layout=go.Layout(title=&quot;Gender Earnings Disparity&quot;,
                xaxis_title=&#39;Annual Salary (in thousands)&#39;,
                yaxis_title=&#39;School&#39;)

fig=go.Figure(data=data,layout=layout)

fig.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/545d2cc1-d657-4c32-b25e-bd3019a9c0b1/image.png" alt=""></p>
<hr>
<h2 id="histogram">Histogram</h2>
<h3 id="일반적인-histogram">일반적인 Histogram</h3>
<pre><code class="language-python">from plotly import graph_objects as go
import numpy as np

np.random.seed(1)

# 표준 정규분포를 따르는 난수 500개를 ndarray로 반환
x = np.random.randn(500)
data=[go.Histogram(x=x)]

fig=go.Figure(data)
fig.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/99e85d69-9945-420b-bbf6-ba09744f1cfd/image.png" alt=""></p>
<h3 id="중첩된-histogram">중첩된 Histogram</h3>
<pre><code class="language-python">import plotly.graph_objects as go
import numpy as np

x0=np.random.randn(500)
x1=np.random.randn(500)+1

fig=go.Figure()
# go.Figure(data = []) 방법이 아닌 add_trace 메소드를 통해 직접 Trace를 추가할 수도 있음
fig.add_trace(go.Histogram(x=x0))
fig.add_trace(go.Histogram(x=x1))

# 중첩해서 표현
fig.update_layout(barmode=&#39;overlay&#39;)
# 중첩해서 보여주기 위해 불투명도 설정(각각의 trace에서 따로 설정가능)
fig.update_traces(opacity=0.75)
fig.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/3ccc3372-8775-42ae-8da8-6870c0cb5887/image.png" alt=""></p>
<hr>
<h3 id="2d-histogram">2D Histogram</h3>
<pre><code class="language-python">import plotly.graph_objects as go
import numpy as np
np.random.seed(1)

x=np.random.randn(500)
y=np.random.randn(500)+1

# 2차원으로 표현해서 색깔이 밝을 수록 해당 구간에 데이터가 많다는 것을 표현
fig=go.Figure(go.Histogram2d(x=x,y=y))
fig.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/563ddd89-3940-4cd2-8e81-33020ff59364/image.png" alt=""></p>
<hr>
<h2 id="box-plot">Box plot</h2>
<p>Box Plots은 주로 데이터에서 이상치를 탐지하는데 사용한다.
q1은 하위 25%를 의미하고 q3는 상위 25%를 의미한다.</p>
<pre><code class="language-python">import plotly.graph_objects as go

yaxis = [1140,1460,489,594,502,508,370,200] 
data = go.Box(y = yaxis) 
fig = go.Figure(data) 
fig.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/c2760ec5-d741-48c1-bea3-30a51738439f/image.png" alt=""></p>
<hr>
<h2 id="violin-plot">Violin plot</h2>
<p>Violin plot은 box plot과 유사하지만 데이터의 밀도를 표현한다는 점이 특징이다.</p>
<pre><code class="language-python">import plotly.graph_objects as go 
import numpy as np

np.random.seed(10)
c1 = np.random.normal(100, 10, 200)
c2 = np.random.normal(80, 30, 200)

# 평균선 표시 여부 설정
trace1 = go.Violin(y=c1, meanline_visible=True)
# 박스 플롯 표시 여부 설정
trace2 = go.Violin(y=c2, box_visible=True)
data = [trace1, trace2]

fig = go.Figure(data=data)
fig.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/dev_dreamer/post/bbd05c5a-a0e7-4a99-9dd3-5bc5f8ef6936/image.png" alt=""></p>
<h2 id="참고-자료">참고 자료</h2>
<p><a href="https://wikidocs.net/book/8909">Plotly Tutorial - 파이썬 시각화의 끝판왕 마스터하기</a></p>
]]></description>
        </item>
    </channel>
</rss>