티스토리 뷰
코로나 확진자 수와 주가데이터 분석 파이썬(python)
peter was here 2022. 1. 1. 23:30안녕하세요. 이번 시간에는 코로나 확진자 수와 주가데이터 분석 에 대해서 알아보고자 합니다.
최근들어, 코로나 확진자 수와 주가데이터 분석에 대한 관심이 많아져서 오늘 알아보는 자료를 포스팅하게 되었습니다.
늘 말씀드리지만, 저보다 훌륭한 글들로 이미 포스팅해주신 다른 분들이 많기 때문에 이번 코로나 확진자 수와 주가데이터 분석 포스팅에서 부족한 부분은 다른 블로거 분들을 통해서 충분히 얻으실 수 있습니다.
그럼 python 초보자 분들도 충분히 하실 수 있을 코로나 확진자 수와 주가데이터 분석 시작합니다.
분석한 목차는 아래와 같습니다. 참고해주세요.
1. 상장종목코드 가져오기
2. 주가 데이터 가져오기
3. 코로나 확진자 수 데이터 가져오기
4. 주가데이터와 확진자 데이터 merge
5. 확진자와 주가 상관관계 분석
6. 주가캔들차트와 확진자 수 데이터 함께 그리기
주가캔들차트와 코로나 확진자수 상관관계 분석¶
from IPython.core.display import display, HTML
display(HTML("<style>.container {width:90% !important;}</style>"))
import warnings
warnings.filterwarnings(action='ignore')
import pandas_datareader.data as web
import FinanceDataReader as fdr
import datetime
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import mpl_finance
import matplotlib.ticker as ticker
from tqdm import tqdm
plt.rcParams["font.family"] = "appleGothic"
참고. FinanceDataReader 사용법¶
- 출처 : https://financedata.github.io/posts/finance-data-reader-users-guide.html
- 주의 : finance-datareader => import FinanceDataReader as fdr
1. 상장종목 코드 가져오기¶
# 한국거래소 상장종목 전체
df_krx = fdr.StockListing('KRX')
df_krx.head()
Symbol | Market | Name | Sector | Industry | ListingDate | SettleMonth | Representative | HomePage | Region | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 060310 | KOSDAQ | 3S | 전자부품 제조업 | 반도체 웨이퍼 캐리어 | 2002-04-23 | 03월 | 박종익, 김세완 (각자 대표이사) | http://www.3sref.com | 서울특별시 |
1 | 095570 | KOSPI | AJ네트웍스 | 산업용 기계 및 장비 임대업 | 렌탈(파렛트, OA장비, 건설장비) | 2015-08-21 | 12월 | 박대현 | http://www.ajnet.co.kr | 서울특별시 |
2 | 006840 | KOSPI | AK홀딩스 | 기타 금융업 | 지주사업 | 1999-08-11 | 12월 | 채형석, 이석주(각자 대표이사) | http://www.aekyunggroup.co.kr | 서울특별시 |
3 | 054620 | KOSDAQ | APS홀딩스 | 기타 금융업 | 인터넷 트래픽 솔루션 | 2001-12-04 | 12월 | 정기로 | http://www.apsholdings.co.kr | 경기도 |
4 | 265520 | KOSDAQ | AP시스템 | 특수 목적용 기계 제조업 | 디스플레이 제조 장비 | 2017-04-07 | 12월 | 김영주 | http://www.apsystems.co.kr | 경기도 |
1-2. 상장종목코드와 상호명 추출하기¶
## 주식회사명 dataframe 만들기
company_code_name_df = df_krx[['Symbol','Market','Name']]
company_code_name_df.head()
Symbol | Market | Name | |
---|---|---|---|
0 | 060310 | KOSDAQ | 3S |
1 | 095570 | KOSPI | AJ네트웍스 |
2 | 006840 | KOSPI | AK홀딩스 |
3 | 054620 | KOSDAQ | APS홀딩스 |
4 | 265520 | KOSDAQ | AP시스템 |
2. 주가 가져오기¶
def getStock(company_code, start_year):
company_code = str(company_code)
start_year = str(start_year)
## 주가정보 dataframe 만들기
df = fdr.DataReader(company_code, start_year)
df = df.reset_index()
## 주식회사명 주가정보 dataframe에 추가하기
target_company = company_code_name_df[company_code_name_df['Symbol'] == company_code].Name.values[0]
df['Name'] = target_company
return df
## 2019년 데이터부터 가져오기
test = getStock('032680', '2019')
test.columns
Index(['Date', 'Open', 'High', 'Low', 'Close', 'Volume', 'Change', 'Name'], dtype='object')
2-1) 전체 주가 정보 가져오기¶
## 빠른 계산을 위한 데이터 분산 준비
total = {}
target_data = company_code_name_df[company_code_name_df['Market'] != 'KONEX'].Symbol ## 비상장데이터 제외한 나머지
cnt = 200
for idx, i in enumerate([i for i in range(1, int(len(target_data)/200))]):
cnt = i*200
cnt_2 = (i+1)*200
total[0] = target_data[:200]
total[i] = target_data[cnt:cnt_2]
## 분산하지 않은 경우 : 총 걸린 시간 = 약 60여분
total_list = []
for i in tqdm(target_data): ## 전체 작업률 프로세스 알려주는 기능 (Tip)
try:
total_list.append(getStock(i, '2020').values)
except Exception as err:
pass
100%|██████████████████████████████████████████████████████████████████| 7187/7187 [35:12<00:00, 3.40it/s]
## 주가 dataframe 하나로 합치기
stock_total = pd.DataFrame(total_list[0])
for i in tqdm(range(1, len(total_list))):
stock_total = pd.concat([stock_total,pd.DataFrame(total_list[i])], axis=0)
100%|██████████████████████████████████████████████████████████████████| 3393/3393 [03:46<00:00, 14.99it/s]
stock_total.columns = ['Date', 'Open', 'High', 'Low', 'Close', 'Volume', 'Change', 'Name']
stock_total = stock_total.reset_index(drop=True)
3. 코로나 확진자 수 데이터 가져오기¶
- 데이터는 공공데이터 포털에서 가져오려다 조회를 해보니 누락되는 날짜도 있었고 원하는 데이터의 품질이 생각보다 좋지 않아서 다른 곳을 찾아봐야 했다.
- 그러다 간결하게 정리한 데이터가 깃헙에 공개가 되어 있어서 그것을 사용하려 한다. 해당 데이터는 https://coronaboard.kr/ 에서도 사용되는 데이터라고 한다.
출처 : https://taetaetae.github.io/posts/make-dashboards-from-elasticstack-1/
import csv, requests
import pandas as pd
CSV_URL = 'https://raw.githubusercontent.com/jooeungen/coronaboard_kr/master/kr_regional_daily.csv'
# 확진, 사망, 격리해제
yesterday_data = {}
yesterday_data['서울'] = [0, 0, 0]
yesterday_data['부산'] = [0, 0, 0]
yesterday_data['대구'] = [0, 0, 0]
yesterday_data['인천'] = [0, 0, 0]
yesterday_data['광주'] = [0, 0, 0]
yesterday_data['대전'] = [0, 0, 0]
yesterday_data['울산'] = [0, 0, 0]
yesterday_data['세종'] = [0, 0, 0]
yesterday_data['경기'] = [0, 0, 0]
yesterday_data['강원'] = [0, 0, 0]
yesterday_data['충북'] = [0, 0, 0]
yesterday_data['충남'] = [0, 0, 0]
yesterday_data['전북'] = [0, 0, 0]
yesterday_data['전남'] = [0, 0, 0]
yesterday_data['경북'] = [0, 0, 0]
yesterday_data['경남'] = [0, 0, 0]
yesterday_data['제주'] = [0, 0, 0]
yesterday_data['검역'] = [0, 0, 0]
flag = False
csv_data = []
with requests.Session() as s:
download = s.get(CSV_URL)
decoded_content = download.content.decode('utf-8')
cr = csv.reader(decoded_content.splitlines(), delimiter=',')
my_list = list(cr)
for row in my_list:
if row[0] == 'date':
continue
# 다음부터 과거 데이터의 차이만 다시 저장한다.
row[2] = int(row[2]) - int(yesterday_data[row[1]][0])
row[3] = int(row[3]) - int(yesterday_data[row[1]][1])
row[4] = int(row[4]) - int(yesterday_data[row[1]][2])
# 누적 데이터 저장
yesterday_data[row[1]][0] += row[2]
yesterday_data[row[1]][1] += row[3]
yesterday_data[row[1]][2] += row[4]
csv_data.append(row)
covid_df = pd.DataFrame(csv_data, columns = ['date','region','confirmed','death','released'])
# df.to_csv('covid19_korea.csv', index=False, header=False, encoding='utf8')
covid_df.head()
date | region | confirmed | death | released | |
---|---|---|---|---|---|
0 | 20200217 | 서울 | 14 | 0 | 3 |
1 | 20200217 | 부산 | 0 | 0 | 0 |
2 | 20200217 | 대구 | 0 | 0 | 0 |
3 | 20200217 | 인천 | 1 | 0 | 1 |
4 | 20200217 | 광주 | 2 | 0 | 0 |
## 전체지역 확진자수 그룹바이
total_covid_df = covid_df.groupby(['date'])['confirmed'].sum().reset_index(name='counts')
total_covid_df = total_covid_df.rename(columns={'date':'Date'})
total_covid_df['Date'] = total_covid_df['Date'].astype(str)
total_covid_df.head()
Date | counts | |
---|---|---|
0 | 20200217 | 30 |
1 | 20200218 | 1 |
2 | 20200219 | 20 |
3 | 20200220 | 57 |
4 | 20200221 | 97 |
## Date 데이터타입 변경
total_covid_df['Date'] = total_covid_df['Date'].apply(lambda x: datetime.datetime.strptime(x,"%Y%m%d"))
total_covid_df.head()
Date | counts | |
---|---|---|
0 | 2020-02-17 | 30 |
1 | 2020-02-18 | 1 |
2 | 2020-02-19 | 20 |
3 | 2020-02-20 | 57 |
4 | 2020-02-21 | 97 |
stock_total['Date'] = stock_total['Date'].astype(str)
total_covid_df['Date'] = total_covid_df['Date'].astype(str)
4. 주가데이터와 확진자 데이터 merge¶
finance_covid = pd.merge(stock_total, total_covid_df, on='Date').reset_index(drop=True)
finance_covid['datetime'] = finance_covid['Date'].apply(lambda x : datetime.datetime.strptime(x,"%Y-%m-%d"))
finance_covid['Close'] = finance_covid['Close'].astype(int)
finance_covid.head()
Date | Open | High | Low | Close | Volume | Change | Name | counts | datetime | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 2020-02-17 | 2870 | 3000 | 2825 | 2950 | 270670 | 0.033275 | 3S | 30 | 2020-02-17 |
1 | 2020-02-17 | 5100 | 5100 | 4920 | 4920 | 77900 | -0.035294 | AJ네트웍스 | 30 | 2020-02-17 |
2 | 2020-02-17 | 30400 | 30700 | 30000 | 30400 | 11912 | 0.006623 | AK홀딩스 | 30 | 2020-02-17 |
3 | 2020-02-17 | 13500 | 14100 | 12550 | 13800 | 889766 | 0.033708 | APS홀딩스 | 30 | 2020-02-17 |
4 | 2020-02-17 | 31900 | 33350 | 31500 | 33300 | 488439 | 0.053797 | AP시스템 | 30 | 2020-02-17 |
5. 확진자와 주가 상관관계 분석¶
covid_stock_corr_df = finance_covid.groupby(['Name'])[['Close','counts']].corr().iloc[0::2,-1].reset_index().sort_values('counts', ascending=False)
covid_stock_corr_df.head(10)
Name | level_1 | counts | |
---|---|---|---|
3125 | 한양디지텍 | Close | 0.925225 |
652 | SOL 유럽탄소배출권선물S&P(H) | Close | 0.916639 |
450 | KODEX 유럽탄소배출권선물ICE(H) | Close | 0.916448 |
1253 | 디엠티 | Close | 0.903084 |
552 | NHN벅스 | Close | 0.892141 |
2406 | 유안타제5호스팩 | Close | 0.891228 |
1032 | 뉴프렉스 | Close | 0.887873 |
649 | SOL 글로벌탄소배출권선물IHS(합성) | Close | 0.884551 |
134 | HANARO 글로벌탄소배출권선물ICE(합성) | Close | 0.879258 |
985 | 네오크레마 | Close | 0.876771 |
6. 주가캔들차트와 확진자 수 데이터 함께 그리기¶
def covid_stock_plot(company):
skhynix = finance_covid[finance_covid['Name'] == company]
skhynix['counts'] = skhynix['counts'].astype(int)
fig = plt.figure(figsize=(30, 10))
ax = fig.add_subplot(111)
day_list = []
name_list = []
for i, day in enumerate(skhynix.datetime):
if day.dayofweek == 0:
day_list.append(i)
name_list.append(day.strftime('%Y-%m-%d') + '(Mon)')
ax.xaxis.set_major_locator(ticker.FixedLocator(day_list))
ax.xaxis.set_major_formatter(ticker.FixedFormatter(name_list))
mpl_finance.candlestick2_ohlc(ax, skhynix['Open'], skhynix['High'], skhynix['Low'], skhynix['Close'], width=0.5, colorup='r', colordown='b')
plt.xticks(rotation =45)
ax2 = ax.twinx()
ax2.plot(skhynix['Date'].values, skhynix['counts'].values, color='black')
plt.grid()
plt.xticks(rotation =90)
plt.figtext(.5,.9,'{} stock & COVID 19'.format(company), fontsize=20, ha='center')
# plt.savefig('{}_covid.png'.format(company))
plt.show()
for i in ['한양디지텍','디엠티','NHN벅스','뉴프렉스','네오크레마']:
covid_stock_plot(i)
이처럼 확진자 수가 올라갈 수록 주가도 올라가는 경향을 보이는 기업을 찾아보았습니다.
어떠신가요? 뭔가 그래도 해석해볼만한 뭔가가 나오셨나요?
다만 주의하셔야할 게, 상관관계는 인과관계가 아니므로 확진자 수가 올라가니까 주가도 오른다고 해석하시면 위험합니다.
"확진자 수가 올라가니 주가도 올라가는 "경향"을 보인다." 라고만 해석하시는게 좋습니다.
간단히 분석한 결과라 이 정도로 인사이트를 발견하기는 쉽지 않습니다만, 모든 데이터 분석은 이렇게 작은 분석부터 시작합니다.
재미있으셨나요? 그럼 오늘도 좋은 하루되세요. 읽어주셔서 감사합니다.
'Business analytics > Business analysis' 카테고리의 다른 글
데이터 분석 vs. 비즈니스 분석 (Data Analytics vs. Business Analytics) (0) | 2020.01.03 |
---|
- Total
- Today
- Yesterday
- early_stopping_rounds
- 보스턴주택가격
- ChatModel
- mac mongodb 설치
- GPT4
- 보스턴집가격
- Python
- 맥북 몽고DB 설치
- 형태소분석
- 파이썬 스크래핑
- wowork
- python 크롤러 기초
- 알바천국 스크래핑
- lightgbm early stopping
- 파이썬 리스트 연산
- load_boston
- python crawler
- 브랜딩기획
- 판매량예측
- python 스크래핑 기초
- 데이터분석
- gpt3.5
- 위워크서울역
- 맥북 몽고DB 실행
- Mac MongoDB install
- 알바천국 크롤러
- 위워크서울스퀘어
- 위워크후기
- 파이썬
- 맥OS 몽고DB 설치
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |