options(scipen = 123)
library(forecast)
library(tidyverse)
library(fpp)
library(TTR)
library(MLmetrics)
library(tseries)
library(lubridate)
library(scales)
library(readr)
library(dplyr)
library(TSstudio)
library(xts)
library(ggplot2)
set.seed(13)Dataset metal adalah data yang di-subset dari data Reckup Control Tab PT. Metalsindo Pacific. Perusahaan yang bergerak dibidang trading tembaga dan Kuningan berkualitas. Selain Tembaga dan Kuningan, perusahaan ini juga menyuplai jenis material Stainless dan beberapa jenis material ferrous metal dan non-ferrous metal. PT.MP membantu menyediakan kebutuhan material Tembaga(Copper) dan Kuningan (Brass) untuk kelancaran usaha di bidang metal stamping. Beberapa jenis Copper and Copper alloy yang tersedia di PT. MP, C1100, C1020, C1030, C1070, C2600, C2680, C2801. Jenis Stainless Steel tersedia mulai dari alloy SUS 301, SUS 304, SUS 316, SUS310 SUS 430, SUS409 Dll. Di Warehasue juga menyediakan material Carbon steel, S45, S55, S60 dll, SGCC, SPCC, SPHC PO dll Selain menyediakan Copper and copper alloy, perusahaan ini juga bisa melakukan slitting dengan lebar min 8mm s.d 400mm, semua material berbentuk lembaran koil. Aktivitas manufakturingnya adalah bidang Slitting dan Shearing Industry untuk raw material yang disupplai ke pabrik automotif, elektronik, dan elektrik di kawasan di Indonesia.
Dengan maksud menganalisa data sales metal dalam rentang waktu tiga tahun terakhir, kami bertujuan mengklarifikasi distribusi atau suplai penggunaan material kuningan, tembaga, stainless dan lainya. Melalui data metal ini kita dapat mengetahui jenis, komposisi raw material, berikut trend, dan seasonal pemakaian raw material untuk perusahaan automotif, elektronik, dan elektrik. Oleh karena itu alangkah tepatnya bila analisis ini berkontribusi pada para trader dan importir.
Data metal berisi ringkasan data inventory pada periode 2017 hingga 2019 dan tidak bersifat konfidensial. Karena akurasi konfidensial data hanya 25%, atau 9 bulan di tahun 2018, selebihnya adalah data markup yang bersifat menyerupai orisinilitas data.Namun data metal bukan berarti data duplikat yang telah direkayasa.
Analisa data metal ini adalah sebagai bahan latihan yang ditugaskan oleh Algoritma Data Science dengan untuk materi Time Series. Mudah-mudahan dengan tugas latihan yang kami kerjakan dapat melatih dan memahami materi lebih baik lagi. Sekaligus memberi pengetahuan baru dari sudut padang yang baru.
## X Date Type Alloy.Type Thick.mm Hard TotalSales_Kg
## 1 1 2017-01-30 BRASS BSR C2680 0.35 3/4H 0.0
## 2 2 2017-01-30 BRASS BSR C2680 0.40 1/2H 0.0
## 3 3 2017-01-30 BRASS BSR C2680 0.45 1/2H 0.0
## 4 4 2017-01-30 BRASS BSR C2680 0.50 1/2H 1825.4
## 5 5 2017-01-30 BRASS BSR C2680 0.50 EH 0.0
## 6 6 2017-01-30 BRASS BSR C2680 0.55 1/2H 0.0
## 'data.frame': 1944 obs. of 7 variables:
## $ X : int 1 2 3 4 5 6 7 8 9 10 ...
## $ Date : Factor w/ 36 levels "2017-01-30","2017-02-28",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ Type : Factor w/ 4 levels "BRASS","COPPER",..: 1 1 1 1 1 1 1 1 1 1 ...
## $ Alloy.Type : Factor w/ 23 levels "BSR 2600","BSR C2680",..: 2 2 2 2 2 2 2 2 2 2 ...
## $ Thick.mm : num 0.35 0.4 0.45 0.5 0.5 0.55 0.7 0.8 0.8 0.9 ...
## $ Hard : Factor w/ 12 levels "-","1/2H","1/2H - TP",..: 7 2 2 2 9 2 2 2 3 2 ...
## $ TotalSales_Kg: num 0 0 0 1825 0 ...
## [1] "Date"
## X Date Type Alloy.Type Thick.mm Hard TotalSales_Kg
## 1 1 2017-01-30 BRASS BSR C2680 0.35 3/4H 0.0
## 2 2 2017-01-30 BRASS BSR C2680 0.40 1/2H 0.0
## 3 3 2017-01-30 BRASS BSR C2680 0.45 1/2H 0.0
## 4 4 2017-01-30 BRASS BSR C2680 0.50 1/2H 1825.4
## 5 5 2017-01-30 BRASS BSR C2680 0.50 EH 0.0
## 6 6 2017-01-30 BRASS BSR C2680 0.55 1/2H 0.0
Pembersihan data atau Data Cleansing adalah proses mendeteksi dan memperbaiki (atau menghapus) data yang rusak, tidak akurat, atau kosong (NA) dengan cara mengatur kembali data-data yang ada pada catatan, tabel atau basis data. Data Cleansing atau Data Cleaning juga biasa disebut Data Scrubbing.
Cek NA :
## X Date Type Alloy.Type Thick.mm
## 0 1 1 1 325
## Hard TotalSales_Kg
## 1 1
Dihapus NA
## X Date Type Alloy.Type Thick.mm Hard TotalSales_Kg
## 1 1 2017-01-30 BRASS BSR C2680 0.35 3/4H 0.0
## 2 2 2017-01-30 BRASS BSR C2680 0.40 1/2H 0.0
## 3 3 2017-01-30 BRASS BSR C2680 0.45 1/2H 0.0
## 4 4 2017-01-30 BRASS BSR C2680 0.50 1/2H 1825.4
## 5 5 2017-01-30 BRASS BSR C2680 0.50 EH 0.0
## 6 6 2017-01-30 BRASS BSR C2680 0.55 1/2H 0.0
## X Date Type Alloy.Type Thick.mm
## 0 0 0 0 0
## Hard TotalSales_Kg
## 0 0
Grup data atau Agregasi Data adalah meringkas atau mengelompokkan data berdasarkan nilai dari varaiabel tertentu. Pada data metal akan diagregasi data tanggal, tipe material, dan total sales yang dijumlah dalam variabel total sales dalam kilogram.
Grup data tipe material kami sajikan untuk mengetahui total sales dalam kilogram dan forecast dalam kategori material.
## # A tibble: 141 x 3
## # Groups: Date [36]
## Date Type Quantity_Kg
## <date> <fct> <dbl>
## 1 2017-01-30 BRASS 30185.
## 2 2017-01-30 COPPER 13356.
## 3 2017-01-30 OTHER 7780
## 4 2017-01-30 STAINLESS 14559.
## 5 2017-02-28 BRASS 24700
## 6 2017-02-28 COPPER 0
## 7 2017-02-28 OTHER 0
## 8 2017-02-28 STAINLESS 9312
## 9 2017-03-30 BRASS 20460
## 10 2017-03-30 COPPER 5870
## # ... with 131 more rows
Mengetahui porsi sebaran data metal secara keseluruhan
##
## BRASS COPPER OTHER STAINLESS
## 0.2553191 0.2553191 0.2340426 0.2553191
## # A tibble: 36 x 3
## # Groups: Date [36]
## Date Type Quantity_Kg
## <date> <fct> <dbl>
## 1 2017-01-30 BRASS 30185.
## 2 2017-02-28 BRASS 24700
## 3 2017-03-30 BRASS 20460
## 4 2017-04-30 BRASS 32860
## 5 2017-05-30 BRASS 29300
## 6 2017-06-30 BRASS 28000
## 7 2017-07-30 BRASS 40150
## 8 2017-08-30 BRASS 33290
## 9 2017-09-30 BRASS 23620
## 10 2017-10-30 BRASS 18860
## # ... with 26 more rows
## # A tibble: 36 x 2
## # Groups: Date [36]
## Date Quantity_Kg
## <date> <dbl>
## 1 2017-01-30 30185.
## 2 2017-02-28 24700
## 3 2017-03-30 20460
## 4 2017-04-30 32860
## 5 2017-05-30 29300
## 6 2017-06-30 28000
## 7 2017-07-30 40150
## 8 2017-08-30 33290
## 9 2017-09-30 23620
## 10 2017-10-30 18860
## # ... with 26 more rows
# KOnversi ke objek ts
brass_ts <- ts(data = brass$Quantity_Kg, start = c(2017,1),frequency = 12)
brass_ts## Jan Feb Mar Apr May Jun Jul Aug
## 2017 30185.30 24700.00 20460.00 32860.00 29300.00 28000.00 40150.00 33290.00
## 2018 11730.10 13512.20 19912.60 19635.00 18334.08 14686.30 15717.30 18125.70
## 2019 40150.00 33290.00 23620.00 18860.00 17660.00 21250.00 30185.30 24700.00
## Sep Oct Nov Dec
## 2017 23620.00 18860.00 17660.00 21250.00
## 2018 8078.40 18334.08 15717.30 11730.10
## 2019 20460.00 32860.00 29300.00 28000.00
# plot time series
brass_ts %>%
autoplot()+
labs(title = "BRASS",
x = "Tahun",
y = "Kilograms") +
theme_minimal()window(x = brass_ts, start = c(2017, 1), end = c(2020, 1)) %>%
autoplot() +
labs(title = "BRASS",
x = "Tahun",
y = "Kilograms")+
theme_minimal()# decompose time series
brass_dc <- decompose(brass_ts, type = "additive")
# plot decompose
autoplot(brass_dc) + theme_minimal()Forecasting Model:
Exponential Smoothing:
Autoregresive Integrated Moving Average (ARIMA):
SARIMA
-Simple Moving Average fungsi untuk membuat model SMA yaitu SMA() dari package TTR. parameter n menunjukkan banyaknya data yang akan digunakan dalam memprediksi future. SMA bagus digunakan ketika data tidak memiliki trend dan seasional
## Jan Feb Mar Apr May Jun Jul Aug
## 2017 NA NA 25115.10 26006.67 27540.00 30053.33 32483.33 33813.33
## 2018 16880.03 15497.43 15051.63 17686.60 19293.89 17551.79 16245.89 16176.43
## 2019 22532.47 28390.03 32353.33 25256.67 20046.67 19256.67 23031.77 25378.43
## Sep Oct Nov Dec
## 2017 32353.33 25256.67 20046.67 19256.67
## 2018 13973.80 14846.06 14043.26 15260.49
## 2019 25115.10 26006.67 27540.00 30053.33
# plot model fitted
# plot data asli
autoplot(brass_ts) +
# plot hasil forecast in-sample data
autolayer(sma_brass) +
theme_minimal()kekurangan dari metode SMA adalah menggunakan bobot yang sama untuk semua data yang digunakan (mean). oleh sebab itu ada metode yang menggunakan bobot berbeda2 yaitu Exponential Smooting.
## # A tibble: 36 x 3
## # Groups: Date [36]
## Date Type Quantity_Kg
## <date> <fct> <dbl>
## 1 2017-01-30 COPPER 13356.
## 2 2017-02-28 COPPER 0
## 3 2017-03-30 COPPER 5870
## 4 2017-04-30 COPPER 8980
## 5 2017-05-30 COPPER 7180
## 6 2017-06-30 COPPER 6540
## 7 2017-07-30 COPPER 3490
## 8 2017-08-30 COPPER 7040
## 9 2017-09-30 COPPER 4490
## 10 2017-10-30 COPPER 3340
## # ... with 26 more rows
## # A tibble: 36 x 2
## # Groups: Date [36]
## Date Quantity_Kg
## <date> <dbl>
## 1 2017-01-30 13356.
## 2 2017-02-28 0
## 3 2017-03-30 5870
## 4 2017-04-30 8980
## 5 2017-05-30 7180
## 6 2017-06-30 6540
## 7 2017-07-30 3490
## 8 2017-08-30 7040
## 9 2017-09-30 4490
## 10 2017-10-30 3340
## # ... with 26 more rows
# KOnversi ke objek ts
copper_ts <- ts(data = copper$Quantity_Kg, start = c(2017,1),frequency = 12)
copper_ts## Jan Feb Mar Apr May Jun Jul Aug Sep
## 2017 13355.6 0.0 5870.0 8980.0 7180.0 6540.0 3490.0 7040.0 4490.0
## 2018 6899.7 7127.2 8804.2 9065.6 2222.4 3768.8 7305.6 6785.8 1843.2
## 2019 3490.0 7040.0 4490.0 3340.0 3060.0 3060.0 13355.6 0.0 5870.0
## Oct Nov Dec
## 2017 3340.0 3060.0 3060.0
## 2018 2222.4 7305.6 6899.7
## 2019 8980.0 7180.0 6540.0
# plot time series
copper_ts %>%
autoplot()+
labs(title = "COPPER",
x = "Tahun",
y = "Kilograms") +
theme_minimal()# decompose time series
copper_dc <- decompose(copper_ts, type = "additive")
# plot decompose
autoplot(copper_dc) + theme_minimal()## # A tibble: 36 x 3
## # Groups: Date [36]
## Date Type Quantity_Kg
## <date> <fct> <dbl>
## 1 2017-01-30 STAINLESS 14559.
## 2 2017-02-28 STAINLESS 9312
## 3 2017-03-30 STAINLESS 12090
## 4 2017-04-30 STAINLESS 11450
## 5 2017-05-30 STAINLESS 10193
## 6 2017-06-30 STAINLESS 10193
## 7 2017-07-30 STAINLESS 8600
## 8 2017-08-30 STAINLESS 8440
## 9 2017-09-30 STAINLESS 5840
## 10 2017-10-30 STAINLESS 5550
## # ... with 26 more rows
## # A tibble: 36 x 2
## # Groups: Date [36]
## Date Quantity_Kg
## <date> <dbl>
## 1 2017-01-30 14559.
## 2 2017-02-28 9312
## 3 2017-03-30 12090
## 4 2017-04-30 11450
## 5 2017-05-30 10193
## 6 2017-06-30 10193
## 7 2017-07-30 8600
## 8 2017-08-30 8440
## 9 2017-09-30 5840
## 10 2017-10-30 5550
## # ... with 26 more rows
# KOnversi ke objek ts
stainless_ts <- ts(data = stainless$Quantity_Kg, start = c(2017,1),frequency = 12)
stainless_ts## Jan Feb Mar Apr May Jun Jul Aug Sep
## 2017 14559.2 9312.0 12090.0 11450.0 10193.0 10193.0 8600.0 8440.0 5840.0
## 2018 8230.1 5957.0 6075.7 8150.9 9406.6 6216.4 10659.2 4496.6 4901.0
## 2019 8600.0 8440.0 5840.0 5550.0 5500.0 5500.0 14559.2 9312.0 12090.0
## Oct Nov Dec
## 2017 5550.0 5500.0 5500.0
## 2018 9406.6 10659.2 8230.1
## 2019 11450.0 10193.0 10193.0
# plot time series
stainless_ts %>%
autoplot()+
labs(title = "COPPER",
x = "Tahun",
y = "Kilograms") +
theme_minimal()# decompose time series
copper_dc <- decompose(copper_ts, type = "additive")
# plot decompose
autoplot(copper_dc) + theme_minimal()## # A tibble: 33 x 3
## # Groups: Date [33]
## Date Type Quantity_Kg
## <date> <fct> <dbl>
## 1 2017-01-30 OTHER 7780
## 2 2017-02-28 OTHER 0
## 3 2017-03-30 OTHER 455
## 4 2017-04-30 OTHER 0
## 5 2017-05-30 OTHER 0
## 6 2017-06-30 OTHER 0
## 7 2017-07-30 OTHER 0
## 8 2017-08-30 OTHER 0
## 9 2017-09-30 OTHER 0
## 10 2017-10-30 OTHER 0
## # ... with 23 more rows
## # A tibble: 33 x 2
## # Groups: Date [33]
## Date Quantity_Kg
## <date> <dbl>
## 1 2017-01-30 7780
## 2 2017-02-28 0
## 3 2017-03-30 455
## 4 2017-04-30 0
## 5 2017-05-30 0
## 6 2017-06-30 0
## 7 2017-07-30 0
## 8 2017-08-30 0
## 9 2017-09-30 0
## 10 2017-10-30 0
## # ... with 23 more rows
# KOnversi ke objek ts
other_ts <- ts(data = other$Quantity_Kg, start = c(2017,1),frequency = 12)
other_ts## Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 2017 7780 0 455 0 0 0 0 0 0 0 0 0
## 2018 11310 0 4554 6186 7780 7056 2352 4554 7780 0 0 0
## 2019 0 0 0 7780 0 455 0 0 0
# plot time series
other_ts %>%
autoplot()+
labs(title = "COPPER",
x = "Tahun",
y = "Kilograms") +
theme_minimal()# decompose time series
other_dc <- decompose(other_ts, type = "additive")
# plot decompose
autoplot(other_dc) + theme_minimal()Validasi data BRASS dengan Exponential time series
# Cross validation dengan 3 tahun sebagai data test
brass_train <- window(brass_ts, start = 2017, end = 2018)
brass_test <- window(brass_ts, start = c(2019,1), end = c(2019,12))3.1 Normality Residuals H0: Residual berdistribusi normal (v) H1: Residual tidak berdistribusi normal Keputusan: Tolak H0 ketika pvalue < 0.05
##
## Shapiro-Wilk normality test
##
## data: model_brass$residuals
## W = 0.88772, p-value = 0.008415
Karena hasil p-value dibawah 0.05, maka kesimpulannya residual / error tidak berdistribusi normal.
H0: Residual tidak mengalami autokorelasi (v) H1: Residual mengalami autokorelasi
Keputusan: Tolak H0 ketika pvalue < 0.05
##
## Box-Pierce test
##
## data: model_brass$residuals
## X-squared = 0.022471, df = 1, p-value = 0.8808
Karena p-value lebih dari 0.05, maka kesimpulannya residual tidak mengalami autokorelasi.
H0: Data tidak stasioner H1: Data stasioner
Tolak H0 ketika p-value < 0.05
##
## Augmented Dickey-Fuller Test
##
## data: brass_ts
## Dickey-Fuller = -2.109, Lag order = 3, p-value = 0.5307
## alternative hypothesis: stationary
Karena p-value > 0.05 maka data belum stasioner. Lanjut ke proses differencing :
##
## Augmented Dickey-Fuller Test
##
## data: diff(brass_ts)
## Dickey-Fuller = -4.2573, Lag order = 3, p-value = 0.01149
## alternative hypothesis: stationary
## Series: brass_train
## ARIMA(0,0,1) with non-zero mean
##
## Coefficients:
## ma1 mean
## 0.9039 22195.373
## s.e. 0.1336 2489.517
##
## sigma^2 estimated as 49896686: log likelihood=-267.13
## AIC=540.26 AICc=541.35 BIC=544.03
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set -40.50901 6786.64 4885.834 -10.0373 26.39 0.3737391 -0.139197
Untuk Seasonal, model AR murni dengan:
P: 1 D: 1 Q: 0
Untuk keseluruhan data, model MA murni dengan:
p: 0 d: 1 q: 1,3,4
Berarti kombinasi model yang mungkin terbentuk adalah:
model_sarima_1 <- arima(brass_train, order = c(0,1,1),
seasonal = list(order = c(0,1,0), period = 12)) #MAPE 21.6%
model_sarima_2 <- arima(brass_train, order = c(0,1,3),
seasonal = list(order = c(0,1,0), period = 12)) #MAPE 21%
model_sarima_3 <- arima(brass_train, order = c(0,1,4),
seasonal = list(order = c(0,1,0), period = 12)) #MAPE 21.7%##
## Call:
## arima(x = brass_train, order = c(0, 1, 3), seasonal = list(order = c(0, 1, 0),
## period = 12))
##
## Coefficients:
## ma1 ma2 ma3
## -0.2069 -0.2086 0.9981
## s.e. 0.7223 0.5427 1.1275
##
## sigma^2 estimated as 83043706: log likelihood = -139.48, aic = 286.96
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 993.1842 6443.83 3724.722 4.16074 21.02897 0.6055661 -0.09955121
Jadi berdasarkan model selection, yang paling kecil MAPE nya adalah model dengan kombinasi SARIMA(0,1,4)(1,1,0)[12]
##
## Shapiro-Wilk normality test
##
## data: model_sarima_2$residuals
## W = 0.80649, p-value = 0.0002275
Karena p-value lebih kecil dari alpha, maka kesimpulannya residual tidak berdistribusi normal.
##
## Box-Pierce test
##
## data: model_sarima_2$residuals
## X-squared = 0.25767, df = 1, p-value = 0.6117
Karena p-value sudah lebih besar dari alpha, maka kesimpulannya residual tidak mengalami autokorelasi.