Kelompok 4

Load Package

library("forecast")
## Warning in register(): Can't find generic `scale_type` in package ggplot2 to
## register S3 method.
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
library("graphics")
library("TTR")
library("TSA")
## Registered S3 methods overwritten by 'TSA':
##   method       from    
##   fitted.Arima forecast
##   plot.Arima   forecast
## 
## Attaching package: 'TSA'
## The following objects are masked from 'package:stats':
## 
##     acf, arima
## The following object is masked from 'package:utils':
## 
##     tar
library("readxl")

Membaca Dataset

Dataset yang digunakan yaitu Data_P2. Data_P2 terdiri dari dua variabel, yaitu period (periode waktu) dan data penjualan (sales). Data dapat dilihat pada tabel di bawah ini.

setwd("C:/Users/Radja Fikri/Documents/Tugas Kuliah/Tugas Kuliah/Semester 6/MPDW")
df2 = read_excel('Data/Data_P2.xlsx')
knitr::kable(head(df2))
Period Sales
1 10618.1
2 10537.9
3 10209.3
4 10553.0
5 9934.9
6 10534.5
str(df2)
## tibble [120 x 2] (S3: tbl_df/tbl/data.frame)
##  $ Period: num [1:120] 1 2 3 4 5 6 7 8 9 10 ...
##  $ Sales : num [1:120] 10618 10538 10209 10553 9935 ...
dim(df2)
## [1] 120   2
colSums(is.na(df2))
## Period  Sales 
##      0      0

Statistik deskriptif Data_P2 dapat dilihat pada tabel di bawah ini.

summary(df2)
##      Period           Sales      
##  Min.   :  1.00   Min.   : 9815  
##  1st Qu.: 30.75   1st Qu.:10210  
##  Median : 60.50   Median :10392  
##  Mean   : 60.50   Mean   :10379  
##  3rd Qu.: 90.25   3rd Qu.:10535  
##  Max.   :120.00   Max.   :10827

Mendefinisikan Data Deret Waktu

Pada R, data deret waktu dapat didefinisikan dengan menggunakan syntax ts().

data.ts = ts(df2[,2])
head(data.ts)
## Time Series:
## Start = 1 
## End = 6 
## Frequency = 1 
##        Sales
## [1,] 10618.1
## [2,] 10537.9
## [3,] 10209.3
## [4,] 10553.0
## [5,]  9934.9
## [6,] 10534.5

Eksplorasi Data Time Series Plot

ts.plot(data.ts, xlab="Period",
        ylab="Sales", main= "Time Series Plot of Sales")
points(data.ts)

Dari plot tersebut dapat kita lihat bahwa data series ini merupakan data yang stasioner karena tidak terlihat memiliki trend maupun seasonality. Titik-titik data terlihat menyebar secara acak dan terlihat bergerak secara horizontal.

Single Moving Average

Simple moving average adalah teknik pemulusan data dengan menggunakan beberapa data periode sebelumnya dan mengambil rata-ratanya. Pemulusan data dengan metode ini cocok ketika data yang akan dilakukan pemulusan sudah dalam bentuk stasioner, atau sudah menyebar secara acak tanpa ada seasonality. Pada kasus ini, nilai m, atau rentang data yang digunakan dalam proses ini, akan dicari nilai optimumnya. Nilai m yang optimum dapat diketahui dari beberapa perhitungan seperti MAPE (Mean Absolute Percentage Error), SSE (Sum Square Error), dan MSE (Mean Square Error) terkecil. Semakin kecil ketiga nilai tersebut, maka semakin akurat peramalan yang dihasilkan (Sungkawa dan Megastri 2011).

sma23 = SMA(data.ts,n=23)
forecast23 = c(NA,sma23)
pemulusan23=c(sma23,NA)
error.sma = data.ts-forecast23[1:length(data.ts)]
MAPE23 = mean(abs((error.sma[24:length(data.ts)]/data.ts[24:length(data.ts)])*100))
SSE23 = sum(error.sma[24:length(data.ts)]^2)
MSE23 = mean(error.sma[24:length(data.ts)]^2)

