일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- SK텔레콤
- Espressif
- 매터
- cluster
- 라즈베리파이
- raspberry pi
- 힐스테이트 광교산
- esp32
- 빅데이터분석기사
- Home Assistant
- 미국주식
- 배당
- RS-485
- 파이썬
- 현대통신
- Bestin
- 해외주식
- 애플
- 나스닥
- homebridge
- 주식
- Python
- matter
- 공모주
- 국내주식
- ConnectedHomeIP
- 월패드
- MQTT
- Apple
- 홈네트워크
- Today
- Total
YOGYUI
공공데이터포털::코로나19 감염현황 데이터 조회 (REST API) 본문
공공데이터포털에서 국내 코로나19 감염현황에 대한 데이터를 얻어보자 (OpenAPI 실습)
데이터 타이틀은 "보건복지부_코로나 19 감염_현황"이고 URL은 아래 링크를 참고
www.data.go.kr/data/15043376/openapi.do
RESTful API로 호출하여 XML 포맷으로 데이터를 받아볼 수 있을 것 같다
1. 데이터 활용신청
로그인 후 페이지 내 "활용신청" 버튼을 클릭 후 개발계정 신청서를 작성하자
승인되면 다음과 같이 API가 활용가능한 것으로 디스플레이된다
(원래 사용하는 계정은 신청/활용건수가 너무 많아 포스팅을 위해 계정을 새로 하나 만들었다...)
개발계정 상세보기로 가면 실제 API에서 사용해야 할 Key (일반 인증키)를 얻을 수 있다
Key값 (일반인증키)는 API 호출 시 필요하므로 메모장같은데 복사해두자
※ 중요: 처리상태가 승인이라고 해서 API를 바로 사용할 수 있는게 아니더라... (SERVICE KEY IS NOT REGISTERED ERROR 응답만 주구장창 볼 수 있음)
공공데이터포털 공식 안내문에는 서버 동기화까지 1시간 정도가 소요된다고 하는데 (일부 데이터셋은 24시간 소요), 실상은 그렇지가 못한 것 같다
데이터포털 사이트 Q&A 게시판보면 Key Not Registered Error 관련 문의글이 넘쳐흐른다
일단 승인완료 후에 괜히 바로 들이대지 말고 맘편하게 하루 이상 기다린 뒤 개발을 시작해보도록 하자
만약 해당 데이터를 본인의 어플리케이션(웹 혹은 모바일 앱)에서 활용하고자 할 경우 '운영계정 신청'을 해줘야 한다
운영계정 신청 시 해당 데이터가 사용될 어플리케이션에서 어떤 방식으로 활용되는지에 대한 개요를 제출해야 한다 (사이트 URL, 웹/앱 스크린샷 및 description)
단순히 활용 계정으로만 신청할 경우 일일 트래픽은 1000건으로 제한되긴 하지만 간단하게 실습할 때는 문제없다 (운영계정으로 등록하면 일일트래픽은 10만건까지 확대)
참고문서 (word파일)을 보면 API에 대한 좀 더 상세한 정보를 확인할 수 있다
(다행히도 SSL 암호화는 안쓰네...)
만약 해당 API로 어플리케이션을 만들고자 할 경우, 평균 응답 시간 및 초당 최대 TR 등을 고려해야한다
2. Test
URL이랑 API 키가 있으니 API 호출 준비는 완료되었다
서비스 URL: http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19InfStateJson
API 호출 시 필요한 파라미터는 데이터 소개 페이지에 기재되어 있다
필수 인자는 발급받는 서비스 키 (ServiceKey)
Python으로 URL Request해보자 (HTTP GET method, requests 라이브러리 활용)
인증키가 UTF-8 URL 인코딩된 결과로 주어질 경우, 코드에서는 해당 문자열을 ASCii 문자열로 디코딩 후 파라미터로 입력해줘야 제대로 된 응답을 받을 수 있다
URL 관련 라이브러리에서 제공하는 unquote는 %xx 이스케이프 문자로 인코딩(UTF-8)된 문자를 단일 문자로 대체해준다 (예: '1%2B2%3D3' → '1+2=3')
(requests 라이브러리나, urllib라이브러리의 parse 모듈이나 구현 결과는 동일하다)
import requests
from urllib import parse
url = "http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19InfStateJson"
api_key_utf8 = "Your API Key form data.go.kr"
api_key_decode = requests.utils.unquote(api_key_utf8, encoding='utf-8')
# api_key_decode = parse.unquote(api_key_utf8, encoding='utf-8')
params={
"ServiceKey": api_key_decode,
"startCreateDt": 20200221,
"endCreateDt": 20200221
}
response = requests.get(url, params=params)
테스트삼아 2021년 2월 21일 하루치의 데이터만 요청해봤다 (output text는 보기좋게 수정)
In [1]: print(response.text)
Out[1]:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<response>
<header>
<resultCode>00</resultCode>
<resultMsg>NORMAL SERVICE.</resultMsg>
</header>
<body>
<items>
<item>
<accDefRate>1.3725500095</accDefRate>
<accExamCnt>6411340</accExamCnt>
<accExamCompCnt>6337984</accExamCompCnt>
<careCnt>7919</careCnt>
<clearCnt>77516</clearCnt>
<createDt>2021-02-21 09:34:28.285</createDt>
<deathCnt>1557</deathCnt>
<decideCnt>86992</decideCnt>
<examCnt>73356</examCnt>
<resutlNegCnt>6250992</resutlNegCnt>
<seq>426</seq>
<stateDt>20210221</stateDt>
<stateTime>00:00</stateTime>
<updateDt>null</updateDt>
</item>
</items>
<numOfRows>10</numOfRows>
<pageNo>1</pageNo>
<totalCount>1</totalCount>
</body>
</response>
별다른 문제가 없다면 header의 resultCode는 00, resultMsg는 NORMAL SERVICE. 값을 가진다
body의 items 태그 안에 요청한 수만큼의 데이터가 하루 단위로 묶여있다
item 내부 각 태그들의 의미는 데이터포털에서 제공하는 명세서 (워드파일)를 참고
3. Data Parsing
XML format으로 얻은 응답 문자열을 beautifulsoup 라이브러리를 사용해 파싱해보자
(일주일치 데이터를 얻은 뒤 각 아이템들의 속성 및 값들을 딕셔너리 형태로 변환한 뒤, pandas DataFrame으로 하나의 데이터셋으로 변환)
속성별로 데이터형식이 정수형 / 실수형 / Date형/ DateTime형이 나뉘므로 각 데이터별 형식을 담은 딕셔너리를 사전 정의해두고 iteration하면 깔끔하게 구현할 수 있다
import requests
import pandas as pd
from bs4 import BeautifulSoup
from datetime import date, datetime
def getCovid19Info(start_date: date, end_date: date):
url = "http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19InfStateJson"
api_key_utf8 = "Your API Key from data.go.kr"
api_key_decode = requests.utils.unquote(api_key_utf8, encoding='utf-8')
params={
"ServiceKey": api_key_decode,
"startCreateDt": int('{:04d}{:02d}{:02d}'.format(start_date.year, start_date.month, start_date.day)),
"endCreateDt": int('{:04d}{:02d}{:02d}'.format(end_date.year, end_date.month, end_date.day)),
}
response = requests.get(url, params=params)
return BeautifulSoup(response.text, "lxml")
convert_method = {
'accdefrate': float,
'accexamcnt': int,
'accexamcompcnt': int,
'carecnt': int,
'clearcnt': int,
'createdt': lambda x: datetime.strptime(x, '%Y-%m-%d %H:%M:%S.%f'),
'deathcnt': int,
'decidecnt': int,
'examcnt': int,
'resutlnegcnt': int,
'seq': int,
'statedt': lambda x: datetime.strptime(x, '%Y%m%d'),
'statetime': str,
'updatedt': lambda x: datetime.strptime(x, '%Y-%m-%d %H:%M:%S')
}
temp = getCovid19Info(date(2021, 2, 15), date(2021, 2, 21))
items = temp.find('items')
item_list = []
for item in items:
item_dict = {}
for tag in list(item):
try:
item_dict[tag.name] = convert_method[tag.name](tag.text)
except Exception:
item_dict[tag.name] = None
item_list.append(item_dict)
df = pd.DataFrame(item_list)
In [2]: df
Out[2]:
accdefrate accexamcnt accexamcompcnt ... statedt statetime updatedt
0 1.372550 6411340 6337984 ... 2021-02-21 00:00 None
1 1.371068 6390631 6314494 ... 2021-02-20 00:00 None
2 1.372585 6345992 6274876 ... 2021-02-19 00:00 None
3 1.372917 6303214 6232494 ... 2021-02-18 00:00 None
4 1.372719 6260567 6188157 ... 2021-02-17 00:00 None
5 1.374134 6213490 6136593 ... 2021-02-16 00:00 None
6 1.378793 6162859 6082713 ... 2021-02-15 00:00 None
[7 rows x 14 columns]
검사기준일을 기준으로 내림차순으로 정렬되어있는 것을 알 수 있다
4. 전체 데이터 불러오기
DataFrame으로 변환하는 구문을 함수화하고, 전체 데이터를 불러오는 함수도 따로 만들어보자
(2020년 1월 31일이 최초로 기록된 데이터이니, 2020년 1월 1일을 시작 날짜로 잡고 오늘 날짜까지 데이터를 불러오도록 구현)
import requests
import pandas as pd
from typing import Union
from bs4 import BeautifulSoup
from datetime import date, datetime
def getCovid19Info(start_date: Union[date, datetime], end_date: Union[date, datetime]):
url = "http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19InfStateJson"
api_key_utf8 = "Your API Key from data.go.kr"
api_key_decode = requests.utils.unquote(api_key_utf8, encoding='utf-8')
params={
"ServiceKey": api_key_decode,
"startCreateDt": int('{:04d}{:02d}{:02d}'.format(start_date.year, start_date.month, start_date.day)),
"endCreateDt": int('{:04d}{:02d}{:02d}'.format(end_date.year, end_date.month, end_date.day)),
}
response = requests.get(url, params=params)
elapsed_us = response.elapsed.microseconds
print('Request Done, Elapsed: {} seconds'.format(elapsed_us / 1e6))
return BeautifulSoup(response.text, "lxml")
def getCovid19DataFrame(start_date: Union[date, datetime], end_date: Union[date, datetime]) -> pd.DataFrame:
convert_method = {
'accdefrate': float,
'accexamcnt': int,
'accexamcompcnt': int,
'carecnt': int,
'clearcnt': int,
'createdt': lambda x: datetime.strptime(x, '%Y-%m-%d %H:%M:%S.%f'),
'deathcnt': int,
'decidecnt': int,
'examcnt': int,
'resutlnegcnt': int,
'seq': int,
'statedt': lambda x: datetime.strptime(x, '%Y%m%d'),
'statetime': str,
'updatedt': lambda x: datetime.strptime(x, '%Y-%m-%d %H:%M:%S')
}
temp = getCovid19Info(start_date, end_date)
items = temp.find('items')
item_list = []
for item in items:
item_dict = {}
for tag in list(item):
try:
item_dict[tag.name] = convert_method[tag.name](tag.text)
except Exception:
item_dict[tag.name] = None
item_list.append(item_dict)
df = pd.DataFrame(item_list)
return df
def getAllCovid19Data() -> pd.DataFrame:
now = datetime.now()
df = getCovid19DataFrame(date(2019, 1, 1), now)
print("Today: {}\nLoaded {} Records".format(now.strftime('%Y-%m-%d'), df.shape[0]))
return df
In [3]: df = getAllCovid19Data()
Request Done, Elapsed: 0.329607 second
Today: 2021-02-23
Loaded 424 Records
>> 2021년 2월 23일 기준으로 총 424 레코드 존재
>> 전체 데이터 불러오는데 330msec 정도 시간이 소요된다 (인터넷 환경에 따라 변동)
데이터프레임을 탐색해보면, 코로나 초기 (2020년 초반)에는 하루에도 여러번 데이터가 업데이트된 것을 알 수 있다 (~2020년 3월 1일까지의 데이터를 보면 statetime을 보면 하루 데이터가 오전 9시, 오후 4시 데이터로 두 차례로 나누어 집계)
In [4]: df[-60:][['createdt', 'decidecnt', 'statetime']]
Out[4]:
createdt decidecnt statetime
364 2020-03-01 17:41:45.450 3736 16:00
365 2020-03-01 10:06:32.320 3526 09:00
366 2020-02-29 17:16:20.200 3150 16:00
367 2020-02-29 10:14:50.500 2931 09:00
368 2020-02-28 17:01:59.590 2337 16:00
369 2020-02-28 10:32:34.340 2022 09:00
370 2020-02-27 17:32:06.060 1766 16:00
371 2020-02-27 10:19:35.350 1595 09:00
372 2020-02-26 17:00:43.430 1261 16:00
373 2020-02-26 10:02:05.050 1146 09:00
374 2020-02-25 17:02:03.030 977 16:00
375 2020-02-25 10:00:40.400 893 09:00
376 2020-02-24 17:03:50.500 833 16:00
377 2020-02-24 10:17:36.360 763 09:00
378 2020-02-23 17:05:12.120 602 16:00
379 2020-02-23 10:22:25.250 556 09:00
380 2020-02-22 17:00:28.280 433 16:00
381 2020-02-22 09:59:46.460 346 09:00
382 2020-02-21 17:13:21.210 204 16:00
383 2020-02-21 17:12:33.330 204 16:00
384 2020-02-21 09:58:51.510 156 09:00
385 2020-02-20 17:12:33.330 104 16:00
386 2020-02-20 10:01:31.310 82 09:00
387 2020-02-19 17:00:13.130 51 16:00
388 2020-02-19 09:53:08.080 46 09:00
389 2020-02-18 16:42:00.000 31 16:00
390 2020-02-18 10:05:31.310 31 09:00
391 2020-02-18 10:04:38.380 31 09:00
392 2020-02-17 16:50:47.470 30 16:00
393 2020-02-17 09:53:13.130 30 09:00
394 2020-02-16 16:57:02.020 29 16:00
395 2020-02-16 10:04:04.040 29 09:00
396 2020-02-15 17:00:21.210 28 16:00
397 2020-02-15 10:00:11.110 28 09:00
398 2020-02-14 17:16:19.190 28 16:00
399 2020-02-14 09:50:49.490 28 09:00
400 2020-02-13 17:09:07.070 28 16:00
401 2020-02-13 09:50:45.450 28 09:00
402 2020-02-12 16:56:47.470 28 16:00
403 2020-02-12 10:05:49.490 28 09:00
404 2020-02-11 17:09:25.250 28 16:00
405 2020-02-11 09:50:10.100 28 09:00
406 2020-02-10 17:03:49.490 27 16:00
407 2020-02-10 09:56:41.410 27 09:00
408 2020-02-09 16:59:21.210 27 16:00
409 2020-02-09 09:58:22.220 25 09:00
410 2020-02-08 17:01:34.340 24 16:00
411 2020-02-08 17:01:12.120 24 16:00
412 2020-02-08 16:48:05.050 24 16:00
413 2020-02-08 16:00:22.220 24 16:00
414 2020-02-08 10:09:34.340 24 09:00
415 2020-02-07 17:20:45.450 24 16:00
416 2020-02-07 09:53:27.270 24 09:00
417 2020-02-06 09:09:49.490 23 09:00
418 2020-02-05 20:05:40.400 19 19:00
419 2020-02-04 23:56:31.310 18 09:00
420 2020-02-03 21:26:59.590 0 00:00
421 2020-02-03 14:41:17.170 15 09:00
422 2020-02-03 12:22:49.490 2 09:00
423 2020-01-31 17:47:33.330 0 18:00
그리고 2020년 3월 2일부터는 누적확진률(accdefrate), 누적 검사 수(accexamcnt), 누적 검사 완료수(accexamcompcnt), 치료 중 환자 수(carecnt), 결과 음성 수(resultnegcnt)가 집계되었음을 알 수 있다
In [5]: df[-65:-55][['createdt', 'accdefrate', 'accexamcnt', 'accexamcompcnt', 'carecnt', 'resutlnegcnt']]
Out[5]:
createdt accdefrate ... carecnt resutlnegcnt
359 2020-03-06 12:55:44.440 4.397235 ... 6134.0 136624.0
360 2020-03-05 10:15:12.120 4.622748 ... 5643.0 118965.0
361 2020-03-04 10:21:44.440 4.919986 ... 5255.0 102965.0
362 2020-03-03 10:46:53.530 5.329140 ... 4750.0 85484.0
363 2020-03-02 10:52:38.380 5.557315 ... 4159.0 71580.0
364 2020-03-01 17:41:45.450 NaN ... NaN NaN
365 2020-03-01 10:06:32.320 NaN ... NaN NaN
366 2020-02-29 17:16:20.200 NaN ... NaN NaN
367 2020-02-29 10:14:50.500 NaN ... NaN NaN
368 2020-02-28 17:01:59.590 NaN ... NaN NaN
[10 rows x 6 columns]
누적확진자를 간단히 plot해보자
import matplotlib.pyplot as plt
plt.plot(df['createdt'], df['decidecnt'])
2020년 5월 근방에 삐죽 튀어나온 glitch가 하나 보인다
In [6]: df[303:311][['createdt', 'decidecnt']]
Out[6]:
createdt decidecnt
303 2020-04-27 10:12:27.270 10738
304 2020-04-26 10:12:24.240 10728
305 2020-04-25 10:58:08.080 10718
306 2020-04-25 10:57:05.050 10718
307 2020-04-25 10:39:03.030 12801
308 2020-04-24 10:11:08.080 10708
309 2020-04-23 10:11:05.050 10702
310 2020-04-22 10:20:28.280 10694
해당 데이터는 2020년 4월 25일 오전 10시 39분에 기록된 데이터 (12801명)로, 이후 오전 10시 58분에 10718명으로 수정되었다 (4월 25일이 무슨 날이었는지는 모르겠는데, 3번이나 기록된 걸 보면 뭔가 전산상의 오류가 있었던 듯? 검색해봐도 뭔 일이 있었는지는 찾을 수가 없네...)
간단한 EDA 결과, 동일한 날짜에도 2차례 이상 레코드가 업데이트된 사례들이 있으므로, 동일 날짜에 대해서는 타임스탬프가 가장 최후인 데이터를 사용해야 할 것으로 보인다
5. 일일확진자 계산 (데이터 전처리)
간단한 데이터 전처리를 해보자 (누적확진자, column 이름은 decidecnt)
앞서 보았듯이 동일한 날짜에 대해서는 최종 업데이트된 값을 사용해야 하므로 다음과 같이 누적확진자 데이터를 우선 전처리해줘야 한다
df = getAllCovid19Data()
생성일자에서 년-월-일만 따로 문자열로 치환한 시리즈를 하나 만들자
date_str_series = df['createdt'].dt.strftime('%Y-%m-%d')
In [7]: date_str_series
Out[7]:
0 2021-02-23
1 2021-02-22
2 2021-02-21
3 2021-02-20
4 2021-02-19
419 2020-02-04
420 2020-02-03
421 2020-02-03
422 2020-02-03
423 2020-01-31
Name: createdt, Length: 424, dtype: object
pandas Series의 duplicated 메서드를 활용하면 0-index부터 순차적으로 시리즈 내에 중복된 데이터가 있는지 여부를 boolean으로 변환한 Series를 반환한다
In [8]: date_str_series.duplicated()
Out[8]:
0 False
1 False
2 False
3 False
4 False
419 False
420 False
421 True
422 True
423 False
Name: createdt, Length: 424, dtype: bool
이를 사용해서 중복된 적이 있는 레코드의 인덱스를 추출할 수 있다
duplicated_idx = date_str_series[date_str_series.duplicated()].index
In [9]: duplicated_idx
Out[9]:
Int64Index([ 67, 191, 306, 307, 331, 341, 365, 367, 369, 371, 373, 375, 377,
379, 381, 383, 384, 386, 388, 390, 391, 393, 395, 397, 399, 401,
403, 405, 407, 409, 411, 412, 413, 414, 416, 421, 422],
dtype='int64')
예를 들어 duplicated_idx 안에 포함된 306, 307번 인덱스는 앞서 살펴본 2020년 4월 25일에 해당하는 데이터를 가리킨다
In [10]: df.iloc[304:309][['createdt', 'decidecnt']]
Out[10]:
createdt decidecnt
304 2020-04-26 10:12:24.240 10728
305 2020-04-25 10:58:08.080 10718
306 2020-04-25 10:57:05.050 10718
307 2020-04-25 10:39:03.030 12801
308 2020-04-24 10:11:08.080 10708
305번 인덱스가 4월 25일에 측정된 '마지막' 레코드이며 306, 307번은 4월 25일에 측정된 첫번째, 두번째 레코드이며 갱신되지 않은 데이터라서 무시하면 된다
(이는 데이터가 측정 시간에 대해 내림차순으로 정렬되어 있기 때문에 나타나는 결과다)
따라서, duplicated_idx에 포함된 인덱스들은 데이터 전처리에서 무시해도 되는 결과로 생각할 수 있다
인덱스를 제외한 데이터프레임을 하나 따로 생성하자
df_process = df[~df.index.isin(duplicated_idx)]
In [11]: df.shape
Out[11]: (424, 14)
In [12]: df_process.shape
Out[12]: (387, 14)
In [13]: df_process.iloc[301:306]
Out[13]:
accdefrate accexamcnt accexamcompcnt ... statedt statetime updatedt
303 1.811510 601660.0 592765.0 ... 2020-04-27 00:00 None
304 1.820508 598285.0 589286.0 ... 2020-04-26 00:00 None
305 1.829316 595161.0 585902.0 ... 2020-04-25 00:00 None
308 1.846462 589520.0 579920.0 ... 2020-04-24 00:00 None
309 1.865006 583971.0 573832.0 ... 2020-04-23 00:00 None
[5 rows x 14 columns]
중복된 데이터 중 일부인 306, 307번 인덱스 레코드가 제거됐다
이제 전처리된 데이터프레임의 누적확진자(decidecnt) 데이터를 통해 일일 신규 확진자를 계산해보자
(1-shift 시킨 ndarray와 뺄셈 연산만 해주면 끝)
import numy as np
v = df_process['decidecnt'].values
df_process['decide_new_daily'] = np.append(v[:-1] - v[1:], 0)
In [14]: df_process[['createdt', 'decide_new_daily']]
Out[14]:
createdt decide_new_daily
0 2021-02-23 09:31:45.903 357
1 2021-02-22 09:30:56.472 332
2 2021-02-21 09:34:28.285 416
3 2021-02-20 09:40:36.883 448
4 2021-02-19 09:33:30.840 561
.. ... ...
417 2020-02-06 09:09:49.490 4
418 2020-02-05 20:05:40.400 1
419 2020-02-04 23:56:31.310 18
420 2020-02-03 21:26:59.590 0
423 2020-01-31 17:47:33.330 0
[387 rows x 2 columns]
In [15]: df_process.iloc[:10]['decide_new_daily']
Out[15]:
0 357
1 332
2 416
3 448
4 561
5 621
6 621
7 457
8 343
9 326
Name: decide_new_daily, dtype: int64
코로나 공식 웹페이지의 일일 신규확진자 자료와 비교하면 제대로 계산된 것을 알 수 있다
신규 확진자 수를 간단하게 플롯해보자
plt.plot(df_process['createdt'], df_process['decide_new_daily'])
으잉? 음수 값을 가진 데이터가 보인다
데이터를 다시 살펴보니 Time Stamp가 역전되어있는 레코드가 하나 있네...
In [16]: df_process.iloc[74:79][['statedt', 'decidecnt', 'decide_new_daily']]
Out[16]:
statedt decidecnt decide_new_daily
75 2020-12-11 40786 688
76 2020-12-10 40098 1352
77 2020-12-08 38746 -686
78 2020-12-09 39432 1271
79 2020-12-07 38161 615
2020년 12월 8일과 2020년 12월 9일 레코드의 순서가 바뀌었다
따라서 데이터 전처리시에 timestamp 기반으로 한 번 sorting해주자
df = getAllCovid19Data()
date_str_series = df['createdt'].dt.strftime('%Y-%m-%d')
duplicated_idx = date_str_series[date_str_series.duplicated()].index
df_process = df[~df.index.isin(duplicated_idx)]
df_process = df_process.sort_values(by=['statedt'], ascending=False)
v = df_process['decidecnt'].values
df_process.loc[:, ('decide_new_daily')] = np.append(v[:-1] - v[1:], 0)
plt.plot(df_process['createdt'], df_process['decide_new_daily'])
In [17]: df_process.iloc[74:79][['statedt', 'decidecnt', 'decide_new_daily']]
Out[17]:
statedt decidecnt decide_new_daily
75 2020-12-11 40786 688
76 2020-12-10 40098 666
78 2020-12-09 39432 686
77 2020-12-08 38746 585
79 2020-12-07 38161 615
기초적인 수준의 데이터 탐색 및 데이터 전처리까지 해봤다
(포스트의 의도는 공공데이터포털에서 REST API로 데이터를 얻어보는 거였기 때문에 이정도로 마무리하자...)
[최종 코드]
import requests
import numpy as np
import pandas as pd
from typing import Union
from bs4 import BeautifulSoup
from datetime import date, datetime
def getCovid19Info(start_date: Union[date, datetime], end_date: Union[date, datetime]):
url = "http://openapi.data.go.kr/openapi/service/rest/Covid19/getCovid19InfStateJson"
api_key_utf8 = "Your API Key from data.go.kr"
api_key_decode = requests.utils.unquote(api_key_utf8, encoding='utf-8')
params={
"ServiceKey": api_key_decode,
"startCreateDt": int('{:04d}{:02d}{:02d}'.format(start_date.year, start_date.month, start_date.day)),
"endCreateDt": int('{:04d}{:02d}{:02d}'.format(end_date.year, end_date.month, end_date.day)),
}
response = requests.get(url, params=params)
elapsed_us = response.elapsed.microseconds
print('Request Done, Elapsed: {} seconds'.format(elapsed_us / 1e6))
return BeautifulSoup(response.text, "lxml")
def getCovid19DataFrame(start_date: Union[date, datetime], end_date: Union[date, datetime]) -> pd.DataFrame:
convert_method = {
'accdefrate': float,
'accexamcnt': int,
'accexamcompcnt': int,
'carecnt': int,
'clearcnt': int,
'createdt': lambda x: datetime.strptime(x, '%Y-%m-%d %H:%M:%S.%f'),
'deathcnt': int,
'decidecnt': int,
'examcnt': int,
'resutlnegcnt': int,
'seq': int,
'statedt': lambda x: datetime.strptime(x, '%Y%m%d'),
'statetime': str,
'updatedt': lambda x: datetime.strptime(x, '%Y-%m-%d %H:%M:%S')
}
temp = getCovid19Info(start_date, end_date)
items = temp.find('items')
item_list = []
for item in items:
item_dict = {}
for tag in list(item):
try:
item_dict[tag.name] = convert_method[tag.name](tag.text)
except Exception:
item_dict[tag.name] = None
item_list.append(item_dict)
df = pd.DataFrame(item_list)
return df
def getAllCovid19Data(with_daily_decide: bool = True) -> pd.DataFrame:
now = datetime.now()
df = getCovid19DataFrame(date(2019, 1, 1), now)
print("Today: {}\nLoaded {} Records".format(now.strftime('%Y-%m-%d'), df.shape[0]))
if with_daily_decide:
date_str_series = df['createdt'].dt.strftime('%Y-%m-%d')
duplicated_idx = date_str_series[date_str_series.duplicated()].index
df = df[~df.index.isin(duplicated_idx)]
df = df.sort_values(by=['statedt'], ascending=False)
v = df['decidecnt'].values
df.loc[:, ('decide_new_daily')] = np.append(v[:-1] - v[1:], 0)
return df
끝~!
'Data Analysis > Data Engineering' 카테고리의 다른 글
공공데이터포털::공휴일 데이터 조회 (REST API) (10) | 2021.04.03 |
---|---|
Python::folium - 빅데이터분석기사 필기시험 고사장 위치 지도시각화 (0) | 2021.02.26 |
Python::BeautifulSoup - 동행복권 연금복권720+ 당첨번호 크롤링 (0) | 2021.02.21 |
Python::BeautifulSoup - 동행복권 로또 6/45 당첨번호 크롤링 (0) | 2021.02.19 |
Python::BeautifulSoup - 기상청 '도시별 현재날씨' 크롤링 (0) | 2021.02.07 |