In [42]:
from datetime import datetime
print(f'Päivitetty {datetime.now().strftime('%d.%m.%Y')} / Tatu Erkinjuntti')
Päivitetty 11.11.2024 / Tatu Erkinjuntti

Tehtävä 2.¶

Osa 1 - aikasarjat¶

Valitse kahden pörssiosakkeen kurssihistoriat, ei kuitenkaan esimerkkimuistioissa esiintyviä Elisaa tai Teliaa (voi myös käyttää raaka-aineiden tai virtuaalivaluuttojen hintahistorioita) ja analysoi niitä opituilla menetelmillä. Lisää mukaan mahdollisimman paljon omia kommentteja ja selitystä.

Osakkeiden kurssihistorioita ja raaka-aineiden/valuuttojen hintahistorioita saat Yahoo Finance -palvelusta:

  1. avaa https://finance.yahoo.com/

  2. Etsi (search) haluamasi yritys esim NOKIA.HE

  3. Klikkaa "Historical Data

  4. Määritä päivämäärät haulle ja sitten "download"

Osa 2 - aikasarjaennustaminen¶

Valitse yksi seuraavista aikasarjoista tai käytä jotain omaa aikasarjaa ja analysoi kommentoiden opituilla menetelmillä.

Aikasarjoja¶

Seuraavissa aikasarjoissa on kaikissa sekä trendi että kausivaihtelu.

Ilman CO2-pitoisuuksia kuukausittain.¶

Siististi käyttäytyvä aikasarja, jolle saa laskettua tarkkoja ennusteita.

Lähde: https://www.esrl.noaa.gov/gmd/webdata/ccgg/trends/co2/co2_mm_mlo.txt

Aukenee säädylliseen dataframeen suoraan lähteestä seuraavan esimerkin mukaisesti.

Lentomatkustajien lukumääriä AirPassengers.csv.¶

Tästä aikasarjasta löytyy netistä paljon laskettuja esimerkkejä eri ennustusmenetelmille.

Lähde: https://www.kaggle.com/rakannimer/air-passengers

tai täällä

Aukenee säädylliseen dataframeen seuraavasti:

df=pd.read_csv('AirPassengers.csv') df.index=pd.to_datetime(df['Month'],format='%Y-%m') df=df.drop('Month',axis=1) df.head()

Oluen tuotantomääriä beer.csv¶

Lähde: https://www.kaggle.com/shenba/time-series-datasets

löytyy myös täältä

Aukenee säädylliseen dataframeen seuraavasti:

df=pd.read_csv('beer.csv') df.index=pd.to_datetime(df['Month'],format='%Y-%m') df=df.drop('Month',axis=1) df.head()

Sähkön tuotantoa Electric_Production.csv (löytyy data-paketista)¶

Lähde: https://www.kaggle.com/shenba/time-series-datasets

löytyy myös täältä

Aukenee säädylliseen dataframeen seuraavasti:

df=pd.read_csv('Electric_Production.csv') df.index=pd.to_datetime(df['DATE'],format='%m/%d/%Y') df=df.drop('DATE',axis=1) df.head()

Tehtävän alustus¶

Haetaan tarvittavat kirjastot ja määritellään käytetyt data-aineistot. Itse teen tämän aina kerralla ohjelman alussa, näin yhdellä silmäyksellä näkee ohjelman riippuvaisuudet. Jos käytössä olisi pysyviä muuttujia, tulisi ne myös alustaa samalla.

In [43]:
import pandas as pd 
import matplotlib.pyplot as plt 
import seaborn as sns

import yfinance as yf

from scipy.stats import pearsonr

from statsmodels.tsa.api import seasonal_decompose
from statsmodels.tsa.api import ExponentialSmoothing

sns.set_style('whitegrid')

electric_procuction = '../Data/Electric_Production.csv'

Osa 1, aikasarjat - Virtuaalivaluutat¶

Valitsin tähän tehtävään kahden virtuaalivaluutan kurssihistorian, Bitcoin (BTC-USD) sekä Ethereum (ETH-USD) . Syy tähän on oikeastaan kiinnostus virtaalivaluutoiden kurssikehitykseen.

Alunperin valitsin tutkittavaksi ajanjaksoksi 10 vuotta, sillä esim. Bitcoinin osalta sen kurssihistoria on ollut varsin korkealentoinen viime vuosikymmenen aikana, mutta ikävä kyllä Ethereum on noteraatu vasta vuodesta 2017, päädyin että tutkittava ajankohta alkaa vuodesta 2018 jotta näillä olisi jotain vertailukelpoisuutta.

  • Molempien virtuaalivaluuttojen kurssihistoria perustuu sen suhteeseen Yhdysvaltain Dollarin arvoon.

Aloitetaan hakemalla data-aineisto.

In [44]:
# HUOM! koska aikaisemmin mainittiin 10 vuotta, niin ulotetaan data-aineisto 10 vuoden päähän.
ethereum_d = yf.download('ETH-USD', start='2018-1-1')
bitcoin_d = yf.download('BTC-USD', start='2018-1-1')
[*********************100%***********************]  1 of 1 completed
[*********************100%***********************]  1 of 1 completed

Aloitetaan tutkimalla Ethereumin data-aineisto.

