# 코드잇 데이터 사이언티스트 강의 듣는 중
<제주도 관광관련 데이터로 이것저것 확인해보기>
[코드잇 강의 가이드 라인]
1. 데이터 불러오기
data 폴더 안에 있는 jeju_card.csv 파일을 DataFrame으로 불러옵시다.
2. 데이터 탐색 및 전처리
데이터를 간단히 탐색하고 전처리해 봅시다.
- 데이터 개수, 컬럼별 데이터 타입, 통계 정보, 결측값 존재 여부 등을 확인해 보세요.
- 각 컬럼이 어떤 값들로 이루어져 있는지 확인해 보세요.
- 2017년과 2018년의 데이터만 추출해 주세요.
3. 데이터 분석
연월별 카드 이용 추이를 비교해 보세요.
- 2017년과 2018년, 두 연도 사이에 어떤 차이가 있나요? 왜 그런 차이가 나는지도 한번 확인해 보세요.
연령대별로 카드 이용에 어떤 차이가 있는지 비교해 보세요.
- 이용자수, 소비금액, 1회당 소비금액을 비교해 보세요.
- 연령대별로 어떤 업종에 많은 금액을 지출하는지 확인해 보세요.
- 연령대별로 연월별 카드 이용 추이를 확인해 보세요.
더 알아보고 싶은 게 있다면 원하는 대로 자유롭게 데이터를 탐색해 보세요!
- 위는 코드잇 실습 데이터 연습 시 요청 과제였고, 아래에는 내가 떠올리지 못했던 방법들을 해설 노트를 보고 정리할 것.
<데이터 탐색 및 전처리 >
- .shape 활용
- 나는 그냥 냅다 .head()로만 로나, 칼럼 형태와 마지막에 나오는 개수를 확인했는데, 강의 노트에는 shape을 활용하고, head()를 씀
- .describe(include='all')
-.info() 결측치를 활용하고 .describe()로 대략적 분포를 활용한 것은 같지만, include='all' 파라미터로 문자형 데이터들까지 확인하지 않았음.
- 타입 칼럼의 이름 구분
- 이 부분이 상당히 인상적이었는데, 'object' 타입만 모아서 칼럼 명을 뽑아줘서 이를 비교하려고 한 것이었음.
object_columns = jeju_card_df.columns[jeju_card_df.dtypes == 'object']
object_columns
#값
Index(['시도명', '시군구명', '지역구분', '업종명', '이용자 구분', '연령대', '성별', '연월'], dtype='object')
- index 자료형의 경우, 리스트와 비슷하게 생겼는데 리스트처럼 안에 들어있는 각 요소에 차례대로 접근할 수 있음.
-so, for문을 이용 가능함.
- for문에 unique()함수를 활용해서 각각의 값들만 뽑아낼 수가 있음.
for col in object_columns:
print(col)
print(jeju_card_df[col].unique(), '\n')
#값
시도명
['제주도']
시군구명
['제주시' '서귀포시']
지역구분
['읍면' '도심']
업종명
['유흥' '식음료' '숙박' '쇼핑' '소매' '문화/레져' '교통' '기타']
이용자 구분
['제주도민' '내국인관광객']
연령대
['60대이상' '50대' '40대' '30대' '20대미만' '20대' '20 미만']
성별
['여' '남']
연월
['2018-12' '2018-11' '2018-10' '2018-09' '2018-08' '2018-07' '2018-06'
'2018-05' '2018-04' '2018-03' '2018-02' '2018-01' '2017-12' '2017-11'
'2017-10' '2017-09' '2017-08' '2017-07' '2017-06' '2017-05' '2017-04'
'2017-03' '2017-02' '2017-01' '2016-12' '2016-11' '2016-10' '2016-09']
--> 이 방법은 전반적인 데이터 구조를 활용하기에 너무 좋은 방법으로 여겨짐.
- 일단 여기까지 해설 코드를 쭉 쓰면
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
#값 불러오기
jeju_card_df = pd.read_csv('data/jeju_card.csv')
#데이터 구조확인
jeju_card_df.shape
jeju_card_df.head()
jeju_card_df.info()
#문자형도 확인
jeju_card_df.describe(include='all')
#문자형 데이터 타입 벡터만 모아서 변수 만들기
object_columns = jeju_card_df.columns[jeju_card_df.dtypes == 'object']
#칼럼 별로, 유니크한 값들만 출력
for col in object_columns:
print(col)
print(jeju_card_df[col].unique(), '\n')
- 2017, 18 데이터만 추출하기
- 이 부분이 나랑 다르게 했는데, 본 데이터를 나두려고 17, 18에 해당 하는 값을 따로 추출했음.
- 내 ver.
#데이트 타입으로 바꿈
jeju_df['연월'] = pd.to_datetime(jeju_df['연월'])
#연도 순서로 맞춰줌
jeju_df = jeju_df.set_index('연월').sort_index()
#2017, 2018만 빼서 값을 만들어줬음
jeju_17_to_18 = jeju_df.loc[['2017', '2018']]
- 해설 ver
#연도 값을 우선 분리함.
jeju_card_df['연도'] = jeju_card_df['연월'].str.split('-').str[0]
#2016이 아닌 데이터만 추출해서 다시 데이터에 담아줬음.
jeju_card_df = jeju_card_df[jeju_card_df['연도'] != '2016']
--> 이 방법이 간단하고 전체 데이터를 전부 볼 수는 있지만, 이러면 되돌아가기가 어렵기 때문에,
--> 나라면 데이터 프레임을 또 만들 것임. 무조건. 원본은 살아있어야 함.
- 연령대 처리
- 나는 10대로 묶어 줬는데 해설은 한 값으로 통일시켜줬음.
#10대로 묶어주기
condition = (jeju_df['연령대'] == '20대미만') | (jeju_df['연령대'] == '20 미만')
jeju_df.loc[condition, '연령대'] = '10대'
jeju_df['연령대'].unique()
#값
array(['20대', '60대이상', '30대', '40대', '50대', '10대'], dtype=object)
- 해설 ver
- 값 합칠 때 그냥 , 로만 해도 된다는 것을 지금 처음 알았음.
#20대미만으로 묶기
jeju_card_df.loc[jeju_card_df['연령대'] == '20 미만', '연령대'] = '20대미만'
jeju_card_df['연령대'].unique()
#값
array(['60대이상', '50대', '40대', '30대', '20대미만', '20대'], dtype=object)
<연월별 이용 금액 시각화>
- .gorupby
- 나는 아까 만들어준 변수를 계속 활용했음.
- 이미, 17-18년도만 추출 했기에 그걸로 계속 만들어줬음.
++ 이렇게 하면 안됌.. 어디서 부터 잘못됐는지 모르겠으나, 연도가 다 01로 되어 있어서.. 월별을 볼 수가 없음.
#날짜별 값 계산되게 resample 처리
jeju_17_to_18.resample('Y')
#년도 별 평균, sum 값을 비교했음.
jeju_17_to_18.resample('Y').mean(numeric_only = True)
jeju_17_to_18.resample('Y').sum(numeric_only = True)
- 반면 해설은 이미 연월 값이 17-18도만 남았기에 그걸로 groupby를 해줬음.
jeju_card_df.groupby('연월').sum(numeric_only=True)
#위는 인덱스 위치에 들어가 있기에 더 편하게 그래프를 만들기 위해서 변수에 따로 담아서, 만들어줌.
groupby_ym = jeju_card_df.groupby('연월').sum(numeric_only=True).reset_index()
groupby_ym
--> 위는 인덱스 위치에 들어가 있기에 더 편하게 그래프를 만들기 위해서 변수에 따로 담아서, 만들어줌.
--> 내가 놓친 게 이 부분으로 이것 때문에 그래프가 계속 이상하게 그려지는 데 방법을 못 찾았음..
sns.barplot(data=groupby_ym, x='연월', y='이용금액')
--> 나 역시 이런 식으로 계속 깨졌음..
--> 그냥 실습에서 나눔고딕만 써있어서.. 생각없이 그것만 해서 인듯.
--> 애플 고딕인데....
# Windows
plt.rc('font', family='Malgun Gothic')
# macOS
plt.rc('font', family='AppleGothic')
--> 사실 나는 그래프도 예쁘게 안 그려졌지만, 그 상태로도 해석을 하는 것에는 무리가 없다고 판단했기에, 그냥 넘겼음.
- but, 그래프를 조정하면 되는 것인데 생각을 못 한 것.
- 사이즈를 조정해주고 글자 겹치는 것은 값에 rotation을 주면 되는 것임.
#플랏 사이즈 조절
plt.rcParams['figure.figsize'] = (10, 5)
#글자 겹치는 것은 xticks()에 rotation을 주면 됨
sns.barplot(data=groupby_ym, x='연월', y='이용금액')
plt.xticks(rotation=90)
plt.title('연월별 카드 이용 금액')
--> 타이틀도 넣어주면 됨
--> 그런데 이용금액이 과학적 표기법이라서 읽기가 어렵기 때문에
--> 1e11 이라서.. 지금 10의 11승을 곱해야 해서 1.50 값이 1,500억을 의미함.
- so, 표기법을 바꿔줘야 함.
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'{x/100000000:,.0f}'))
- y축 값의 형식을 지정해주고 있는데, x를 1억 단위로 나눠서 단위를 1억으로 고쳐줌.
- 고정 소수점 표기법으로 , --> 천 단위로 ,를 찍는 것을 의미
- .0f --> 소수점 아래 숫자가 0개임을 의미
sns.barplot(data=groupby_ym, x='연월', y='이용금액')
plt.xticks(rotation=90)
plt.title('연월별 카드 이용 금액')
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'{x/100000000:,.0f}'))
plt.ylabel('이용금액(억)')
--> 다시 그리면 이렇게 바뀜.
--> label 까지 해주면 됨.
--> 이러면 전체 값의 비교가 됨
--> 둘 다 겨울에 이용금액이 감소하고 봄 여름에 상승하지만, 2018년도에 전반적로 소비액이 감소했음을 확인 가능.
<2017년과 2018년 이용 금액 비교>
- .gorupby
- 여기서.. 부터 상당히 꼬이기 시작했음. 그래서 플랏으로 비교하기 보단, 숫자로 확인하기도 했음.
- 아니면 플랏을 그려도 보기도 힘든데 차이만 확인할 수 있는 정도였음.
groupby_ym_age = jeju_card_df.groupby(['연도', '연령대']).sum(numeric_only=True).reset_index()
groupby_ym_age
--> 아마도.. 반복적으로 reset_index()를 하지 않아서 그런 듯.
sns.barplot(data=groupby_ym_age, x='연도', y='이용금액', hue='연령대')
plt.title('연도별/연령대별 카드 이용 금액')
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'{x/100000000:,.0f}'))
plt.ylabel('이용금액(억)')
--> hue도 계속 주고 싶었는데, 내가 짠 코드에서는 계속 에러가 떴었다.
--> 이건 연령대 오름차순이 아직 적용 안되었음.
- .Categorical()
- 범주에 순서를 주고 싶을 때 사용한다고 보면 됨. 파라미터로 ordered = True 를 주면 됨.
#카테고리컬로 해주고
jeju_card_df['연령대'] = pd.Categorical(jeju_card_df['연령대'],
categories=['20대미만', '20대', '30대', '40대', '50대', '60대이상'],
ordered=True)
#그래프 다시 그리기
groupby_ym_age = jeju_card_df.groupby(['연도', '연령대']).sum(numeric_only=True).reset_index()
sns.barplot(data=groupby_ym_age, x='연도', y='이용금액', hue='연령대')
plt.title('연도별/연령대별 카드 이용 금액')
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'{x/100000000:,.0f}'))
plt.ylabel('이용금액(억)')
--> 사실 큰 차이가 없음.
--> 그냥 전반적으로 값이 감소한 것임.
- 그래서 제주도민과 내국인관광객의 차이가 있는지 확인하고자 함.
groupby_ym_user = jeju_card_df.groupby(['연도', '이용자 구분']).sum(numeric_only=True).reset_index()
groupby_ym_user
--> 그냥 표로도 충분하지만, 그래프 그림.
sns.barplot(data=groupby_ym_user, x='연도', y='이용금액', hue='이용자 구분')
plt.title('연도별/이용자 구분별 카드 이용 금액')
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'{x/100000000:,.0f}'))
plt.ylabel('이용금액(억)')
--> 둘 다 줄어서 딱히 큰 의미가 없다고 했지만,
--> 도민의 수는 크게 변화가 없을 것으로 여겨지기에
이 부분은 확인을 해야 하지 않나 싶음..??
+ 2000억대의 차이는.. 꽤 큰데?
- 업종의 차이를 확인하고자 함.
groupby_ym_market = jeju_card_df.groupby(['연도', '업종명']).sum(numeric_only=True).reset_index()
sns.barplot(data=groupby_ym_market, x='연도', y='이용금액', hue='업종명')
plt.title('연도별/업종별 카드 이용 금액')
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'{x/100000000:,.0f}'))
plt.ylabel('이용금액(억)')
--> 기타가 2018년도에 사라짐.
--> 확인해 볼 필요가 있음.
- 기타를 확인할 필요가 있음.
jeju_card_df[jeju_card_df['업종명'] == '기타']
--> 데이터를 보면 18년도가 아예 없음..
--> 이것은 18년도의 '기타' 업종의 데이터가 누락되어 있는 것으로 여겨짐.
- unique()해서 제대로 확인해도 없음
jeju_card_df[jeju_card_df['업종명'] == '기타']['연월'].unique()
#값
array(['2017-11', '2017-10', '2017-09', '2017-08', '2017-07', '2017-06',
'2017-05', '2017-04', '2017-03', '2017-02', '2017-01'],
dtype=object)
- then, 기타를 제외하고 계산하는 것이 더 좋을 수 있음.
jeju_card_df = jeju_card_df[jeju_card_df['업종명'] != '기타']
- 불린 인덱싱으로 제외하는 것이 더 편한 듯.
- 다시 그림을 그려보면,
groupby_ym_age = jeju_card_df.groupby(['연도', '연령대']).sum(numeric_only=True).reset_index()
sns.barplot(data=groupby_ym_age, x='연도', y='이용금액', hue='연령대')
plt.title('연도별/연령대별 카드 이용 금액')
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'{x/100000000:,.0f}'))
plt.ylabel('이용금액(억)')
--> 이렇게 하면, 차이가 크지 않음.
groupby_ym_user = jeju_card_df.groupby(['연도', '이용자 구분']).sum(numeric_only=True).reset_index()
sns.barplot(data=groupby_ym_user, x='연도', y='이용금액', hue='이용자 구분')
plt.title('연도별/이용자 구분별 카드 이용 금액')
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'{x/100000000:,.0f}'))
plt.ylabel('이용금액(억)')
--> 이것도 차이가 없음.
groupby_ym_market = jeju_card_df.groupby(['연도', '업종명']).sum(numeric_only=True).reset_index()
sns.barplot(data=groupby_ym_market, x='연도', y='이용금액', hue='업종명')
plt.title('연도별/업종별 카드 이용 금액')
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'{x/100000000:,.0f}'))
plt.ylabel('이용금액(억)')
--> 이것도 차이가 없어서 사실상 연간 차이가 없다고 보는 게 맞을 듯.
<연령대별 이용 금액 시각화>
- .gorupby
- 그룹바이 별로 새로운 데이터를 만들어줌.
groupby_age = jeju_card_df.groupby('연령대').sum(numeric_only=True).reset_index()
groupby_age
--> 파이 차트를 그려줌.
--> 나도 시도는 했는데.. 너무 잘게 쪼개졌고, 어떻게 처리할 지를 몰라서 포기 했음.
- labes 에 연령대 칼럼을 넣음.
groupby_age.plot(kind='pie', y='이용자수', labels=groupby_age['연령대'])
plt.title('연령대별 카드 이용자 수 비중')
--> 나는 이게 안 됐었는데,, 아마도 데이터 전처리 과정에 실수였던 것 같음.
groupby_age.plot(kind='pie', y='이용자수', labels=groupby_age['연령대'], autopct='%.1f%%')
plt.title('연령대별 카드 이용자 수 비중')
--> automatic percentage인 autopct를 파라미터로 넣어서 퍼센트를 확인함.
--> %.1%는 25.3%처럼 소수 첫째 자리까지 표현된 숫자값 뒤에 % 기호를 붙인 형태를 의미함.
- 범례 안 겹치게 하기
groupby_age.plot(kind='pie', y='이용자수', labels=groupby_age['연령대'], autopct='%.1f%%')
plt.title('연령대별 카드 이용자 수 비중')
plt.legend(loc='upper left', bbox_to_anchor=(1, 1))
--> 그래프의 왼쪽 아래의 좌표가 (0,0)이면
파이 차트의 가로와 세로의 길이를 각각 1로 보면 (1,1)이 왼쪽 상단의 꼭짓점이 됨.
- 이용 금액도 확인. y값만 바꾸면 됨.
groupby_age.plot(kind='pie', y='이용금액', labels=groupby_age['연령대'], autopct='%.1f%%')
plt.title('연령대별 카드 이용 금액 비중')
plt.legend(loc='upper left', bbox_to_anchor=(1, 1))
--> 2-30대는 이용자 수에 비해 이용 금액의 비중이 비교적 작고, 5-60대 이상은 이용자 수에 비해 이용 금액의 비중이 큼.
- 인당 이용금액 확인하기
groupby_age['인당이용금액'] = groupby_age['이용금액'] / groupby_age['이용자수']
groupby_age
--> 새로운 칼럼을 만들어줌.
--> 이건 나도 했음.. 플랏을 계속 실패했지만,,
sns.barplot(data=groupby_age, x='연령대', y='인당이용금액')
plt.title('연령대별 인당 카드 이용 금액')
--> 연령대가 높아질 수록 소비액이 증가하는 것 확인 가능
- 이전에는 억으로 나눠줬지만 굳이 그럴 필요가 없이 , 만 찍어주면 됌.
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'{x:,.0f}'))
sns.barplot(data=groupby_age, x='연령대', y='인당이용금액')
plt.title('연령대별 인당 카드 이용 금액')
--> 그러면 수정 됌.
<연령대별/업종별 이용 금액 시각화>
- .gorupby
- 그룹바이 별로 새로운 데이터를 만들어줌.
groupby_age_market = jeju_card_df.groupby(['연령대', '업종명']).sum(numeric_only=True).reset_index()
groupby_age_market.head()
--> 그냥 리셋 인덱스는 한 세트라고 생각하면 됨.
- 앞에서 활용했던 것 다 넣어서 막대그래프 그리기
sns.barplot(data=groupby_age_market, x='연령대', y='이용금액', hue='업종명')
plt.title('연령대별/업종별 인당 카드 이용 금액')
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'{x/100000000:,.0f}'))
plt.ylabel('이용금액(억)')
--> hue,,, 가 2개가 아니라 여러 개도 가능임..
--> 이렇게 생각못하고 업종을 축으로 넣었던 것 같은데
그래서 그래프가 이상해졌음.
--> 20대미만은 값이 너무 작아서 확인이 안됨
- 20대미만 확인하려고 인당이용금액 추가해줌.
- 값이 작아지니깐 굳이 억으로 나눌 필요 없고, 걍 천단위로 , 만 찍어줌
groupby_age_market['인당이용금액'] = groupby_age_market['이용금액'] / groupby_age_market['이용자수']
sns.barplot(data=groupby_age_market, x='연령대', y='인당이용금액', hue='업종명')
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'{x:,.0f}'))
plt.title('연령대별/업종별 인당 카드 이용 금액')
--> ... 가독성이 너무 떨어짐.
- so, 연령대 별로 파이 차트를 그려주는 for문을 만듦.
-... 진짜 생각도 못해봤음...
- 파이썬을 잘 해야 해.. for문은 무조건 하나씩 거치게 되는 거니깐.. 맞는 말임...
for age in groupby_age_market['연령대'].unique():
data = groupby_age_market[groupby_age_market['연령대'] == age]
data.plot(y='인당이용금액', labels=data['업종명'], kind='pie', autopct='%.1f%%')
plt.title(f'업종별 인당 이용 금액({age})')
plt.xticks(rotation=90)
plt.show()
- 이미지는 생략
<연령대별/연월별 이용 금액 시각화>
- .gorupby
- 그룹바이 별로 새로운 데이터를 만들어줌.
groupby_age_ym = jeju_card_df.groupby(['연령대', '연월']).sum(numeric_only=True).reset_index()
sns.barplot(data=groupby_age_ym, x='연령대', y='이용자수', hue='연월')
--> hue에 넣을 순 있지만, 사실상 가독성이 제로임..
--> so, 마찬가지로 for 문을 사용해서 연령대별로 반복문을 돌면서 bargraph 를 그리도록 함.
for age in groupby_age_ym['연령대'].unique():
data = groupby_age_ym[groupby_age_ym['연령대'] == age]
sns.barplot(data=data, x='연월', y='이용금액')
plt.title(f'{age} 연월별 카드 이용 금액')
plt.xticks(rotation=90)
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f'{x/100000000:,.0f}'))
plt.ylabel('이용금액(억)')
plt.show()
--> .. for문 생각도 안하는 나란 사람...
다음 실습에서는 적용해서 해봐야 겠음...
--> 국비 시작하기 전에 파이썬 강의 많이 들어야 할 듯..
'Data Science > Pandas' 카테고리의 다른 글
[pandas] RFM분석 (2) | 2024.07.14 |
---|---|
[pandas] 데이터 전처리 및 분석 연습2 (0) | 2024.07.08 |
[데이터 전처리] 원하는 시간 간격으로 묶기 .resample() (0) | 2024.06.26 |
[데이터 전처리] 그룹 별로 분석하기 groupby(), category 타입, 멀티 인덱싱 (2) | 2024.06.26 |
[데이터 전처리] 데이터 합치기) 같은 형식 concat() / 칼럼 기준 merge() / 인덱스 기준 join() (0) | 2024.06.25 |