sma24 = SMA(data.ts,n=23)
forecast24 = c(NA,sma24)
pemulusan24=c(sma24,NA)
error.sma = data.ts-forecast24[1:length(data.ts)]
MAPE24 = mean(abs((error.sma[25:length(data.ts)]/data.ts[25:length(data.ts)])*100))
SSE24 = sum(error.sma[25:length(data.ts)]^2)
MSE24 = mean(error.sma[25:length(data.ts)]^2)

sma25 = SMA(data.ts,n=25)
forecast25 = c(NA,sma25)
pemulusan25=c(sma25,NA)
error.sma = data.ts-forecast25[1:length(data.ts)]
MAPE25 = mean(abs((error.sma[26:length(data.ts)]/data.ts[26:length(data.ts)])*100))
SSE25 = sum(error.sma[26:length(data.ts)]^2)
MSE25 = mean(error.sma[26:length(data.ts)]^2)

sma26 = SMA(data.ts,n=26)
forecast26 = c(NA,sma26)
pemulusan26=c(sma26,NA)
error.sma = data.ts-forecast26[1:length(data.ts)]
MAPE26 = mean(abs((error.sma[27:length(data.ts)]/data.ts[27:length(data.ts)])*100))
SSE26 = sum(error.sma[27:length(data.ts)]^2)
MSE26 = mean(error.sma[27:length(data.ts)]^2)

sma27 = SMA(data.ts,n=27)
forecast27 = c(NA,sma27)
pemulusan27=c(sma27,NA)
error.sma = data.ts-forecast27[1:length(data.ts)]
MAPE27 = mean(abs((error.sma[28:length(data.ts)]/data.ts[28:length(data.ts)])*100))
SSE27 = sum(error.sma[28:length(data.ts)]^2)
MSE27 = mean(error.sma[28:length(data.ts)]^2)
baris<- c('m=23','m=24','m=25','m=26','m=27')
akurasi.sma <-cbind("M" = baris, "MAPE"= c(MAPE23, MAPE24, MAPE25, MAPE26, MAPE27), "SSE"=c(SSE23,SSE24,SSE25,SSE26,SSE27), "MSE"=c(MSE23,MSE24,MSE25,MSE26,MSE27))
knitr::kable(akurasi.sma)
M MAPE SSE MSE
m=23 1.67124818777071 4424012.11446125 45608.3723140334
m=24 1.6627142298079 4360290.99005671 45419.6978130907
m=25 1.64995568036271 4232360.20289602 44551.1600304844
m=26 1.65592567938655 4202375.65118344 44706.12394876
m=27 1.66382923999482 4184774.64292181 44997.5768056109

Pada Single Moving Average didapatkan nilai MAPE dan MSE yang memiliki nilai error paling kecil yaitu ketika rentang m = 25.

Plot untuk peramalan dengan rentan m = 25 dapat dilihat pada grafik di bawah ini.

ramalan25 = c(forecast25,rep(forecast25[length(forecast25)],25))
ts.plot(data.ts, xlab="Period",
        ylab="Sales", main= "Single Moving Average Dengan Rentang m=25")
points(data.ts)
lines(pemulusan25,col="green",lwd=2)
lines(forecast25,col="red",lwd=2)
legend("topleft",c("data aktual","data pemulusan","data peramalan"), lty=8,
       col=c("black","green","red"), cex=0.8)

Hasil peramalan dapat dilihat di bawah ini.

data = cbind(aktual=c(data.ts,rep(NA,25)),pemulusan=c(sma25,rep(NA,25)),ramalan=c(ramalan25))
## Warning in cbind(aktual = c(data.ts, rep(NA, 25)), pemulusan = c(sma25, : number
## of rows of result is not a multiple of vector length (arg 1)
knitr::kable(tail(data,30))
aktual pemulusan ramalan
[117,] 10741.6 10430.48 10405.75
[118,] 10246.0 10421.81 10430.48
[119,] 10354.4 10427.76 10421.81
[120,] 10155.4 10413.07 10427.76
[121,] NA NA 10413.07
[122,] NA NA 10413.07
[123,] NA NA 10413.07
[124,] NA NA 10413.07
[125,] NA NA 10413.07
[126,] NA NA 10413.07
[127,] NA NA 10413.07
[128,] NA NA 10413.07
[129,] NA NA 10413.07
[130,] NA NA 10413.07
[131,] NA NA 10413.07
[132,] NA NA 10413.07
[133,] NA NA 10413.07
[134,] NA NA 10413.07
[135,] NA NA 10413.07
[136,] NA NA 10413.07
[137,] NA NA 10413.07
[138,] NA NA 10413.07
[139,] NA NA 10413.07
[140,] NA NA 10413.07
[141,] NA NA 10413.07
[142,] NA NA 10413.07
[143,] NA NA 10413.07
[144,] NA NA 10413.07
[145,] NA NA 10413.07
[146,] 10618.1 NA 10413.07