In [45]:
ethereum_d
Out[45]:
Price Adj Close Close High Low Open Volume
Ticker ETH-USD ETH-USD ETH-USD ETH-USD ETH-USD ETH-USD
Date
2018-01-01 00:00:00+00:00 772.640991 772.640991 782.530029 742.004028 755.757019 2595760128
2018-01-02 00:00:00+00:00 884.443970 884.443970 914.830017 772.346008 772.346008 5783349760
2018-01-03 00:00:00+00:00 962.719971 962.719971 974.471008 868.450989 886.000000 5093159936
2018-01-04 00:00:00+00:00 980.921997 980.921997 1045.079956 946.085999 961.713013 6502859776
2018-01-05 00:00:00+00:00 997.719971 997.719971 1075.390015 956.325012 975.750000 6683149824
... ... ... ... ... ... ...
2024-11-07 00:00:00+00:00 2895.585449 2895.585449 2918.744385 2701.590820 2724.005859 35352318438
2024-11-08 00:00:00+00:00 2962.296631 2962.296631 2983.744873 2889.484375 2895.597900 32303261101
2024-11-09 00:00:00+00:00 3131.144531 3131.144531 3156.366211 2957.182373 2962.791016 29210133088
2024-11-10 00:00:00+00:00 3191.331299 3191.331299 3249.914062 3073.248779 3130.729248 47418730187
2024-11-11 00:00:00+00:00 3324.701172 3324.701172 3335.869873 3114.547607 3187.581299 53515177984

2507 rows × 6 columns

Katsotaan nyt miltä Bitcoinin data-aineisto näyttää.

In [46]:
bitcoin_d
Out[46]:
Price Adj Close Close High Low Open Volume
Ticker BTC-USD BTC-USD BTC-USD BTC-USD BTC-USD BTC-USD
Date
2018-01-01 00:00:00+00:00 13657.200195 13657.200195 14112.200195 13154.700195 14112.200195 10291200000
2018-01-02 00:00:00+00:00 14982.099609 14982.099609 15444.599609 13163.599609 13625.000000 16846600192
2018-01-03 00:00:00+00:00 15201.000000 15201.000000 15572.799805 14844.500000 14978.200195 16871900160
2018-01-04 00:00:00+00:00 15599.200195 15599.200195 15739.700195 14522.200195 15270.700195 21783199744
2018-01-05 00:00:00+00:00 17429.500000 17429.500000 17705.199219 15202.799805 15477.200195 23840899072
... ... ... ... ... ... ...
2024-11-07 00:00:00+00:00 75904.859375 75904.859375 76943.117188 74480.421875 75637.085938 63467654989
2024-11-08 00:00:00+00:00 76545.476562 76545.476562 77252.750000 75648.742188 75902.835938 55176858003
2024-11-09 00:00:00+00:00 76778.867188 76778.867188 76932.765625 75773.789062 76556.187500 29009480361
2024-11-10 00:00:00+00:00 80474.187500 80474.187500 81474.421875 76565.429688 76775.546875 82570594495
2024-11-11 00:00:00+00:00 86205.460938 86205.460938 86255.359375 80444.125000 80444.125000 100115922944

2507 rows × 6 columns

Huomaamme data-aineiston riveistä, että koska valittu aineisto yltää yli kymmenen vuoden päähän, on meillä molemmissa tapauksissa sopivan suuri aineisto pohja.

Tarkastetaan seuraavaksi kehitystä yleisesti viivakaavion avulla. Keskitytään päivän päätös hintaan => 'Close'.

In [47]:
fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(10, 3))
ethereum_d['Close'].plot(ax=axs[0])
bitcoin_d['Close'].plot(ax=axs[1])
Out[47]:
<Axes: xlabel='Date'>
No description has been provided for this image

Huomaamme että Bitcoin painii aivan omassa sarjassaan arvonsa osalta mutta pystymme näkemään yhtäläisyyksiä kurssikehityksen suhteen. Vuodet 2021 - 2022 olivat erittäin tuottavia molempien virtuaalivaluuttojen osalta.

Tarkastellaan tarkkemmin noita vuosia 2021 - 2022, keskitytään tähän aikaväliin.

In [48]:
fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(10, 3))
ethereum_d['Close']['2021':'2022'].plot(ax=axs[0])
bitcoin_d['Close']['2021':'2022'].plot(ax=axs[1])
Out[48]:
<Axes: xlabel='Date'>
No description has been provided for this image

Vuoden 2021 nousujohde ei mielestäni näy tässä kunnolla, varsinkin Bitcoinin osalta. Otetaan vuosi 2020 mukaan, jotta saamme nousun alun näkymään.

In [49]:
fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(10, 3))
ethereum_d['Close']['2020':'2022'].plot(ax=axs[0])
bitcoin_d['Close']['2020':'2022'].plot(ax=axs[1])
Out[49]:
<Axes: xlabel='Date'>
No description has been provided for this image

Aggregoidaan tämä kuukaisitasolle.

In [50]:
fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(10, 3))
ethereum_d['Close']['2020':'2022'].resample('ME').mean().plot(ax=axs[0])
bitcoin_d['Close']['2020':'2022'].resample('ME').mean().plot(ax=axs[1])
Out[50]:
<Axes: xlabel='Date'>
No description has been provided for this image

