방송통신대학교(방송대/방통대) 오픈소스 기반 데이터분석 공공 데이터 수집 분석
General 2025. 10. 19. 16:24 |서울 열린 데이터 광장의 공공 데이터(에코 마일리지 에너지 사용량 통계 정보)를 수집하고 분석해 보자.


주의 할 점은 Open API 사용 정보에 요청인자 목록이 자세히 적혀 있어 파이썬 requests.get(url, param) 과 같은 명령으로 데이터를 불러 올 수 있을거 같지만 제대로 실행되지 않는다. url에 필요한 모든 요청인자를 넣어서 데이터를 불러와야 한다.
1-1. Python을 사용해 2015.01~2024.12 기간의 개인 현년 전기, 가스, 수도, 지역난방 에너지 사용량 데이터를 수집해 보자.
import requests
year_months = [] # 마지막 출력에 사용하기 위해 전역변수로 선언
def get_year_months():
for year in range(2015, 2024+1):
for month in range(1, 12+1):
year_months.append(f"{year}/{month:02d}")
return year_months
start_index = 1
end_index = 7
url1 = "http://openapi.seoul.go.kr:8088/"
url2 = f"/json/energyUseDataSummaryInfo/{start_index}/{end_index}/"
api_key = "your_api_key"
count = 0
missing = 0
responses = []
for year_month in get_year_months():
response = requests.get(url1 + api_key + url2 + year_month)
if response.status_code == 200:
found = False
for i in range(end_index):
if response.json()['energyUseDataSummaryInfo']['row'][i]['MM_TYPE'] == '개인':
data = []
data.append(response.json()[
'energyUseDataSummaryInfo']['row'][i]['EUS'])
data.append(response.json()[
'energyUseDataSummaryInfo']['row'][i]['GUS'])
data.append(response.json()[
'energyUseDataSummaryInfo']['row'][i]['WUS'])
data.append(response.json()[
'energyUseDataSummaryInfo']['row'][i]['HUS'])
responses.append(data)
found = True
count += 1
break
if not found:
missing += 1
print(
f"\n{response.json()['energyUseDataSummaryInfo']['row'][i]['YEAR']}/{response.json()['energyUseDataSummaryInfo']['row'][i]['MON']}: No 개인 data found.")
else:
print(
f"Failed to retrieve data.\nStatus code: {response.status_code}\nReason: {response.reason}")
print(f"■ Total months with 개인 data: {count}")
print(f"■ Total months without 개인 data: {missing}\n")
for ym, row in zip(year_months, responses):
print(f"{ym}: {row}")

