-
여행 갈 수 있을까..? ARIMA 모형과 함께하는 유로 환율 예측(1) - 전처리데이터 2025. 2. 2. 18:23
계기: 월간데이터노또(트)
어느 날 글또 '데이터-ai 빌리지' 슬랙 채널에 올라온 글 하나...보는 순간 너무 재밌어보이잖아?! 물론 내가 이걸 꾸준히 할 수 있을까? 란 생각도 잠시 들었지만 할 수 있는 건 다 용기내어 해보기를 목표로 삼았기에 일단 신청! (안되면 되게 하라 어차피 하게는 되어있을테니..) 올라온 글을 살짝 늦게 확인한 터라 걱정했는데 다행히도 참여할 수 있었습니다🫢
주제 선정
해보고 싶은 건 많지만 할 수 있는 것을 염두에 두고 정리하려니 너무 복잡...하지만 사실 할 건 정해져있었다! 5월에 프랑스 여행을 앞두고 최근 유로화 환전을 얼마쯤에 하면 그래도 괜찮을까? 를 고민하고 있었기에 그리고 오랜만에 비교적 간단한(?) 시계열 분석도 돌려보고 싶어서 유로 환율을 ARIMA 모형으로 예측해보는 것을 택했습니다. 그래서 첫 분석 주제는 유로 환율 예측해보자..!(feat.프랑스 여행)
물론 분석 작업을 하며 이 선택은 약간의 후회를 동반하게 되었지만..데이터 출처
환율 데이터를 얻는 방법은 파이썬의 라이브러리(forex-python, FinanceDataReader, yfinance 등)부터 크롤링, OpenAPI 까지 다양하게 있는데 그 중 저는 한국수출입은행의 Open API를 활용하기로 했습니다. 일별 환율 데이터에 과거 데이터까지 충분히 가져올 수 있을 것으로 확인되어서 선택했습니다. 다만 한 가지 주의할 점은 주말과 공휴일에는 데이터가 없다는 사실🥲 최근 주말에도 고시환율 업데이트하는 곳도 많다보니 이 부분을 처음에 미처 생각못했습니다.
우선 데이터를 가져오기 전, 한국수출입은행 Open API 페이지를 살펴보면 개인적으로 제가 눈여겨 본 부분은 요 두가지!
- 당행 환율 API에서 제공하는 데이터는 일환율 데이터로, 영업일 11시 전후로 업데이트 됩니다.
- RESULT 3으로 반환되는 경우, 최초 신청 시 입력해주셨던 개인정보의 보유기간이 만료되어 API 키가 파기되었을 가능성이 높습니다.
그리고 개발명세 부분입니다. 요청 URL과 예시, 요청변수 그리고 출력결과(Response Element)에 대해 상세히 나와있습니다.
데이터 가져오기(+전처리)
# 요청 변수 정의 from datetime import datetime, timedelta API_KEY = current_date = datetime.now().date() api_data = 'AP01' url = "https://www.koreaexim.go.kr/site/program/financial/exchangeJSON"
우선 요청 보낼 변수와 URL을 지정합니다. 저는 당일 오전 11시 이후에 작업했던 관계로 당일 치 데이터까지를 기준으로 잡았습니다.
import requests # 초기 데이터 프레임 설정 first_params = {'authkey' : API_KEY, 'searchdate': current_date.strftime('%Y%m%d'), 'data': api_data} first_response = requests.get(url, params=first_params) # first_response.text df = pd.DataFrame(first_response.json()) df.insert(0, 'search_date', current_date.strftime('%Y%m%d')) df.insert(1, 'reg_dt', datetime.now())
확인 겸 초기 셋팅을 위한 데이터 프레임 설정 작업을 진행합니다. 받아오는 response에서 기준일자가 따로 없어 별도로 추가해줬습니다. 그리고 데이터 입력 시기 확인을 위한 메타데이터로 '등록일자' 또한 별도로 추가했습니다.
이렇게 각국 통화 환율 정보를 비교적 깔끔하게 확인할 수 있습니다. 하지만 저는 하루가 아닌 2년치 정도의 데이터를 쓸 예정이었기에 과거 데이터까지 적재하는 작업 추가합니다.
# API 호출 대상 날짜 리스트 만들기 start_date = datetime(2022,12,30).date() target_days = [] target_date = start_date while target_date < current_date: target_days.append(target_date.strftime('%Y%m%d')) target_date += timedelta(days=1) # target_days
원하는 시점만큼의 API 호출할 대상 날짜 리스트를 먼저 만들어 줍니다.
# 데이터 프레임 만들기 for target_date in target_days: search_date = target_date params = {'authkey' : API_KEY, 'searchdate': search_date, 'data': api_data} response = requests.get(url, params=params) try: tmp_df = pd.DataFrame(response.json()) tmp_df.insert(0, 'search_date', search_date) print("insert search_date OK") tmp_df.insert(1, 'reg_dt', datetime.now()) print("insert reg_dt OK") df = pd.concat([df, tmp_df]) print("search_date = {}".format(search_date)) except HTTPError as e: print(e.response.text) except: print("fail") sys.exit(1)
조금 조잡하지만 중간 중간 확인을 위한 print 구문과 에러처리를 추가해서 데이터 프레임으로 분석할 데이터 셋 만드는 작업을 합니다.
# 데이터 타입 처리 df['search_date'] = pd.to_datetime(df['search_date']) df['deal_bas_r'] = df['deal_bas_r'].str.replace(',', '') df['deal_bas_r'] = df['deal_bas_r'].astype('float') # 유로 환율 데이터만 추출 df_eur = df[df['cur_unit'] == 'EUR'] # 필요한 컬럼만 추출 df_eur = df_eur[['search_date','cur_unit','deal_bas_r','cur_nm','reg_dt']]
전체 컬럼이 필요하지도 않고, 저는 유로 환율 정보만 있으면 되었기에 필요한 것만 남깁니다.
빈 날짜 채워넣기
여기서 저는 추가로 작업을 더 진행해줬는데요. 주말과 공휴일 빈 날짜를 채워넣는 작업을 진행했습니다. 처음엔 결측 처리를 어떻게 할까하다가 고시환율 업데이트를 하지않는 경우 기본적으로 환율 데이터를 그대로 둔다는 점을 반영하기로 하였습니다. 수출입은행에서 데이터가 빈 날짜들(주말, 공휴일)에 대해 이전 날짜의 환율 정보를 가져와서 넣어주는 식으로 방향성을 잡았습니다.
# 일 단위 전체 날짜 데이터 생성 start_date = '20221230' end_date = '20250124' date_table = pd.date_range(start=start_date, end=end_date, freq='D') base_date=pd.DataFrame({'base_date': date_table}) df_eur_f = pd.merge(base_date, df_eur, left_on='base_date', right_on='search_date', how='left') df_eur_f = df_eur_f.sort_values('base_date', ascending=True) # 결측 부분 채워넣기 df_eur_f['search_date'] = df_eur_f['search_date'].fillna(df_eur_f['base_date']) df_eur_f['reg_dt'] = df_eur_f['reg_dt'].fillna(datetime.now()) df_eur_f[['deal_bas_r','cur_unit','cur_nm']] = df_eur_f[['deal_bas_r','cur_unit','cur_nm']].fillna(method='ffill')
기준이 될 날짜 데이터프레임 생성 -> 해당 데이터를 기준으로 left join 시행 -> 결측 부분 기준에 맞게 채워넣기
- pandas.DataFrame.fillna
DataFrame.fillna(value=None, *, method=None, axis=None, inplace=False, limit=None, downcast=<no_default>)[source]
이 중 parameter 의 method를 활용하여 이전 날짜의 유효한 데이터를 채워넣을 수 있습니다. (SQL에서 window 함수 중 하나인 lag와 유사하지만 조금 다른 기능입니다.) 마지막 유요한 데이터 이므로 설날과 같이 3일 연속 휴일로 데이터가 없는 경우 설날 시작 전 날의 비어있지않은 데이터를 자동으로 채워넣는다는 점이 차이점일 것 같습니다.
이렇게 분석을 위한 데이터 준비가 완료 되었습니다. 이제 순차적으로 그래프로 추세를 보고 기초통계량도 확인하고 본격적으로 ARIMA 모형을 적용해볼 차례입니다. 이 부분은 다음 글에서 다뤄보는 걸로 하겠습니다..!
Comment
한 번에 다 쓰려고 했는데 쓰다보니 글이 너무 길어지는 것 같아 자르기로했습니다..간단하게 쓰려면 한없이 간단하고 구구절절이 쓰려니까 너무 말이 많아지네요. 개인적인 아쉬움도 많았던 미니 프로젝트였던만큼 흔적을 잘 남겨놓고자 합니다.🙇🏻♀️
'데이터' 카테고리의 다른 글
데이터 웨어하우스 알아가기 #2. 모델링 편(Star Schema, Snowflake Schema) (1) 2025.03.02 여행 갈 수 있을까..? ARIMA 모형과 함께하는 유로 환율 예측(2) (1) 2025.02.16 데이터 웨어하우스 알아가기 #1. DW(Data Warehouse)란? (2) 2025.01.18 [Amazon Redshift]DELETE vs TRUNCATE (1) 2024.11.24 Amazon Redshift 분산방식(diststyle) - AUTO, ALL, EVEN, KEY (0) 2024.11.10