Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
Tags
- 과제형 코딩테스트
- ddim
- 프로그래머스
- 포스코 코딩테스트
- 코딩테스트
- 포스코 채용
- posco 채용
- DDPM
- KT
- controlNet
- diffusion models
- ip-adapter
- kt인적성
- classifier-free guidance
- dp
- 논문 리뷰
- colorization
- Image Generation
- Generative Models
- stable diffusion
- manganinja
Archives
- Today
- Total
Paul's Grit
[Python] [Data Analysis] Pandas DataFrame 가지고 놀기 본문
01.데이터 불러오기¶
In [1]:
import pandas as pd
import numpy as np
In [2]:
seoul_cctv = pd.read_csv('../data/01_seoul_cctv.csv')
In [3]:
seoul_cctv.head()
Out[3]:
기관명 | 소계 | 2013년도 이전 | 2014년 | 2015년 | 2016년 | |
---|---|---|---|---|---|---|
0 | 강남구 | 3238 | 1292 | 430 | 584 | 932 |
1 | 강동구 | 1010 | 379 | 99 | 155 | 377 |
2 | 강북구 | 831 | 369 | 120 | 138 | 204 |
3 | 강서구 | 911 | 388 | 258 | 184 | 81 |
4 | 관악구 | 2109 | 846 | 260 | 390 | 613 |
In [4]:
seoul_cctv.tail()
Out[4]:
기관명 | 소계 | 2013년도 이전 | 2014년 | 2015년 | 2016년 | |
---|---|---|---|---|---|---|
20 | 용산구 | 2096 | 1368 | 218 | 112 | 398 |
21 | 은평구 | 2108 | 1138 | 224 | 278 | 468 |
22 | 종로구 | 1619 | 464 | 314 | 211 | 630 |
23 | 중구 | 1023 | 413 | 190 | 72 | 348 |
24 | 중랑구 | 916 | 509 | 121 | 177 | 109 |
In [5]:
seoul_cctv.columns
Out[5]:
Index(['기관명', '소계', '2013년도 이전', '2014년', '2015년', '2016년'], dtype='object')
In [6]:
seoul_cctv.index
print(seoul_cctv.tail(1)) # 데이터 확인 시, tail()로 데이터 개수를 확인해본다
기관명 소계 2013년도 이전 2014년 2015년 2016년 24 중랑구 916 509 121 177 109
In [7]:
# column 이름 변경
# 따로 저장이 필요함: inplace = True
seoul_cctv.rename(columns={'기관명':'구별'}, inplace=True)
seoul_cctv.head(3)
Out[7]:
구별 | 소계 | 2013년도 이전 | 2014년 | 2015년 | 2016년 | |
---|---|---|---|---|---|---|
0 | 강남구 | 3238 | 1292 | 430 | 584 | 932 |
1 | 강동구 | 1010 | 379 | 99 | 155 | 377 |
2 | 강북구 | 831 | 369 | 120 | 138 | 204 |
In [8]:
# .xls 불러오기 위해 xlrd 라이브러리 설치 필요
# !pip install xlrd
# header = 2: 2번재 인덱스의 값을 columns으로 사용
pop_seoul = pd.read_excel('../data/02_seoul_population.xls', header=2, usecols='B, D, G, J, N')
pop_seoul.head()
Out[8]:
자치구 | 계 | 계.1 | 계.2 | 65세이상고령자 | |
---|---|---|---|---|---|
0 | 합계 | 10124579 | 9857426 | 267153 | 1365126 |
1 | 종로구 | 164257 | 154770 | 9487 | 26182 |
2 | 중구 | 134593 | 125709 | 8884 | 21384 |
3 | 용산구 | 244444 | 229161 | 15283 | 36882 |
4 | 성동구 | 312711 | 304808 | 7903 | 41273 |
In [9]:
pop_seoul.rename(columns={
'자치구':'구별',
'계':'인구수',
'계.1':'한국인',
'계.2':'외국인',
'65세이상고령자':'고령자'},
inplace=True)
pop_seoul.head()
Out[9]:
구별 | 인구수 | 한국인 | 외국인 | 고령자 | |
---|---|---|---|---|---|
0 | 합계 | 10124579 | 9857426 | 267153 | 1365126 |
1 | 종로구 | 164257 | 154770 | 9487 | 26182 |
2 | 중구 | 134593 | 125709 | 8884 | 21384 |
3 | 용산구 | 244444 | 229161 | 15283 | 36882 |
4 | 성동구 | 312711 | 304808 | 7903 | 41273 |
In [10]:
# 컬럼을 인덱스 슬라이싱으로 접근 가능 ex) pop_seoul.columns[0]
pop_seoul.rename(columns={
pop_seoul.columns[0]:'구별',
pop_seoul.columns[1]:'인구수',
pop_seoul.columns[2]:'한국인',
pop_seoul.columns[3]:'외국인',
pop_seoul.columns[4]:'고령자'},
inplace=True)
pop_seoul.head()
Out[10]:
구별 | 인구수 | 한국인 | 외국인 | 고령자 | |
---|---|---|---|---|---|
0 | 합계 | 10124579 | 9857426 | 267153 | 1365126 |
1 | 종로구 | 164257 | 154770 | 9487 | 26182 |
2 | 중구 | 134593 | 125709 | 8884 | 21384 |
3 | 용산구 | 244444 | 229161 | 15283 | 36882 |
4 | 성동구 | 312711 | 304808 | 7903 | 41273 |
In [11]:
pop_seoul.sort_values(by='인구수', ascending=False).head(6)
Out[11]:
구별 | 인구수 | 한국인 | 외국인 | 고령자 | |
---|---|---|---|---|---|
0 | 합계 | 10124579 | 9857426 | 267153 | 1365126 |
24 | 송파구 | 671173 | 664496 | 6677 | 76582 |
16 | 강서구 | 608255 | 601691 | 6564 | 76032 |
23 | 강남구 | 561052 | 556164 | 4888 | 65060 |
11 | 노원구 | 558075 | 554403 | 3672 | 74243 |
21 | 관악구 | 520929 | 503297 | 17632 | 70046 |
In [12]:
# 첫번째 행 삭제
pop_seoul.drop(0, inplace=True)
In [13]:
pop_seoul.head()
Out[13]:
구별 | 인구수 | 한국인 | 외국인 | 고령자 | |
---|---|---|---|---|---|
1 | 종로구 | 164257 | 154770 | 9487 | 26182 |
2 | 중구 | 134593 | 125709 | 8884 | 21384 |
3 | 용산구 | 244444 | 229161 | 15283 | 36882 |
4 | 성동구 | 312711 | 304808 | 7903 | 41273 |
5 | 광진구 | 372298 | 357703 | 14595 | 43953 |
In [14]:
seoul_cctv.head(3)
Out[14]:
구별 | 소계 | 2013년도 이전 | 2014년 | 2015년 | 2016년 | |
---|---|---|---|---|---|---|
0 | 강남구 | 3238 | 1292 | 430 | 584 | 932 |
1 | 강동구 | 1010 | 379 | 99 | 155 | 377 |
2 | 강북구 | 831 | 369 | 120 | 138 | 204 |
In [15]:
# '최근 증가율'이라는 컬럼을 생성
seoul_cctv['최근 증가율'] = (seoul_cctv['2014년'] + seoul_cctv['2015년'] + seoul_cctv['2016년']) / seoul_cctv['2013년도 이전'] * 100
seoul_cctv.head(3)
Out[15]:
구별 | 소계 | 2013년도 이전 | 2014년 | 2015년 | 2016년 | 최근 증가율 | |
---|---|---|---|---|---|---|---|
0 | 강남구 | 3238 | 1292 | 430 | 584 | 932 | 150.619195 |
1 | 강동구 | 1010 | 379 | 99 | 155 | 377 | 166.490765 |
2 | 강북구 | 831 | 369 | 120 | 138 | 204 | 125.203252 |
In [16]:
# 최근 증가율이 가장 낮은 구
seoul_cctv.sort_values(by='최근 증가율', ascending=True).head()
Out[16]:
구별 | 소계 | 2013년도 이전 | 2014년 | 2015년 | 2016년 | 최근 증가율 | |
---|---|---|---|---|---|---|---|
18 | 양천구 | 2482 | 1843 | 142 | 30 | 467 | 34.671731 |
13 | 서대문구 | 1254 | 844 | 50 | 68 | 292 | 48.578199 |
20 | 용산구 | 2096 | 1368 | 218 | 112 | 398 | 53.216374 |
5 | 광진구 | 878 | 573 | 78 | 53 | 174 | 53.228621 |
14 | 서초구 | 2297 | 1406 | 157 | 336 | 398 | 63.371266 |
In [17]:
# 외국인 비율, 고령자 비율 컬럼 추가
# 고령자 비율이 가장 적은 곳
pop_seoul['외국인 비율'] = pop_seoul['외국인'] / pop_seoul['인구수'] * 100
pop_seoul['고령자 비율'] = pop_seoul['고령자'] / pop_seoul['인구수'] * 100
pop_seoul.sort_values(by='고령자 비율', ascending=True).head()
Out[17]:
구별 | 인구수 | 한국인 | 외국인 | 고령자 | 외국인 비율 | 고령자 비율 | |
---|---|---|---|---|---|---|---|
24 | 송파구 | 671173 | 664496 | 6677 | 76582 | 0.994825 | 11.410173 |
23 | 강남구 | 561052 | 556164 | 4888 | 65060 | 0.871220 | 11.596073 |
15 | 양천구 | 475018 | 471154 | 3864 | 55234 | 0.813443 | 11.627770 |
5 | 광진구 | 372298 | 357703 | 14595 | 43953 | 3.920247 | 11.805865 |
22 | 서초구 | 445401 | 441102 | 4299 | 53205 | 0.965198 | 11.945415 |
In [215]:
data_result = pd.merge(seoul_cctv, pop_seoul, on='구별')
data_result.head()
Out[215]:
구별 | 소계 | 2013년도 이전 | 2014년 | 2015년 | 2016년 | 최근 증가율 | 인구수 | 한국인 | 외국인 | 고령자 | 외국인 비율 | 고령자 비율 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 강남구 | 3238 | 1292 | 430 | 584 | 932 | 150.619195 | 561052 | 556164 | 4888 | 65060 | 0.871220 | 11.596073 |
1 | 강동구 | 1010 | 379 | 99 | 155 | 377 | 166.490765 | 440359 | 436223 | 4136 | 56161 | 0.939234 | 12.753458 |
2 | 강북구 | 831 | 369 | 120 | 138 | 204 | 125.203252 | 328002 | 324479 | 3523 | 56530 | 1.074079 | 17.234651 |
3 | 강서구 | 911 | 388 | 258 | 184 | 81 | 134.793814 | 608255 | 601691 | 6564 | 76032 | 1.079153 | 12.500021 |
4 | 관악구 | 2109 | 846 | 260 | 390 | 613 | 149.290780 | 520929 | 503297 | 17632 | 70046 | 3.384722 | 13.446362 |
In [216]:
# 컬럼 삭제
data_result.drop(columns=['2013년도 이전', '2014년', '2015년', '2015년'], inplace = True)
data_result.head()
Out[216]:
구별 | 소계 | 2016년 | 최근 증가율 | 인구수 | 한국인 | 외국인 | 고령자 | 외국인 비율 | 고령자 비율 | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 강남구 | 3238 | 932 | 150.619195 | 561052 | 556164 | 4888 | 65060 | 0.871220 | 11.596073 |
1 | 강동구 | 1010 | 377 | 166.490765 | 440359 | 436223 | 4136 | 56161 | 0.939234 | 12.753458 |
2 | 강북구 | 831 | 204 | 125.203252 | 328002 | 324479 | 3523 | 56530 | 1.074079 | 17.234651 |
3 | 강서구 | 911 | 81 | 134.793814 | 608255 | 601691 | 6564 | 76032 | 1.079153 | 12.500021 |
4 | 관악구 | 2109 | 613 | 149.290780 | 520929 | 503297 | 17632 | 70046 | 3.384722 | 13.446362 |
In [217]:
data_result['CCTV 비율'] = data_result['소계'] / data_result['인구수'] * 100
data_result.head()
Out[217]:
구별 | 소계 | 2016년 | 최근 증가율 | 인구수 | 한국인 | 외국인 | 고령자 | 외국인 비율 | 고령자 비율 | CCTV 비율 | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 강남구 | 3238 | 932 | 150.619195 | 561052 | 556164 | 4888 | 65060 | 0.871220 | 11.596073 | 0.577130 |
1 | 강동구 | 1010 | 377 | 166.490765 | 440359 | 436223 | 4136 | 56161 | 0.939234 | 12.753458 | 0.229358 |
2 | 강북구 | 831 | 204 | 125.203252 | 328002 | 324479 | 3523 | 56530 | 1.074079 | 17.234651 | 0.253352 |
3 | 강서구 | 911 | 81 | 134.793814 | 608255 | 601691 | 6564 | 76032 | 1.079153 | 12.500021 | 0.149773 |
4 | 관악구 | 2109 | 613 | 149.290780 | 520929 | 503297 | 17632 | 70046 | 3.384722 | 13.446362 | 0.404854 |
In [218]:
# 구별이라는 컬럼을 인덱스로 설정
data_result.set_index('구별', inplace=True)
data_result.head(3)
Out[218]:
소계 | 2016년 | 최근 증가율 | 인구수 | 한국인 | 외국인 | 고령자 | 외국인 비율 | 고령자 비율 | CCTV 비율 | |
---|---|---|---|---|---|---|---|---|---|---|
구별 | ||||||||||
강남구 | 3238 | 932 | 150.619195 | 561052 | 556164 | 4888 | 65060 | 0.871220 | 11.596073 | 0.577130 |
강동구 | 1010 | 377 | 166.490765 | 440359 | 436223 | 4136 | 56161 | 0.939234 | 12.753458 | 0.229358 |
강북구 | 831 | 204 | 125.203252 | 328002 | 324479 | 3523 | 56530 | 1.074079 | 17.234651 | 0.253352 |
In [219]:
# 한글 깨짐
# !pip install koreanize_matplotlib
import koreanize_matplotlib
import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format = 'retina'
In [220]:
data_result['인구수'].plot(kind='barh', figsize=(10, 10)); # DataFrame에서 바로 plot() 사용 가능
In [221]:
# 정렬 후 plot
data_result['소계'].sort_values(ascending=True).plot(kind='barh', grid=True, figsize=(10, 10)); # ;(세미콜론) 붙이면 내부적인 결과 값이 같이 줄력 안됨
In [222]:
plt.figure(figsize=(7, 5))
x = data_result['인구수']
y = data_result['소계']
plt.scatter(x, y)
plt.title('인구수 대비 CCTV 개수', fontsize=18)
plt.xlabel('인구수', fontsize=15)
plt.ylabel('CCTV', fontsize=15)
plt.grid()
plt.show()
In [223]:
# !pip install scikit-learn
from sklearn.linear_model import LinearRegression
In [224]:
# Linear regression 예시
x = data_result['인구수'].values.reshape(-1, 1)
y = data_result['소계']
# 회귀분석 모델
model = LinearRegression()
# 회귀분석 모델 훈련
model.fit(x, y)
Out[224]:
LinearRegression()In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
LinearRegression()
In [225]:
data_result.describe()
Out[225]:
소계 | 2016년 | 최근 증가율 | 인구수 | 한국인 | 외국인 | 고령자 | 외국인 비율 | 고령자 비율 | CCTV 비율 | |
---|---|---|---|---|---|---|---|---|---|---|
count | 25.000000 | 25.000000 | 25.000000 | 25.000000 | 25.000000 | 25.000000 | 25.000000 | 25.000000 | 25.000000 | 25.000000 |
mean | 1515.320000 | 385.880000 | 119.030748 | 404983.160000 | 394297.040000 | 10686.120000 | 54605.040000 | 3.090717 | 13.789954 | 0.414207 |
std | 616.774656 | 182.479981 | 61.350043 | 129038.641046 | 130626.795817 | 8052.299756 | 14796.822602 | 2.458736 | 1.572868 | 0.211560 |
min | 825.000000 | 81.000000 | 34.671731 | 134593.000000 | 125709.000000 | 2068.000000 | 21384.000000 | 0.597284 | 11.410173 | 0.149773 |
25% | 1010.000000 | 292.000000 | 64.973730 | 328002.000000 | 324479.000000 | 4408.000000 | 49266.000000 | 0.965198 | 12.753458 | 0.253352 |
50% | 1327.000000 | 377.000000 | 104.347826 | 408493.000000 | 396217.000000 | 8884.000000 | 55718.000000 | 2.527254 | 13.446362 | 0.385813 |
75% | 1884.000000 | 467.000000 | 150.619195 | 475018.000000 | 471154.000000 | 14595.000000 | 65060.000000 | 4.197688 | 15.157463 | 0.515715 |
max | 3238.000000 | 932.000000 | 248.922414 | 671173.000000 | 664496.000000 | 33474.000000 | 76582.000000 | 8.326369 | 17.234651 | 0.985651 |
In [226]:
new_x = np.linspace(100000, 700000, 100)
print(len(new_x))
predicted = model.predict(new_x.reshape(-1, 1))
100
In [227]:
plt.figure(figsize=(5,5))
plt.scatter(data_result['인구수'], data_result['소계'])
plt.plot(new_x, predicted, c='r')
plt.grid()
plt.show()
In [228]:
data_result['오차'] = data_result['소계'] - model.predict(x)
In [247]:
from matplotlib.colors import ListedColormap
color_step = ['#e74c3c', '#496ccc', '#f07f9d', '#7ff0b9', '#ebb791', '#91e8eb']
my_cmap = ListedColormap(color_step)
my_cmap
Out[247]:
from_list
under
bad
over
In [231]:
# 색상 추가, 커스터마이징 예시
# 색에 너무 집학하지 말자!
# 보기에 편한 것이 중요!
plt.figure(figsize=(5, 5))
plt.scatter(data_result['인구수'], data_result['소계'], c=data_result['오차'], cmap=my_cmap)
plt.plot(new_x, predicted, c='r')
plt.text(data_result['인구수'][0], data_result['소계'][0], data_result.index[0])
plt.title('인구수 대비 CCTV 개수', fontsize=15)
plt.xlabel('인구수')
plt.ylabel('CCTV 개수')
plt.colorbar()
plt.grid()
plt.show()
In [246]:
# 오차를 기준으로 상위 5개, 하위 5개의 지역 표시
plt.figure(figsize=(5, 5))
plt.scatter(data_result['인구수'], data_result['소계'], c=data_result['오차'], cmap=my_cmap)
plt.plot(new_x, predicted, c='r')
data_error_top = data_result.sort_values(by='오차', ascending=False)
data_error_bot = data_result.sort_values(by='오차', ascending=True)
for i in range(5):
plt.text(
data_error_top['인구수'][i] * 1.02,
data_error_top['소계'][i],
data_error_top.index[i],
c='b')
for i in range(5):
plt.text(
data_error_bot['인구수'][i] * 1.02,
data_error_bot['소계'][i],
data_error_bot.index[i],
c='r')
plt.title('인구수 대비 CCTV 개수', fontsize=15)
plt.xlabel('인구수')
plt.ylabel('CCTV 개수')
plt.colorbar()
plt.grid()
plt.show()
'Data Analysis > Pandas' 카테고리의 다른 글
[Python] [Data Analysis] Pandas를 활용한 서울시 범죄 데이터 전처리 (1) | 2023.08.08 |
---|---|
[Python] [Data Analysis] Pandas 기초 (2) | 2023.08.04 |
[Python] [Data Analysis] Numpy 기초 (0) | 2023.08.04 |