본문 바로가기
데이터 분석

boxplot / 따릉이 실시간 데이터 예제

by 코낄2 2023. 12. 24.

1. 데이터 이상치 알아보기- boxplot

박스 플롯(boxplot)은 데이터의 분포를 시각적으로 나타내는 통계 그래픽스입니다. 주로 데이터의 중앙값, 사분위수, 이상치 등을 파악하는 데 사용됩니다. 박스 플롯은 다음과 같은 구성 요소로 이루어져 있습니다.

  1. 상자(Box): 데이터의 사분위수(Q1, Q2, Q3)를 나타냅니다. 상자의 아래 경계는 Q1이고1/4분위수 즉 25%값을 나타냅니다. 상자 내부의 가로선은 중앙값(Q2) (50%)입니다. 상자의 윗 경계는 Q3 (75%)입니다.
  2. 수염(Whisker): 상자 위아래로 나타나는 선분으로, 전체 데이터 범위를 나타냅니다. 일반적으로 최대값과 최소값 중 1.5배 사분위 범위를 벗어나는 값은 이상치로 표시되며, 수염은 그 범위 내의 최대값과 최소값을 나타냅니다.
  3. 이상치(Outliers): 수염 바깥에 위치한 점들로, 일반적인 데이터 패턴에서 벗어난 극단값을 나타냅니다.

박스 플롯은 주로 데이터의 중심 경향과 분포를 파악하는 데 사용되며, 다수의 그룹 간 비교에도 유용합니다. 이를 통해 데이터의 대략적인 형태를 빠르게 파악할 수 있습니다.

 

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 코랩에서 ANSI인코딩을 알맞게 가져와주는 방법 encoding='ms949'
# 다른 이름 저장으로 인코딩을 UTF-8로 바꿔도 상관없음.
park = pd.read_csv('/content/drive/MyDrive/KDT/데이터분석/데이터/전국도시공원표준데이터.csv', encoding='ms949')
park.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 18137 entries, 0 to 18136
Data columns (total 20 columns):
 #   Column        Non-Null Count  Dtype  
---  ------        --------------  -----  
 0   관리번호          18137 non-null  object 
 1   공원명           18137 non-null  object 
 2   공원구분          18137 non-null  object 
 3   소재지도로명주소      8039 non-null   object 
 4   소재지지번주소       17158 non-null  object 
 5   위도            18137 non-null  float64
 6   경도            18137 non-null  float64
 7   공원면적          18137 non-null  float64
 8   공원보유시설(운동시설)  4845 non-null   object 
 9   공원보유시설(유희시설)  6964 non-null   object 
 10  공원보유시설(편익시설)  5084 non-null   object 
 11  공원보유시설(교양시설)  1160 non-null   object 
 12  공원보유시설(기타시설)  3116 non-null   object 
 13  지정고시일         15225 non-null  object 
 14  관리기관명         17383 non-null  object 
 15  전화번호          16957 non-null  object 
 16  데이터기준일자       18137 non-null  object 
 17  제공기관코드        18137 non-null  object 
 18  제공기관명         18137 non-null  object 
 19  Unnamed: 19   0 non-null      float64
dtypes: float64(4), object(16)
memory usage: 2.8+ MB

park.drop(columns=['공원보유시설(운동시설)','공원보유시설(유희시설)','공원보유시설(편익시설)','공원보유시설(교양시설)',
                   '공원보유시설(기타시설)','지정고시일','관리기관명','Unnamed: 19'], inplace=True)
park.head()

sns.boxplot(y=park['위도'])
# Q3 - Q1을 이용해서 최소,최대값을 예측. 해당 범위를 벗어나면 이상치로 예측해볼 수 있음

sns.boxplot(y=park['경도'])

# 위도와 경도의 이상치로 판별되는 데이터를 확인
park.loc[(park['위도']<32) | (park['경도']>132)]

park.plot.scatter(x='경도', y='위도',figsize = (8,10), grid=True)

 

이상치인 점을 확인할 수 있음

park = park.loc[(park['위도']>=32) & (park['경도']<=132)]

>> 이상치가 아닌 데이터들로만 재저장.

 

2. 따릉이 실시간 예제.

import requests
import folium
import json
from pandas.io.json import json_normalize
import warnings
warnings.filterwarnings('ignore') # 필요없는 경고가 뜨는것을 방지
  • import json: json을 파이썬의 딕셔너리처럼 이용하게 해주는 모듈
  • json_normalize : 딕셔너리처럼 바꾼 json을 pandas의 데이터 프레임으로 변경해줌
targetSite = 'https://www.bikeseoul.com/app/station/getStationRealtimeStatus.do'
request = requests.post(targetSite, data={'stationGrpSeq':'ALL'})
# data={'stationGrpSeq':'ALL'} : API 명세서에서 요청하는 항목
print(request) // <Response [200]>
print(request.text)
// {"stationImgPath":"/nas_link/spb/attachFiles/file_admin/basePath","appUserSessionVO":{"regDttm":null,
"orgType":null,"snsId":null,"viewFlg":"list","usrBirthDate":null,"sexCd":null,"rentEncPwd":null,
"telecomClsCd":null,"authCiVal":null,"authClsCd":null,"mbTelNo":null,....}
# json.loads(): json 타입의 문자열 데이터를 파이썬에서 처리할 수 있도록 변환(딕셔너리로 변환)
bike_json = json.loads(request.text)
print(bike_json)
// {'stationImgPath': '/nas_link/spb/attachFiles/file_admin/basePath', 'appUserSessionVO': {'regDttm': None, 
'orgType': None, 'snsId': None, 'viewFlg': 'list', 'usrBirthDate': None,...}
print(type(bike_json)) // <class 'dict'>
bike_df = json_normalize(bike_json, 'realtimeList')
# json_normalize(): 딕셔너리 타입의 데이터를 판다스 데이터프레임으로 변환
# 안에 정보들중에 realtimeList 리스트만 데이터 프레임으로 만들겠다.

