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:
Etsi (search) haluamasi yritys esim NOKIA.HE
Klikkaa "Historical Data
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.
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.
# 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.
ethereum_d
| 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ää.
bitcoin_d
| 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'.
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])
<Axes: xlabel='Date'>
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.
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])
<Axes: xlabel='Date'>
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.
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])
<Axes: xlabel='Date'>
Aggregoidaan tämä kuukaisitasolle.
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])
<Axes: xlabel='Date'>
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.
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])
<Axes: xlabel='Date'>
Vaikka graafia saatinkin mukavasti tasoitettua, kokeillaan hieman pidempää aikaväliä, vaikka vuosineljännes (~ 90 päivää).
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])
<Axes: xlabel='Date'>
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.
# 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()
| 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 |
ethereum_d.head()
| 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 |
# 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
| 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.
value_changes[(abs(value_changes['Bitcoin_value_change_%']) >10) | abs(value_changes['Ethereum_value_change_%'] > 10)]
| 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.
value_changes.corr()
| 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.
#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()
<Axes: xlabel='Date'>
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.
# 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
| 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
ethereum_value_change_volume
| 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ä.
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
| 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.
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
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.
sns.jointplot(data=bitcoin_value_change_volume, x='Bitcoin_value_change_%', y='Volume', kind='reg')
<seaborn.axisgrid.JointGrid at 0x23d74f75f30>
sns.jointplot(data=ethereum_value_change_volume, x='Ethereum_value_change_%', y='Volume', kind='reg')
<seaborn.axisgrid.JointGrid at 0x23d74f75e00>
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.
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)
<Axes: xlabel='Date'>
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.
# 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
| 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.
# 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
| 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.
electric_p_df.plot()
<Axes: xlabel='Vuosi-Kuukausi'>
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.
electric_p_decompose = seasonal_decompose(electric_p_df['Tuotanto (TWh)']).plot()
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.
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
| 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
# Silmäillään ennustemallin statistiikkaa vielä.
model.summary()
| 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.
electric_p_df.plot()
<Axes: xlabel='Vuosi-Kuukausi'>
Tarkastellaan vielä ennustevirheet mallista jotta saadaan selville onko tämä toimiva.
# Otetaan ennustemallin virheet omaksi sarakkeekseen.
electric_p_df['Ennustevirhe'] = model.resid
# Tarkastetaan lisäys
electric_p_df
| 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.
electric_p_df['Ennustevirhe'].plot()
plt.ylabel('Ennustevirhe')
Text(0, 0.5, 'Ennustevirhe')
sns.jointplot(data=electric_p_df, x='Ennuste', y='Tuotanto (TWh)', kind='reg')
<seaborn.axisgrid.JointGrid at 0x23d7c152f90>
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ä.
# Tarkastetaan viimeisin päiväys.60
electric_p_df.tail()
| 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)
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
| 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.
electric_p_df['Tuotanto (TWh)'].plot()
electric_p_forecast_df['Tuotanto (TWh) ennuste'].plot()
<Axes: xlabel='Vuosi-Kuukausi'>
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.