Pandas는 Python으로 제공하는 외부라이브러리이다.
데이터를 읽는 것 부터 변환, 가공하여 쓰는데까지 많은 편의성을 제공한다. 데이터를 핸들링 하는 모든 과정은 빠르고 유연하다. 또한 많은 유틸리티 함수를 제공함으로써 데이터 조작을 손쉽게 할 수 있다.
이전 블로그에서 다트 Open API를 사용하여 기업 재무제표 데이터를 json형태로 결과를 수신했다. 해당 데이터를 행,열 데이터 구조로 가공하기 위해서 Pandas의 Dataframe으로 가공해보도록 한다.
참조: 공식 레퍼런스 사이트
관련 포스트 시리즈
- python - 다트.전자공시 Open API 활용(1), 전체 상장사(고유코드) 조회 - HTTP로 얻은 Stream zip파일 읽기
- python - 다트.전자공시 Open API 활용(2), 기업개황 응답데이터 JSON 핸들링( JSON 기초 )
- python - 다트.전자공시 Open API 활용(3), 공시대상회사 추출 및 가공 ( xml to dict - xmltodict library)
- python - 다트.전자공시 Open API 활용(4), 공시대상회사 조회 - 대화형 콘솔 만들기
- 전자공시 Open API 활용(5), 기업 재무제표 조회 API ( 분기/반기/사업보고서 - 재무상태표, 손익계산서 )
Pandas library 설치
pip install pandas
Pandas DataFrame이란 ?
Pandas 활용에 앞서 DataFrame은 무엇인지 공식레퍼런스 사이트에서 제공하는 이미지를 확인해보자.
위에서 보는바와 같이 dataframe은 행(row)과 열(column)로 구성된 2차원 데이터 구조를 갖는 자료구조(Data Structure)다. 엑셀과 SQL에서와 같이 데이터를 표현하는데 이상적인 구조이다.
Pandas는 DataFrame 데이터구조 외에 1차원 데이터 구조의 Series를 제공한다.
Pandas는 다른 데이터 포맷과의 호환성을 위해 다양한 API를 제공하는데 JSON, CSV, XLS, HTML, SQL, PARQUET등 여러 포맷을 읽고 쓸수있다.
개략적인 이해만 하고 코드실습으로 Pandas를 파헤쳐보자!!
JSON 데이터를 DataFrame으로 변환
전 블로그의 코드를 아래와 같이 수정하였다.(requests 인스톨 선행 할 것 : pip install requests)
import requests # urllib에서 requests로 대체 함.
import json
import pandas as pd
URL = 'https://opendart.fss.or.kr/api/fnlttSinglAcnt.json'
PARAMS = {
'crtfc_key': 'Insert your crtfc_key ', # API 인증키
'corp_code': '00126380', # 삼성전자 고유번호
'bsns_year': '2018', # 사업연도(4자리)
'reprt_code': '11011', # 사업보고서
}
resp = requests.get(url = URL, params = PARAMS)
if resp.status_code == 200:
data_json = resp.json()
# OUTPUT
# data_str = json.dumps(data_json, indent=4, ensure_ascii=False)
# print(data_str)
if data_json['status'] == "000":
detail = data_json['list']
# for x in detail:
# if x['fs_div'] == 'CFS' and x['sj_div'] == 'IS' and x['account_nm'] == '당기순이익':
# print(json.dumps(x, indent=4, ensure_ascii=False))
# Json 코드 DataFrame으로 변환
df = pd.json_normalize(detail)
print(df)
else :
print(data_json['message'])
json 형태로 구조화 되어있는 데이터를 json_normalize 함수를 사용하여 dataframe으로 변환하였다.
OUTPUT
rcept_no reprt_code bsns_year corp_code stock_code fs_div ... frmtrm_dt frmtrm_amount bfefrmtrm_nm bfefrmtrm_dt bfefrmtrm_amount ord
0 20190401004781 11011 2018 00126380 005930 CFS ... 2017.12.31 현재 146,982,464,000,000 제 48 기 2016.12.31 현재 141,429,704,000,000 1
1 20190401004781 11011 2018 00126380 005930 CFS ... 2017.12.31 현재 154,769,626,000,000 제 48 기 2016.12.31 현재 120,744,620,000,000 3
2 20190401004781 11011 2018 00126380 005930 CFS ... 2017.12.31 현재 301,752,090,000,000 제 48 기 2016.12.31 현재 262,174,324,000,000 5
3 20190401004781 11011 2018 00126380 005930 CFS ... 2017.12.31 현재 67,175,114,000,000 제 48 기 2016.12.31 현재 54,704,095,000,000 7
4 20190401004781 11011 2018 00126380 005930 CFS ... 2017.12.31 현재 20,085,548,000,000 제 48 기 2016.12.31 현재 14,507,196,000,000 9
... 중략 ...
20 20190401004781 11011 2018 00126380 005930 OFS ... 2017.12.31 현재 150,928,724,000,000 제 48 기 2016.12.31 현재 140,747,574,000,000 19
21 20190401004781 11011 2018 00126380 005930 OFS ... 2017.12.31 현재 151,569,775,000,000 제 48 기 2016.12.31 현재 137,546,762,000,000 22
22 20190401004781 11011 2018 00126380 005930 OFS ... 2017.01.01 ~ 2017.12.31 161,915,007,000,000 제 48 기 2016.01.01 ~ 2016.12.31 133,947,204,000,000 24
23 20190401004781 11011 2018 00126380 005930 OFS ... 2017.01.01 ~ 2017.12.31 34,857,091,000,000 제 48 기 2016.01.01 ~ 2016.12.31 13,647,436,000,000 26
24 20190401004781 11011 2018 00126380 005930 OFS ... 2017.01.01 ~ 2017.12.31 36,533,552,000,000 제 48 기 2016.01.01 ~ 2016.12.31 14,725,074,000,000 28
25 20190401004781 11011 2018 00126380 005930 OFS ... 2017.01.01 ~ 2017.12.31 28,800,837,000,000 제 48 기 2016.01.01 ~ 2016.12.31 11,579,749,000,000 30
행,열 구조의 DataFrame을 확인할 수 있다. DataFrame의 Schema는 다음과 같이 확인 할 수있다.
print(df.info(verbose=True))
Data columns (total 20 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 rcept_no 26 non-null object
1 reprt_code 26 non-null object
2 bsns_year 26 non-null object
3 corp_code 26 non-null object
4 stock_code 26 non-null object
5 fs_div 26 non-null object
6 fs_nm 26 non-null object
7 sj_div 26 non-null object
8 sj_nm 26 non-null object
9 account_nm 26 non-null object
10 thstrm_nm 26 non-null object
11 thstrm_dt 26 non-null object
12 thstrm_amount 26 non-null object
13 frmtrm_nm 26 non-null object
14 frmtrm_dt 26 non-null object
15 frmtrm_amount 26 non-null object
16 bfefrmtrm_nm 26 non-null object
17 bfefrmtrm_dt 26 non-null object
18 bfefrmtrm_amount 26 non-null object
19 ord 26 non-null object
dtypes: object(20)
memory usage: 2.1+ KB
None
Selection
특정 컬럼 한개를 추출하면 Series가 반환된다. Series는 위에서 언급한것 처럼 1차원 데이터 구조를 갖는다.
# 특정컬럼 추출
_account_nm_sr = df['account_nm']
print('_account_nm_sr: ', type(_account_nm_sr))
print(_account_nm_sr)
_account_nm_sr: <class 'pandas.core.series.Series'>
0 유동자산
1 비유동자산
2 자산총계
... 중략 ...
23 영업이익
24 법인세차감전 순이익
25 당기순이익
Name: account_nm, dtype: object
N개의 컬럼을 추출하면 DataFrame으로 반환된다.
# N개 컬럼 추출
_main_columns = df[['account_nm', 'fs_div', 'sj_div']]
print('_main_columns: ', type(_main_columns))
print(_main_columns)
_main_columns: <class 'pandas.core.frame.DataFrame'>
account_nm fs_div sj_div
0 유동자산 CFS BS
1 비유동자산 CFS BS
2 자산총계 CFS BS
... 중략 ...
23 영업이익 OFS IS
24 법인세차감전 순이익 OFS IS
25 당기순이익 OFS IS
Boolean indexing
컬럼 중 연결재무제표의 손익계산서 매출액, 영업이익, 법인세차감전 순이익, 당기순이익 데이터를 추출해보자. Row는 계정과목별로 나뉘어있다.
연결재무제표와 손익계산서 데이터는 다음과 같이 정의되어있다.
조건식은 아래와 같이 두가지 방식으로 처리할 수 있다.
# 1. 조건을 Series로 선언한 후 조립
_fs = df['fs_div'] == 'CFS'
_sj = df['sj_div'] == 'IS'
result_01 = df[_fs & _sj]
# 2. 내부에 바로 선언, 각 조건은 ()을 묶어줘야한다.
result_02 = df[
(df['fs_div'] == 'CFS')
& (df['sj_div'] == 'IS')
]
OUTPUT
rcept_no reprt_code bsns_year corp_code stock_code fs_div fs_nm ... frmtrm_nm frmtrm_dt frmtrm_amount bfefrmtrm_nm bfefrmtrm_dt bfefrmtrm_amount ord
9 20190401004781 11011 2018 00126380 005930 CFS 연결재무제표 ... 제 49 기 2017.01.01 ~ 2017.12.31 239,575,376,000,000 제 48 기 2016.01.01 ~ 2016.12.31 201,866,745,000,000 23
10 20190401004781 11011 2018 00126380 005930 CFS 연결재무제표 ... 제 49 기 2017.01.01 ~ 2017.12.31 53,645,038,000,000 제 48 기 2016.01.01 ~ 2016.12.31 29,240,672,000,000 25
11 20190401004781 11011 2018 00126380 005930 CFS 연결재무제표 ... 제 49 기 2017.01.01 ~ 2017.12.31 56,195,967,000,000 제 48 기 2016.01.01 ~ 2016.12.31 30,713,652,000,000 27
12 20190401004781 11011 2018 00126380 005930 CFS 연결재무제표 ... 제 49 기 2017.01.01 ~ 2017.12.31 42,186,747,000,000 제 48 기 2016.01.01 ~ 2016.12.31 22,726,092,000,000 29
[4 rows x 20 columns]
result_01 과 result_02의 데이터는 모두 같다. == 연산자를 사용하여 각 필드 데이터를 비교할 수 있다.
print(result_01 == result_02)
OUTPUT
rcept_no reprt_code bsns_year corp_code stock_code fs_div fs_nm sj_div ... thstrm_amount frmtrm_nm frmtrm_dt frmtrm_amount bfefrmtrm_nm bfefrmtrm_dt bfefrmtrm_amount ord
9 True True True True True True True True ... True True True True True True True True
10 True True True True True True True True ... True True True True True True True True
11 True True True True True True True True ... True True True True True True True True
12 True True True True True True True True ... True True True True True True True True
[4 rows x 20 columns]
주요컬럼 추출
# 계정과목명, 당기금액, 전기금액 추출
_extract_cols = ['account_nm', 'thstrm_amount', 'frmtrm_amount']
extracted_df = result_01.loc[:, _extract_cols]
account_nm thstrm_amount frmtrm_amount
9 매출액 243,771,415,000,000 239,575,376,000,000
10 영업이익 58,886,669,000,000 53,645,038,000,000
11 법인세차감전 순이익 61,159,958,000,000 56,195,967,000,000
12 당기순이익 44,344,857,000,000 42,186,747,000,000
보고자 했던 데이터가 깔끔하게 추출되었다! 이제 이것으로 무엇을 하고 싶은가? 전기 대비 당기 금액 증감율을 보고 싶지 않은가?
위에 info() 함수를 통해 확인했듯이 모든 컬럼은 object 타입이다. 이를 변환하기 위해서 astype 함수를 사용한다. 인자로써 변환할 형을 지정하게 되는데 이때 int가 아닌 numpy 모듈에서 제공하는 int64를 사용한다. 이유는 변환하는 대상의 값이 int 허용범위를 넘기 때문이다.
# numpy 모듈 상단 추가
import numpy as np
... 중략 ... 코드 마지막 이어서.
# comma(,) 제거 후 np.int64 파싱
extracted_df.loc[:, ['thstrm_amount', 'frmtrm_amount']] = extracted_df[['thstrm_amount', 'frmtrm_amount']].apply(lambda x: x.str.replace(',', '').astype(np.int64))
extracted_df.loc[:,'ratio'] = extracted_df.thstrm_amount / extracted_df.frmtrm_amount * 100
extracted_df.loc[:,'gap'] = extracted_df.thstrm_amount - extracted_df.frmtrm_amount
print(extracted_df)
apply 함수를 사용하여 각 Series에 comma(,) 를 제거하고 np.int64 타입으로 변환한다.
account_nm thstrm_amount frmtrm_amount ratio gap
9 매출액 243771415000000 239575376000000 101.751 4196039000000
10 영업이익 58886669000000 53645038000000 109.771 5241631000000
11 법인세차감전 순이익 61159958000000 56195967000000 108.833 4963991000000
12 당기순이익 44344857000000 42186747000000 105.116 2158110000000
'python > 주식' 카테고리의 다른 글
2. Python - Plotly 캔들 + 거래량 차트 만들기 ( 복수 차트 생성 ) (1) | 2021.01.26 |
---|---|
1. Python - 캔들차트(candlestick) + 스타일링 ( mplfinance, Plotly ) (4) | 2021.01.20 |
전자공시 Open API 활용(5), 기업 재무제표 조회 API ( 분기/반기/사업보고서 - 재무상태표, 손익계산서 ) (4) | 2020.03.28 |
python - 다트.전자공시 Open API 활용(4), 공시대상회사 조회 - 대화형 콘솔 만들기 (0) | 2020.03.07 |
python - 다트.전자공시 Open API 활용(3), 공시대상회사 추출 및 가공 ( xml to dict - xmltodict library) (0) | 2020.03.07 |