Nyt molempien kurssian vuosien 2020 - 2022 aikana tapahtunut piikki näkyy selkeämmin.

Palaan takaisin koko data-aineiston pariin. Vaikka molempien virtuaalivaluuttojen kursseissa ei näy nopeatempoista fluktuaatiota, tasoitetaan viivakaavioita liukuvilla keskiarvoilla. Tutkitaan aluksi kuukauden (30 päivää) liukuvalla keskiarvolla.

In [51]:
fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(10, 3))
ethereum_d['Close'].rolling(30).mean().plot(ax=axs[0])
bitcoin_d['Close'].rolling(30).mean().plot(ax=axs[1])
Out[51]:
<Axes: xlabel='Date'>
No description has been provided for this image

Vaikka graafia saatinkin mukavasti tasoitettua, kokeillaan hieman pidempää aikaväliä, vaikka vuosineljännes (~ 90 päivää).

In [52]:
fig, axs = plt.subplots(nrows=1, ncols=2, figsize=(10, 3))
ethereum_d['Close'].rolling(90).mean().plot(ax=axs[0])
bitcoin_d['Close'].rolling(90).mean().plot(ax=axs[1])
Out[52]:
<Axes: xlabel='Date'>
No description has been provided for this image

Tämä näyttää paljon paremmalla.

Voidaan jälkiviisana todeta että molempiin virtuaalivaluuttoihin olisi ollut kannattavaa sijoittaa viimeistään vuoden 2020 aikana. Ajankohta sijoituksensa myymiseen voitolla vaihtelee näiden kahden virtuaalivaluutan kanssa. Ethereumin osalta otollisin aika olisi ollut alkuvuodesta 2022. Bitcoinin osalta toistuu myös sama ajankohta, mutta jos olisi malttanut pitää omistuksistaan kiinni 2022 alkaneen pudotuksen ajan, joka kesti alkuvuoteen 2024 asti, olisi vuoden 2024 arvon nousu tuonnut vielä suuremmat tuotot kuin vuoden 2022 piikki.

Koska näiden molemmissa virtuaalivaluutoissa on tapahtunut merkittävä arvon muutos tarkasteltavalla aikavälillä, voitaisiin tutkia onko näiden välillä jotain yhteyttä. Toisin sanoen voidaanko olettaa että Bitcoinin arvon nousu on vaikuttanut myös Ethereumiin.

Aloitetaan tämä tarkastelemella näiden virtuaalivaluuttoje arvon muutosprosenttia valitulla ajanjaksolla.

In [53]:
# Tehdään taulukkoon oma sarake päiväkohtaiselle muutosprosentille. 
# Otetaan arvonmuutos päivän päätöshinnan mukaan.

# kerrotaan prosenttiluku 100, jotta sitä on helpompi katsella ja tarkastella.

bitcoin_d['Bitcoin_value_change_%'] = (bitcoin_d['Close'].pct_change()*100)
ethereum_d['Ethereum_value_change_%'] = (ethereum_d['Close'].pct_change()*100)

# Tarkastetaan muutos mutta otetaan vain ensimmäiset viisi riviä.
bitcoin_d.head()
Out[53]:
Price Adj Close Close High Low Open Volume Bitcoin_value_change_%
Ticker BTC-USD BTC-USD BTC-USD BTC-USD BTC-USD BTC-USD
Date
2018-01-01 00:00:00+00:00 13657.200195 13657.200195 14112.200195 13154.700195 14112.200195 10291200000 NaN
2018-01-02 00:00:00+00:00 14982.099609 14982.099609 15444.599609 13163.599609 13625.000000 16846600192 9.701106
2018-01-03 00:00:00+00:00 15201.000000 15201.000000 15572.799805 14844.500000 14978.200195 16871900160 1.461080
2018-01-04 00:00:00+00:00 15599.200195 15599.200195 15739.700195 14522.200195 15270.700195 21783199744 2.619566
2018-01-05 00:00:00+00:00 17429.500000 17429.500000 17705.199219 15202.799805 15477.200195 23840899072 11.733293
In [54]:
ethereum_d.head()
Out[54]:
Price Adj Close Close High Low Open Volume Ethereum_value_change_%
Ticker ETH-USD ETH-USD ETH-USD ETH-USD ETH-USD ETH-USD
Date
2018-01-01 00:00:00+00:00 772.640991 772.640991 782.530029 742.004028 755.757019 2595760128 NaN
2018-01-02 00:00:00+00:00 884.443970 884.443970 914.830017 772.346008 772.346008 5783349760 14.470236
2018-01-03 00:00:00+00:00 962.719971 962.719971 974.471008 868.450989 886.000000 5093159936 8.850306
2018-01-04 00:00:00+00:00 980.921997 980.921997 1045.079956 946.085999 961.713013 6502859776 1.890688
2018-01-05 00:00:00+00:00 997.719971 997.719971 1075.390015 956.325012 975.750000 6683149824 1.712468
In [55]:
# Luodaan uusi muuttuja, johon tallennetaan aikaisemmin lasketut muutosprosentit.
value_changes = pd.concat([bitcoin_d['Bitcoin_value_change_%'], ethereum_d['Ethereum_value_change_%']], axis=1)

