[Python] 파이썬 기후 데이터 시각화하기 (Indian Summers, plt, 선 차트, 막대 차트, 파이 차트)
학교 과제에서 Python을 활용한 데이터 시각화를 진행했습니다. 😀
만들다 보니 하루 종일 하루종일 잡고 있었네요.
인도의 여름 기후에 관련된 데이터였습니다.
csv 파일을 pandas 라이브러리로 불러오고 전처리하고,
matplotlib 라이브러리를 활용해 차트를 그리는 방식입니다.
📝 CSV 파일 다운로드
https://www.kaggle.com/datasets/akashram/indian-summer-over-the-years
⦁ 캐글
✔ 해당 링크를 통해 다운받을 수 있습니다.
📝 주피터 노트북
# 필요한 패키지 설치
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# 데이터 불러오기
df = pd.read_csv('Indian Summers - Over the years.csv', encoding='euc-kr')
df.head()
City | Date | tempmax | tempmin | temp | feelslikemax | feelslikemin | feelslike | dew | humidity | windspeed | winddir | sealevelpressure | cloudcover | visibility | sunrise | sunset | moonphase | conditions | description | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | New Delhi | 2021-04-01 | 34.0 | 19.0 | 27.1 | 31.6 | 19.0 | 26.1 | 3.1 | 22.60 | 22.8 | 272.9 | 1002.8 | 0.0 | 3.1 | 2021-04-01 06:11:12 | 2021-04-01 18:39:13 | 0.60 | Clear | Clear conditions throughout the day. |
1 | New Delhi | 2021-04-02 | 33.9 | 16.0 | 25.8 | 31.8 | 16.0 | 24.9 | 4.5 | 27.62 | 12.4 | 275.0 | 1006.2 | 0.0 | 3.5 | 2021-04-02 06:10:04 | 2021-04-02 18:39:46 | 0.65 | Clear | Clear conditions throughout the day. |
2 | New Delhi | 2021-04-03 | 34.8 | 14.6 | 26.0 | 32.2 | 14.6 | 25.1 | 1.3 | 23.18 | 16.5 | 127.5 | 1008.8 | 1.4 | 3.5 | 2021-04-03 06:08:55 | 2021-04-03 18:40:19 | 0.70 | Clear | Clear conditions throughout the day. |
3 | New Delhi | 2021-04-04 | 36.8 | 16.9 | 27.1 | 34.2 | 16.9 | 26.0 | 4.8 | 28.00 | 18.3 | 157.6 | 1009.5 | 2.6 | 3.2 | 2021-04-04 06:07:47 | 2021-04-04 18:40:53 | 0.76 | Clear | Clear conditions throughout the day. |
4 | New Delhi | 2021-04-05 | 38.8 | 21.0 | 29.9 | 37.1 | 21.0 | 28.9 | 8.1 | 28.85 | 13.5 | 100.4 | 1007.8 | 38.4 | 3.1 | 2021-04-05 06:06:39 | 2021-04-05 18:41:26 | 0.81 | Partially cloudy | Partly cloudy throughout the day. |
df1 = df
#원하는 행, 열 선택 (기온 관련)
df1 = df1[["City", "Date", "tempmax", "tempmin", "temp", "humidity"]]
df1 = df1.loc[0:90]
#x, y축 데이터 지정
x = df1['Date']
y1 = df1['tempmax']
y2 = df1['temp']
y3 = df1['tempmin']
#차트 생성
plt.plot(x, y1)
plt.plot(x, y2)
plt.plot(x, y3)
#습도 막대 차트 추가
plt.bar(x, df1["humidity"], alpha=0.2, label="humidity")
#라벨지정
plt.legend(['tempmax', 'temp', 'tempmin'])
plt.xlabel('Date')
plt.ylabel('Temp')
#제목지정
plt.title('Temperature and Humidity in New Delhi for April-June 2021', pad=30) #패딩 추가
#x축 눈금 일주일 간격으로 설정
plt.xticks(range(0, len(x), 7), x[::7], rotation=45)
#크기설정
plt.figure(figsize=(10, 6))
#그래프 크기 설정
plt.rcParams["figure.figsize"] = (20, 10)
plt.show()
<Figure size 720x432 with 0 Axes>
해당 선 그래프는 New Delhi 지역의 4~6월 기온과 습도의 변화를 시각화한 시간 시각화입니다. 선 그래프는 시계열 데이터의 가장 대표적인 표현 형태입니다.
많은 도시 중에서 New Delhi의 기온을 시각화한 이유는 New Delhi가 인도의 수도이기 때문입니다. New Delhi는 인도의 중심부에 위치하여, 매년 매우 높은 기온과 습도로 인해 여름철에는 생명을 위협하는 열파가 발생한다고 합니다. 열파란 장기간에 걸쳐 더위가 맹렬하게 이어지는 현상을 말합니다.
New Delhi는 대륙성 기후로 4~6월이 여름입니다. 따라서 해당 그래프는 New Delhi의 가장 더운 시기인 여름의 기온을 시각화한 자료가 된 것입니다.
대부분 최고 기온이 35℃는 넘는 모습을 확인할 수 있고, 심한 날에는 약 45℃ 정도가 되기도 합니다. 이렇게 보면 인도와 한국의 여름 기온이 크게 다를 것 없는 것 같기도 합니다. 모두 더위를 조심하셔야 합니다.
df2 = df
#뉴 델리의 데이터만 추출 (완전탐색 필터링 방법도 있다.)
df2 = df2[df2['City'] == 'New Delhi']
#날씨 카운트
weather_count = df2['conditions'].value_counts()
#차트 형태 옵션 설정
wedgeprops={'width': 0.7, 'edgecolor': 'w', 'linewidth': 5}
#파이 차트 생성
plt.pie(weather_count, labels=None, autopct='%1.1f%%', startangle=90, counterclock=False, wedgeprops=wedgeprops)
plt.legend(labels=weather_count.index, loc='center left', bbox_to_anchor=(1, 0.5))
#제목지정
plt.title('Weather Conditions in New Delhi')
#그래프 보여주기
plt.show()
New Delhi의 기온과 습도를 알아봤으니, 이번에는 날씨를 파이 차트로 시각화했습니다. 변수들이 어떤 요소로, 어느 정도의 비율로 구성되어 있는지 확인하는 분포 시각화입니다.
질적 척도로 이루어진 변수는 구성이 단순한 경우 파이차트나 도넛차트를 사용합니다. 전체를 100%로 하여 구성 요소들의 분포 정도를 면적으로 표현합니다. 날씨 같은 경우에는 구성이 단순하기 때문에 파이차트를 선택했습니다.
Partially cloudy(부분적으로 흐림)가 45.3% Clear(맑음)가 36.5% Rain, Partially cloudy가 17.7% Rain, Overcast(흐림)와 Rain은 잘 보이지도 않을 정도로 작은 비율을 차지하고 있습니다.
시각화된 결과를 확인하면, 인도의 수도인 New Delhi의 여름(4~6월)은 대부분 부분적으로 흐리거나 맑다는 사실을 알 수 있습니다. 또한, 여름의 약 18% 정도는 비가 내린다는 것을 알게 되었습니다.
df3 = df
#원하는 열 선택 (기온 관련)
df3 = df3[["City", "temp",]]
#City 그룹바이
df3 = df3.groupby('City')['temp'].mean().reset_index()
#temp 소수점 2자리까지 표현
df3['temp'] = df3['temp'].round(2)
#정렬
df_sorted = df3.sort_values('temp', ascending=False)
df_sorted
plt.title('India\'s Summer Hot Cities Ranking')
plt.bar(df_sorted['City'], df_sorted['temp'])
plt.show()
기온에 대해 조사하다 보니, 인도의 가장 더운 도시는 어디인가라는 궁금증이 생겼습니다. 순위 시각화에는 정렬된 데이터를 막대 차트로 그리는 방법이 많이 사용된다고 합니다.
따라서 City속성을 기준으로 groupby하고 temp의 평균 값을 구했습니다. 그리고 temp의 평균 값을 기준으로 sort_values()메서드를 사용해서 내림차순 정렬한 후 막대 차트로 시각화 했습니다.
기대했던 결과는 가장 더운 도시가 어디인지 명확하게 판별되는 것이었는데, 시각화된 차트를 보면 상위에 배치된 도시들은 대체로 기온이 비슷하다는 결과가 도출되었습니다. 즉, 인도 대부분의 도시들은 여름에 평균적으로 30~35℃이고, 모두 덥습니다.
하지만 시각화된 결과를 통해 뜻밖에 알게 된 사실이 있습니다. 가장 더운 지역인 Ahmedabad와 가장 덥지 않은 도시인 Bengaluru가 기온 차이가 꽤 크다는 사실입니다.
그래서 조사해 봤습니다. 각각 인도의 서쪽과 남쪽에 위치한 도시로, 기후가 상당히 다르다고 합니다. Ahmedabad는 건조한 아열대 기후에 속하며, 여름철에는 매우 더워집니다. 일 년 내내 거의 강수가 없기 때문에 대기 중 습도가 낮고, 낮과 밤의 기온 차이가 큽니다. 반면 Bengaluru는 인도의 남쪽에 위치한 지역으로, 열대 기후에 속하며, 비교적 온화한 기후를 가지고 있습니다. 겨울철에는 오히려 매우 서늘하게 느껴지는 날씨도 있다고 하네요.
따라서 Ahmedabad와 Bengaluru는 기온 차이가 상당히 큰 도시 중 하나라는 결과 또한 데이터 시각화를 통해 도출되었습니다. 정리하면, 인도의 도시들은 대체적으로 비슷하게 덥지만 위치(서쪽, 남쪽)에 따라 다르기도 하다라는 2가지 결과가 도출되었습니다.
df4 = df
#필요한 열 선택
df4 = df4[["City", "Date", "feelslike"]]
#Ahmedabad와 Bengaluru 2021년 데이터만 필터링
df_filtered = df4[((df4["City"] == "Ahmedabad") & (df4["Date"].str.startswith("2021"))) | ((df4["City"] == "Bengaluru") & (df4["Date"].str.startswith("2021")))]
#크기설정
plt.figure(figsize=(12,6))
# 필터링된 데이터로 선 그래프 그리기
for city in df_filtered["City"].unique():
plt.plot(df_filtered[df_filtered["City"]==city]["Date"], df_filtered[df_filtered["City"]==city]["feelslike"], label=city)
#x축 눈금 일주일 간격으로 설정
plt.xticks(range(0, len(x), 7), x[::7], rotation=45)
#그래프 옵션 설정
plt.title("Daily Feels Like Temperature in Ahmedabad and Bengaluru (2021)", pad = 30)
plt.xlabel("Date")
plt.ylabel("temp")
plt.legend()
#그래프 출력
plt.show()
앞에서 알게 된 내용에 대해 더 자세히 알고자 Ahmedabad와 Bengaluru의 2021년 체감 온도 데이터를 선 차트로 시각화했습니다.
이번 시각화에서는 temp속성을 사용하지 않고, feelslike(체감 온도)속성을 사용했습니다. 그 결과 예상과 동일하게 Ahmedabad보다 Bengaluru가 훨씬 체감 온도가 낮다는 사실을 한눈에 알기 쉽게 확인할 수 있습니다.
df5 = df
#필요한 열 선택
df5 = df5[["City", "Date", 'humidity', "sealevelpressure"]]
#결측치가 있는 행 제거
df5.dropna(inplace=True)
#City 필터링
df_filtered = df5[(df5["City"] == "New Delhi") | ((df5["City"] == "Mumbai"))]
#IQR 계산
Q1 = df_filtered['sealevelpressure'].quantile(0.25)
Q3 = df_filtered['sealevelpressure'].quantile(0.75)
IQR = Q3 - Q1
#이상치 제거
df_filtered = df_filtered[~((df_filtered['sealevelpressure'] < (Q1 - 1.5 * IQR)) | (df_filtered['sealevelpressure'] > (Q3 + 1.5 * IQR)))]
#산점도
plt.scatter(df_filtered['humidity'], df_filtered['sealevelpressure'], c=df_filtered['sealevelpressure'], cmap='cool')
#색상 막대
cbar = plt.colorbar()
cbar.set_label('sealevelpressure')
#라벨
plt.xlabel('Humidity')
plt.ylabel('sealevelpressure')
plt.show()
데이터의 다른 속성인 습도(Humidity)와 해면기압(sealevelpressure)을 사용해서 산점도를 그려봤습니다. 산점도는 데이터의 상관관계를 나타내기 위한 그래프입니다. 습도와 해면기압에 따른 상관관계가 있지 않을까 하는 생각에 해당 시각화를 진행하게 되었습니다.
산점도를 그릴 때 처음에는 csv 파일의 전체 데이터를 가지고 진행하였지만, 데이터가 너무 많으니 확인도 어렵고 유의미한 결과를 도출하기 어렵다는 결론이 나왔습니다. 따라서 지역을 New Delhi와 Mumbai 지역으로만 제한하여 데이터의 수를 줄였습니다.
sealevelpressure에 결측치가 많이 존재했기 때문에, 결측치를 제거하였고 Humidity에 극단적인 값이 있는 경우가 있어서 IQR을 활용해서 이상치를 제거했습니다.
일반적으로 습도가 높을수록 공기가 더 많은 수증기를 포함하고 있으며, 이로 인해 기압이 감소합니다. 반대로 습도가 낮으면, 공기가 더 건조해져서 기압이 상승하게 됩니다. 따라서 일반적으로 습도와 기압은 서로 반비례 관계에 있습니다.
시각화 결과, 대각선의 형태를 띠는 분포를 예상했지만 그렇지 않았습니다. 인도의 해면기압은 습도에 크게 상관없이 대체로 비슷한 해면기압을 가지고 있었습니다. 즉, 그래프에서 볼 수 있는 것처럼 인도에서는 습도와 해면기압 사이에 큰 상관 관계가 없다는 결론이 나왔습니다.
#필요한 열 선택
df6 = df[["Date", "City", "sunrise"]]
#Ahmedabad와 Bengaluru 2021년 데이터만 필터링
df_ahme = df6[(df6["City"] == "Ahmedabad") & (df6["Date"].str.startswith("2021"))].copy() # .copy() 메소드로 복사
df_beng = df6[(df6["City"] == "Bengaluru") & (df6["Date"].str.startswith("2021"))].copy() # .copy() 메소드로 복사
#Date 객체로 변환
df_ahme.loc[:, 'Date'] = pd.to_datetime(df_ahme['Date'])
df_beng.loc[:, 'Date'] = pd.to_datetime(df_beng['Date'])
#문자열 자르기, 타입변경
df_ahme.loc[:, 'sunrise'] = pd.to_datetime(df_ahme['sunrise'], format='%Y-%m-%d %H:%M:%S').dt.time
df_beng.loc[:, 'sunrise'] = pd.to_datetime(df_beng['sunrise'], format='%Y-%m-%d %H:%M:%S').dt.time
#sunrise 시간 정보를 초 단위로 변환
df_ahme.loc[:, "sunrise_sec"] = df_ahme["sunrise"].apply(lambda x: x.hour * 3600 + x.minute * 60 + x.second)
df_beng.loc[:, "sunrise_sec"] = df_beng["sunrise"].apply(lambda x: x.hour * 3600 + x.minute * 60 + x.second)
#선차트
plt.plot(df_ahme["Date"], df_ahme["sunrise_sec"])
plt.plot(df_beng["Date"], df_beng["sunrise_sec"])
#라벨지정
plt.xlabel('Date')
plt.ylabel('sunrise (sec)')
plt.legend(['Ahmedabad', 'Bengaluru'])
#제목지정
plt.title('2021 Sunrise time of Ahmedabad and Bengaluru', pad=30) #패딩 추가
plt.show()
인도의 각각 서쪽과 남쪽에 위치한 Ahmedabad와 Bengaluru의 일출(sunrise) 시간데이터를 시각화한 그래프입니다. 일출 시간은 지구의 위도, 경도 및 시즌에 따라 변화합니다.
앞에서 진행한 데이터 시각화에서 두 지역 간 온도가 크게 상이하다는 점에서 거리가 꽤 멀다는 사실을 알게 되었습니다. 그렇다면 일출 시간도 분명 다를 것이라고 판단해서 sunrise속성을 이용해서 선 차트로 시각화했습니다. y축에는 숫자 데이터만 표시할 수 있기 때문에 데이터 전처리 과정에서 문자로 표현된 시간 정보를 초 단위로 변환했습니다.
시각화된 결과를 보면, 두 지역 모두 일출시간이 대체로 비슷하지만, 4월 초에는 남쪽에 위치한 Bengaluru 지역이 해가 더 빨리 뜬다는 사실을 확인할 수 있습니다.
#필요한 열 선택
df6 = df[["Date", "City", "sunset"]]
#Ahmedabad와 Bengaluru 2021년 데이터만 필터링
df_ahme = df6[(df6["City"] == "Ahmedabad") & (df6["Date"].str.startswith("2021"))].copy() # .copy() 메소드로 복사
df_beng = df6[(df6["City"] == "Bengaluru") & (df6["Date"].str.startswith("2021"))].copy() # .copy() 메소드로 복사
#Date 객체로 변환
df_ahme.loc[:, 'Date'] = pd.to_datetime(df_ahme['Date'])
df_beng.loc[:, 'Date'] = pd.to_datetime(df_beng['Date'])
#문자열 자르기, 타입변경
df_ahme.loc[:, 'sunset'] = pd.to_datetime(df_ahme['sunset'], format='%Y-%m-%d %H:%M:%S').dt.time
df_beng.loc[:, 'sunset'] = pd.to_datetime(df_beng['sunset'], format='%Y-%m-%d %H:%M:%S').dt.time
#sunset 시간 정보를 초 단위로 변환
df_ahme.loc[:, "sunset_sec"] = df_ahme["sunset"].apply(lambda x: x.hour * 3600 + x.minute * 60 + x.second)
df_beng.loc[:, "sunset_sec"] = df_beng["sunset"].apply(lambda x: x.hour * 3600 + x.minute * 60 + x.second)
#선차트
plt.plot(df_ahme["Date"], df_ahme["sunset_sec"])
plt.plot(df_beng["Date"], df_beng["sunset_sec"])
#라벨지정
plt.xlabel('Date')
plt.ylabel('sunset (sec)')
plt.legend(['Ahmedabad', 'Bengaluru'])
#제목지정
plt.title('2021 Sunset time of Ahmedabad and Bengaluru', pad=30) #패딩 추가
plt.show()
간단하게 sunrise속성을 sunset속성으로 변경만 해주면 동일한 방법으로 일몰시간도 확인할 수 있습니다. 일출시간이 Ahmedabad보다 Bengaluru가 더 빨랐기 때문에 당연하게 일몰시간도 더 빠른 모습을 확인할 수 있습니다.
📝 ipynb 파일도 올리겠습니다. 😀
참고 문헌 :