API로 받고 JSON으로 변환한 데이터 형태는 아래 '더보기'를 클릭하면 확인 할 수 있다.
{'energyUseDataSummaryInfo': {'list_total_count': 7, 'RESULT': {'CODE': 'INFO-000', 'MESSAGE': '정상 처리되었습니다'}, 'row': [{'YEAR': '2015', 'MON': '01', 'MM_TYPE': '개인', 'CNT': '767791', 'EUS': '193784708', 'EUS1': '194781915', 'EUS2': '204969429', 'ECO2_1': '-6090964', 'ECO2_2': '-2582568.736', 'GUS': '59133720', 'GUS1': '57163993', 'GUS2': '68297619', 'GCO2_1': '-3597086', 'GCO2_2': '-8057472.64', 'WUS': '12819757.886', 'WUS1': '12723680.426', 'WUS2': '12899476.73', 'WCO2_1': '8179.308', 'WCO2_2': '2715.530256', 'HUS': '22740838.937', 'HUS1': '23400055.303', 'HUS2': '27090493.875', 'HCO2_1': '-2504435.652', 'HCO2_2': '-33660084.213069', 'REG_DATE': '2015-06-04 17:03:55.0'}, {'YEAR': '2015', 'MON': '01', 'MM_TYPE': '학교', 'CNT': '1382', 'EUS': '134955565', 'EUS1': '128707423', 'EUS2': '145561511', 'ECO2_1': '-2178902', 'ECO2_2': '-923854.448', 'GUS': '9107197', 'GUS1': '8410968', 'GUS2': '10745416', 'GCO2_1': '-470995', 'GCO2_2': '-1055028.8', 'WUS': '2075819.2', 'WUS1': '2097433.8', 'WUS2': '2133200.8', 'WCO2_1': '-39498.1', 'WCO2_2': '-13113.3692', 'HUS': '0', 'HUS1': '0', 'HUS2': '0', 'HCO2_1': '0', 'HCO2_2': '0', 'REG_DATE': '2015-06-04 17:03:55.0'}, {'YEAR': '2015', 'MON': '01', 'MM_TYPE': '종교단체', 'CNT': '32', 'EUS': '372270', 'EUS1': '363376', 'EUS2': '411363', 'ECO2_1': '-15099.5', 'ECO2_2': '-6402.188', 'GUS': '53331', 'GUS1': '45727', 'GUS2': '63312', 'GCO2_1': '-1188.5', 'GCO2_2': '-2662.24', 'WUS': '5945', 'WUS1': '4548', 'WUS2': '4519', 'WCO2_1': '1411.5', 'WCO2_2': '468.618', 'HUS': '0', 'HUS1': '0', 'HUS2': '0', 'HCO2_1': '0', 'HCO2_2': '0', 'REG_DATE': '2015-06-04 17:03:55.0'}, {'YEAR': '2015', 'MON': '01', 'MM_TYPE': '소상공인', 'CNT': '2058', 'EUS': '10249618', 'EUS1': '9927610', 'EUS2': '11039593', 'ECO2_1': '-233983.5', 'ECO2_2': '-99209.004', 'GUS': '536119', 'GUS1': '523810', 'GUS2': '642921', 'GCO2_1': '-47246.5', 'GCO2_2': '-105832.16', 'WUS': '147273', 'WUS1': '146480.6', 'WUS2': '147325.6', 'WCO2_1': '369.9', 'WCO2_2': '122.8068', 'HUS': '0', 'HUS1': '0', 'HUS2': '0', 'HCO2_1': '0', 'HCO2_2': '0', 'REG_DATE': '2015-06-04 17:03:55.0'}, {'YEAR': '2015', 'MON': '01', 'MM_TYPE': '공동주택관리소', 'CNT': '1747', 'EUS': '327102096', 'EUS1': '329852334', 'EUS2': '351694752', 'ECO2_1': '-13671447', 'ECO2_2': '-5796693.528', 'GUS': '22834274', 'GUS1': '21141017', 'GUS2': '25338506', 'GCO2_1': '-405487.5', 'GCO2_2': '-908292', 'WUS': '12844807.5', 'WUS1': '12763070', 'WUS2': '12979835.8', 'WCO2_1': '-26645.4', 'WCO2_2': '-8846.2728', 'HUS': '0', 'HUS1': '0', 'HUS2': '0', 'HCO2_1': '0', 'HCO2_2': '0', 'REG_DATE': '2015-06-04 17:03:55.0'}, {'YEAR': '2015', 'MON': '01', 'MM_TYPE': '기업', 'CNT': '16751', 'EUS': '583090528', 'EUS1': '586779350', 'EUS2': '632471031', 'ECO2_1': '-26534662.5', 'ECO2_2': '-11250696.9', 'GUS': '37835680', 'GUS1': '35765271', 'GUS2': '47713673', 'GCO2_1': '-3903792', 'GCO2_2': '-8744494.08', 'WUS': '6581017', 'WUS1': '6591203.4', 'WUS2': '6684708.2', 'WCO2_1': '-56938.8', 'WCO2_2': '-18903.6816', 'HUS': '0', 'HUS1': '0', 'HUS2': '0', 'HCO2_1': '0', 'HCO2_2': '0', 'REG_DATE': '2015-06-04 17:03:55.0'}, {'YEAR': '2015', 'MON': '01', 'MM_TYPE': '공공기관', 'CNT': '2981', 'EUS': '247059373', 'EUS1': '242471579', 'EUS2': '261884067', 'ECO2_1': '-5118450', 'ECO2_2': '-2170222.8', 'GUS': '11524542', 'GUS1': '10057837', 'GUS2': '13760048', 'GCO2_1': '-384400.5', 'GCO2_2': '-861057.12', 'WUS': '1522465.2', 'WUS1': '1495786.6', 'WUS2': '1522178.8', 'WCO2_1': '13482.5', 'WCO2_2': '4476.19', 'HUS': '0', 'HUS1': '0', 'HUS2': '0', 'HCO2_1': '0', 'HCO2_2': '0', 'REG_DATE': '2015-06-04 17:03:55.0'}]}}
문제와는 다르지만 Pandas를 쓰면 조금 더 간단히 필터링 할 수 있다. 아래 '더보기'를 클릭하면 확인 할 수 있다.
import requests
import pandas as pd
def get_year_months():
year_months = []
for year in range(2015, 2024+1):
for month in range(1, 12+1):
year_months.append(f"{year}/{month:02d}")
return year_months
start_index = 1
end_index = 7
url1 = "http://openapi.seoul.go.kr:8088/"
url2 = f"/json/energyUseDataSummaryInfo/{start_index}/{end_index}/"
api_key = "your_api_key"
df = pd.DataFrame()
for year_month in get_year_months():
response = requests.get(url1 + api_key + url2 + year_month)
if response.status_code == 200:
data = pd.DataFrame(response.json()['energyUseDataSummaryInfo']['row'])
data = data[data['MM_TYPE'] == '개인']
df = pd.concat([df, data], ignore_index=True)
else:
print(
f"Failed to retrieve data.\nStatus code: {response.status_code}\nReason: {response.reason}")
df = df[['YEAR', 'MON', 'EUS', 'GUS', 'WUS', 'HUS']]
print(df)

