서울시에서 코로나 확진자 데이터 제공 이력
- 처음에는 html 형식 1페이지로 제공 -> 데이터 많지 않았기 때문에
- 그 다음에는 여러 페이지 제공
- API로 변경
- API 페이징 추가
- 요약된 데이터만 제공
=> 스타트업에서 서비스 운영하는 것과 비슷 : 처음부터 잘 만들어진 서비스를 제공하기 어렵고, 상황이 어떻게 변화할지 예측하기 어렵게 때문에 서비스를 하면서 프로덕트를 보완해 나간다.
데이터 시각화 도구
라이브러리 로드
# pandas, numpy, matplotlib.pyplot 불러오기
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
pandas : 분석
numpy : 다차원 연산
pyplot : 시각화
matplotlib 한글 설정 방법
import matplotlib.pyplot as plt
# 한글폰트 사용을 위해 설치
!pip install koreanize-matplotlib #pip~ 해서 prompt 설치도 가능
import koreanize_matplotlib
# 그래프에 retina display 적용
%config InlineBackend.figure_format = 'retina' #뚜렷하게
-> 작년에 나온 라이브러리임 koreanize_matplotlib => 간편! (그동안 jupyter notebook에서 한글 폰트 지정해도 오류 났었는데 이 방법으로 하니까 드디어 한글이 보임...
- 아나콘다는 여러 도구를 한번에 설치해 주기도 하지만 가상환경을 제공
- 설치했음에도 불구하고 No Module Not Found 오류가 발생할 때는 보통 여러 버전의 파이썬 혹은 아나콘다 등이 설치되어 있는데 현재 사용하고 있는 위치가 아닌 다른 위치에 설치되었을 때 이런 오류가 발생
- 보통 오류 메시지에 보면 어느 경로에 없다는 메시지가 나오게 됩니다. 해당 경로에 가서 보면 여러 라이브러리가 설치되어있는 폴더를 볼 수 있는데, 해당 위치에 사용하고자 하는 라이브러리를 다운로드 받아 옮겨주면 보통 잘 import 가 됩니다.
- (base) <- 아나콘다의 기본 가상환경이라서 해당 가상환경에 설치해 주면 보통 문제 적게 발생
https://github.com/seongminp/koreanize-matplotlib
파일 불러오기
from glob import glob
-> glob는 파일들의 리스트를 뽑을 때 사용
from glob import glob
# 파일 목록 보기
# 파일 이름이 길거나 특수문자 등이 포함되었을 때 직접 타이핑 하면 한 글자라도 틀리면 오류가 남
files = glob('data/seoul-covid*.csv')
file_paths = sorted(files)
file_paths
>> ['data\\seoul-covid19-2021-12-18.csv', 'data\\seoul-covid19-2021-12-26.csv']
df_01 = pd.read_csv(file_paths[0])
df_01.shape
>> (200000, 7)
df_02 = pd.read_csv(file_paths[1])
+) 추가 설명
>>> from glob import glob
>>> glob('*.exe') # 현재 디렉터리의 .exe 파일
['python.exe', 'pythonw.exe']
>>> glob('*.txt') # 현재 디렉터리의 .txt 파일
['LICENSE.txt', 'NEWS.txt']
위의 glob() 함수는 인자로 받은 패턴과 이름이 일치하는 모든 파일과 디렉터리의 리스트를 반환합니다. 패턴을 그냥 *라고 주면 모든 파일과 디렉터리를 볼 수 있음
데이터 합치기 및 중복 제거
# pd.concat 으로 [df_01, df_02] 합치고 df 변수에 할당하기
df = pd.concat([df_01, df_02])
df = df.drop_duplicates()
df
인덱스 값 설정
# shape
df.shape
>> (218646, 7)
# 연번의 nunique()
df.nunique()
>>
연번 218646
환자 218644
확진일 671
거주지 34
여행력 183
접촉력 1417
퇴원현황 2
dtype: int64
# set_index 를 통해 인덱스 값을 변
df = df.set_index('연번')
df = df.sort_index()
df
df.set_index('연번') 두 번 하면 오류 why?
-> 이미 '연번'이 인덱스이기 때문에 '연번' 칼럼이 더이상 없음
- unique() 는 데이터에 고유값들의 종류를 알고 싶을때
- nunique()는 데이터의 고유값들의 수를 출력
연번은 서울, 환자는 전국
데이터 요약 / 결측치 보기 / 기술통계
df.info()
# 결측치의 합
df.isnull().sum()
# 결측치의 평균
df.isnull().mean()
#기술통계
df.describe()
df.describe(include = 'object')
날짜 데이터 타입 변경 / 파생변수 만들기
df['확진일'] = pd.to_datetime(df['확진일'])
df['연도'] = df['확진일'].dt.year
df['월'] = df['확진일'].dt.month
df['일'] = df['확진일'].dt.day
df['요일'] = df['확진일'].dt.dayofweek
참고
https://pandas.pydata.org/docs/reference/series.html#accessors
확진일, 연도, 월, 일, 요일 컬럼만 가져오기
df[['확진일', '연도', '월', '일', '요일']].head(2)
- 2차원 형태로 가져올 때는 대괄호 [] 두 개! 1차원 형태로 가져올 대는 대괄호 []하나
연도-월 만들기
- 연도-월 파생변수 만들기
- astype(str) 을 통해 수치 데이터를 문자 데이터로 변환하고 문자열 연결하기
- df["연도월"]
- df['연도'].astype(str) + '-'+ df['월'].astype(str) 할 수도 있지만
- 문자열 슬라이싱으로도 만들 수 있음
df['연도월'] = df['확진일'].astype(str).str[:7]
df['연도월']
value_counts
- 1개의 변수에 대한 빈도, 비율 확인
요일 한글로 만들기
- 함수와 Series의 map 활용
dayofweek = "월화수목금토일"
dayofweek[1]
>> '화'
find_dayofweek 함수로 요일 숫자를 넘겨주면 요일명을 반환하는 함수
def find_dayofweek(day_no) :
dayofweek = "월화수목금토일"
day = dayofweek[day_no]
return day
map을 사용해서 요일 칼럼을 요일명으로 변환하고 '요일명'이라는 새로운 칼럼에 저장
df["요일명"] = df['요일'].map(find_dayofweek)
df[['요일', '요일명']].sample(5)
전체 수치 변수 히스토그램 그리기
- df.hist로 히스토그램 그리기
- bins 잘게 나눌수록 구간을 자세히 볼 수 있음
- 월요일이 적은 이유는 일요일 선별진료소 안 해서 검사를 적게 해서 결과가 늦게 뜸
- 50개로 해도 요일은 막대가 늘어나지 않는다
- 월말 적은 이유 31일ㅇ ㅣ매달 있는게 아니라서
- 수치 데이터일지라도 연속된 데이터가 아니라 끊어진 데이터가 있음을 볼 수 있음
- 수치데이터임에도 범주형으로 볼 수 있는 데이도 있다는 것을 볼 수 있습니다
- 월요일 이런거는 막대가 이어지지 않음 환자나 확진일 같은 경우 아무리 구간을 나누어도 붙어잇음 -> 연속된 수치데이터 -> 아 이데이터는 범주형 데이터에 더 가깝구나
df.hist(bins = 50, figsize = (12, 5))
value_counts로 하나의 변수에 대한 빈도수 구하기
연도
# "연도" 컬럼을 통해 빈도수 구하기
df['연도'].value_counts()
df['연도'].value_counts(normalize = True) * 100
df['연도'].value_counts(1)
연도 시각화
df['연도'].value_counts(1).plot.bar(rot = 0) # rot 은 x축 각도
연도월
- 연도월에 대한 빈도수 구하기
- 빈도수를 구하고 sort_index로 정렬
year_month = df['연도월'].value_counts().sort_index()
df['연도월'].value_counts().sort_index()
year_month.plot()
year_month.plot(kind = 'bar', figsize = (12, 3), title = '월별 확진자 수', rot = 80)
요일 / 요일명
연도월 한 것 처럼 하면
df["요일명"].value_counts().sort_index().plot.bar(rot = 0, figsize = (6, 3))
하지만 '월화수목금토일' 순서대로 하고 싶음
1. 빈도수 구하고 인덱스 번호로 정렬
- weekday_count 변수에 담아 재사용
weekday_count = df["요일"].value_counts().sort_index()
weekday_count
2. 리스트컴프리헨션 사용해서 리스트 만들기
3. '월화수목긐토일' 리스트로 만들어 weekday_list 변수로 재사
weekday_list = [w for w in "월화수목금토일"]
weekday_list
>> ['월', '화', '수', '목', '금', '토', '일']
list('월화수목금토일')과 동일
4. 인덱스 값을 요일명으로 변경하고 시각화
weekday_count.index = weekday_list
weekday_count.plot.bar(rot=0, figsize=(6, 3), title="요일별 확진수") ;
1. df['요일명']을 value_counts()해서 w_count라는 변수에 넣어줌ㅈ
w_count = df["요일명"].value_counts()
w_count[["월", "화", "수"]]
>>
월 24516
화 35471
수 34548
Name: 요일명, dtype: int64
weekday_list
>> ['월', '화', '수', '목', '금', '토', '일']
w_count[weekday_list]
w_count[list("월화수목금토일")].plot.bar(figsize=(6, 3), rot=0) ;
확진일 빈도수 구하기
df['확진일'] 빈도수 구하고 인덱스 값인 날짜로 정렬하기
day_count = df['확진일'].value_counts().sort_index()
day_count
day_count.plot(figsize = (10,3), title = '확진일 별 빈도수') ;
; 한 이유는 로그 안 뜨게 하기 위해
전체 확진일 데이터 만들기
day_count = day_count.sort_index()
day_count.head(10)
day_count.head(10).plot.bar(figsize = (6, 3), rot = 60) ;
-> 0명인 날의 날짜는 보이지 않음
- 기존 확진일수로 연산을 한다면 확진자가 있는 날만 연산을 하게 됨
- 확진자가 없던 날은 0으로 표기하기 위해 전체 날짜를 구하고
- 전체 날짜에서 확진자가 없는 날은 0으로 결측치를 대체할 예정
첫 확진일과 마지막 확진일자 찾기(1)
last_day = day_count.index[-1]
first_day = day_count.index[0]
첫 확진일과 마지막 확진일자 찾기(2)
last_day = day_count.index.max()
first_day = day_count.index.min()
first_day, last_day
>> (Timestamp('2020-01-24 00:00:00'), Timestamp('2021-12-26 00:00:00'))
date_range
all_day = pd.date_range(start = first_day, end = last_day)
all_day
all_day = pd.date_range(start = first_day, end = last_day)
all_day
all_day를 데이터 프레임으로 변환
df_all_day = all_day.to_frame()
- '확진수'라는 칼럼을 생성해서 위에서 구한 day_cout 를 추가한다
- 확진자가 없는 날도 인덱스에 생성됨
- 필요 없는 0칼럼은 제
df_all_day['확진수'] = day_count
df_all_day.head(5)
del df_all_day[0]`
결측치 채우기
- 비어있는 값은 확진자가 없었던 날이기 때문에 0을 채워 넣음
df_all_day['확진수'] = df_all_day.fillna(0).astype(int)
df_all_day
누적 확진수 구하기
- cumsum으로 '누적확진수' 구해서 새로운 변수에 넣기
df_all_day["누적확진수"] = df_all_day['확진수'].cumsum()
df_all_day
시각화 1
df_all_day.plot(figsize = (10,3)) ;
시각화 2 : subplots
df_all_day.plot(figsize = (10,3), subplots = True) ;
시각화 3 : 2축 그래
df_all_day.plot(figsize = (10,3), secondary_y = '누적확진수') ;
거주지
df['거주지'].value_counts()
송파구 13235
강남구 12150
타시도 11320
관악구 10992
구로구 10346
영등포구 10225
강서구 10150
은평구 9393
노원구 9327
성북구 9142
동대문구 9091
강동구 8882
동작구 8558
중랑구 8236
서초구 8087
양천구 7709
마포구 7370
광진구 6819
도봉구 6501
강북구 6449
서대문구 5946
금천구 5635
성동구 5530
용산구 5137
기타 4995
종로구 3838
중구 3570
양천구 5
용산구 2
동작구 2
타시도 1
금천구 1
마포구 1
강동구 1
Name: 거주지, dtype: int64
-> 강동구 두 개 있음
타시도, 기타 전처리
- 공백 없애기
- 타시도 -> 기타
- 거주구 빈도수 구하기
df['거주구'] = df['거주지'].str.strip()
df['거주구'] = df['거주구'].str.replace('타시도', '기타')
gu_count = df['거주구'].value_counts()
시각화
- gu_count 변수에 담긴 값 시각화 하기
- 선그래프 -> 연속형 데이터 시각화
- 막대그래프 -> 범주형(끊어져 있는) 데이터 시각화
gu_count.plot.bar()
plt.axhline(5000, c = 'r', ls = ':') ;
[더하기]
- plt.axhline(): 수평선( horizontal line )을 그리는 함수입니다.
- plt.axvine(): 수직선( vertical line )을 그리는 함수입니다.
- map 은 시리즈에만 !
'AI SCHOOL > Python' 카테고리의 다른 글
[Python] FinanceDataReader - 1 (0) | 2023.01.31 |
---|---|
[Python] 서울 코로나 데이터 분석(EDA) - 2 (0) | 2023.01.31 |
[Python] Open API 사용하여 서울시 다산 콜센터 자주 묻는 질문 목록 데이터 수집 (0) | 2023.01.24 |
[Python] 네이버 금융 ETF 수집, json 데이터 수집 (0) | 2023.01.24 |
[Python] 다산콜센터 주요 민원 내용 수집(2) (0) | 2023.01.24 |