bike_df

bike_df.columns

Index(['stationImgFileName', 'stationId', 'stationName', 'stationLongitude',
       'stationLatitude', 'rackTotCnt', 'parkingBikeTotCnt',
       'parkingQRBikeCnt', 'parkingELECBikeCnt', 'stationSeCd', 'mode'],
      dtype='object')

stationImgFileName : 대여소 사진
stationId : 고유한 대여소 번호
stationName : 대여소 이름
stationLongitude : 대여소 경도
stationLatitude : 대여소 위도
rackTotCnt : 주차 가능한 전체 자전거 대수
parkingBikeTotCnt : 주차된 따릉이 총 대수
parkingQRBikeCnt : 주차된 따릉이 QR형 총 대수
parkingELECBikeCnt : 주차된 새싹 따릉이 총 대수

bike_df_map = bike_df[['stationName', 'stationLongitude', 'stationLatitude',
                       'rackTotCnt', 'parkingBikeTotCnt', 'parkingQRBikeCnt',
                       'parkingELECBikeCnt']]
bike_df_map

bike_df_map.dtypes
 # json이었던 것을 받았기 때문에 전부 문자열
stationName           object
stationLongitude      object
stationLatitude       object
rackTotCnt            object
parkingBikeTotCnt     object
parkingQRBikeCnt      object
parkingELECBikeCnt    object
dtype: object
# 위도, 경도 -> float로 변환
# 주차 할 수 있는 자전거 대수, 주차된 자전거 총 대수, 주차된 QR 자전거 총 대수, 주차된 새싹 자전거 총 대수 - >int
# 전체 주차된 총 대수[total] = 자전거 + QR 자전거 + 새싹 자전거

bike_df_map['stationLongitude']  = bike_df_map['stationLongitude'].astype(float)
bike_df_map['stationLatitude']   = bike_df_map['stationLatitude'].astype(float)
bike_df_map['rackTotCnt']        = bike_df_map['rackTotCnt'].astype(int)
bike_df_map['parkingBikeTotCnt'] = bike_df_map['parkingBikeTotCnt'].astype(int)
bike_df_map['parkingQRBikeCnt']  = bike_df_map['parkingQRBikeCnt'].astype(int)
bike_df_map['parkingELECBikeCnt']= bike_df_map['parkingELECBikeCnt'].astype(int)

print(bike_df_map.dtypes)

stationName            object
stationLongitude      float64
stationLatitude       float64
rackTotCnt              int64
parkingBikeTotCnt       int64
parkingQRBikeCnt        int64
parkingELECBikeCnt      int64
dtype: object

bike_df_map['total'] = bike_df_map['parkingBikeTotCnt'] + bike_df_map['parkingQRBikeCnt'] 
				+ bike_df_map['parkingELECBikeCnt']
bike_df_map.shape
// (2724, 8)

문제. 따릉이 모든 데이터를 지도에 표기하기 (팝업: 대여소 이름 일반: -대, QR: -대, 새싹: -대, 총: -대)

bike_map = folium.Map(location=[bike_df_map['stationLatitude'].mean(), bike_df_map['stationLongitude'].mean()], zoom_start=12)
for index, data in bike_df_map.iterrows():
    string = '{} 일반:{}대, QR:{}대, 새싹:{}대, 총:{}대'.format(data['stationName'],
                                                       data['parkingBikeTotCnt'],
                                                       data['parkingQRBikeCnt'],
                                                       data['parkingELECBikeCnt'],
                                                       data['total'])
    popup = folium.Popup(string, max_width=600)
    folium.Marker(location=[data['stationLatitude'], data['stationLongitude']],
                  popup=popup).add_to(bike_map)
bike_map

 

✔️ iterrows()는 Pandas 데이터프레임의 각 행을 반복적으로 접근하기 위한 함수입니다. 이 함수를 사용하여 데이터프레임의 각 행에 대한 인덱스와 데이터를 제공받을 수 있습니다. 한 가지 유의해야 할 점은 iterrows()는 행 단위로 데이터프레임을 순회하면서 각 행을 시리즈(Series) 객체로 반환합니다. 따라서 data['stationName'], data['parkingBikeTotCnt'] 등과 같이 시리즈의 특정 열에 접근할 수 있습니다.

'데이터 분석' 카테고리의 다른 글

상권별 업종 밀집 통계 예제  (0) 2023.12.23
가상 쇼핑몰 데이터 예제  (0) 2023.12.16
Matplotlib  (0) 2023.12.10
판다스3  (0) 2023.12.08
판다스2  (0) 2023.12.08