본문 바로가기

Python/Pandas

Pandas : 대중교통 / 범죄현황 / seaborn / pairplot

subwayfee.csv 파일을 통한 지하철 유무임별 이용현황 데이터 분석

  • 자료출처 : t-money.co.kr 에서 자료를 제공함.
df = pd.read_csv('data/subwayfee.csv', encoding='cp949')
df.head(3)

df['역ID'].nunique()

df['지하철역'].nunique()

df['호선명'].nunique()

df['호선명'].unique()

#####out
array(['1호선', '2호선', '3호선', '4호선', '경부선', '경인선', '경원선', '안산선', '과천선',
       '분당선', '일산선', '중앙선', '장항선', '경의선', '경춘선', '수인선', '경강선', '5호선',
       '6호선', '7호선', '8호선', '9호선', '공항철도 1호선', '9호선2~3단계', '우이신설선'],
      dtype=object)

유임승차, 유임하차, 무임승차, 무임하차 4가지 별로, 각각 가장 많은 역을 찾아보세요.

df.loc[df['유임승차']==df['유임승차'].max(),]

df.loc[df['유임하차']==df['유임하차'].max(),]

df.loc[df['무임승차']==df['무임승차'].max(),]

df.loc[df['무임하차']==df['무임하차'].max(),]


무임승차 대비 유임승차 비율이 가장 높은 역은 어디입니까?

df['승차비율'] = df['유임승차']/df['무임승차']
df['유임승차']/df['무임승차']

#####out
0      6.856190
1      6.611439
2      7.639985
3      1.816531
4      2.075986
         ...   
593    3.263665
594    1.922061
595    2.441451
596    1.981258
597    1.956611
Length: 598, dtype: float64

df.loc[df['승차비율'] == df['승차비율'].max(),]

df.loc[df['무임승차'] == 0,'무임승차'] = np.nan
df.fillna(0, inplace=True)

전체승차인원(유임+무임)이 만명이상인 역 중, 유임승차 비율이 가장 높은 역은 어디입니까?

csv 파일로 처리하는 방법

Pandas로 처리하는 방법

df['전체승차인원'] = df['유임승차'] + df['무임승차']
df_crowd = df.loc[df['전체승차인원']>=10000,]
df_crowd.loc[df_crowd['승차비율']==df_crowd['승차비율'].max(),]​


모든 역의 유임승차, 유임하차, 무임 승차, 무임하차, 총 4개를, 파이차트로 나타내세요.

# 한글 찍기
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb

%matplotlib inline

import platform

from matplotlib import font_manager, rc
plt.rcParams['axes.unicode_minus'] = False

if platform.system() == 'Darwin':
    rc('font', family='AppleGothic')
elif platform.system() == 'Windows':
    path = "c:/Windows/Fonts/malgun.ttf"
    font_name = font_manager.FontProperties(fname=path).get_name()
    rc('font', family=font_name)
else:
    print('Unknown system... sorry~~~~')
    
    df.head(3)


plt.pie(df.iloc[0,4:8] , autopct= '%.1f' , labels= data.index , startangle= 90 , wedgeprops= {'width':0.7})
plt.title(df['지하철역'][0])
plt.show()

결과값

data = df.iloc[0,4:8]
plt.pie(df.iloc[1,4:8] , autopct= '%.1f' , labels= data.index , startangle= 90 , wedgeprops= {'width':0.7})
plt.title(df['지하철역'][1])
plt.show()

결과값


for i in range(df.shape[0]):
    plt.pie(df.iloc[i,4:8] , autopct= '%.1f' , labels= data.index , startangle= 90 , wedgeprops= {'width':0.7})
    plt.title(df['지하철역'][i])
    plt.show()

레퍼런스 : 파이썬으로 데이터 주무르기

시작하기전에, 셋팅되어있는 데이터를 불러온다.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb
%matplotlib inline
import platform
from matplotlib import font_manager, rc
plt.rcParams['axes.unicode_minus'] = False
if platform.system() == 'Darwin':
 rc('font', family='AppleGothic')
elif platform.system() == 'Windows':
 path = "c:/Windows/Fonts/malgun.ttf"
 font_name = font_manager.FontProperties(fname=path).get_name()
 rc('font', family=font_name)