2-1. 수집한 JSON 형태의 데이터를 Pandas DataFrame으로 변환하자.
import requests
import pandas as pd
def get_year_months():
year_months = []
for year in range(2015, 2024+1):
for month in range(1, 12+1):
year_months.append(f"{year}/{month:02d}")
return year_months
start_index = 1
end_index = 7
url1 = "http://openapi.seoul.go.kr:8088/"
url2 = f"/json/energyUseDataSummaryInfo/{start_index}/{end_index}/"
api_key = "your_api_key"
df = pd.DataFrame()
for year_month in get_year_months():
response = requests.get(url1 + api_key + url2 + year_month)
if response.status_code == 200:
for i in range(end_index):
if response.json()['energyUseDataSummaryInfo']['row'][i]['MM_TYPE'] == '개인':
data = pd.DataFrame([response.json()['energyUseDataSummaryInfo']['row'][i]])
df = pd.concat([df, data], ignore_index=True)
break
else:
print(f"Failed to retrieve data.\nStatus code: {response.status_code}\nReason: {response.reason}")
df.info()

2-2. 연도별, 계절별 분석을 위해 계절(season) 칼럼을 추가하자.
import requests
import pandas as pd
def get_year_months():
year_months = []
for year in range(2015, 2024+1):
for month in range(1, 12+1):
year_months.append(f"{year}/{month:02d}")
return year_months
start_index = 1
end_index = 7
url1 = "http://openapi.seoul.go.kr:8088/"
url2 = f"/json/energyUseDataSummaryInfo/{start_index}/{end_index}/"
api_key = "your_api_key"
df = pd.DataFrame()
for year_month in get_year_months():
response = requests.get(url1 + api_key + url2 + year_month)
if response.status_code == 200:
for i in range(end_index):
if response.json()['energyUseDataSummaryInfo']['row'][i]['MM_TYPE'] == '개인':
data = pd.DataFrame(
[response.json()['energyUseDataSummaryInfo']['row'][i]])
df = pd.concat([df, data], ignore_index=True)
break
else:
print(f"Failed to retrieve data.\nStatus code: {response.status_code}\nReason: {response.reason}")
df['SEASON'] = df['MON'].apply(lambda x: '겨울' if x in ['01', '02', '12'] else (
'봄' if x in ['03', '04', '05'] else ('여름' if x in ['06', '07', '08'] else '가을')))
print(df)

