본문 바로가기
국비 교육/데이터

[데이터 분석] Pandas 문제 실습 - 4 서울시 공공자전거 대여소 정보 분석

by 육츠 2023. 11. 16.
Contents 접기

대여소 정보 데이터 읽기

import pandas as pd
place_df= pd.read_excel('서울특별시 공공자전거 대여소 정보(19.12.9).xlsx', skiprows= 0, engine='openpyxl')
place_df.head()

NA 값이 몇 개인지 확인하기

import numpy as np 

place_df.isna().sum()
place_df.shape

isna().sum() 을 통해 na값이 존재 한다는 것을 알게 되었다.

place_df[place_df['대여소ID'].isna()] # 불린인덱싱 통해

불린 인덱싱을 이용하여 해당 컬럼이 어디에 존재해 있는지 확인한 결과 가장 마지막 행에 합계로 들어가 있었다.

place_df = place_df.drop(1540)
# place_df.dropna(inplace = True)

drop()을 통해 결측치 항목을 정리하였다.

타입 변환

대여소ID ==> int32

place_df['대여소ID'] = place_df['대여소ID'].astype(np.int32)
place_df.info()

해당 열은 결측치가 존재하던 열이므로, float() 의 형태로 값을 읽어오게 된다. 때문에 보기 편하게 정수형식으로 변경하였다.

기준시작일자 ==> 날짜타입

lace_df['기준시작일자'] = place_df['기준시작일자'].replace('개통','',regex=True)
place_df['기준시작일자'] = pd.to_datetime(place_df['기준시작일자'])
place_df.info()

datetime() 모듈은 str 을 쓸수 없기 때문에 바로 replace 를 해주었으며, regrex = true 를 통해 일부만 맞아도 변경할 수 있게 설정.

** # 특정 문자열이 포함되어있는지 확인

place_df['기준시작일자'].str.contains('개통').sum()

 

대여소_구의 목록, 개수 출력

print(place_df['대여소_구'].unique())
print('개수:', len(place_df['대여소_구'].unique()))
['마포구' '서대문구' '영등포구' '중구' '종로구' '광진구' '성동구' '동대문구' '양천구' '용산구' '은평구' '강동구'
 '강서구' '송파구' '성북구' '중랑구' '강북구' '노원구' '도봉구' '금천구' '구로구' '동작구' '관악구' '서초구'
 '강남구']
개수: 25

대여소_구별 거치대 수

place_df.groupby('대여소_구')['거치대수'].sum()

대여소_구별 거치대 수구별 거치대수의 합계, 평균, 최대, 최소 출력하고 거치대가 많은 순으로 합계별 내림차순으로 10개 출력

goo_place_df = place_df.groupby('대여소_구')['거치대수'].agg(['sum','mean','max','min']).round(2)
goo_place_df['sum'].sort_values(ascending= False).head(10)
대여소_구
송파구     1298
영등포구    1250
서초구     1227
강남구     1218
마포구     1075
강서구     1002
노원구      879
광진구      841
구로구      788
종로구      784
Name: sum, dtype: int64

 

서울시 공공자전거 대여 정보 분석

# 한글데이터 포함되었기 때문
info_df = pd.read_csv('서울특별시 공공자전거 대여정보_201911_2.csv',encoding='CP949')
info_df.head()

한글 데이터 포함되어 encoding = 'CP949' 로 데이터를 읽어온다.

info_df.isna().sum()

결측치 확인하기

대여일시, 반납일시를 날짜타입으로 변경

info_df['대여일시'] = pd.to_datetime(info_df['대여일시'])
info_df['반납일시'] = pd.to_datetime(info_df['반납일시'])

info_df.info()

to_datetime() 은 두 요소가 한번에 바뀌지 않는 것 같다.

요일별 대여 건수 확인

week_info_df = info_df['대여일시'].dt.dayofweek

map_data = {0:'일',1:'월',2:'화',3:'수',4:'목',5:'금',6:'토'}
week_info_df = week_info_df.map(map_data)
week_info_df.value_counts()


info_df['요일'] = info_df['대여일시'].dt.dayofweek
map_data = {0:'일',1:'월',2:'화',3:'수',4:'목',5:'금',6:'토'}
info_df['요일'] = info_df['요일'].map(map_data)
info_df.groupby('요일')['요일'].count().sort_values(ascending = False).apply(lambda x: f'{x:,}건')
대여일시
금    119574
목    113660
월    104938
일     95045
수     91159
화     88768
토     65686
Name: count, dtype: int64

대여일시를 day0fweek로 읽어오면 요일을 숫자로 표현해준다. 그것을 value_counts 로 읽어오면 그 숫자의 수를 카운팅해주는데, 시각적으로  보이는 것을 편리하게 하기 위해 숫자와 글을 mapping 해준다.

일자별로 대여 건수 내림차순으로 정렬하여 출력

day_info_df = info_df['대여일시'].dt.day
day_info_df.value_counts().sort_values(ascending=False)

info_df['day'] = info_df['대여일시'].dt.day
info_df.groupby('day')['day'].count().sort_values(ascending=False)

 

대여소 정보와 대여정보 Join

join_df = pd.merge(place_df,info_df, left_on= '대여소ID',right_on='대여 대여소번호')

공통적으로 보이는 열 요소를 join 하는데 이름이 같은 사항이 없어 명시적으로 join을 해준다.

이후 중복되는 컬럼(즉, 명시적으로 연결해준 컬럼을 drop())

join_df.drop('대여 대여소번호', axis=1, inplace=True)

 

구별 평균 이용시간, 평균 이용거리, 최대 이용시간, 최소 이용시간 확인 (구 이름 정렬)

time = join_df.groupby('대여소_구')[['이용시간']].agg(['mean','max','min'])
dist = join_df.groupby('대여소_구')[['이용거리']].agg('mean')
pd.concat([time,dist],axis=1).sort_index()

B의 단계에는 데이터의 위치값이 나와있지 않다. C의 단계는 A 와 B의 데이터를 적절히 섞어 도출할 수 있는 결론이다.