Double Moving Average

Prinsip dari double moving average sama dengan pada single moving average, dimana beberapa data pada periode sebelumnya diambil rata-ratanya. Hanya saja, pada double moving average, dilakukan proses single moving average kembali pada data yang sudah dilakukan proses single moving average sebelumnya. Sama seperti sebelumnya, nilai m optimum dicari dengan menggunakan perhitungan MAPE, SSE, dan MSE dengan mencari nilai m yang memberikan nilai terkecil untuk ketiga perhitungan tersebut.

data.sma<-SMA(data.ts, n=24)
dma24 <- SMA(data.sma, n = 24)
At <- 2*data.sma - dma24
Bt <- 2/(24-1)*(data.sma - dma24)
data.dma24<- At+Bt
data.ramal24<- c(NA, data.dma24)

t = 1:5
f = c()

for (i in t) {
  f[i] = At[length(At)] + Bt[length(Bt)]*(i)
}
error.dma = data.ts-data.ramal24[1:length(data.ts)]
MAPE24 = mean(abs((error.dma[48:length(data.ts)]/data.ts[48:length(data.ts)])*100))
SSE24 = sum(error.dma[48:length(data.ts)]^2)
MSE24 = mean(error.dma[48:length(data.ts)]^2)



data.sma<-SMA(data.ts, n=25)
dma25 <- SMA(data.sma, n = 25)
At <- 2*data.sma - dma25
Bt <- 2/(25-1)*(data.sma - dma25)
data.dma25<- At+Bt
data.ramal25<- c(NA, data.dma25)

t = 1:5
f = c()

for (i in t) {
  f[i] = At[length(At)] + Bt[length(Bt)]*(i)
}
error.dma = data.ts-data.ramal25[1:length(data.ts)]
MAPE25 = mean(abs((error.dma[50:length(data.ts)]/data.ts[50:length(data.ts)])*100))
SSE25 = sum(error.dma[50:length(data.ts)]^2)
MSE25 = mean(error.dma[50:length(data.ts)]^2)



data.sma<-SMA(data.ts, n=26)
dma26 <- SMA(data.sma, n = 26)
At <- 2*data.sma - dma26
Bt <- 2/(26-1)*(data.sma - dma26)
data.dma26<- At+Bt
data.ramal26<- c(NA, data.dma26)

t = 1:5
f = c()

for (i in t) {
  f[i] = At[length(At)] + Bt[length(Bt)]*(i)
}
error.dma = data.ts-data.ramal26[1:length(data.ts)]
MAPE26 = mean(abs((error.dma[52:length(data.ts)]/data.ts[52:length(data.ts)])*100))
SSE26 = sum(error.dma[52:length(data.ts)]^2)
MSE26 = mean(error.dma[52:length(data.ts)]^2)




data.sma<-SMA(data.ts, n=27)
dma27 <- SMA(data.sma, n = 27)
At <- 2*data.sma - dma27
Bt <- 2/(27-1)*(data.sma - dma27)
data.dma27<- At+Bt
data.ramal27<- c(NA, data.dma27)

t = 1:5
f = c()

for (i in t) {
  f[i] = At[length(At)] + Bt[length(Bt)]*(i)
}
error.dma = data.ts-data.ramal27[1:length(data.ts)]
MAPE27 = mean(abs((error.dma[54:length(data.ts)]/data.ts[54:length(data.ts)])*100))
SSE27 = sum(error.dma[54:length(data.ts)]^2)
MSE27 = mean(error.dma[54:length(data.ts)]^2)



