Python_10_문제풀이(matplotlab, seaborn)
- 1. 데이터 불러오기
- 2022년 주유소들의 일자별 가격 데이터
- https://www.opinet.co.kr/user/opdown/opDownload.do
필요한 라이브러리 모두 불러오기
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import datetime
import warnings
warnings.filterwarnings(action = 'ignore')
pd.read_csv -> csv 파일을 읽어오기
encoding = 'cp949' -> default값인 UTF-8에서 에러가 뜰 시에 입력(오래된 자료일 경우 이런 오류가 발생)
# 상반기, 하반기 주유소 가격 데이터 조회
df1 = pd.read_csv('data/2022년_서울_상반기_일별_가격.csv', encoding = 'cp949')
df2 = pd.read_csv('data/2022년_서울_하반기_일별_가격.csv', encoding = 'cp949')
DataFrame 합치기
pd.concat([df, df]) -> 두 개의 DataFrame을 합친다.
# 상반기, 하반기 DataFrame 합치기
df_concat = pd.concat([df1, df2], ignore_index = True) # 원본의 index이름을 무시하고 붙인다.
df_concat
# DataFrame 기본 정보 조회
df_concat.info()
수치형과 문자형 각각의 통계량 확인 -> df.describe()
# 통계량
df_concat.describe() # 수치형
df_concat.describe(include = 'object') # 문자형
df['column'].unique() -> 특정 column의 고유값 조회
# 상표 컬럼의 고유값 조회
df_concat['상표'].unique()
# 지역 컬럼의 고유값 조회
df_concat['지역'].unique()
- str accessor
- Series.str.String메소드()
- 문자열 타입 Series에 String 메소드들을 사용하여 일괄처리 할 수 있도록 한다.
- str accessor 메소드 : https://pandas.pydata.org/pandas-docs/stable/reference/series.html#api-series-str
- datetime으로 변환
- pd.to_datetime(변환할 Series, format="날짜형식")
- x 또는 y 축이 날짜 일 경우 datetime 타입으로 처리하는 것이 좋다.
- format: 년월일의 형식을 strftime 형식문자열로 지정한다.
- strftime 형식 - datetime을 변환하면 날짜만의 기능을 다룰 수 있다.
- dt accessor를 이용해 datetime의 속성값들을(년, 월, 일 등) 추출할 수 있다.
- https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.dt.html
df['column'].str.removeprefix('str') -> df의 특정 컬럼의 str문자열을 제외한 컬럼 생성
# 지역 컬럼의 값을 이용하여 "구" 컬럼 생성 (지역에서 구만 추출해서 파생변수컬럼 생성)
df_concat['구'] = df_concat['지역'].str.removeprefix('서울 ')
# 강사님 버전
df_concat['구'] = df_concat['지역'].apply(lambda addr : addr.split()[1])
df_concat
pd.to_datetime(df['column'], format = '~~') -> 특정 column을 datetime 타입으로 변경
# 기간 컬럼을 datetime 타입으로 변경
df_concat['기간'] = pd.to_datetime(df_concat['기간'], format = '%Y%m%d')
df_concat['기간']
df['column'].dt.month -> 특정 datetime 타입의 column의 특정 속성만 빼서 생성(month, day, weekday 등..)
# 기간 컬럼을 이용해 "월", "일", "요일" 컬럼 생성 (dt accessor 이용)
df_concat['월'] = df_concat['기간'].dt.month
df_concat['일'] = df_concat['기간'].dt.day
df_concat['요일'] = df_concat['기간'].dt.weekday
df['column'].replace([n1, ~~], [n2, ~~]) -> 특정 column의 n1 ~ 값들을 n2 ~값들로 변경
inplace = True -> 원본을 함께 변경 (default = False)
# 요일 - 0:월, 1:화, 2:수, 3:목, 4:금, 5:토, 6:일 로 변경
df_concat['요일'].replace([0, 1, 2, 3, 4, 5, 6], ['월', '화', '수', '목', '금', '토', '일'], inplace = True)
df_concat['요일']
# 강사님 버전
df_concat['요일'] = df_concat['요일'].apply(lambda x : '월화수목금토일'[x]) # +'요일')
df_concat['요일']
df.to_csv('경로') -> DataFrame을 경로 장소에 csv파일로 저장
# 전처리한 DataFrame -> 저장
df_concat.to_csv('data/2022년_서울주유소_데이터셋.csv', index = False)
df.sort_values('column') -> 특정 컬럼의 값들을 정렬
ascending = False -> 내림차순으로 정렬 (default -> True(오름차순))
# 휘발유 가격이 가장 비싼 5개 행 조회
df_concat.sort_values('휘발유', ascending = False).head(5)
DataFrame의 columns별 null값 개수 조회
df_concat.isnull().sum()
np.NaN -> null값을 의미
# 휘발유 가격이 가장 저렴한 5개 행 조회 (단 0원인 주유소 제외)
# df_concat = df_concat.replace(0, np.NaN) # 0을 NaN값 처리
df_concat.sort_values(['휘발유']).head(5)
# 강사님 풀이
df_concat.query('휘발유 != 0').sort_values('휘발유').head(5)
df.groupby('column1')['column2'] -> column1에 대한 column2의 값들 조회
df.['column'].mean() -> DataFrame의 column의 값들의 평균
# 상표별 휘발유 평균가격 조회
df_concat.groupby('상표')['휘발유'].mean()
# 강사님 풀이
# 0원인 주유소는 빼고 계산
휘발유_상표별_평균 = df_concat.query('휘발유 != 0').groupby('상표')['휘발유'].mean()
휘발유_상표별_평균
df.plot(kind = 'type', ~) -> DataFrame의 값 type의 형태로 시각화
plt.axhline(data) -> data에 대한 값의 수평선 그리기
# 상표별 휘발유 평균가격 시각화
전체평균 = df_concat['휘발유'].mean()
# 상표별 평균 시각화
휘발유_상표별_평균.sort_values(ascending = False).plot(kind = 'bar', rot = 45)
# 전체평균 표시
plt.axhline(전체평균, color = 'red', linestyle = ':', label = f"전체평균 : {전체평균}")
plt.legend(bbox_to_anchor = (1,1), loc = 'upper left')
plt.show()
normalize = True -> 값들의 비율 조회
# 셀프주유소와 일반주유소 개수 확인
df_concat.value_counts(['셀프여부'])
df_concat.value_counts(['셀프여부'], normalize = True) # 비율
# df_concat['셀프여부'].value_counts
unstack() -> index 값을 column으로 올려준다.
# 상표별 일반/셀프 주유소의 휘발유 가격 평균 비교
df_concat.query('휘발유 != 0').groupby(['상표', '셀프여부'])['휘발유'].mean()
df_concat.query('휘발유 != 0').groupby(['상표', '셀프여부'])['휘발유'].mean().unstack()
df.pivot_table() -> 피봇테이블(pivot table)이란 데이터 열 중에서 두 개의 열을 각각 행 인덱스, 열 인덱스로 사용하여 데이터를 조회하여 펼쳐놓은 것을 말한다.
margins = True -> 각 행과 열의 값들의 합산을 조회
# pivot table
상표_셀프여부_휘발유_평균 = df_concat.query('휘발유 != 0').pivot_table(index = '상표', columns = '셀프여부', values = '휘발유', aggfunc = 'mean', margins = True)
상표_셀프여부_휘발유_평균
- DataFrame.plot()
- index명이 x축으로 들어오고 컬럼의 값을 이용해서 그래프를 그림.
- 컬럼이 여러개일때는 하나의 Axes에 따로 따로 그린다.
# 상표별 일반/셀프 주유소의 휘발유 가격 평균 비교 시각화
# 상표_셀프여부_휘발유_평균에서 All을 빼고 시각화
상표_셀프여부_휘발유_평균.iloc[:-1,:-1].plot(kind = 'bar', rot = 45)
plt.legend(bbox_to_anchor = (1,1), loc = 'upper left')
plt.show()
sns.boxplot(data = 'df', y = 'column1', x = 'column2') -> df의 data들을 column1과 2로 시각화
boxplot은 극단치 측정에 활용
# 상표별 휘발유 가격의 분포를 boxplot으로 시각화
# 범주형 컬럼을 이용해 group별로 나눠서 시각화 ---> seaborn 사용이 편하다.
plt.figure(figsize = (10, 6))
sns.boxplot(data = df_concat.query('휘발유 != 0')
,y = '휘발유'
,x = '상표'
)
plt.show()
sns.violinplot (data = 'df', y = 'column1', x = 'column2')
plt.figure(figsize = (10, 6))
sns.violinplot(data = df_concat.query('휘발유 != 0')
,y = '휘발유'
,x = '상표'
)
plt.show()
hue = 'columns' -> 분류 기준을 하나 더 추가
# 상표별 일반/셀프 주유소의 휘발유 가격에 대한 분포 확인 - boxplot으로 시각화
plt.figure(figsize = (10, 6))
sns.boxplot(data = df_concat.query('휘발유 != 0')
,y = '휘발유'
,x = '상표'
,hue = '셀프여부'
)
plt.show()
violinplot에 hue추가
plt.figure(figsize = (10, 6))
sns.violinplot(data = df_concat.query('휘발유 != 0')
,y = '휘발유'
,x = '상표'
,hue = '셀프여부'
)
plt.show()
# 구별 휘발유 가격의 평균
구별_휘발유_평균 = df_concat.query('휘발유 != 0').groupby('구')['휘발유'].mean().sort_values(ascending = False)
구별_휘발유_평균
df.idxmax() -> 가장 높은 value의 index명 가져오기
# 평균 가격이 가장 높은 구의 상표별 휘발유 평균가격
h_price = df_concat.query('휘발유 != 0').groupby('구')['휘발유'].mean().idxmax()
df_concat[df_concat['구'] == h_price].groupby('상표')['휘발유'].mean()
# 다른 방법
구별_휘발유_평균.index[0]
df_concat.query('구 == @구별_휘발유_평균.index[0]').groupby('상표')['휘발유'].mean()
# 월 평균 휘발유 가격
월별_휘발유_평균 = df_concat.query('휘발유 != 0').groupby('월')['휘발유'].mean()
월별_휘발유_평균
# 각 구의 월별 평균 휘발유 가격
월_구별_휘발유_평균가격 = df_concat.query('휘발유 != 0').groupby(['구', '월'])['휘발유'].mean()
월_구별_휘발유_평균가격.unstack()
# pivot_table 사용
월_구별_휘발유_평균가격 = round(df_concat.query('휘발유 != 0').pivot_table(index= '월', columns = '구', values = '휘발유', aggfunc = 'mean'), 2)
월_구별_휘발유_평균가격
# 한개 구(강남구)
월_구별_휘발유_평균가격['강남구'].plot(figsize = (10, 4), marker = '.')
# 각 구의 월별 평균가격의 변화추이 시각화
월_구별_휘발유_평균가격.plot(figsize = (15, 5))
plt.legend(bbox_to_anchor = (1, 1), loc = 'upper left', ncol = 3, title = '구')
plt.show()
# 가장 휘발유가격이 비싼 주유소 상위 5 - (같은 주유소가 여러개 나오므로 가장 비싼 가격을 기준으로 집계)
# 주유소별로 제일 비쌀때 가격.
휘발유_비싼_주유소 = df_concat.query('휘발유 != 0').groupby(['상호', '주소'])['휘발유'].max().sort_values(ascending = False).head(5)
휘발유_비싼_주유소
# 가장 휘발유가격이 저렴한 주유소 상위 5 - (같은 주유소가 여러개 나오므로 가장 비싼 가격을 기준으로 집계)
휘발유_싼_주유소 = df_concat.query('휘발유 != 0').groupby(['상호', '주소'])['휘발유'].max().sort_values().head(5)
휘발유_싼_주유소
multi index, level
df.index.get_level_values(level)
# 휘발유_비싼_주유소.head().index
# multi index에서 index명을 각각 조회
휘발유_비싼_주유소.head().index.get_level_values(0) # level 지정하면 그 level의 index이름들을 묶어서 반환
# 휘발유_비싼_주유소.head().index.get_level_values(1)
# 휘발유 비싼 주유소의 상위 5개의 상호, 주소, 상표, 셀프여부, 조회 - 위에서 조회한 결과에 추가 정보(상표, 셀프여부 등) 조회 (중복제거-drop_duplicates)
df_concat.query('상호 in @휘발유_비싼_주유소.head().index.get_level_values(0) and 주소 in @휘발유_비싼_주유소.head().index.get_level_values(1)')[['상호','주소','상표','셀프여부']].drop_duplicates()
# 휘발유 저렴한 주유소의 상위 5개의 상호, 주소, 상표, 셀프여부, 조회 - 위에서 조회한 결과에 추가 정보(상표, 셀프여부 등) 조회 (중복제거-drop_duplicates)
df_concat.query('상호 in @휘발유_싼_주유소.head().index.get_level_values(0) and 주소 in @휘발유_싼_주유소.head().index.get_level_values(1)')[['상호','주소','상표','셀프여부']].drop_duplicates()
size()
# 고급 휘발유를 가장 많이 파는 구 조회
df_concat.query('고급휘발유 != 0').groupby('구')['고급휘발유'].size().idxmax()
drop_duplicates()
# 고급 휘발유를 가장 많이 파는 구 조회 -> 실제 주유소가 몇개인지.
df_concat.query('고급휘발유 != 0')[['구', '상호', '주소']].drop_duplicates().groupby('구')['상호'].count().sort_values(ascending = False)