3-1. 연도별 에너지 총사용량(전기+가스+수도+지역난방) 변화량을 선 그래프로 시각화 하자.
import requests
import pandas as pd
import matplotlib.pyplot as plt
def get_year_months():
year_months = []
for year in range(2015, 2024+1):
for month in range(1, 12+1):
year_months.append(f"{year}/{month:02d}")
return year_months
start_index = 1
end_index = 7
url1 = "http://openapi.seoul.go.kr:8088/"
url2 = f"/json/energyUseDataSummaryInfo/{start_index}/{end_index}/"
api_key = "your_api_key"
df = pd.DataFrame()
for year_month in get_year_months():
response = requests.get(url1 + api_key + url2 + year_month)
if response.status_code == 200:
for i in range(end_index):
if response.json()['energyUseDataSummaryInfo']['row'][i]['MM_TYPE'] == '개인':
data = pd.DataFrame(
[response.json()['energyUseDataSummaryInfo']['row'][i]])
df = pd.concat([df, data], ignore_index=True)
break
else:
print(f"Failed to retrieve data.\nStatus code: {response.status_code}\nReason: {response.reason}")
df['SEASON'] = df['MON'].apply(lambda x: '겨울' if x in ['01', '02', '12'] else (
'봄' if x in ['03', '04', '05'] else ('여름' if x in ['06', '07', '08'] else '가을')))
df = df.astype({'EUS': 'float', 'GUS': 'float','WUS': 'float', 'HUS': 'float'})
year_group = df.groupby('YEAR')[['EUS', 'GUS', 'WUS', 'HUS']].sum().reset_index()
year_group['에너지 총사용량'] = year_group[['EUS', 'GUS', 'WUS', 'HUS']].sum(axis=1)
plt.rc('font', family='GULIM')
plt.plot(year_group['YEAR'], year_group['에너지 총사용량'], marker='o', color='red')
plt.xlabel('연도')
plt.ylabel('에너지 사용 총액')
plt.title('연도별 에너지 사용 총액 변화')
plt.show()

3-2. 계절별 가스 사용량 평균을 막대 그래프로 시각화 하고 각 막대의 수치를 표시하자.
import requests
import pandas as pd
import matplotlib.pyplot as plt
def get_year_months():
year_months = []
for year in range(2015, 2024+1):
for month in range(1, 12+1):
year_months.append(f"{year}/{month:02d}")
return year_months
start_index = 1
end_index = 7
url1 = "http://openapi.seoul.go.kr:8088/"
url2 = f"/json/energyUseDataSummaryInfo/{start_index}/{end_index}/"
api_key = "your_api_key"
df = pd.DataFrame()
for year_month in get_year_months():
response = requests.get(url1 + api_key + url2 + year_month)
if response.status_code == 200:
for i in range(end_index):
if response.json()['energyUseDataSummaryInfo']['row'][i]['MM_TYPE'] == '개인':
data = pd.DataFrame(
[response.json()['energyUseDataSummaryInfo']['row'][i]])
df = pd.concat([df, data], ignore_index=True)
break
else:
print(f"Failed to retrieve data.\nStatus code: {response.status_code}\nReason: {response.reason}")
df['SEASON'] = df['MON'].apply(lambda x: '겨울' if x in ['01', '02', '12'] else (
'봄' if x in ['03', '04', '05'] else ('여름' if x in ['06', '07', '08'] else '가을')))
df = df.astype({'GUS': 'float'})
season_group = df.groupby('SEASON')['GUS'].mean().reset_index()
plt.rc('font', family='GULIM')
plt.bar(season_group['SEASON'], season_group['GUS'])
plt.xlabel('계절')
plt.ylabel('가스 사용량 평균')
plt.title('계절별 가스 사용량 평균')
plt.bar_label(plt.gca().containers[0])
plt.show()