# Muutetaan NaN (Not a Number) lukemat numeraaliseen muotoon, jotta se ei vaikutua laskutoimenpiteisiin.
value_changes = value_changes.fillna(0)
value_changes
Out[55]:
Bitcoin_value_change_% Ethereum_value_change_%
Date
2018-01-01 00:00:00+00:00 0.000000 0.000000
2018-01-02 00:00:00+00:00 9.701106 14.470236
2018-01-03 00:00:00+00:00 1.461080 8.850306
2018-01-04 00:00:00+00:00 2.619566 1.890688
2018-01-05 00:00:00+00:00 11.733293 1.712468
... ... ...
2024-11-07 00:00:00+00:00 0.351381 6.292423
2024-11-08 00:00:00+00:00 0.843974 2.303893
2024-11-09 00:00:00+00:00 0.304905 5.699898
2024-11-10 00:00:00+00:00 4.812939 1.922197
2024-11-11 00:00:00+00:00 7.121878 4.179130

2507 rows × 2 columns

Katsotaan uteliaisuudesta kuinka usein päiväkohtainen muutos on yli 10 prosenttia.

In [56]:
value_changes[(abs(value_changes['Bitcoin_value_change_%']) >10) | abs(value_changes['Ethereum_value_change_%'] > 10)]
Out[56]:
Bitcoin_value_change_% Ethereum_value_change_%
Date
2018-01-02 00:00:00+00:00 9.701106 14.470236
2018-01-05 00:00:00+00:00 11.733293 1.712468
2018-01-07 00:00:00+00:00 -5.987336 10.702902
2018-01-09 00:00:00+00:00 -3.788368 13.165521
2018-01-11 00:00:00+00:00 -10.468634 -8.033786
... ... ...
2024-01-10 00:00:00+00:00 1.057758 10.119141
2024-03-20 00:00:00+00:00 9.692505 11.267192
2024-05-20 00:00:00+00:00 7.800174 19.272223
2024-08-08 00:00:00+00:00 12.144256 14.840581
2024-11-06 00:00:00+00:00 9.053569 12.445812

101 rows × 2 columns

Näitä löytyy yllättävän paljon, 101 päiväkohtaista tapausta jolloin jomman kumman virtuaalivaluutan arvossa on ollut 10 prosentin muutos.

Tarkastellaan näiden kahden korrelaatiota.

In [57]:
value_changes.corr()
Out[57]:
Bitcoin_value_change_% Ethereum_value_change_%
Bitcoin_value_change_% 1.000000 0.818503
Ethereum_value_change_% 0.818503 1.000000

Voidaan todeta että näiden kahden virtuaalivaluutan arvonvaihtelulla on hyvin voimakas korrelaatio (yli 0.80). Tehdään tästä vielä liukuva korrelaatio, jotta tämän pystyy näkemään paremmin suhteessa valittuun ajanjaksoon.

In [58]:
#Pidetään valittuna aikavälinä samaa vuosineljännestä (90 päivää) mitä käytettiin aikaisemmin.
value_changes['Bitcoin_value_change_%'].rolling(90).corr(value_changes['Ethereum_value_change_%']).plot()
Out[58]:
<Axes: xlabel='Date'>
No description has been provided for this image

Nähdään että koko valittuna ajanjaksona molemmilla virtuaalivaluutoilla on ollut erittäin voimakas positiivinen korrelaatio toisiinsa.

Tutkitaan vielä vielä käydyn kauppamäärän ja arvonmuutoksen suhdetta toisiinsa, kasvaako kaupankäynti kun virtuaalivaluutan arvo laskee tai nousee. Toisin sanoen, löydetäänkö viitteitä markkinapaniikista suuntaan tai toiseen.

In [59]:
# Luodaan uusi taulu, johon otetaan arvon muutosprosentti ja käyty kauppamäärä päiväkohtaisesti.

bitcoin_value_change_volume = pd.concat([bitcoin_d['Bitcoin_value_change_%'], bitcoin_d['Volume']], axis=1)
ethereum_value_change_volume = pd.concat([ethereum_d['Ethereum_value_change_%'], ethereum_d['Volume']], axis=1)

# Muutetaan taas NAN arvot nolliksi. käytetään inplace parametria, jotta tätä muutosta ei tarvitse osoittaa uuteen tai samaan muuttujaan.
bitcoin_value_change_volume.fillna(0, inplace=True)
ethereum_value_change_volume.fillna(0, inplace=True)

# Tarkastetaan vielä dataframe.
bitcoin_value_change_volume
Out[59]:
Bitcoin_value_change_% BTC-USD
Date
2018-01-01 00:00:00+00:00 0.000000 10291200000
2018-01-02 00:00:00+00:00 9.701106 16846600192
2018-01-03 00:00:00+00:00 1.461080 16871900160
2018-01-04 00:00:00+00:00 2.619566 21783199744
2018-01-05 00:00:00+00:00 11.733293 23840899072
... ... ...
2024-11-07 00:00:00+00:00 0.351381 63467654989
2024-11-08 00:00:00+00:00 0.843974 55176858003
2024-11-09 00:00:00+00:00 0.304905 29009480361
2024-11-10 00:00:00+00:00 4.812939 82570594495
2024-11-11 00:00:00+00:00 7.121878 100115922944

