🐝 괄호 안의 내용을 콘솔 창에 표시. 콘솔 창은 웹 브라우저의 개발자 도구 창에 포함되어 있는 공간이다.
🐝 콘솔 창에서 소스 코드의 오류를 발견하거나 변숫값을 확인할 수도 있다.
🐝 괄호 안에 변수, 따옴표 사이에 표시할 텍스트를 넣을 수 있다. but! html 태그는 불가
주의점 : 자바 스크립트가 각각의 문장을 구별하는 방법은 1) 문장의 끝에 ;(세미 콜론) 2) 줄 바꿈 둘 중 하나 다른 언어로의 확장(파이썬, 코틀린을 제외한 대부분의 언어가 세미 콜론 사용, 즉 1번 사용) 및 명료성을 위해 세미 콜론을 붙이는 것이 좋음. (해당 라인을 작업 중인지 완료 했는지 구분)
- 분석에 활용할 변수를 전처리 - 변수의 특징을 파악하고 이상치와 결측치를 정제한 다음, 변수의 값을 다루기 편하게 바꿈 - 전처리는 분석에 활용할 변수 각각 진행.
< 2단계 : 변수 간 관계 분석 > - 전처리를 완료하면 본격적으로 변수 간 관계를 파악하는 분석을 함 - 데이터를 요약한 표와 데이터의 특징을 쉽게 이해할 수 있는 그래프를 만든 다음 분석 결과를 해석
1) 데이터 준비하기
📌 Koweps_hpwc14_2019_beta2.sav : 2020년에 발간된 복지패널 데이터로 6,331가구, 14,418명의 정보를 담고 있음
2) 패키지 설치 및 로드하기
📌 데이터 파일은 통계 분석 소프트웨어인 SPSS 전용파일 📌 pyreadstat 패키지를 설치하면 pandas 패키지의 함수를 이용해 SPSS, SAS, STATA 등 다양한 통계 분석 소프트웨어의 데이터 파일을 불러올 수 있다.
pip install pyreadstat
3) 데이터 불러오기
👾 데이터 원본은 복구할 상황을 대비해 그대로 두고 복사본을 만들어 분석에 활용
import pandas as pd
import numpy as np
import seaborn as sns
import pyreadstat
raw_welfare = pd.read_spss('../input/Koweps_hpwc14_2019_beta2.sav')
# 복사본 만들기
welfare = raw_welfare.copy()
4) 데이터 검토
👾 데이터의 구조와 특징을 파악
# 앞부분, 뒷부분 출력
welfare.head()
# 행, 열 개수 출력
welfare.shape # (14418, 830)
# 변수 속성 출력
welfare.info()
'''
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 14418 entries, 0 to 14417
Columns: 830 entries, h14_id to h14_pers_income5
dtypes: float64(826), object(4)
memory usage: 91.3+ MB
'''
# 요약 통계량
welfare.describe()
5) 변수명 바꾸기
👾 복지패널 데이터와 같은 대규모 데이터는 변수의 수가 많고 변수명이 코드로 되어 있어 전체 구조를 한 눈에 파악하기 어려움 👾 규모가 큰 데이터는 데이터 전체를 한 번에 파악하기보다 변수명을 쉬운 단어로 바꾼 다음 분석에 사용할 변수를 살펴봐야 함
⚡️ 규모가 큰 조사 자료는 데이터의 특징을 설명해 놓은 코드북 codebook을 함께 제공 ⚡️ 코드북에는 코드로 된 변수명과 값의 의미가 설명되어 있음 ⚡️ 코드북을 보면 데이터의 특징이 어떠한지 감을 잡을 수 있고, 분석에 어떤 변수를 활용할지, 분석 방향의 아이디어를 얻을 수 있음 ⚡️ 코드북의 파일명은 Koweps_Codebook_2019.xlsx
# 코드북을 참고해 분석에 사용할 변수 7개의 이름을 알기 쉬운 단어로 바꿈.
welfare = welfare.rename(columns={'h14_g3': 'sex', # 성별
'h14_g4': 'birth', # 태어난 연도
'h14_g10': 'marriage_type', # 혼인 상태
'h14_g11': 'religion', # 종교
'p1402_8aq1': 'income', # 월급
'h14_eco9': 'code_job', # 직업 코드
'h14_reg7': 'code_region'}) # 지역 코드
· 1단계 : 변수 검토 및 전처리 성별 / 월급 · 2단계 : 변수 간 관계 분석 성별 월급 평균표 만들기 / 그래프 만들기
1) 성별 변수 검토 및 전처리하기
a. 변수 검토하기
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
welfare = pd.read_csv ('../output/Koweps_hpwc14_2019_beta2_step_01.csv')
welfare.head()
# sex 성별 변수의 타입을 파악
welfare['sex'].dtypes # dtype('float64')
# value_counts()를 이용해 각 범주마다 몇 명이 있는지 알아봄
welfare['sex'].value_counts()
'''
sex
2.0 7913
1.0 6505
Name: count, dtype: int64
'''
b. 전처리하기
· 코드북을 보면 성별 변수의 값이 1이면 남자, 2면 여자를 의미. 모른다고 답하거나 응답하지 않으면 9로 입력 · 이 정보를 바탕으로 데이터에 이상치가 있는지 검토하고, 분석할 때 제거하기 편하도록 NaN을 부여해 결측치 처리 ➡️ 즉 값이 9인 경우 성별을 알 수 없어 분석에서 제외해야 하므로 결측 처리
# 이상치 확인
welfare['sex'].value_counts()
# 1, 2만 있고 9나 다른 값이 없으니 이상치를 결측 처리하는 절차를 건너뛰어도 됨
# 만일 이상치가 있으면 이상치를 결측 처리한 후에 다음 결측치 확인
# 이상치 결측 처리
# sex 열에서 9인 값을 NaN으로 변경
welfare['sex'] = np.where(welfare['sex'] == 9, np.nan, welfare['sex'])
-> '9'인 값이 존재하면 np.nan 값이 들어가게 되고, 아니면 원래 값이 들어가게 됨
# 결측치 확인
welfare['sex'].isna().sum() # 0
💡 np.where(condition, T, F) : 조건에 해당하는 값이면 'T', 해당하지 않는 값이면 'F' 가 기입되게 된다.
# 성별이 1, 2로 되어 있어, 값의 의미를 이해하기 쉽도록 문자 male과 female로 변경
# 변경 후 잘 반영이 되었는지 value_counts()와 countplot()을 이용해
# 바꾼 값이 잘 반영이 됐는지 출력 결과를 확인
# 성별 항목 이름 부여
welfare['sex'] = np.where(welfare['sex'] == 1, 'male', 'female')
#-> 1이면 male, 아니면 female 기입되게 된다.
welfare['sex'].value_counts()
'''
sex
female 7913
male 6505
Name: count, dtype: int64
'''
# 빈도 막대 그래프 만들기
sns.countplot(data=welfare, x='sex')
plt.show()
3. 월급 변수 검토 및 전처리하기
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
welfare = pd.read_csv('../output/Koweps_hpwc14_2019_beta2_step_02.csv')
welfare['sex'].head()
'''
0 female
1 male
2 male
3 male
4 female
Name: sex, dtype: object
'''
1) 변수 검토하기
📍 코드북을 보면 월급은 '일한 달의 평균 임금'을 의미하며 1만원 단위로 기록 ▶️ 변수 이름은 income 📍 성별은 범주 변수이므로 df.value_counts()를 이용해 범주별 빈도를 확인하면 특징을 파악할 수 있음 📍 월급은 연속 변수이므로 df.value_acount()을 이용하면 너무 많은 항목이 출력되어 알아보기 어려움
welfare['income'].dtypes # dtype('float64')
# 요약 통계량 구하기
welfare['income'].describe()
'''
count 4534.000000
mean 268.455007
std 198.021206
min 0.000000
25% 150.000000
50% 220.000000
75% 345.750000
max 1892.000000
Name: income, dtype: float64
'''
✏️ 출력 결과를 보면 float64 타입이고, 0~1892만원의 값을 지님 ✏️ 150~345 만원에 가장 많이 분포하고 평균은 268만원, 중앙값은 평균보다 작은 220만원으로 전반적으로 낮은 쪽에 치우침
➡️ 월급이 평균값보다 낮은 사람이 50% 이상
# 히스토그램을 만들어 분포를 확인
sns.histplot(data=welfare, x='income') # 히스토그램 만들기
plt.show()
2) 전처리 하기
📍 코드북을 보면 월급은 만원 단위로 되어 있고, '모름/무응답'은 9999
welfare['income'].describe() # 이상치 확인
welfare['income'].isna().sum() # # 결측치 확인 14418 - 4534 = 9884
# 9884
✏️ 출력 결과를 보면 최소값은 0 ~ 1,892이고 결측치 9,884개가 있음 ▶️ 즉 9999가 입력된 데이터는 없음
# 이상치 결측 처리
welfare['income'] = np.where(welfare['income'] == 9999, np.nan, welfare['income'])
# 결측치 확인
print(welfare['income'].isna().sum())
# 9884
4. 성별에 따른 월급 차이 분석
1) 성별 월급 평균표 만들기
📍 income 결측치 제거 : dropna(subset=['income']) 📍 sex별 분리 : groupby('sex', as_index=False) 📍 income 평균 구하기 : agg(mean_income=('income', 'mean')
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
welfare = pd.read_csv('../output/Koweps_hpwc14_2019_beta2_step_02.csv')
sex_income = welfare.dropna(subset=['income'])
sex_income = sex_income.groupby('sex', as_index=False)
sex_income = sex_income.agg(mean_income=('income', 'mean'))
sex_income
'''
sex mean_income
0 female 186.293096
1 male 349.037571
'''
✏️ 평균 남자 월급은 349만원, 여자 월급은 186만원으로, 남성이 여성보다 약 163만원이 많음
2) 그래프 만들기
📍 분석 결과를 쉽게 이해할 수 있도록 성별 월급 평균표를 이용해 막대 그래프로 만듦
# 막대 그래프 만들기
sns.barplot(data=sex_income, x='sex', y='mean_income')
plt.show()
5. 나이와 월급의 관계 - 몇 살 때 월급을 가장 많이 받을까?
< 분석 절차 > · 1단계 : 변수 검토 및 전처리 나이 / 월급 · 2단계 : 변수 간 관계 분석 나이에 따른 월급 평균표 만들기 / 그래프 만들기
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
welfare = pd.read_csv('../output/Koweps_hpwc14_2019_beta2_step_02.csv')
welfare['birth'].head()
'''
0 1945.0
1 1948.0
2 1942.0
3 1962.0
4 1963.0
Name: birth, dtype: float64
'''
1) 나이 변수 검토 및 전처리하기
a. 변수 검토하기
📍 나이 변수는 없고 태어난 연도 변수만 있음. 따라서 태어난 연도 변수를 기반으로 나이 변수를 만들어야 함
welfare['birth'].dtypes
# dtype('float64')
welfare['birth'].describe() # 요약 통계량 구하기
'''
count 14418.000000
mean 1969.280205
std 24.402250
min 1907.000000
25% 1948.000000
50% 1968.000000
75% 1990.000000
max 2018.000000
Name: birth, dtype: float64
'''
sns.histplot(data = welfare, x = 'birth') # 히스토그램 만들기
plt.show()
b. 전처리
📍 코드북을 보면 태어난 연도는 '모름/무응답'일 경우 9999로 코딩, 이 정보를 바탕으로 전처리
welfare['birth'].describe() # 이상치 확인
welfare['birth'].isna().sum() # 결측치 확인
# 0
# 이상치와 결측치가 없으므로 파생변수를 만드는 단계로 넘어감
# 만일 이상치가 발견되면 아래와 같이 전처리한 다음 분석을 진행
# 이상치 결측 처리
welfare['birth'] = np.where(welfare['birth'] == 9999, np.nan, welfare['birth'])
# 결측치 확인
welfare['birth'].isna().sum() # 0
c. 파생변수 만들기 - 나이
📍 2019년에 조사가 진행됐으니 2019에서 태어난 연도를 뺀 다음 1을 더해 나이를 구함
📍 df.assign(kwargs) : DataFrame에 새 열을 할당하는 메서드.
kwargs : 새열이름 = 내용 형식으로 입력되는 키워드. 콤마(,)를 통해 여러개를 입력.
# 나이 변수 만들기
welfare = welfare.assign(age=2019 - welfare['birth'] + 1)
welfare['age'].describe() # 요약 통계량 구하기
'''
count 14418.000000
mean 50.719795
std 24.402250
min 2.000000
25% 30.000000
50% 52.000000
75% 72.000000
max 113.000000
Name: age, dtype: float64
'''
# 히스토그램 만들기
sns.histplot(data=welfare, x='age')
# 변경된 자료 저장
welfare.to_csv('../output/Koweps_hpwc14_2019_beta2_step_03.csv', mode='w', index=False)
6. 나이와 월급의 관계 분석
1) 나이에 따른 월급_평균표 만들기
📍 income 결측치 제거 : dropna(subset=['income']) 📍 age별 분리 : groupby('age') 📍 income 평균 구하기 : agg(mean_income=('income', 'mean'))
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
welfare = pd.read_csv('../output/Koweps_hpwc14_2019_beta2_step_03.csv')
age_income = welfare.dropna(subset=['income']).groupby('age').agg(mean_income=('income', 'mean'))
age_income.head()
'''
mean_income
age
19.0 162.000000
20.0 121.333333
21.0 136.400000
22.0 123.666667
23.0 179.676471
'''
2) 그래프 만들기
📍 평균표를 이용해 그래프 작성, x축을 나이, y축을 월급으로 지정해 나이에 따른 월급의 변화를 나타낸 선 그래프 만듦
# 선 그래프 만들기
sns.lineplot(data=age_income, x='age', y='mean_income')
plt.show()
🚀 folium 라이브러리의 Map() 함수를 이용하여 지도 객체를 생성 🚀 지도 화면은 고정된 것이 아니고 줌 Zoom 기능과 화면 이동 Scroll이 가능
⚡️ folium은 웹 기반 지도를 만들기 때문에 웹 환경에서만 지도를 확인할 수 있음 ⚡️ 지도를 보려면 지도 객체에 save() 메서드를 적용하여 HTML 파일로 저장하고 웹 브라우저에서 파일을 열어서 확인 ➡️ 주피터 노트북에서는 바로 지도 객체를 확인할 수 있음
import folium
# 서울 지도 만들기
# location 옵션에 [위도, 경도] 수치를 입력하면 그 지점을 중심으로 지도를 보여줌
# zoom_start 옵션을 사용하면 화면 확대 비율을 조절할 수 있음
seoul_map = folium.Map(location=[37.55, 126.98], zoom_start=12)
seoul_map
# 지도를 HTML 파일로 저장하기
seoul_map.save('../output/seoul.html')
3. 지도 스타일 적용하기
🚀 Map() 함수에 tiles 옵션을 적용하면 지도에 적용하는 스타일을 변경하여 지정할 수 있다
🚀 tiles 스타일 종류
→ tiles = 'OpenStreetMap' (기본값) → tiles = 'Cartodb Positron' or 'cartodbpositron' (단계 구분도가 잘 표현 되도록 밝은 색으로 바꿈)
📌 서울 시내 주요 대학교의 위치 데이터를 데이터 프레임으로 변환하고, folium 지도에 위치를 표시
import pandas as pd
import folium
# 대학교 리스트를 데이터프레임 변환
df = pd.read_excel('../input/서울지역 대학교 위치.xlsx')
'''
name 위도 경도
0 KAIST 서울캠퍼스 37.592573 127.046737
1 KC대학교 37.548345 126.854797
2 가톨릭대학교(성신교정) 37.585922 127.004328
3 가톨릭대학교(성의교정) 37.499623 127.006065
4 감리교신학대학교 37.567645 126.961610
'''
# 서울 지도 만들기
seoul_map = folium.Map(location=[37.55, 126.98], zoom_start=12)
# 대학교 위치정보를 Marker로 표시
for name, lat, lng in zip(df['name'], df['위도'], df['경도']):
folium.Marker([lat, lng], popup=name).add_to(seoul_map)
seoul_map
⚡️ folium.Marker() 함수의 인수
[위도, 경도] 는 마커를 찍을 좌표
popup = '클릭문구' 는 마우스 클릭시 표시되는 문구
tooltip = '오버문구' 는 마우스를 갖다 놓으면 표시되는 문구
icon = folium.Icon(color='red', icon='star') 은 아이콘의 색상과 모양을 설정
add_to(m) 은 설정한 모든 내용을 현재 지도에 적용하라는 의미
# 지도를 HTML 파일로 저장하기
seoul_map.save('../output/seoul_colleges.html')
💡 대학교 위치정보를CircleMarker()로 표시 - Marker() 대신 CircleMarker()를 사용. 원형 마커의 크기, 색상, 투명도 들을 설정할 수 있음
for name, lat, lng in zip(df['name'], df['위도'], df['경도']):
folium.CircleMarker([lat, lng], popup=name,
radius=10, # 원의 반지름
color='brown', # 원의 둘레 색상
fill=True,
fill_color='coral', # 원을 채우는 색
fill_opacity=0.7 # 투명도
).add_to(seoul_map)
seoul_map
5. 단계 구분도 Choropleth Map 표시
🚀 행정구역과 같이 지도 상의 어떤 경계에 둘러싸인 영역에 색을 칠하거나 음영 등으로 정보를 나타내는 시각화 방법
# int -> str 타입 변경
df.columns = df.columns.map(str)
# 경기도 시군구 경계 정보를 가진 geo-json 파일 불러오기
# 경기도 행정구역 경계 지리 정보를 사용
geo_path = '../input/경기도행정구역경계.json'
geo_data = json.load(open(geo_path))
geo_data
'''
{'type': 'FeatureCollection',
'features': [{'type': 'Feature',
'properties': {'code': 31380,
'name': '양평군',
'name_eng': 'Yangpyeong-gun',
'base_year': 2013},
'geometry': {'type': 'Polygon',
'coordinates': [[[127.56113535909492, 37.6256560539258],
'''생략'''
'''
# 경기도 지도 만들기
g_map = folium.Map(location=[37.5502, 126.982], zoom_start=9)
g_map
# 출력할 연도 선택 (2007 ~ 2017년 중에서 선택)
year = '2017'
# Choropleth 클래스로 단계구분도 표시하기
folium.Choropleth(geo_data=geo_path, # 지도 경계
data=df[year], # 표시하려는 데이터
columns=[df.index, df[year]], # 열 지정
fill_color='YlOrRd', fill_opacity=0.7, line_opacity=0.5,
threshold_scale=[10000, 100000, 300000, 500000, 700000],
# -> 임계값 수치, 10000명/100000명...
key_on='feature.properties.name'
).add_to(g_map)
g_map
📌 geo_data : Choropleth 맵에 사용될 지리 정보
📌 key_on:geo_data 내용에서 지리 영역을 구분할 열 이름 호출 ( ex. '양평군', '이천시'...)
# x축에는 시간을 나타낸 date, y축에는 실업자 수를 나타낸 uneploy를 지정
sns.lineplot(data=economics, x='date', y='unemploy')
plt.show()
📍 출력된 그래프를 보면 x축에 굵은 선이 표시 ▶️ date 변수에는 '1967-07-01' 처럼 '연월일'을 나타낸 문자가 있는데 이 값이 x축에 가로로 여러 번 겹쳐 표시되어서 굵은 선으로 보임
(1) x축에 연도 표시하기
🥕 x축에 연도를 표시하려면 변수 타입을 날짜 시간 타입 datetime64으로 바꿔야 함 ( economics 데이터의 date가 문자 object 타입으로 되어 있음 )
🥕 pd.to_datetime()을 이용하면 변수의 타입을 날짜 시간 타입으로 바꿀 수 있음
⚡️ 변수의 타입을 날짜 시간 타입으로 바꾸더라도 값이 달라지지 않음
🥕 날짜 시간 타입은 df.dt를 이용해 연, 월, 일을 추출할 수 있음
# 날짜 시간 타입 변수 만들기
# date 타입을 날짜 시간 타입으로 변경해서 date2 변수 추가
economics['date2'] = pd.to_datetime(economics['date'])
# 변수 타입 확인
economics.info()
'''
RangeIndex: 574 entries, 0 to 573
Data columns (total 7 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 date 574 non-null object
... 생략...
6 date2 574 non-null datetime64[ns]
'''
# 연도 변수 추가
economics['year'] = economics['date2'].dt.year
economics.head()
# 연도를 나타낸 변수를 sns.lineplot()의 x에 입력하면 x축에 연도가 표시
sns.lineplot(data=economics, x='year', y='unemploy')
plt.show()
📍 선의 위아래에 표시된 면적은 신뢰구간 confidence interval 📍 신뢰 구간을 표시하지 않으려면 errorbar = None을 입력
🍒데이터의 분포 또는 퍼져 있는 형태를 직사각형 상자 모양으로 표현한 그래프 🍒 상자 그림을 보면 데이터가 어떻게 분포하고 있는지 알 수 있기 때문에 평균값만 볼 때 보다 데이터의 특징을 더 자세히 이해할 수 있음 🍒 사람의 나이가 500살, 키가 5미터 등은 표현은 가능하지만 현실적으로 불가능한 값들 이를 이상치, 극단치라고 하는데
이상치는 효과적인 데이터 분석을 위해 제거해야 함 ⚡️ 이상치를 제거하기 위해 값의 정상 범위를 정하는 방법이 있다.
▶️ 나이의 경우 121살은 이상치로 보는 것 ⚡️ 다른 방법으로 통계적인 기법을 사용 ▶️ 정규 분포에서 상하위 0.2% 밖의 데이터를 극단적인 값으로 가정하여 제거
1) 상자 그림 만들기
✏️ sns.boxplot()을 사용하여 그래프 생성
✏️ 값을 크기순으로 나열해 4등분했을 때 위치하는 값인 '사분위수'를 이용해 그래프가 생성 된다 ✏️ 다음은 상자 그림의 요소가 나타내는 값
import seaborn as sns
import pandas as pd
import matplotlib.pyplot as plt
# 데이터 준비
mpg = pd.read_csv('../input/mpg.csv')
# 그래프 생성
sns.boxplot(data=mpg, x='drv', y='hwy')
plt.show()
📍 전륜구동(f)은 26 ~ 29 사이의 좁은 범위에 자동차가 모여 있는 뾰족한 형태의 분포 📍 수염의 위아래에 점 표식이 있는 것을 보면 연비가 극단적으로 높거나 낮은 자동차들이 존재 📍 4륜구동(4)은 17 ~ 22 사이에 자동차 대부분이 모여 있는 형태 ▶️ 중앙값이 상자 밑면에 가까운 것을 보면 낮은 값 쪽으로 치우친 형태의 분포 📍 후륜구동(r)은 17 ~ 24 사이의 넓은 범위에 자동차가 분포 ▶️ 수염이 짧고 극단치가 없는 것을 보면 자동차 대부분이 사분위 범위에 해당
🌻 데이터를 x축과 y축에 점으로 표현한 그래프 🌻 나이와 소득처럼 연속값으로 된 두 변수의 관계를 표현할 때 사용
1) 데이터 준비
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
mpg = pd.read_csv('../input/mpg.csv')
mpg.head()
'''
manufacturer model displ year cyl trans drv cty hwy fl category
0 audi a4 1.8 1999 4 auto(l5) f 18 29 p compact
1 audi a4 1.8 1999 4 manual(m5) f 21 29 p compact
2 audi a4 2.0 2008 4 manual(m6) f 20 31 p compact
3 audi a4 2.0 2008 4 auto(av) f 21 30 p compact
4 audi a4 2.8 1999 6 auto(l5) f 16 26 p compact
'''