4. 연도별 에너지 사용량 변화에서 나타나는 주요 트랜드를 찾아 분석하고 그 원인을 추론해 보자.
import requests
import pandas as pd
import matplotlib.pyplot as plt
def get_year_months():
year_months = []
for year in range(2015, 2024+1):
for month in range(1, 12+1):
year_months.append(f"{year}/{month:02d}")
return year_months
start_index = 1
end_index = 7
url1 = "http://openapi.seoul.go.kr:8088/"
url2 = f"/json/energyUseDataSummaryInfo/{start_index}/{end_index}/"
api_key = "your_api_key"
df = pd.DataFrame()
for year_month in get_year_months():
response = requests.get(url1 + api_key + url2 + year_month)
if response.status_code == 200:
for i in range(end_index):
if response.json()['energyUseDataSummaryInfo']['row'][i]['MM_TYPE'] == '개인':
data = pd.DataFrame(
[response.json()['energyUseDataSummaryInfo']['row'][i]])
df = pd.concat([df, data], ignore_index=True)
break
else:
print(f"Failed to retrieve data.\nStatus code: {response.status_code}\nReason: {response.reason}")
df = df.astype({'EUS': 'float', 'GUS': 'float','WUS': 'float', 'HUS': 'float'})
year_group = df.groupby('YEAR')[['EUS', 'GUS', 'WUS', 'HUS']].sum().reset_index()
year_group['에너지 총사용량'] = year_group[['EUS', 'GUS', 'WUS', 'HUS']].sum(axis=1)
plt.rc('font', family='GULIM')
plt.bar(year_group['YEAR'], year_group['에너지 총사용량'], color='blue', alpha=0.5, label='총사용량')
plt.plot(year_group['YEAR'], year_group['EUS'], color='red', marker='o', label='전기')
plt.plot(year_group['YEAR'], year_group['GUS'], color='green', marker='o', label='가스')
plt.plot(year_group['YEAR'], year_group['WUS'], color='orange', marker='o', label='수도')
plt.plot(year_group['YEAR'], year_group['HUS'], color='purple', marker='o', label='난방')
plt.legend(loc='upper left')
plt.xlabel('연도')
plt.ylabel('에너지 사용량 X 1e9')
plt.ylim(0, 5000000000)
plt.grid(True, axis='y', alpha=0.5)
plt.title('연도별 에너지 사용량 변화')
plt.show()

연도별 에너지 사용량 변화 원인을 추론하고 트렌드를 찾기 조금 더 자세한 그래프를 그려 보았다. 기후변화나 에너지 요금 등의 다양한 요인들로 인해...
이하 생략.
'General' 카테고리의 다른 글
| [Visual Studio] IntelliCode 비주얼 스튜디오 코드 자동 완성 (0) | 2025.10.19 |
|---|---|
| [Visual Studio] Debugging Breakpoint 디버깅 브레이크 포인트 활용 (0) | 2025.05.28 |
| PDF 파일 프린트 속도가 너무 느릴 때 해결 방법 (1) | 2024.10.28 |
| GIMP Alpha Channel Transparent Layer/Background 투명 배경 (0) | 2024.02.20 |
| Pixel(JPG/PNG) Image To Vector(AI) Image 픽셀 이미지를 벡터 이미지로 변환하기 (0) | 2023.12.17 |

