2507 rows × 2 columns

In [60]:
ethereum_value_change_volume
Out[60]:
Ethereum_value_change_% ETH-USD
Date
2018-01-01 00:00:00+00:00 0.000000 2595760128
2018-01-02 00:00:00+00:00 14.470236 5783349760
2018-01-03 00:00:00+00:00 8.850306 5093159936
2018-01-04 00:00:00+00:00 1.890688 6502859776
2018-01-05 00:00:00+00:00 1.712468 6683149824
... ... ...
2024-11-07 00:00:00+00:00 6.292423 35352318438
2024-11-08 00:00:00+00:00 2.303893 32303261101
2024-11-09 00:00:00+00:00 5.699898 29210133088
2024-11-10 00:00:00+00:00 1.922197 47418730187
2024-11-11 00:00:00+00:00 4.179130 53515177984

2507 rows × 2 columns

Huomataan että "Volume" sarakkeen nimeksi on tullut sen "Ticker" ("virtuaalivaluutta"-USD), muutetaan tämä jotta tämä on helpommin ymmärrettävä.

In [61]:
bitcoin_value_change_volume.rename(columns = {'BTC-USD': 'Volume'}, inplace=True)
ethereum_value_change_volume.rename(columns = {'ETH-USD': 'Volume'}, inplace=True)

# Tarkastetaan muutokset

bitcoin_value_change_volume
Out[61]:
Bitcoin_value_change_% Volume
Date
2018-01-01 00:00:00+00:00 0.000000 10291200000
2018-01-02 00:00:00+00:00 9.701106 16846600192
2018-01-03 00:00:00+00:00 1.461080 16871900160
2018-01-04 00:00:00+00:00 2.619566 21783199744
2018-01-05 00:00:00+00:00 11.733293 23840899072
... ... ...
2024-11-07 00:00:00+00:00 0.351381 63467654989
2024-11-08 00:00:00+00:00 0.843974 55176858003
2024-11-09 00:00:00+00:00 0.304905 29009480361
2024-11-10 00:00:00+00:00 4.812939 82570594495
2024-11-11 00:00:00+00:00 7.121878 100115922944

2507 rows × 2 columns

Tarkastestellaan kaupankäynti määärien ja arvonvaihtelun mahdollinen korrelaatio ja otetaan mukaan vielä P-arvo, jolloin saadaan viitettä onko tämä vain sattumaa vai voidaanko olettaa että näiden välillä on oikeasti suhde.

In [62]:
r, p = pearsonr(bitcoin_value_change_volume['Volume'], bitcoin_value_change_volume['Bitcoin_value_change_%'])
print(f'Bitcoin arvon muutoksen suhde kauppamäärään: Korrelaatiokerroin (r) = {r:>6.3f}, P-arvo (p) = {p:.3f}')
Bitcoin arvon muutoksen suhde kauppamäärään: Korrelaatiokerroin (r) =  0.020, P-arvo (p) = 0.325
In [63]:
r, p = pearsonr(ethereum_value_change_volume['Volume'], ethereum_value_change_volume['Ethereum_value_change_%'])
print(f'Ethereum arvon muutoksen suhde kauppamäärään: Korrelaatiokerroin (r) = {r:>6.3f}, P-arvo (p) = {p:.3f}')
Ethereum arvon muutoksen suhde kauppamäärään: Korrelaatiokerroin (r) =  0.023, P-arvo (p) = 0.254

P-arvo (Alle 0.05) molemmissa tapauksissa osoittaa että näiden kahden muuttujan välillä on todella korrelaatiota. Korrelaatio näyttää olevan positiivinen (yli 0.25) mutta ei läheskään niin voimakas kun kahden virtuaalivaluutan arvon suhde toisiinsa. Tehdään näistä vielä hajontakaaviot, jotta pystymme paremmin näkemään tuloksen.

In [64]:
sns.jointplot(data=bitcoin_value_change_volume, x='Bitcoin_value_change_%', y='Volume', kind='reg')
Out[64]:
<seaborn.axisgrid.JointGrid at 0x23d74f75f30>
No description has been provided for this image
In [65]:
sns.jointplot(data=ethereum_value_change_volume, x='Ethereum_value_change_%', y='Volume', kind='reg')
Out[65]:
<seaborn.axisgrid.JointGrid at 0x23d74f75e00>
No description has been provided for this image

Voidaan todeta että vaikka meillä on viittetteitä siitä, että virtuaalivaluutan arvonmuutoksella on vaikutusta kaupankäynnin määrään, ei suhde ole niin selkeä että voisi todeta että tällä on voimakas vaikutus siihen.

Katsotaan vielä liukuva volatiteetti näiden kahden virtuaalivalutaan hinnan muutoksen osalta. Meillä on kuvaa jo siitä miten arvonmuutos on kehittynyt vuosien saatossa, mutta huomioidaan tässä liukuva keskiarvo vuodella (oletus on 252 päivää). Liukuva volatiteetti antaa meille lisää kuvaa mahdollisesta kaupan käynnin riskeistä valittuihin virtuaalivaluuttoihin liittyen.