data.sma<-SMA(data.ts, n=28)
dma28 <- SMA(data.sma, n = 28)
At <- 2*data.sma - dma28
Bt <- 2/(28-1)*(data.sma - dma28)
data.dma28<- At+Bt
data.ramal28<- c(NA, data.dma28)

t = 1:5
f = c()

for (i in t) {
  f[i] = At[length(At)] + Bt[length(Bt)]*(i)
}
error.dma = data.ts-data.ramal28[1:length(data.ts)]
MAPE28 = mean(abs((error.dma[56:length(data.ts)]/data.ts[56:length(data.ts)])*100))
SSE28 = sum(error.dma[56:length(data.ts)]^2)
MSE28 = mean(error.dma[56:length(data.ts)]^2)
baris<- c('m=24','m=25','m=26','m=27','m=28')
akurasi.dma <-cbind("M" = baris, "MAPE"= c(MAPE24, MAPE25, MAPE26, MAPE27, MAPE28), "SSE"=c(SSE24,SSE25,SSE26,SSE27,SSE28), "MSE"=c(MSE24,MSE25,MSE26,MSE27,MSE28))
knitr::kable(akurasi.dma)
M MAPE SSE MSE
m=24 1.73506500078678 3627979.40339164 49698.3479916664
m=25 1.73437878003934 3608649.27616209 50826.046143128
m=26 1.66590633881641 3161325.44135142 45816.3107442235
m=27 1.70997073175906 3176364.07798257 47408.4190743668
m=28 1.71845450807912 3182114.66376946 48955.6102118378

Pada Double Moving Average didapatkan nilai MAPE dan MSE yang memiliki nilai error paling kecil yaitu ketika rentang m = 26

ramalan26 = c(data.ramal26,rep(data.ramal26[length(data.ramal26)],26))
ts.plot(data.ts, xlab="Period",
        ylab="Sales", main= "Double Moving Average Dengan Rentang m=26")
points(data.ts)
lines(dma26,col="green",lwd=2)
lines(data.ramal26,col="red",lwd=2)
legend("topleft",c("data aktual","data pemulusan","data peramalan"), lty=8,
       col=c("black","green","red"), cex=0.8)

Hasil ramalan dapat dilihat pada tabel di bawah ini.

data = cbind(aktual=c(data.ts,rep(NA,26)),pemulusan=c(dma26,rep(NA,25)),ramalan=c(ramalan26))
## Warning in cbind(aktual = c(data.ts, rep(NA, 26)), pemulusan = c(dma26, : number
## of rows of result is not a multiple of vector length (arg 1)
knitr::kable(tail(data,30))
aktual pemulusan ramalan
[118,] 10246.0 10386.35 10456.24
[119,] 10354.4 10388.46 10463.38
[120,] 10155.4 10390.73 10452.43
[121,] NA NA 10445.97
[122,] NA NA 10445.97
[123,] NA NA 10445.97
[124,] NA NA 10445.97
[125,] NA NA 10445.97
[126,] NA NA 10445.97
[127,] NA NA 10445.97
[128,] NA NA 10445.97
[129,] NA NA 10445.97
[130,] NA NA 10445.97
[131,] NA NA 10445.97
[132,] NA NA 10445.97
[133,] NA NA 10445.97
[134,] NA NA 10445.97
[135,] NA NA 10445.97
[136,] NA NA 10445.97
[137,] NA NA 10445.97
[138,] NA NA 10445.97
[139,] NA NA 10445.97
[140,] NA NA 10445.97
[141,] NA NA 10445.97
[142,] NA NA 10445.97
[143,] NA NA 10445.97
[144,] NA NA 10445.97
[145,] NA NA 10445.97
[146,] NA NA 10445.97
[147,] 10618.1 NA 10445.97

Kesimpulan

Dengan metode Single Moving Average, diketahui SSE, MSE, dan MAPE bernilai lebih kecil maka Metode SMA lebih baik digunakan. Selain itu bentuk data series yang tidak memiliki trend sehingga metode SMA lebih cocok digunakan.

Daftar Pustaka

Megasari RT, Sungkawa I. 2011. Penerapan ukuran ketepatan nilai ramalan data deret waktu dalam seleksi model peramalan volume penjualan PT. Satriamandiri Citramulia. J ComTech. 2(2) : 636 – 645.