else:
 print('Unknown system... sorry~~~~')

 

● 서울시 구별 범죄 발생과 검거율 데이터 분석

'서울시 관서별 5대 범죄 발생 검거 현황' 파일을 가지고 분석한다.

 

실습 1. crime_in_Seoul.csv 파일을 pandas 로 읽어오세요.

(한글이 깨지지 않도록 encoding='euc-kr' 옵션을 넣는다.)

 

df = pd.read_csv('data/crime_in_Seoul.csv', encoding='euc-kr' , thousands=',')
df.head(3)

df.describe()


실습 2. 경찰서들은 하나의 구에 여러개가 있을 수 있습니다. 따라서 우 리는 구 단위로 데이터를 통합하겠습니다.

실습 2-1. 구글 맵 API 를 이용해서, 경찰서가 무슨 구에 있는지 확인하기 위해 아나콘다 프롬프트웨어 다음을 실행. pip install googlemaps

# 아나콘다 기준으로 아나콘다 프롬프트를 실행하여 pip install googlemaps 입력

import googlemaps

실습 2-2. 구글 클라우드의 MAPS API 페이지로 이동하여, API 키를 생성합니다.

https://cloud.google.com/maps-platform/?hl=ko (https://cloud.google.com/mapsplatform/?hl=ko)

콘솔로 이동 => Geocoding API 선택 => 사용자인증정보 에서 API 키 생성

* 구글 맵스를 사용해서 경찰서의 위치(위도, 경도) 정보를 받아온다

import googlemaps
gmaps_key = "AIzaSyCRNpyrML6AAW-VA6LuxX49_hU3QGdMnRE" # 자신의 key를 사용합니다.
gmaps = googlemaps.Client(key=gmaps_key)

# api 호출(api call)

gmaps.geocode('서울중부경찰서', language='ko')

결과

[{'address_components': [{'long_name': '27',
 'short_name': '27',
 'types': ['premise']},
 {'long_name': '수표로',
 'short_name': '수표로',
 'types': ['political', 'sublocality', 'sublocality_level_4']},
 {'long_name': '중구',
 'short_name': '중구',
 'types': ['political', 'sublocality', 'sublocality_level_1']},
 {'long_name': '서울특별시',
 'short_name': '서울특별시',
 'types': ['administrative_area_level_1', 'political']},
 {'long_name': '대한민국',
 'short_name': 'KR',
 'types': ['country', 'political']},
 {'long_name': '100-032',
 'short_name': '100-032',
 'types': ['postal_code']}],
 'formatted_address': '대한민국 서울특별시 중구 수표로 27',
 'geometry': {'location': {'lat': 37.56361709999999, 'lng': 126.9896517},
 'location_type': 'ROOFTOP',
 'viewport': {'northeast': {'lat': 37.5649660802915,
 'lng': 126.9910006802915},
 'southwest': {'lat': 37.5622681197085, 'lng': 126.9883027197085}}},
 'partial_match': True,
 'place_id': 'ChIJc-9q5uSifDURLhQmr5wkXmc',
 'plus_code': {'compound_code': 'HX7Q+CV 대한민국 서울특별시',
 'global_code': '8Q98HX7Q+CV'},
 'types': ['establishment', 'point_of_interest', 'police']}]

* api를 통해 주고받은 데이터를 json 이라고 함

result = [{'address_components': [{'long_name': '27',
 'short_name': '27',
 'types': ['premise']},
 {'long_name': '수표로',
 'short_name': '수표로',
 'types': ['political', 'sublocality', 'sublocality_level_4']},
 {'long_name': '중구',
 'short_name': '중구',
 'types': ['political', 'sublocality', 'sublocality_level_1']},
 {'long_name': '서울특별시',
 'short_name': '서울특별시',
 'types': ['administrative_area_level_1', 'political']},
 {'long_name': '대한민국',
 'short_name': 'KR',
 'types': ['country', 'political']},
 {'long_name': '100-032',
 'short_name': '100-032',
 'types': ['postal_code']}],
 'formatted_address': '대한민국 서울특별시 중구 수표로 27',
 'geometry': {'location': {'lat': 37.56361709999999, 'lng': 126.9896517},
 'location_type': 'ROOFTOP',
 'viewport': {'northeast': {'lat': 37.5649660802915,
 'lng': 126.9910006802915},
 'southwest': {'lat': 37.5622681197085, 'lng': 126.9883027197085}}},
 'partial_match': True,
 'place_id': 'ChIJc-9q5uSifDURLhQmr5wkXmc',
 'plus_code': {'compound_code': 'HX7Q+CV 대한민국 서울특별시',
 'global_code': '8Q98HX7Q+CV'},
 'types': ['establishment', 'point_of_interest', 'police']}]
result[0]['formatted_address']
###### out
'대한민국 서울특별시 중구 수표로 27'

참고사항

# 정확한 지명 api를 호출해야함

# 관서명 컬럼에 있는 값들을 가져와서

# 왼쪽에는 서울, 오른쪽에는 경찰서라고 붙인다.

 

name_series = '서울'+df['관서명'].str[:-1]+'경찰서'

* 시리즈를 리스트로 바꾸기

station_list = name_series.to_list()

station_list 의 값

['서울중부경찰서',
'서울종로경찰서',
'서울남대문경찰서',
'서울서대문경찰서',
'서울혜화경찰서',
'서울용산경찰서',
'서울성북경찰서',
'서울동대문경찰서',
'서울마포경찰서',
'서울영등포경찰서',
'서울성동경찰서',
'서울동작경찰서',
'서울광진경찰서',
'서울서부경찰서',
'서울강북경찰서',
'서울금천경찰서',
'서울중랑경찰서',
'서울강남경찰서',

등등 데이터가 아래에 더 있다.

# station_names 리스트에 있는 경찰서 명칭을 구글맵api에 넣어서 호출한다.

station_address = []
for name in station_list: #name = '서울중부경찰서'
 result = gmaps.geocode(name,language = 'ko')
 if len(result) != 0:
 station_address.append(result[0]['formatted_address'])

station_address
##### out
['대한민국 서울특별시 중구 수표로 27',
'대한민국 서울특별시 종로구 종로1.2.3.4가동 율곡로 46',
'대한민국 서울특별시 중구 한강대로 410',
'대한민국 서울특별시 서대문구 통일로 113',
'대한민국 서울특별시 종로구 창경궁로 112-16',
'대한민국 서울특별시 용산구 백범로 329',
'대한민국 서울특별시 성북구 삼선동 보문로 170',
'대한민국 서울특별시 동대문구 약령시로21길 29',
'대한민국 서울특별시 마포구 마포대로 183',
'대한민국 서울특별시 영등포구 당산동3가 국회대로 608',
'대한민국 서울특별시 성동구 행당동 왕십리광장로 9',
'대한민국 서울특별시 동작구 노량진로 148',
'대한민국 서울특별시 광진구 구의동 자양로 167',
'대한민국 서울특별시 은평구 녹번동 177-15',
'대한민국 서울특별시 강북구 오패산로 406',
'대한민국 서울특별시 금천구 시흥대로73길 50',
'대한민국 서울특별시 중랑구 묵2동 249-2',
등등 데이터가 아래 더 있다.

 

station_address.insert(21,'대한민국 서울특별시 성북구 하월곡동 27-5')
station_address
######out
['대한민국 서울특별시 중구 수표로 27',
'대한민국 서울특별시 종로구 종로1.2.3.4가동 율곡로 46',
'대한민국 서울특별시 중구 한강대로 410',
'대한민국 서울특별시 서대문구 통일로 113',
'대한민국 서울특별시 종로구 창경궁로 112-16',
'대한민국 서울특별시 용산구 백범로 329',
'대한민국 서울특별시 성북구 삼선동 보문로 170',
'대한민국 서울특별시 동대문구 약령시로21길 29',
'대한민국 서울특별시 마포구 마포대로 183',
'대한민국 서울특별시 영등포구 당산동3가 국회대로 608',
'대한민국 서울특별시 성동구 행당동 왕십리광장로 9',
'대한민국 서울특별시 동작구 노량진로 148',
'대한민국 서울특별시 광진구 구의동 자양로 167',
'대한민국 서울특별시 은평구 녹번동 177-15',
'대한민국 서울특별시 강북구 오패산로 406',
'대한민국 서울특별시 금천구 시흥대로73길 50',
'대한민국 서울특별시 중랑구 묵2동 249-2',
'대한민국 서울특별시 강남구 테헤란로114길 11',
'대한민국 서울특별시 관악구 관악로5길 33',
'대한민국 서울특별시 강서구 화곡6동 980-27',
'대한민국 서울특별시 강동구 성내로 57',
'대한민국 서울특별시 성북구 하월곡동 27-5',
'대한민국 서울특별시 구로구 가마산로 235',
'대한민국 서울특별시 서초구 서초3동 반포대로 179',
'대한민국 서울특별시 양천구 목동동로 99',
'대한민국 서울특별시 송파구 중대로 221',
'대한민국 서울특별시 노원구 하계동 노원로 283',
'대한민국 서울특별시 서초구 동작대로 204',
'대한민국 서울특별시 은평구 불광동 연서로 365',
'대한민국 서울특별시 도봉구 노해로 403',
'대한민국 서울특별시 강남구 개포로 617']

실습 3. station_addreess 에 저장된 주소에서, 구만 따로 띄어냅니다. (예, 종로구)

따로 띄어낸 구를, crime_anal_police 에 '구별' 컬럼을 만들어서 넣습니다.

 

df['구별'] = pd.Series(station_address).str.split().str[2]
df

 

 

결과

아래에 더 많은 데이터가 있다. 너무 길기 때문에, 생략한다.

 

new_list = []
for address in station_address:
 print(address.split()[2])
 new_list.append(address.split()[2])

#### out
중구
종로구
중구
서대문구
종로구
용산구
성북구
동대문구
마포구
영등포구
성동구
동작구
광진구
은평구
강북구
금천구
중랑구
강남구
관악구
강서구
강동구
성북구
구로구
서초구
양천구
송파구
노원구
서초구
은평구
도봉구
강남구


new_list
##### out
['중구',
'종로구',
'중구',
'서대문구',
'종로구',
'용산구',
'성북구',
'동대문구',
'마포구',
'영등포구',
'성동구',
'동작구',
'광진구',
'은평구',
'강북구',
'금천구',
'중랑구',
'강남구',
'관악구',
'강서구',
'강동구',
'성북구',
'구로구',
'서초구',
'양천구',
'송파구',
'노원구',
'서초구',
'은평구',
'도봉구',
'강남구']

실습 4 . crime_anal_police 데이터프레임을, csv 파일로 저장합니다.

저장할 파일명은 new_crime_in_Seoul.csv 로 저장하세요.

저장하는 함수는, 데이터프레임의 to_csv 입니다.

df.to_csv('new_crime_in_Seoul.csv')

pandas의 pivot_table 익히기

import pandas as pd
import numpy as np

* 피봇팅 한다. 즉 컬럼의 값을 열로 만드는것.

df = pd.read_excel('data/sales-funnel.xlsx')

df

아래에 더 많은 데이터가 있다. 너무 길기 때문에, 생략한다.

참고사항

* 인덱스를 중복된값으로 설정한것은 잘못 만든것이다.

중복데이터가 있으면 하나로 합쳐서 인덱스로 뽑되, 수치데이터만을 뽑아 평균데이터로 하나로 합치는것이다.

pd.pivot_table(df, index=['Name'])

pd.pivot_table(df,index=['Name'] , aggfunc = np.sum)

pd.pivot_table(df,index=['Name'] , aggfunc = np.max)

pd.pivot_table(df,index=['Manager','Rep'],aggfunc= np.sum)

pd.pivot_table(df,index= ['Name'] , values = ['Price','Quantity'],aggfunc= np.sum)

pd.pivot_table( df, index=['Name'] , values= ['Price', 'Quantity'] , aggfunc=[np.sum, np.mean,np.std


범죄 데이터 구별로 정리하기

crime_anal = pd.read_csv('new_crime_in_Seoul.csv' , index_col=0)

crime_anal.head()


실습 5. 인덱스를 '구별' 로 피봇팅 한다.

pd.pivot_table(crime_anal, index=['구별'])

아래에 더 많은 데이터가 있다. 너무 길기 때문에, 생략한다.


실습 6. '강간검거율' , '강도검거율', '살인검거율', '절도검거율', '폭력검 거율' 을 계산하여, crime_anal에 각 컬럼을 추가한다. ( 검거율은 * 100 까지 한 값)

crime_anal['강간검거율'] = (crime_anal['강간 검거']/crime_anal['강간 발생'])*100

crime_anal['강도검거율'] = (crime_anal['강도 검거']/crime_anal['강도 발생'])*100

crime_anal['살인검거율'] = (crime_anal['살인 검거']/crime_anal['살인 발생'])*100

crime_anal['절도검거율'] = (crime_anal['절도 검거']/crime_anal['절도 발생'])*100

crime_anal['폭력검거율'] = (crime_anal['폭력 검거']/crime_anal['폭력 발생'])*100

crime_anal


실습 7. 이제 필요없는, '강간 검거' , '강도 검거', '살인 검거', '절도 검거', '폭력 검거' 컬럼을 제거한다.

crime_anal.drop(['강간 검거' , '강도 검거', '살인 검거', '절도 검거', '폭력 검거'],axis=1,inplace=True
crime_anal

아래에 더 많은 데이터가 있다. 너무 길기 때문에, 생략한다.


실습 7. describe() 함수로 값을 확인해 보니, 검거율이 100 이상인 경우 도 있다. 따라서 100보다 크면, 100으로 값을 셋팅하세요.

crime_anal.describe()

def over100(ratio):
 if ratio > 100:
 return 100
 else:
 return ratio
 
 over100(10)
#### out
10

crime_anal['강간검거율'] = crime_anal['강간검거율'].apply(over100)

crime_anal['강도검거율'] = crime_anal['강도검거율'].apply(over100)

crime_anal['살인검거율'] = crime_anal['살인검거율'].apply(over100)

crime_anal['절도검거율'] = crime_anal['절도검거율'].apply(over100)

crime_anal['폭력검거율'] = crime_anal['폭력검거율'].apply(over100)
crime_anal.describe()

crime_anal.loc[crime_anal['강간검거율']>100,'강간검거율'] = 100

실습 9. 강간 발생, 강도 발생, 살인 발생, 절도 발생, 폭력 발생 의 컬럼 명을, 강간, 강도, 살인, 절도, 폭력으로 rename 하세요.

crime_anal.rename(columns={'강간 발생':'강간', '강도 발생':'강도', '살인 발생':'살인', '절도 발생':'절도')
crime_anal.head(3)

crime_anal.describe()


실습 9. 강간, 강도, 살인, 절도, 폭력 을 노멀라이징 합니다. 데이터 노멀라이징 하는 이유는, 각각의 레인지를 통일하여, 해석하기 쉽게 하기 위함입니다.

from sklearn.preprocessing import StandardScaler, MinMaxScaler

표준화로 피쳐 스케일링하기

s_scaler = StandardScaler()

x_scaled1 = s_scaler.fit_transform(crime_anal[['강도','강간','살인','절도','폭력']])

 

 

 

 

정규화로 피쳐 스케일링하기

m_scaler = MinMaxScaler()
x_scaled2 = m_scaler.fit_transform(crime_anal[['강도','강간','살인','절도','폭력']])
crime_anal.head(3)

crime_anal[['강도','강간','살인','절도','폭력']] = x_scaled1

 

 

 


 

 

Visualization using seaborn

# 한글 그래프 처리 코드 실행
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sb
%matplotlib inline
import platform
from matplotlib import font_manager, rc
plt.rcParams['axes.unicode_minus'] = False
if platform.system() == 'Darwin':
 rc('font', family='AppleGothic')
elif platform.system() == 'Windows':
 path = "c:/Windows/Fonts/malgun.ttf"
 font_name = font_manager.FontProperties(fname=path).get_name()
 rc('font', family=font_name)
else:
 print('Unknown system... sorry~~~~')

실습 1.  sb의 pairplot 으로 "강도", "살인", "폭력" 을 나타내세요. (연관성 확인)

sb.pairplot(data = crime_anal , vars=['강도','살인','폭력'])
plt.show()


실습 2. x_vars는 "인구수", "CCTV" 를, y_vars는 "살인", "강도"로 pariplot을 나타내고, 연관성을 확인하세요.

sb.pairplot(data = crime_anal ,x_vars=['인구수','CCTV'] ,y_vars=['강도','살인'])
plt.show()


실습 3. x_vars는 "인구수", "CCTV" 를, y_vars는 "살인검거율", "폭 력검거율"로 pariplot을 나타내고, 연관성을 확인하세요.

sb.pairplot(data = crime_anal ,x_vars=['인구수','CCTV'] ,y_vars=['살인검거율','폭력검거율'])
plt.show()

sb.pairplot(data = crime_anal ,x_vars=['인구수','CCTV'] ,y_vars=['살인검거율','폭력검거율','강간검거
plt.show()

crime_anal.loc[ :, '강간검거율':'인구수'].corr()[['CCTV','인구수']]

 

 

 


실습 4.  x_vars는 "인구수", "CCTV" 를, y_vars는 "절도검거율", "강 도검거율"로 pariplot을 나타내고, 연관성을 확인하세요.

 

sb.pairplot(data = crime_anal ,x_vars=['인구수','CCTV'] ,y_vars=['절도검거율','강도검거율'])
plt.show()

 

 


 

실습 5. 검거가 가장 높은 구는 어디입니까? 이를 확인하기 위해, 검거 가 가장 높은 구부터 정렬하여 5개의 구까지 나타내세요.

crime_anal.set_index('구별',inplace=True)
crime_anal.sort_values('검거', ascending=False , inplace=True)
crime_anal.head(5)

crime_anal['검거'].sort_values(ascending=False)
구별
도봉구 100.000000
금천구 97.997139
강서구 96.572809
광진구 96.375820
서초구 95.508100
동대문구 95.444250
용산구 94.776790
성동구 94.088810
강북구 94.070728
성북구 93.731246
종로구 90.355894
강남구 89.046725
서대문구 88.875144
노원구 88.646174
강남구 88.506198
은평구 88.260438
중랑구 87.066663
마포구 85.925381
강동구 85.550226
관악구 85.212224
송파구 85.103066
성북구 83.330863
은평구 82.558305
영등포구 81.958753
양천구 81.823827
중구 80.702116
종로구 77.481643
구로구 75.277906
동작구 74.633368
서초구 71.628338
중구 60.550251
Name: 검거, dtype: float64

 

 


 

실습 6. 검거가 가장 큰값이 432.593167 입니다. 검거의 값이 최대가 100이 되도록 정규화를 하세요. 그리고 검거값으로 정렬하세요.

crime_anal['검거'] = crime_anal['검거']/crime_anal['검거'].max()*100
crime_anal.head()

 

crime_anal['검거'].sort_values(ascending=False)

Out[116]:
구별
도봉구 100.000000
금천구 97.997139
강서구 96.572809
광진구 96.375820
서초구 95.508100
동대문구 95.444250
용산구 94.776790
성동구 94.088810
강북구 94.070728
성북구 93.731246
종로구 90.355894
강남구 89.046725
서대문구 88.875144
노원구 88.646174
강남구 88.506198
은평구 88.260438
중랑구 87.066663
마포구 85.925381
강동구 85.550226
관악구 85.212224
송파구 85.103066
성북구 83.330863
은평구 82.558305
영등포구 81.958753
양천구 81.823827
중구 80.702116
종로구 77.481643
구로구 75.277906
동작구 74.633368
서초구 71.628338
중구 60.550251
Name: 검거, dtype: float64

 

 

 


 

 

실습 7. sb.heatmap 을 이용해서 '강간검거율', '강도검거율', '살인검 거율', '절도검거율', '폭력검거율' 을 보여주세요. 단, '검거' 로 정렬한 데 이터로 보여주세요.

crime1 = crime_anal.sort_values('검거',ascending=False)
crime1 = crime1.loc[ : , '강간검거율':'폭력검거율']

plt.figure(figsize= (10,8))
sb.heatmap(data=crime1, cmap= 'RdPu' , annot=True, fmt='.1f', linewidths= 0.8)
plt.show()

 

 

 


 

실습 8. 위에서 배운 히트맵을 이용해서, 살기 무서운 구가 어디인지 분 석하세요.

crime2 = crime_anal.sort_values('범죄',ascending=False)
crime2 = crime2.loc[ : , '살인':'폭력' ]
plt.figure(figsize= (10,8))
sb.heatmap(data=crime2, cmap= 'RdPu' , annot=True, fmt='.1f', linewidths= 0.8)
plt.show()