In [66]:
plt.figure(figsize = (10, 6))
(value_changes['Bitcoin_value_change_%'].rolling(252).std() * (252**0.5)).plot(label='Bitcoin', legend=True)
(value_changes['Ethereum_value_change_%'].rolling(252).std() * (252**0.5)).plot(label='Ethereum', legend=True)
Out[66]:
<Axes: xlabel='Date'>
No description has been provided for this image

Tulosten puolesta voisi päätellä, että näistä kahdesta virtuaalivaluutasta Bitcoin on vakaampi, vaikka molemmissa virtuaalivaluutoissa esiintyy yli 20 prosentin suuruisia arvon muutoksia vuoden sisällä.

Osa 2 - aikasarjaennustaminen - Sähkön tuotanto¶

Osaan 2 valitsin sähkön tuotannom aikasarjaennustamisen. Tämä on ollut viime vuosina yleisesti kuumaperuna, kun sähkönhinnan osalta on ollut saatavuuden takia paljon heilahtelua. Myönnettäköön että hintaan vaikuttaa nykyään myös sähkönvalmistuksen ympäristövaikutukset mutta usein korkeisiin hintoihin vaikuttaa suoraan sähkön saatavuus.

Tein hieman taustatutkimusta ja näyttää siltä että käytettävästä datasta ei ole saatavilla paikkatietoa, mistä maasta data on peräisin.

In [67]:
# Aloitetaan lukemalla data-ainesto data-frameen.
electric_p_df = pd.read_csv(electric_procuction)
# Tarkistetaan data-aineistoa kokonaisuudessaan hieman näin alkuun.
electric_p_df
Out[67]:
DATE IPG2211A2N
0 1/1/1985 72.5052
1 2/1/1985 70.6720
2 3/1/1985 62.4502
3 4/1/1985 57.4714
4 5/1/1985 55.3151
... ... ...
392 9/1/2017 98.6154
393 10/1/2017 93.6137
394 11/1/2017 97.3359
395 12/1/2017 114.7212
396 1/1/2018 129.4048

397 rows × 2 columns

