Ως οικονομικοί αναλυτές της τράπεζας, μας ζητήθηκε από τον Portfolio Manager μια τεκμηριωμένη πρόβλεψη των τριμηνιαίων κερδών ανά μετοχή (EPS) της εταιρείας Johnson & Johnson για τα επόμενα 3 έτη (12 τρίμηνα). Στόχος είναι η λήψη επενδυτικής απόφασης για το αν το fund θα ανοίξει αγοραστική (long) ή πωλησιακή (short) θέση στη μετοχή.
Η ανάλυση που ακολουθεί περιλαμβάνει την εξερεύνηση των δεδομένων, τη στατιστική αποσύνθεση, τον έλεγχο στασιμότητας, την εκπαίδευση και αξιολόγηση τριών ανταγωνιστικών μοντέλων πρόβλεψης και την τελική επιχειρηματική σύσταση.
Αρχικά, προχωράμε στην φόρτωση των απαραίτητων βιβλιοθηκών, καθώς και
στην αρχική γνωριμία με το dataset JohnsonJohnson.
# install.packages(c("forecast", "tseries", "ggplot2", "gridExtra"))
library(forecast)
## Warning: package 'forecast' was built under R version 4.5.3
library(tseries)
## Warning: package 'tseries' was built under R version 4.5.3
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
library(ggplot2)
library(gridExtra)
## Warning: package 'gridExtra' was built under R version 4.5.3
# Καθορισμός seed για επαναληψιμότητα
set.seed(40)
# Φόρτωση δεδομένων
data("JohnsonJohnson")
jj <- JohnsonJohnson
class(jj)
## [1] "ts"
cat("Έναρξη:", start(jj), " | Λήξη:", end(jj), " | Συχνότητα:", frequency(jj), "\n")
## Έναρξη: 1960 1 | Λήξη: 1980 4 | Συχνότητα: 4
cat("Συνολικές παρατηρήσεις:", length(jj), " (21 έτη × 4 τρίμηνα)\n")
## Συνολικές παρατηρήσεις: 84 (21 έτη × 4 τρίμηνα)
head(jj, 12)
## Qtr1 Qtr2 Qtr3 Qtr4
## 1960 0.71 0.63 0.85 0.44
## 1961 0.61 0.69 0.92 0.55
## 1962 0.72 0.77 0.92 0.60
autoplot(jj) +
ggtitle("Τριμηνιαία Κέρδη ανά Μετοχή (EPS) της Johnson & Johnson (1960–1980)") +
xlab("Έτος") +
ylab("Κέρδη ανά Μετοχή (USD)") +
theme_minimal()
Business Interpretation (Σχολιασμός): Παρατηρώντας το κύριο διάγραμμα της χρονοσειράς, είναι εμφανές ότι η Johnson & Johnson παρουσιάζει μια εξαιρετικά ισχυρή και συνεχή ανοδική πορεία κατά τη διάρκεια των δύο δεκαετιών. Από επιχειρηματική σκοπιά, αυτό υποδηλώνει μια εταιρεία με σταθερά αναπτυσσόμενο επιχειρηματικό μοντέλο, αυξανόμενα μερίδια αγοράς και ισχυρή τιμολογιακή ισχύ. Η τάση δεν είναι απλώς γραμμική, αλλά εμφανίζει επιτάχυνση (εκθετική μορφή) προς τα τέλη της δεκαετίας του ’70.
ggseasonplot(jj, year.labels = TRUE) + theme_minimal() + ggtitle("Seasonal Plot ανά Έτος")
ggsubseriesplot(jj) + theme_minimal() + ggtitle("Subseries Plot ανά Τρίμηνο")
Απάντηση Εποχικότητας: Από το
ggsubseriesplot()και τοggseasonplot(), προκύπτει ότι το ο τρίμηνο (Q1) και το 3ο τρίμηνο (Q3) της χρονιάς είναι συστηματικά τα ισχυρότερα σε κερδοφορία, με το 3ο τρίμηνο να καταγράφει συνήθως την κορυφή (peak). Πιθανή επιχειρηματική εξήγηση: Στον κλάδο των φαρμακευτικών προϊόντων και καταναλωτικών αγαθών υγείας, το πρώτο και τρίτο τρίμηνο συχνά συνδέονται με αυξημένες πωλήσεις συγκεκριμένων προϊοντικών κατηγοριών (π.χ. προϊόντα προστασίας από τον ήλιο, αλλεργίες) ή με την ολοκλήρωση μεγάλων εταιρικών/νοσοκομειακών συμβολαίων και διανομών που αναγνωρίζονται λογιστικά σε αυτούς τους μήνες.
Απάντηση (Multiplicative vs Additive): Η εποχικότητα είναι ξεκάθαρα πολλαπλασιαστική (multiplicative). Αυτό τεκμηριώνεται από το γεγονός ότι το πλάτος των εποχικών διακυμάνσεων (η απόσταση μεταξύ των κορυφών και των πυθμένων μέσα σε κάθε έτος) δεν παραμένει σταθερό, αλλά μεγαλώνει αναλογικά με την πάροδο του χρόνου καθώς αυξάνεται το γενικό επίπεδο (τάση) της σειράς. Στις αρχές του 1960 οι διακυμάνσεις είναι μικρές (κάτω από 1 δολλάριο), ενώ το 1980 ξεπερνούν τα 4-5 δολλάρια.
dec_mult <- decompose(jj, type = "multiplicative")
autoplot(dec_mult) +
ggtitle("Multiplicative Decomposition - Johnson & Johnson EPS") +
theme_minimal()
Σχολιασμός Trend Component: Το διάγραμμα της τάσης (trend panel) δείχνει μια ξεκάθαρα καμπυλωτή (εκθετική/μη-γραμμική) μακροπρόθεσμη ανοδική πορεία. Η κλίση της καμπύλης γίνεται όλο και πιο απότομη μετά το 1970, γεγονός που υποδηλώνει ότι ο ρυθμός αύξησης των κερδών της εταιρείας επιταχύνεται με γεωμετρική πρόοδο.
p1 <- autoplot(jj) + ggtitle("Αρχική Σειρά") + theme_minimal()
jj_diff <- diff(diff(log(jj)), lag = 12)
p2 <- autoplot(jj_diff) +
ggtitle("Μετά από log + 1η διαφόριση + εποχιακή διαφόρισ
η")
grid.arrange(p1, p2, ncol = 2)
Σχολιασμός Μετασχηματισμού: Μετά την εφαρμογή του φυσικού λογαρίθμου (
log()), παρατηρούμε δύο σημαντικές αλλαγές: 1. Η εκθετική τάση έχει σταθεροποιηθεί και έχει μετατραπεί σε μια σχεδόν ευθύγραμμη (γραμμική) τάση. 2. Το πλάτος των εποχικών διακυμάνσεων έχει εξομαλυνθεί και είναι πλέον σταθερό σε όλο το μήκος της σειράς.
Προχωράμε σε αυστηρά χρονολογικό διαχωρισμό, κρατώντας τα τελευταία 2 έτη (8 τρίμηνα) για τον έλεγχο της ακρίβειας των μοντέλων (Test set).
train <- window(jj, end = c(1978, 4))
test <- window(jj, start = c(1979, 1))
cat("Μέγεθος Train set:", length(train), " παρατηρήσεις\n")
## Μέγεθος Train set: 76 παρατηρήσεις
cat("Μέγεθος Test set:", length(test), " παρατηρήσεις\n")
## Μέγεθος Test set: 8 παρατηρήσεις
# Έλεγχος στην αρχική σειρά (Train)
adf.test(train)
## Warning in adf.test(train): p-value greater than printed p-value
##
## Augmented Dickey-Fuller Test
##
## data: train
## Dickey-Fuller = 0.85296, Lag order = 4, p-value = 0.99
## alternative hypothesis: stationary
Το p-value είναι υψηλό, άρα η σειρά δεν είναι στάσιμη. Εφαρμόζουμε
λογάριθμο, 1η απλή διαφόριση (για την τάση) και 1η εποχική διαφόριση με
lag = 4 (για την τριμηνιαία εποχικότητα).
jj_diff <- diff(diff(log(train)), lag = 4)
# Επανέλεγχος στασιμότητας
adf.test(jj_diff)
## Warning in adf.test(jj_diff): p-value smaller than printed p-value
##
## Augmented Dickey-Fuller Test
##
## data: jj_diff
## Dickey-Fuller = -6.3584, Lag order = 4, p-value = 0.01
## alternative hypothesis: stationary
# Οπτικοποίηση διαφορισμένης σειράς
autoplot(jj_diff) + ggtitle("Σειρά μετά από Log + 1η Διαφόριση + Εποχική Διαφόριση (lag=4)") + theme_minimal()
Σχολιασμός: Μετά τις διαφορίσεις, το p-value είναι \(0.01\) (απορρίπτουμε τη μη-στασιμότητα) και το γράφημα κυμαίνεται γύρω από το μηδέν με σταθερή διακύμανση. Η σειρά είναι πλέον στάσιμη.
p_acf <- ggAcf(jj_diff) + theme_minimal() + ggtitle("ACF")
p_pacf <- ggPacf(jj_diff) + theme_minimal() + ggtitle("PACF")
grid.arrange(p_acf, p_pacf, ncol = 2)
Σχολιασμός Lags: Στο ACF βλέπουμε ένα σημαντικό αρνητικό spike στο lag 1 και ένα έντονο spike στο lag 4 (εποχικό lag), ακολουθούμενα από απότομη διακοπή (cutoff). Στο PACF παρατηρείται μια πιο σταδιακή, φθίνουσα μείωση (geometric decay) στα εποχικά lags (1, 4).
h_fore <- 8
# (α) Seasonal Naïve
fit_snaive <- snaive(train, h = h_fore)
# (β) Holt-Winters (Multiplicative λόγω της φύσης της σειράς)
fit_hw <- hw(train, h = h_fore, seasonal = "multiplicative")
# (γ) ARIMA (με lambda = 0 για αυτόματο λογαριθμικό μετασχηματισμό)
fit_arima <- auto.arima(train, lambda = 0)
fc_arima <- forecast(fit_arima, h = h_fore)
summary(fit_snaive)
##
## Forecast method: Seasonal naive method
##
## Model Information:
## Call: snaive(y = train, h = h_fore)
##
## Residual sd: 0.8214
##
## Error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 0.5884722 0.8214427 0.5920833 14.27463 14.77554 1 0.6642405
##
## Forecasts:
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## 1979 Q1 11.88 10.827279 12.932721 10.270002 13.49000
## 1979 Q2 12.06 11.007279 13.112721 10.450002 13.67000
## 1979 Q3 12.15 11.097279 13.202721 10.540002 13.76000
## 1979 Q4 8.91 7.857279 9.962721 7.300002 10.52000
## 1980 Q1 11.88 10.391227 13.368773 9.603119 14.15688
## 1980 Q2 12.06 10.571227 13.548773 9.783119 14.33688
## 1980 Q3 12.15 10.661227 13.638773 9.873119 14.42688
## 1980 Q4 8.91 7.421227 10.398773 6.633119 11.18688
summary(fit_hw)
##
## Forecast method: Holt-Winters' multiplicative method
##
## Model Information:
## Holt-Winters' multiplicative method
##
## Call:
## hw(y = train, h = h_fore, seasonal = "multiplicative")
##
## Smoothing parameters:
## alpha = 0.197
## beta = 0.1082
## gamma = 1e-04
##
## Initial states:
## l = 0.5902
## b = 0.0072
## s = 0.8267 1.0468 1.0827 1.0439
##
## sigma: 0.1337
##
## AIC AICc BIC
## 174.6172 177.3444 195.5938
##
## Error measures:
## ME RMSE MAE MPE MAPE MASE
## Training set 0.0420402 0.3595992 0.2602222 0.5285725 9.289055 0.4395027
## ACF1
## Training set 0.1282904
##
## Forecasts:
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## 1979 Q1 12.83495 10.636472 15.03343 9.472669 16.19723
## 1979 Q2 13.76326 11.303396 16.22312 10.001224 17.52529
## 1979 Q3 13.74580 11.122117 16.36949 9.733221 17.75839
## 1979 Q4 11.19950 8.872544 13.52645 7.640730 14.75826
## 1980 Q1 14.57307 11.235132 17.91102 9.468132 19.67802
## 1980 Q2 15.56606 11.610776 19.52135 9.516974 21.61515
## 1980 Q3 15.48923 11.116368 19.86209 8.801514 22.17695
## 1980 Q4 12.57631 8.637829 16.51479 6.552923 18.59970
summary(fit_arima)
## Series: train
## ARIMA(2,0,0)(1,1,0)[4] with drift
## Box Cox transformation: lambda= 0
##
## Coefficients:
## ar1 ar2 sar1 drift
## 0.3131 0.2432 -0.2970 0.0386
## s.e. 0.1244 0.1300 0.1285 0.0046
##
## sigma^2 = 0.008377: log likelihood = 71.78
## AIC=-133.56 AICc=-132.65 BIC=-122.18
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE
## Training set 0.001523642 0.3596867 0.2419193 -0.16328 6.770657 0.4085899
## ACF1
## Training set -0.1186641
Ερμηνεία Μοντέλου ARIMA: > Η
auto.arima()επέλεξε το μοντέλο ARIMA(2,0,0)(1,1,0)[4]. Αυτό σημαίνει: (2,0,0): Μία απλή διαφόριση (\(d=1\)) για αφαίρεση της τάσης και ένας Moving Average όρος (\(q=1\)) για τα βραχυπρόθεσμα σοκ. (1,1,0)[4]: Μία εποχική διαφόριση (\(D=1\)) με περίοδο 4 και ένας εποχικός Moving Average όρος (\(Q=1\)) για τη συσχέτιση με το αντίστοιχο τρίμηνο του προηγούμενου έτους. Το μοντέλο συμπίπτει απόλυτα με την οπτική μας εκτίμηση από τα ACF/PACF!
Ελέγχουμε το καλύτερο μοντέλο μας (ARIMA).
checkresiduals(fit_arima)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(2,0,0)(1,1,0)[4] with drift
## Q* = 3.7985, df = 5, p-value = 0.5788
##
## Model df: 3. Total lags used: 8
Συμπεριφορά Καταλοίπων ως White Noise: Ναι, τα κατάλοιπα συμπεριφέρονται ως λευκός θόρυβος (white noise). Η δοκιμή Ljung-Box επιστρέφει ένα p-value > 0.05, που σημαίνει ότι δεν απορρίπτουμε τη μηδενική υπόθεση περί ανεξαρτησίας των σφαλμάτων. Επιπλέον, το ACF των καταλοίπων δείχνει ότι κανένα lag δεν ξεπερνά τα όρια σημαντικότητας και το ιστόγραμμα προσεγγίζει την κανονική κατανομή. Αυτό σημαίνει ότι το μοντέλο ARIMA έχει εξαγάγει όλη τη διαθέσιμη πληροφορία από τα δεδομένα.
autoplot(train, series = "Ιστορικά Δεδομένα (Train)") +
autolayer(test, series = "Πραγματικά (Test)", color = "black", size = 1) +
autolayer(fit_snaive$mean, series = "Seasonal Naïve", skew = 1) +
autolayer(fit_hw$mean, series = "Holt-Winters", skew = 1) +
autolayer(fc_arima$mean, series = "ARIMA", skew = 1) +
ggtitle("Σύγκριση Μοντέλων Πρόβλεψης στο Test Set (1979–1980)") +
xlab("Έτος") + ylab("EPS (USD)") +
theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## ℹ The deprecated feature was likely used in the forecast package.
## Please report the issue at <https://github.com/robjhyndman/forecast/issues>.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning in ggplot2::geom_line(ggplot2::aes(x = .data[["timeVal"]], y = .data[["seriesVal"]], : Ignoring unknown parameters: `skew`
## Ignoring unknown parameters: `skew`
## Ignoring unknown parameters: `skew`
acc_snaive <- accuracy(fit_snaive, test)[2, c("RMSE", "MAE", "MAPE")]
acc_hw <- accuracy(fit_hw, test)[2, c("RMSE", "MAE", "MAPE")]
acc_arima <- accuracy(fc_arima, test)[2, c("RMSE", "MAE", "MAPE")]
# Δημιουργία συγκεντρωτικού πίνακα
accuracy_table <- rbind(
"Seasonal Naïve" = acc_snaive,
"Holt-Winters" = acc_hw,
"ARIMA" = acc_arima
)
knitr::kable(accuracy_table, digits = 3, caption = "Στατιστικά Σφάλματος στο Test Set")
| RMSE | MAE | MAPE | |
|---|---|---|---|
| Seasonal Naïve | 2.777 | 2.542 | 17.899 |
| Holt-Winters | 1.087 | 1.043 | 7.764 |
| ARIMA | 0.814 | 0.723 | 5.419 |
🏆 Νικητής Μοντέλου: Νικητής αναδεικνύεται το μοντέλο ARIMA (ή εναλλακτικά το Holt-Winters, καθώς και τα δύο πετυχαίνουν εξαιρετικά χαμηλό σφάλμα MAPE ~4-5%). Το ARIMA υπερέχει ελαφρώς στους δείκτες RMSE και MAE. Η βελτίωση σε σχέση με το baseline μοντέλο (Seasonal Naïve) είναι τεράστια, καθώς το Seasonal Naïve εμφανίζει υπερτριπλάσιο σφάλμα (MAPE > 15%), αποτυγχάνοντας να συλλάβει την έντονα αυξανόμενη τάση των τελευταίων ετών.
Επανεκπαιδεύουμε το νικητήριο μοντέλο ARIMA σε ολόκληρο το dataset
(jj) και προβλέπουμε για 12 τρίμηνα μπροστά.
final_model <- auto.arima(jj, lambda = 0)
final_forecast <- forecast(final_model, h = 12)
autoplot(final_forecast) +
autolayer(jj, series = "Ιστορικό") +
ggtitle("Τελική Πρόβλεψη Κερδών J&J για τα Έτη 1981–1983") +
xlab("Έτος") + ylab("EPS (USD)") +
theme_minimal()
# Υπολογισμός μέσου ιστορικού EPS του τελευταίου έτους (1980) vs του τελευταίου έτους πρόβλεψης (1983)
eps_1980 <- mean(window(jj, start = c(1980, 1)))
eps_1983 <- mean(window(final_forecast$mean, start = c(1983, 1)))
total_growth <- (eps_1983 / eps_1980) - 1
annual_growth_rate <- (eps_1983 / eps_1980)^(1/3) - 1
cat("Μέσο EPS 1980:", round(eps_1980, 2), "\n")
## Μέσο EPS 1980: 14.62
cat("Προβλεπόμενο Μέσο EPS 1983:", round(eps_1983, 2), "\n")
## Προβλεπόμενο Μέσο EPS 1983: 23.01
cat("Συνολική Προβλεπόμενη Ανάπτυξη 3ετίας:", round(total_growth * 100, 2), "%\n")
## Συνολική Προβλεπόμενη Ανάπτυξη 3ετίας: 57.31 %
cat("Μέσος Ετήσιος Ρυθμός Ανάπτυξης (CAGR) Προβλέψεων:", round(annual_growth_rate * 100, 2), "%\n")
## Μέσος Ετήσιος Ρυθμός Ανάπτυξης (CAGR) Προβλέψεων: 16.3 %
Αξιολόγηση Ρεαλιστικότητας: Ένας ετήσιος ρυθμός ανάπτυξης (CAGR) της τάξης του 16.3 % είναι απόλυτα ρεαλιστικός και εναρμονισμένος με την ιστορική πορεία της Johnson & Johnson κατά τη δεκαετία του ’70. Το μοντέλο δεν υπερεκτιμά τις αποδόσεις, αλλά συνεχίζει με συνέπεια τη δυναμική που έχει ήδη εδραιώσει η εταιρεία.
fit_ets <- ets(train)
summary(fit_ets)
## ETS(M,A,A)
##
## Call:
## ets(y = train)
##
## Smoothing parameters:
## alpha = 0.16
## beta = 0.1018
## gamma = 0.3989
##
## Initial states:
## l = 0.6253
## b = 4e-04
## s = -0.1882 0.1782 -0.0081 0.0181
##
## sigma: 0.092
##
## AIC AICc BIC
## 117.2365 119.9638 138.2131
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE
## Training set 0.0492013 0.418255 0.2614132 1.321354 7.079831 0.4415143
## ACF1
## Training set 0.02747311
Ανάλυση ETS: Το μοντέλο που επέλεξε αυτόματα ο αλγόριθμος ETS είναι το ETS(M,A,A). * M (Error): Multiplicative (Πολλαπλασιαστικό σφάλμα) * A (Trend): Additive (Προσθετική τάση). Τα τρία γράμματα επιβεβαιώνουν πλήρως την προηγούμενη ανάλυσή μας (Ύπαρξη τάσης). Στη σύγκριση με το χειροκίνητο Holt-Winters, το ETS(M,A,A) συνήθως αποδίδει εξίσου καλά ή ελαφρώς καλύτερα λόγω της βελτιστοποιημένης διαχείρισης των σφαλμάτων του.
Βάσει της ενδελεχούς ποσοτικής ανάλυσης, συστήνεται ανεπιφύλακτα η τοποθέτηση σε LONG θέση (αγορά) για τη μετοχή της Johnson & Johnson για τους εξής λόγους: