import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import folium
import requests
import json
import plotly.express as px
# 지수표현식 제거하기
pd.options.display.float_format = '{:.5f}'.format
import koreanize_matplotlib
# 그래프에 retina display 적용
%config InlineBackend.figure_format = 'retina'
file_name = ("data/서울특별시 친환경자동차 현황.CSV")
raw = pd.read_csv(file_name, encoding='cp949')
raw = raw.loc[raw['연료'] == '전기', ['기준년월', '사용본거지시읍면동_행정동기준', '차명', '연료']]
raw = raw.rename(columns={"사용본거지시읍면동_행정동기준":"주소"})
raw = raw.dropna()
raw["구"] = raw["주소"].map(lambda x : x.split()[1])
df = raw.groupby("구")["차명"].count().sort_values(ascending=False).to_frame()
df = df.rename(columns={"차명" : "전기차수"})
df
# 구 별 전기차 top 5
explode = [0.1,0.05, 0.05,0.05,0.05]
plt.figure(figsize=(10,10))
plt.pie(ev_car_top5['전기차수'],
labels=ev_car_top5.index,
explode=explode,
autopct='%.d%%')
plt.show()
# 서울시 전체 전기차 수 비율
wedgeprops = {'width': 0.7, 'edgecolor': 'w', 'linewidth': 1}
colors = ['#c1abff', '#d8e1c5', '#80afe5', '#ddadd0', '#ebbfea', '#84cec0', '#9acee9', '#d6c2b6', '#d48c9d', '#dcf6c5']
plt.figure(figsize=(10,10))
plt.pie(df['전기차수'], labels=df.index, autopct='%.d%%', colors = colors,
shadow=True,
wedgeprops=wedgeprops)
plt.title("서울시 전기차 수 비율")
plt.show()
df["전기차수"].sum()
=> 41673
ev_raw = pd.read_excel("Data/서울시충전기.xlsx")
ev_raw.head(2)
=>
운영기관 충전소 지역 시군구 주소 충전용량
0 환경부(한국자동차환경협회) DMC 산학협력연구센터 서울특별시 마포구 서울특별시 마포구 매봉산로 37 급속(100kW멀티)
1 환경부(한국자동차환경협회) Park M (주차복합빌딩) 서울특별시 마포구 서울특별시 마포구 매봉산로 80 급속(200kW동시)
# 시군구로 count
ev_df = ev_raw.groupby("시군구")["충전소"].count().sort_values(ascending=False).to_frame()
# index 이름으로 시군구 -> 구 변경
ev_df.index = ev_df.index.set_names("구")
ev_df
# 구 별 전기차 충전소 pie chart 시각화
explode = [0.1,0.05, 0.05,0.05,0.05]
wedgeprops = {'width': 0.7, 'edgecolor': 'w', 'linewidth': 1}
colors = ['#c1abff', '#d8e1c5', '#80afe5', '#ddadd0', '#ebbfea', '#84cec0', '#9acee9', '#d6c2b6', '#d48c9d', '#dcf6c5']
plt.figure(figsize=(10,10))
plt.pie(ev_df['충전소'], labels=ev_df.index, autopct='%.d%%', colors = colors,
shadow=True,
wedgeprops=wedgeprops)
plt.title("구 별 전기차 충전소")
plt.show()
ev_df["충전소"].sum()
=> 29556
# index 공백 제거
ev_df.index = ev_df.index.str.strip()
df = df.merge(ev_df, left_index=True, right_index=True)
df
df["현재충전소당전기차"] = df["전기차수"] / df["충전소"]
plt.figure(figsize=(20,6))
sns.barplot(data=df, x=df.index, y="현재충전소당전기차", ci=None).set_title("현재충전소당전기차")
# 현재 전기차 수 / 충전소 수 / 전기차 대 충전소 비율
df["전기차수"].sum(), df['충전소'].sum(), df['충전소'].sum() / df['전기차수'].sum()
=> (41673, 29556, 0.7092361960981931)
# 필요한 충전소 수
ev_easy_count = round(400000 * (df["충전소"].sum() / df["전기차수"].sum()))
ev_easy_count
=> 283694
# 서울시 목표량
seoul_ev = 220000 + df['충전소'].sum()
seoul_ev
=> 249556
# 부족한 충전소 수
round(400000 * (df['충전소'].sum() / df['전기차수'].sum())) - (220000 + df["충전소"].sum())
=> 34138
# 비율 * 40만대
df['미래전기차수'] = round((df['전기차수'] / df['전기차수'].sum()) * 400000).astype(int)
df
ev_st_top = df['현재충전소당전기차'].sort_values(ascending=False).head(1).to_frame()
ev_st_tail = df['현재충전소당전기차'].sort_values(ascending=False).tail(1).to_frame()
aa = pd.concat([ev_st_top, ev_st_tail])
aa.plot(kind='bar', rot=0, title="충전소 1곳 당 전기차 수용가능 수치 최대-최소 차이 비교", figsize=(10,3))
# 현재 기준 단순 예측
future_station = round((df["충전소"] / df["충전소"].sum()) * ev_easy_count).astype(int)
# pie chart 시각화
explode = [0.1,0.05, 0.05,0.05,0.05]
wedgeprops = {'width': 0.7, 'edgecolor': 'w', 'linewidth': 1}
colors = ['#c1abff', '#d8e1c5', '#80afe5', '#ddadd0', '#ebbfea', '#84cec0', '#9acee9', '#d6c2b6', '#d48c9d', '#dcf6c5']
plt.figure(figsize=(10,10))
plt.pie(ev_df['충전소'], labels=ev_df.index, autopct='%.d%%', colors = colors,
shadow=True,
wedgeprops=wedgeprops)
plt.title("미래 구 별 전기차 충전소 설치 개수 가정")
plt.show()
people = pd.read_csv("data/서울시인구데이터2021.csv", encoding="cp949")
# 전처리
people = people[["행정구역별(읍면동)", "2021"]].iloc[2:]
people = people.reset_index(drop=True)
people = people.rename(columns={"행정구역별(읍면동)":"구","2021":"인구"})
people = people.set_index("구")
people
# 숫자타입으로 변경
people['인구'] = people["인구"].astype(int)
# 시각화
plt.figure(figsize=(20,6))
sns.barplot(data=people, x=people.index, y="인구", ci=None).set_title("인구")
oil = pd.read_csv("data/서울시주유소.csv", encoding="cp949")
oil.head()
=>
연번 자치구명 주유소명 주소
0 1 용산구 현대오일뱅크(주) 직영소월길주유소 서울특별시 용산구 소월로66
1 2 용산구 선익상사(주) 동자동주유소 서울특별시 용산구 한강대로 104길 6
2 3 용산구 현대오일뱅크㈜ 직영갈월동주유소 서울특별시 용산구 한강대로 322
3 4 용산구 서계주유소 서울특별시 용산구 청파로 367
4 5 용산구 ㈜영원에너지 풍기주유소 서울특별시 용산구 원효로178
oil_df = oil.groupby("자치구명")[["주유소명"]].count()
oil_df.index = oil_df.index.set_names("구")
oil_df = oil_df.rename(columns={"주유소명":"주유소 수"})
oil_df
df_op = people.merge(oil_df, left_index=True, right_index=True)
df_op
df = df_op.merge(df, left_index=True, right_index=True)
df
df.corr()
# 히트맵 시각화
plt.figure(figsize=(15, 10))
sns.heatmap(df.corr(), cmap="Greens", annot=True)
car_raw = pd.read_csv("data/서울시자동차등록수.csv", encoding="cp949")
car_raw = car_raw[4:]
car_raw["구"] = car_raw["행정동-연료별 분류"].map(lambda x : x.split()[1].strip())
car_df = car_raw[["구","경유","하이브리드(경유-전기)","하이브리드(휘발유-전기)","휘발유","휘발유(무연)","휘발유(유연)"]]
car_df
# 결측치 확인
car_df.isnull().sum()
=>
구 0
경유 3
하이브리드(경유-전기) 75
하이브리드(휘발유-전기) 22
휘발유 12
휘발유(무연) 9
휘발유(유연) 89
dtype: int64
# 결측치 0 변경
car_df = car_df.fillna(0)
# 구 별로 묶어주기
car_df = car_df.groupby("구").sum()
car_df["휘발유자동차수"] = car_df.sum(axis=1).astype(int)
car_df
car_df = car_df['휘발유자동차수']]
car_df
df = df.merge(car_df, left_index=True, right_index=True)
df
df["자동차당주유소비율"] = df["주유소 수"] / df["휘발유자동차수"] * 100
df
# 서울시 목표 충전소 수
seoul_ev
=> 249556
# 자동차 당 주유소비율로 전기차 충전소 예측
(df["자동차당주유소비율"] * df["미래전기차수"] * 37).sum()
=> 260029.803241865
df["주유소비율로본미래충전소개수"] = (df["자동차당주유소비율"] * df["미래전기차수"] * 37)
plt.figure(figsize=(20,6))
sns.barplot(data=df, x=df.index, y="주유소비율로본미래충전소개수", ci=None).set_title("주유소비율로본미래충전소개수")
df["미래충전소당전기차예측(주유소기준)"] = df["미래전기차수"] / df["주유소비율로본미래충전소갯수"]
df["미래충전소당전기차예측(주유소기준)"].to_frame()
# 주유소기준 미래 충전소 당 전기차 예측
plt.figure(figsize=(20,6))
sns.barplot(data=df, x=df.index, y="미래충전소당전기차예측(주유소기준)", ci=None).set_title("미래충전소당전기차예측(주유소기준)")
df["인구비"] = df["인구"] / df["인구"].sum()
(df["인구비"] * df["미래전기차수"] * 13.7).sum()
=> 249381.5231770858
df["인구비율로본미래충전소개수"] = (df["인구비"] * df["미래전기차수"] * 13.7)
plt.figure(figsize=(20,6))
sns.barplot(data=df, x=df.index, y="인구비율로본미래충전소개수", ci=None).set_title("인구비율로본미래충전소개수")
df["미래충전소당전기차예측(인구기준)"] = df["미래전기차수"] / df["인구비율로본미래충전소개수"]
plt.figure(figsize=(20,6))
sns.barplot(data=df, x=df.index, y="미래충전소당전기차예측(인구기준)", ci=None).set_title("미래충전소당전기차예측(인구기준)")
# 서울 행정구역 json raw파일(githubcontent)
r = requests.get('https://raw.githubusercontent.com/southkorea/seoul-maps/master/kostat/2013/json/seoul_municipalities_geo_simple.json')
c = r.content
seoul_geo = json.loads(c)
# 위도
lat = 37.394946
# 경도
lon = 127.111104
# 서울시 전기차 대수
m1 = folium.Map(
location=[lat, lon],
zoom_start=11,
tiles='cartodbpositron'
)
folium.GeoJson(
seoul_geo,
name='지역구'
).add_to(m1)
m1.choropleth(geo_data=seoul_geo,
data=df['전기차수'],
fill_color='YlGnBu', # 색상 변경도 가능하다
fill_opacity=0.5,
line_opacity=0.2,
key_on='properties.name',
legend_name="행정동별 전기차 수"
)
m1
m2 = folium.Map(
location=[lat, lon],
zoom_start=11,
tiles='cartodbpositron'
)
folium.GeoJson(
seoul_geo,
name='지역구'
).add_to(m2)
m2.choropleth(geo_data=seoul_geo,
data=df['충전소'],
fill_color='YlGnBu', # 색상 변경도 가능하다
fill_opacity=0.5,
line_opacity=0.2,
key_on='properties.name',
legend_name="행정동별 충전소 개수"
)
m2
현재 자동차당 주유소 비율 기준으로 충전소는 늘리는 것이 인구비율로 충전소를 늘리는 것 보다
충전소당 감당해야 하는 전기차 수의 표준편차를 줄이는데 더 효과적인다.
https://data.seoul.go.kr/dataList/OA-21245/F/1/datasetView.do
https://www.data.go.kr/data/15098386/fileData.do
https://www.ev.or.kr/evmonitor
https://data.seoul.go.kr/dataList/OA-21279/S/1/datasetView.do