Palatekseni alkuperäiseen kysymykseen data alkuperästä, päivän formatoinnista voidaan päätellä että data-aineisto on mahdollisesti peräisin yhdysvalloista, Keniasta, Kanadasta, Ghanasta, Filippiineiltä. Togolta, Puerto Ricosta, Caymanin saarilta tai Grönlannista, koska se on muodossa kuukausi-päivä-vuosi. (https://en.wikipedia.org/wiki/List_of_date_formats_by_country).

Huomaamme myös että materiaali viimeinen päivitys on vuodelta 2018, eli emme pääse tutkimaan ajankohtaista aineistoa. Tämä liittyy oikeastaan siihen sähkön saatavuuden haasteisiin viime vuosina.

In [68]:
# Ajan muotoilu ei oikein ole mieleinen, loogista olisi että tämä olisi muodossa vuosi-kuukausi-päivä,
# jotta aineisto olisi helppolukuisempi. 

# Pandasin to_datetime funktio myös muutta aikaisemman merkkijonon tieodn aikaleimoiksi, jotta niitä pystyy helpommin käsittelemään.
electric_p_df.index=pd.to_datetime(electric_p_df['DATE'],format='%m/%d/%Y')
electric_p_df = electric_p_df.drop('DATE',axis=1)

# Tuosta IPG2211A2N nimi ei oikein ole esittelykelpoinen maallikolle (minulle tässä tapauksessa). Tuotannon määrä on myös hieman kysymysmerkki, joten ehkä turvallisinta käyttää muotoa TWh (TeraWattitunti)
# Nimetään siis IPG2211A2N uudestaan muotoon "Tuotanto (TWh)"
# Date nimi aiheuttaa nyt myös ongelman kielen puolesta, joten nimetään se muotoon "Vuosi-Kuukausi".

electric_p_df.rename(columns = {'IPG2211A2N': 'Tuotanto (TWh)'}, inplace=True)
electric_p_df.index.names = ['Vuosi-Kuukausi']
# Tarkistetaan muutokset
electric_p_df
Out[68]:
Tuotanto (TWh)
Vuosi-Kuukausi
1985-01-01 72.5052
1985-02-01 70.6720
1985-03-01 62.4502
1985-04-01 57.4714
1985-05-01 55.3151
... ...
2017-09-01 98.6154
2017-10-01 93.6137
2017-11-01 97.3359
2017-12-01 114.7212
2018-01-01 129.4048

397 rows × 1 columns

En nyt ihan varma onko tuo 'Vuosi-Kuukausi' nimi tyylikäin, mutta ainakin se kuvaava. Jatketaan sillä.

Voisi olettaa että sähkötuonannossa on trendi ja kausivaihtelu, vuosi vuodelta kulutus kasvaa ja syyrin kysyntä on talvisin. Tarkastellaan tätä hieman jotta voidaan todentaa onko epäilys oikein.

In [69]:
electric_p_df.plot()
Out[69]:
<Axes: xlabel='Vuosi-Kuukausi'>
No description has been provided for this image

Graaffista näemme että sähkön tuotanto kasvu on nousujohteinen ja voidaan kyllä päätellä että selkeitä kysyntä piikkejä on nähtävissä.

Koska voidaan nähdä että valitussa datassa on sekä tredi että kausivaihtelua, sopii tämän tutkimiseen parhaiten kolminkertainen eksponentiaalinen tasoitus (Holt-Winter menetelmä), mutta tarkastetaan tämä vielä varmuuden vuoksi.

In [70]:
electric_p_decompose = seasonal_decompose(electric_p_df['Tuotanto (TWh)']).plot()
No description has been provided for this image

Kyllä tässä hyvin esiintyy trendi sekä kausivaihtelu.

Aloitetaan rakentamaan ennustemallia, jos pystyisimme sen avulla luotettavammin ennustamaan sähköntuotannon kehtitystä.

Muodostetaan ennustemalli.

  • Käytetään trendiin summamallia.
  • Käytetään sekäkausivaihteluun tulomallia
    • Jälkihuomio Testailin näiden vaihtelua mutta näyttäisi että tämä yhdistelmä tuottaa parhaimman tuloksen jos vertailee ennustevirheitä.
  • kausijaksoiksi laitetaan 12 (kuukaudet vuodessa) ja tämä meneekin yhteen aineiston kanssa
  • Frekvenssiksi määritellään kuukauden alku.
In [71]:
model = ExponentialSmoothing(electric_p_df['Tuotanto (TWh)'],trend='add', seasonal='mul', seasonal_periods=12, freq='MS').fit()
electric_p_df['Ennuste'] = model.fittedvalues
# Tarkastetaan muutokset.
electric_p_df
Out[71]:
Tuotanto (TWh) Ennuste
Vuosi-Kuukausi
1985-01-01 72.5052 73.211512
1985-02-01 70.6720 67.503962
1985-03-01 62.4502 65.031167
1985-04-01 57.4714 56.983155
1985-05-01 55.3151 57.668310
... ... ...
2017-09-01 98.6154 99.641281
2017-10-01 93.6137 91.656919
2017-11-01 97.3359 96.281876
2017-12-01 114.7212 111.787369
2018-01-01 129.4048 122.277771

397 rows × 2 columns

In [72]:
# Silmäillään ennustemallin statistiikkaa vielä.
model.summary()
Out[72]:
ExponentialSmoothing Model Results
Dep. Variable: Tuotanto (TWh) No. Observations: 397
Model: ExponentialSmoothing SSE 2230.903
Optimized: True AIC 717.312
Trend: Additive BIC 781.054
Seasonal: Multiplicative AICC 719.121
Seasonal Periods: 12 Date: Mon, 11 Nov 2024
Box-Cox: False Time: 21:22:55
Box-Cox Coeff.: None
coeff code optimized
smoothing_level 0.6632327 alpha True
smoothing_trend 1.0455e-07 beta True
smoothing_seasonal 9.7566e-09 gamma True
initial_level 44.673831 l.0 True
initial_trend 0.0808268 b.0 True
initial_seasons.0 1.6358412 s.0 True
initial_seasons.1 1.5152704 s.1 True
initial_seasons.2 1.4132112 s.2 True
initial_seasons.3 1.2695042 s.3 True
initial_seasons.4 1.2752254 s.4 True
initial_seasons.5 1.4047853 s.5 True
initial_seasons.6 1.5246805 s.6 True
initial_seasons.7 1.5258281 s.7 True
initial_seasons.8 1.3820400 s.8 True
initial_seasons.9 1.2785931 s.9 True
initial_seasons.10 1.3228874 s.10 True
initial_seasons.11 1.5231780 s.11 True

Pikaisella silmäyksellä voisin sanoa että ennuste on ihan OK. Aineiston alusta ja lopusta ei ilmene mitään mahdottoman isoja heittoja, mutta tarkastetaan tämä vielä kaaviolla.

In [73]:
electric_p_df.plot()
Out[73]:
<Axes: xlabel='Vuosi-Kuukausi'>
No description has been provided for this image

Tarkastellaan vielä ennustevirheet mallista jotta saadaan selville onko tämä toimiva.

In [74]:
# Otetaan ennustemallin virheet omaksi sarakkeekseen.
electric_p_df['Ennustevirhe'] = model.resid
# Tarkastetaan lisäys
electric_p_df
Out[74]:
Tuotanto (TWh) Ennuste Ennustevirhe
Vuosi-Kuukausi
1985-01-01 72.5052 73.211512 -0.706312
1985-02-01 70.6720 67.503962 3.168038
1985-03-01 62.4502 65.031167 -2.580967
1985-04-01 57.4714 56.983155 0.488245
1985-05-01 55.3151 57.668310 -2.353210
... ... ... ...
2017-09-01 98.6154 99.641281 -1.025881
2017-10-01 93.6137 91.656919 1.956781
2017-11-01 97.3359 96.281876 1.054024
2017-12-01 114.7212 111.787369 2.933831
2018-01-01 129.4048 122.277771 7.127029

397 rows × 3 columns

Tarkastellaan vielä graaffilla miten ennuste pitää paikkaansa vertailuna toteutuneeseen.

In [75]:
electric_p_df['Ennustevirhe'].plot()
plt.ylabel('Ennustevirhe')
Out[75]:
Text(0, 0.5, 'Ennustevirhe')
No description has been provided for this image
In [76]:
sns.jointplot(data=electric_p_df, x='Ennuste', y='Tuotanto (TWh)', kind='reg')
Out[76]:
<seaborn.axisgrid.JointGrid at 0x23d7c152f90>
No description has been provided for this image

Pääasiassa malli ennustaa ihan hyvin, mutta huomaamme että muutamia virhepiikkejä esiintyy. Tätä Seabornin hajontakaaviota käytetään enemmän korrelaation osoittamiseen, mutta se osaltaan pystyy myös hyvin kuvaamaan miten hyvin ennuste pitää paikkaansa.

Ennusteen laskeminen¶

Kokeillaan laskea ennustemallilla ennuste viiden vuoden päähän datan viimeisestä merkinnästä.

In [77]:
# Tarkastetaan viimeisin päiväys.60
electric_p_df.tail()
Out[77]:
Tuotanto (TWh) Ennuste Ennustevirhe
Vuosi-Kuukausi
2017-09-01 98.6154 99.641281 -1.025881
2017-10-01 93.6137 91.656919 1.956781
2017-11-01 97.3359 96.281876 1.054024
2017-12-01 114.7212 111.787369 2.933831
2018-01-01 129.4048 122.277771 7.127029

Aloitamme siis helmikuusta 2018 ja tarkoitus olisi edetä tammihelmikuuhun 2023.

Ennusteen luominen

  • Määritellään alkavaksi päiväykseksi ensimmäinen helmikuuta 2018.
  • Ennusteen pituudeksi määritellään 60 kuukautta (viisi vuotta).
  • Frekvenssiksi määritellään kuukauden alku (niin kuin ennustemallin kanssa)
In [78]:
electric_p_forecast_range = pd.date_range('2018-02-01', periods=60, freq='MS')
electric_p_forecast = model.forecast(60)
# Määritellään ennusteen nimi kuvaavaksi
electric_p_forecast_df = pd.DataFrame(data=electric_p_forecast, index=electric_p_forecast_range, columns=['Tuotanto (TWh) ennuste'])
# Nimetään myös indeksi kuvaavasti.
electric_p_forecast_df.index.names = ['Vuosi-Kuukausi']
# Tarkastetaan tulokset.
electric_p_forecast_df
Out[78]:
Tuotanto (TWh) ennuste
Vuosi-Kuukausi
2018-02-01 117.766163
2018-03-01 109.948392
2018-04-01 98.870539
2018-05-01 99.419186
2018-06-01 109.633486
2018-07-01 119.113689
2018-08-01 119.326672
2018-09-01 108.193493
2018-10-01 100.198460
2018-11-01 103.776561
2018-12-01 119.611877
2019-01-01 128.591289
2019-02-01 119.235858
2019-03-01 111.319098
2019-04-01 100.101860
2019-05-01 100.656056
2019-06-01 110.996019
2019-07-01 120.592512
2019-08-01 120.806608
2019-09-01 109.533965
2019-10-01 101.438597
2019-11-01 105.059660
2019-12-01 121.089242
2020-01-01 130.177929
2020-02-01 120.705554
2020-03-01 112.689804
2020-04-01 101.333180
2020-05-01 101.892926
2020-06-01 112.358552
2020-07-01 122.071334
2020-08-01 122.286543
2020-09-01 110.874437
2020-10-01 102.678733
2020-11-01 106.342758
2020-12-01 122.566607
2021-01-01 131.764568
2021-02-01 122.175249
2021-03-01 114.060509
2021-04-01 102.564501
2021-05-01 103.129796
2021-06-01 113.721086
2021-07-01 123.550156
2021-08-01 123.766479
2021-09-01 112.214909
2021-10-01 103.918870
2021-11-01 107.625857
2021-12-01 124.043972
2022-01-01 133.351208
2022-02-01 123.644944
2022-03-01 115.431215
2022-04-01 103.795822
2022-05-01 104.366666
2022-06-01 115.083619
2022-07-01 125.028979
2022-08-01 125.246414
2022-09-01 113.555381
2022-10-01 105.159006
2022-11-01 108.908956
2022-12-01 125.521337
2023-01-01 134.937847

Tarkastellaan miltä mallennettu ennuste näyttää sähkötuotannon osalta.

In [79]:
electric_p_df['Tuotanto (TWh)'].plot()
electric_p_forecast_df['Tuotanto (TWh) ennuste'].plot()
Out[79]:
<Axes: xlabel='Vuosi-Kuukausi'>
No description has been provided for this image

Alustavasti ennuste näyttää ihan uskottavalta, mutta täytyy huomioida että vuodesta 2009 eteenpäin tuotannon nousu ei ole enää ollut niin suoraviivainen kuin ennen sitä ja tätä trendiä malli ei näytä ottavan huomioon. Voi siis olla että tuotantkokapasiteetti ei kasva enää samalla tavalla kuin ennen ja tästä syystä voisi olettaa että vaikka trendi onkin ollut nouseva tähän päivään asti, ei nousu ole enää jatkossa niin jyrkkä kuin ennuste antaa ymmärtää, vaikea sanoa.