Może się wydawać, że Polska jest szczególnym miejscem jeśli chodzi o zmianę klimatu. W sumie czasem pada śnieg albo jest zimno, czasem latem trzeba zakładać kurtkę, etc. Spójrzmy, co zmieniło się na przestrzeni lat.
Zbiór danych przetwarzany tutaj opisuje temperaturę lądu, nie temperaturę powietrza. Ląd ogrzewa się szybciej niż powietrze, więc łatwiej z niego wyłowić trendy.
Na początku analizy posiłkowałem się trochę tym wpisem Tomasza Tomaszewskiego, ale w końcu zrozumiałem to i owo i dopisałem kilka rzeczy, a z kilku zrezygnowałem.
Nie chciałem umieszczać w repozytorium całego zbioru danych, gdyż waży on około 500MB. W związku z tym ograniczyłem go tylko do Polski. Jeśli chcesz coś policzyć na danych z całego świata, cały zbiór możesz ściągnąć na kaggle.
Zaczynamy.
Najpierw kilka ustawień początkowych i import potrzebnych bibliotek.
In [1]:
%matplotlib inline
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import calendar, datetime
sns.set(style='whitegrid', palette='Set2')
CITY = 'Torun'
SELECTED_CITIES = ['Torun', 'Cracow', 'Katowice', 'Olsztyn', 'Szczecin', 'Bialystok',
'Zielona Gora', 'Warsaw', 'Poznan', 'Bialystok', 'Wroclaw']
START_YEAR = 1753
MONTH = int(datetime.datetime.now().strftime("%m"))
# when global average temperature started to rise
RISE_START_YEAR = 1970
# Baseline years
BASE_YEAR_START = 1850
BASE_YEAR_END = 1900
Teraz wczytujemy dane z udostępnionego zbioru i czyścimy je z niepotrzebnych w tej analizie informacji.
In [2]:
df = pd.read_csv('./data/climate/GlobalLandTemperaturesByCityPoland.csv')
date_index = pd.to_datetime(df['dt'], format='%Y-%m-%d', errors='ignore')
df['di'] = date_index
df['Year'] = df['di'].dt.year
df['Month'] = df['di'].dt.month
df['Day'] = df['di'].dt.day
poland = df
poland_clean = poland.copy()
poland_clean.drop('Latitude', axis=1, inplace=True)
poland_clean.drop('Longitude', axis=1, inplace=True)
poland_clean.drop('AverageTemperatureUncertainty', axis=1, inplace=True)
poland_clean.drop('Country', axis=1, inplace=True)
poland_clean.drop('dt', axis=1, inplace=True)
city = df[df['City'] == CITY].dropna().copy()
climate_city = city[city['Year'] >= START_YEAR].copy()
month_city = climate_city[climate_city['Month'] == MONTH].copy()
current_month_city = month_city[month_city['Year'] > RISE_START_YEAR]
baseline_month_city = month_city[
month_city['Year'].between(BASE_YEAR_START, BASE_YEAR_END)].copy()
Do dyspozycji w Polsce miałem następujące miasta:
In [3]:
poland['City'].unique()
Out[3]:
Wybierzmy kilka i zobaczmy, jak się zmieniała dla nich temperatura na przestrzeni lat.
To co widać na poniższym wykresie to znaczący wzrost średnich temperatur od początku XX wieku. Dane kończą się na roku 2013 i do tej chwili średnia temperatura wzrosła o 1 stopień.
Ciekawe jest to, że najchłodniejsze z miast (Białystok) ma średnią temperaturę niższą o ponad 2 stopnie od najcieplejszego (Zielonej Góry).
In [4]:
sns.lmplot(x='Year', y='AverageTemperature', hue='City', data=poland[poland['City'].isin(SELECTED_CITIES)],
scatter=False, lowess=True)
Out[4]:
Sam mieszkam obecnie w Toruniu i dlatego analizę przeprowadzę dla tego właśnie miasta.
Część wykresów dotyczyć będzie obecnego miesiąca (tego, w którym uruchomię notebook albo w którym Ty go sforkujesz i uruchomisz ;) )
Próbka zbioru danych dla Torunia po usunięciu kolumn, które mnie nie interesowały, wygląda tak:
In [5]:
climate_city.head()
Out[5]:
Od 1753 roku mamy pełne dane. Widać też, że są to średnie z całego miesiąca.
Na początek sprawdźmy jaka była średnia temperatura w aktualnym miesiącu od 1753 i 1970 roku. W 1970 uśredniona temperatura całego świata zaczęła dramatycznie rosnąć.
Należy wziąć pod uwagę, że naukowcy badający klimat odchylenia od średniej mierzą względem okresu 1850-1900 (o tym więcej poniżej).
In [6]:
print("Average temperature in {city} in {from_year}-2013: {temperature}".format(
city=calendar.month_name[MONTH],
from_year=START_YEAR,
temperature=month_city['AverageTemperature'].mean()
))
print("Average temperature in {city} in {from_year}-2013: {temperature}".format(
city=calendar.month_name[MONTH],
from_year=RISE_START_YEAR,
temperature=current_month_city['AverageTemperature'].mean()
))
print("Average temperature in {city} in {from_year}-{to_year}: {temperature} (baseline)".format(
city=calendar.month_name[MONTH],
from_year=BASE_YEAR_START,
to_year=BASE_YEAR_END,
temperature=baseline_month_city['AverageTemperature'].mean()
))
Poniższy wykres przedstawia rozkład temperatur w całym roku i w miesiącu zdefiniowanym w MONTH
.
In [7]:
fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=False)
sns.distplot(climate_city['AverageTemperature'], bins=50, rug=True, ax=ax1)
ax1.set_title("Whole year")
sns.distplot(month_city['AverageTemperature'], bins=50, rug=True, ax=ax2)
ax2.set_title("Current month")
plt.show()
Następny wykres przedstawia zmiany średniej temperatury na przestrzeni lat we wszystkich miesiącach. Dokładniej rzecz ujmując nie jest to średnia, tylko krzywa regresji.
In [8]:
sns.lmplot(y="AverageTemperature", x="Year", data=climate_city,
lowess=True, markers=".", col="Month", col_wrap=3, sharex=False, sharey=False)
Out[8]:
Poniżej zaś można zobaczyć zakresy temperatur, jakie zdarzały się w całym zbiorze danych przez te nieco ponad 200 lat.
In [9]:
sns.swarmplot(x='Month', y='AverageTemperature', data=climate_city)
Out[9]:
Taka prezentacja danych nie mówi jednak wiele o tym, co jest szczególnie istotne w kontekście globalnego ocieplenia, czyli o trendzie. Sprawdźmy jak to wygląda.
In [10]:
from scipy.stats import spearmanr
sns.jointplot(month_city['Year'], month_city['AverageTemperature'],
kind="hex", stat_func=spearmanr)
Out[10]:
Co to mówi? Coraz ciemniejsze sześciokąty w górnej części wykresu w miarę upływu czasu wskazują na coraz częstsze odchylenia temperatury w górę.
Wybrałem jeden miesiąc (taki jak jest teraz) i sprawdziłem, jak często występowała dana temperatura. Sprawdźmy jak to było porównując wszystkie dostępne dane (1753-2013) z okresem po 1970 oraz 1995 roku (niedługo przed El Niño).
Warto zwrócić uwagę, że jeśli miesiącem zdefiniowanym w MONTH
jest wrzesień, zmiana nie jest duża. Wynika to z tego, że ten akurat miesiąc aż tak bardzo się nie ocieplił na przestrzeni lat (co widać tam, gdzie jest tak dużo wykresów :) ). Polecam zmienić wartość zmiennej MONTH
i uruchomić dwie komórki poniżej.
In [11]:
before_1970 = month_city[month_city['Year'] < RISE_START_YEAR]['AverageTemperature'].copy()
after_1970 = month_city[month_city['Year'] >= RISE_START_YEAR]['AverageTemperature'].copy()
after_1995 = month_city[month_city['Year'] >= 1995]['AverageTemperature'].copy()
In [12]:
fig, ax = plt.subplots()
sns.distplot(before_1970, hist=False, ax=ax)
sns.distplot(after_1970, hist=False, ax=ax)
sns.distplot(after_1995, hist=False, ax=ax)
Out[12]:
W drugim i trzecim przypadku danych oczywiście nie ma zbyt dużo (43 i 19 pomiarów), ale da się zauważyć, że zwiększa się prawdopodobieństwo wystąpienia temperatury w okolicach 19 stopni.
Kostka klimatyczna jest koncepcją, która ma ułatwić zrozumienie tego, że globalne ocieplenie, zwłaszcza w początkowej fazie, nie oznacza, że nie będzie zim w ogóle, a tylko to, że będą one rzadziej.
Załóżmy, że pomalowaliśmy ściany kostki na trzy kolory: czerwony, biały i niebieski oznaczające odpowiednio od wysokich, przez średnie, do niskich temperatur. Dostosujmy te przedziały tak, żeby prawdopodobieństwa były analogiczne do szans, że wypadnie ściana kostki zamalowana danym kolorem. Globalne ocieplenie sprawia, że dodatkowe ściany kostki zostają zamalowane na czerwono.
W tym notebooku zmieniłem trochę tę koncepcję — zamiast ścian kostki, pokazuję liczbę miesięcy w roku, które uznalibyśmy za ciepłe, normalne lub chłodne (ciepłe jak na styczeń, itd.) Zobaczmy, jak to wygląda.
In [13]:
def label_bin(row):
if row['AverageTemperature'] < (row['MonthMeanBaseline'] - row['MonthStdBaseline']):
return 'Low'
elif row['AverageTemperature'] > (row['MonthMeanBaseline'] + row['MonthStdBaseline']):
return 'High'
return 'Medium'
In [14]:
monthly_frames = []
for i, group in climate_city.groupby('Month'):
g2 = group.copy()
g_temp_series = g2[(g2['Year'] >= BASE_YEAR_START) & (g2['Year'] <= BASE_YEAR_END)]['AverageTemperature']
g2['MonthMeanBaseline'] = g_temp_series.mean()
g2['MonthStdBaseline'] = g_temp_series.std()
g2['TemperatureBin'] = g2.apply(label_bin, axis=1)
monthly_frames.append(g2)
In [15]:
all_with_bins = pd.concat(monthly_frames).sort_index()
city_grouped_with_counted_bins = all_with_bins.groupby(['Year','TemperatureBin'])['City'] \
.agg(['count']).reset_index()
In [16]:
sns.lmplot(x='Year', y='count', hue='TemperatureBin',
data=city_grouped_with_counted_bins,
scatter=False, lowess=True)
Out[16]:
Spadek ilości miesięcy o temperaturze "normalnej" w okresie bazowym (1850-1900) jest aż nadto widoczny.
Na moje pytanie:
(...) Otóż zrobiłem mała analizę zmian temperatury lądu na podstawie zbioru danych z Berkeley. Chciałem jednak to pokrótce opisać i nie mogę doszukać się informacji na temat tego, co paryskie porozumienie definiuje jako erę pre-industrialną. Znalazłem jedynie coś takiego: https://www.climate-lab-book.ac.uk/2017/defining-pre-industrial/ Państwo pewnie macie tę informację po prostu w głowie, stąd moje pytanie 🙂 Będę bardzo wdzięczny i dzisiaj podeślę linka 🙂
Niestety, w porozumieniu (przezornie?) nie podano ścisłej definicji tego terminu. Klasycznie uznaje się, że "epoka przedprzemysłowa" oznacza "przed rokiem 1750". Z praktycznych względów - przede wszystkim dostępności danych - punkt odniesienia wykresów czy podawanych wartości jest jednak późniejszy, np. okres przed 1850, 1850-1900, 1801-1900, pierwsze 30 lat danej serii pomiarowej.
Z jednej strony, pewnie wielu osobom będzie teraz zależało na dokładnym ustaleniu, co ma oznaczać "przedprzemysłowe" (przykładem jest artykuł, który Pan linkuje), żeby móc śledzić, czy już nam te 1,5C stuknęło, czy nie. Z drugiej - nie ma to wielkiego znaczenia o tyle, że
Na Pana miejscu przyjęłabym jako punkt odniesienia okres 1850-1900, bo jest on powszechie wykorzystywany w praktyce (np. w podsumowaniu http://naukaoklimacie.pl/aktualnosci/1-5-czy-2-stopnie-co-to-w-ogole-za-roznica-191) i to pewnie projekcje z takim okresem referencyjnym oglądali politycy (np. w raporcie Global Carbon Budget -załączony obrazek). Dla uniknięcia wątpliwości można zaznaczyć, że przyjął go Pan w ślad za innymi i że choć są w tej kwestii pewne rozbieżności to tak w sumie nie robi to wielkiej różnicy (na wykresie http://naukaoklimacie.pl/aktualnosci/ziemskie-progi-bezpieczenstwa-193 widać, jak płaski był wykres przed XIX wiekiem.
Z tego miejsca dziękuję Pani Aleksandrze :)