Pengantar Data Sains

UTS_pds


Kontak : \(\downarrow\)
Email
Instagram https://www.instagram.com/arifin.alicia/
RPubs https://rpubs.com/aliciaarifin/
Nama Alicia Arifin
NIM 20214920001
Prodi Statistika, 2021

Group 1:
1. Alicia Arifin, Statistika, 2021492001
2. Diyas Arya Nugroho, Statistika, 2021492007
3. Dhela Asafiani Agatha, Statistika, 2021492009

Question

One of the leading retail stores in the US, Walmart, would like to predict the sales and demand accurately. There are certain events and holidays which impact sales on each day. There are sales data available for 45 stores of Walmart The business isfacing a challenge due to unforeseen demands and runs out of stock sometimes, due to the inappropriatemachine learningalgorithm. An ideal ML algorithm will predict demand accurately and ingest factors like economic conditionsincluding CPI,Unemployment Index, etc.Walmart runs several promotional markdown events throughout the year. These markdowns precede prominentholidays, thefour largest of all, which are the Super Bowl, Labour Day, Thanksgiving, and Christmas. The weeks includingthese holidays areweighted five times higher in the evaluation than non-holiday weeks. Part of the challenge presented by thi competition is modelling the effects of markdowns on these holiday weeks in the absence of complete/ideal historical data. Historical sales data for 45 Walmart stores located in different regions are available.
Objective: 1. Understand the Dataset & cleanup (if required).
2. Exploratory Data Analysis (EDA).
3. Build Regression models to predict the sales w.r.t single & multiple features.
4. Build Classification models to predict the sales w.r.t single & multiple features.
5. Also evaluate the models & compare their respective scores like R2, RMSE, etc.

Understand the Dataset & cleanup (if required).

#import data
setwd(getwd())

set.seed(5)
Walmart = read.csv('Walmart.csv')

Walmart
glimpse(Walmart)
## Rows: 6,435
## Columns: 8
## $ Store        <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ~
## $ Date         <chr> "05-02-2010", "12-02-2010", "19-02-2010", "26-02-2010", "~
## $ Weekly_Sales <dbl> 1643691, 1641957, 1611968, 1409728, 1554807, 1439542, 147~
## $ Holiday_Flag <int> 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ~
## $ Temperature  <dbl> 42.31, 38.51, 39.93, 46.63, 46.50, 57.79, 54.58, 51.45, 6~
## $ Fuel_Price   <dbl> 2.572, 2.548, 2.514, 2.561, 2.625, 2.667, 2.720, 2.732, 2~
## $ CPI          <dbl> 211.0964, 211.2422, 211.2891, 211.3196, 211.3501, 211.380~
## $ Unemployment <dbl> 8.106, 8.106, 8.106, 8.106, 8.106, 8.106, 8.106, 8.106, 7~

Keterangan :
Store - the store number
Date - the week of sales
Weekly_Sales - sales for the given store
Holiday_Flag - whether the week is a special holiday week, 1 – Holiday week, 0 – Non-holiday week
Temperature - Temperature on the day of sale
Fuel_Price - Cost of fuel in the region
CPI – Prevailing consumer price index
Unemployment - Prevailing unemployment rate

# cek NA
colSums(is.na(Walmart))
##        Store         Date Weekly_Sales Holiday_Flag  Temperature   Fuel_Price 
##            0            0            0            0            0            0 
##          CPI Unemployment 
##            0            0


Tidak ada NA pada dataset.

# memisahkan tanggal bulan dan tahun
Walmart$Month <- sapply(Walmart$Date, FUN = function(x) {strsplit(x, split = '[-]')[[1]][2]})
Walmart$Year <- sapply(Walmart$Date, FUN = function(x) {strsplit(x, split = '[-]')[[1]][3]})
Walmart$dayOfWeek <- wday(Walmart$Date, label=TRUE)
Walmart
Walmart %>% arrange(mdy(Walmart$Date))
Walmart %>% arrange(desc(mdy(Walmart$Date)))
# data dari tanggal 01-10-2010 sampai 12-10-2012
# holiday atau tidak
x = Walmart$Holiday_Flag

a = ifelse(x == 1,"Holiday", ifelse (x == 1,"Holiday", ifelse(x == 1,"Holiday", "Not_Holiday")))

Walmart$TypeOfDay = a

# menentukan season
#spring runs from March 1 to May 31;
#summer runs from June 1 to August 31;
#fall (autumn) runs from September 1 to November 30; and
#winter runs from December 1 to February 28 

season = Walmart$Month
Walmart$Season = ifelse( (season >= "03" &season <= "05"), "Spring", 
                         ifelse(season >= "06" & season<="08", "Summer",
                                ifelse(season >= "09" & season<= "11", "Autumn", "Winter")))


Walmart$Quarter = as.yearqtr(Walmart$Date, format="%d-%m-%Y", with_year = T)

Holiday = Walmart$Date
Walmart$Super_Bowl <- ifelse(Holiday == "12-02-2010", "1",
                             ifelse(Holiday == "11-02-2011", "1",
                             ifelse(Holiday == "10-02-2012", "1",
                             ifelse(Holiday == "8-02-2013", "1", "0"))))
Walmart$Labour_Day <- ifelse(Holiday == "10-09-2010", "1",
                              ifelse(Holiday == "9-09-2011", "1",
                                     ifelse(Holiday == "7-09-2012", "1",
                                            ifelse(Holiday == "6-09-2013", "1", "0"))))
Walmart$Chrismast <- ifelse(Holiday == "31-12-2010", "1",
                              ifelse(Holiday == "30-12-2011", "1",
                                     ifelse(Holiday == "28-12-2012", "1",
                                            ifelse(Holiday == "27-12-2013", "1", "0"))))
Walmart$Thanksgiving <- ifelse(Holiday == "26-11-2010", "1",
                              ifelse(Holiday == "25-11-2011", "1",
                                     ifelse(Holiday == "23-11-2012", "1",
                                            ifelse(Holiday == "29-11-2013", "1", "0"))))


Walmart


Pada step ini kita membuat kolom baru agar dapat mengetahui infomasi data lebih detail.
Pertama, kita membuat kolom TypeOfDay yang berisi Holiday atau Not_Holiday, dibuat berdasarkan kolom Holiday dengan menggunakan function ifelse() kondisi jika Holiday bernilai 1 maka TypeOfDaynya bernilai Holiday, jika bernilai selain 1 maka bernilai Not_Holiday.


Kedua, kita membuat kolom Season yang berisi Spring, Summer, Autumn, dan Winter, dibuat berdasarkan kolom Month dengan kondisi seperti dibawah ini :
1. Spring runs from March 1 to May 31
2. Summer runs from June 1 to August 31
3. fall (Autumn) runs from September 1 to November 30


Ketiga, kita membuat kolom Super_Bowl, Labour_Day, Chrismast, dan Thanksgiving untuk mengkategorikan jenis liburan berdasarkan kolom Date dengan kondisi sebagai berikut :
1. Super_Bowl terjadi pada 12-02-2010, 11-02-2011, 10-02-2012, dan 08-02-2013.
2. Labour_Day terjadi pada 10-09-2010, 09-09-2011, 07-09-2012, dan 06-09-2013.
3. Chrismast terjadi pada 31-12-2010, 30-12-2011, 28-12-2012, dan 27-12-2013.
4. Thanksgiving terjadi pada 26-11-2010, 25-11-2011, 23-11-2012, dan 29-11-2013.

Exploratory Data Analysis (EDA).

type hari libur dengan tidak labur


Berdasarkan grafik di atas dapat dilihat bahwa Frekuensi Tidak Libur adalah yang tertinggi dengan frek 6000.

jumlah penghasilan per store


Output yang dihasilkan menjelaskan Total penjualan per minggu terbesar terdapat pada Store Region ke-20. Berikut urutan 5 penjualan terbesar :
1. Store ke-20 dengan Total Penjualan 301397792.
2. Store ke-4 dengan Total Penjualan 299543953.
3. Store ke-14 dengan Total Penjualan 288999911.
4. Store ke-13 dengan Total Penjualan 286517704.
5. Store ke-2 dengan Total Penjualan 275382441.

per season weekly_sales


Dari plot di atas didapat bahwa Penjualan tertinggi terjadi pada Summer yaitu 1885721073.

Persentase Sales saat Holiday


Plot menghasilkan presentasi penjualan yang paling banyak terjadi pada Super_Bowl yaitu 35.51%.

Penjualan Walmart Per Bulan dari 2010-2012


Penjualan per bulan dari 2010 sampai 2012 mengalami kenaikan terbesar pada Desember 2010 dan Desember 2011, penurunan terbesar dialami pada Januari 2011 dan Januari 2012, sedangkan penjualan yang stabil terjadi pada April 2012 hingga Mei 2021.

Fuel_Price, Temperatur, Weekly_Sales

Hubungan antara Fuel_Price dengan Temperatur

pada grafik, temperatur dan fuel price ini terlihat kalau temperatur tidak terlalu berpengaruh pada fuel price. Walaupun pada faset winter sepertinya memiliki hubunganya, season lain tidak memiliki hubungan yang tidak bisa ditebak. jadi temperatur dan fuel price ini tidak memiliki hubungan


### Hubungan antara Fuel_Price dengan Sales Pada plot di atas ini dapat disimpulkan bahwa weekly sales tidak memiliki hubungan yang siknifikan dengan fuel price. pada plot di atas seperti “rata” saja. jadi kita tidak akan membandingkan sales dengan fuel price pada regresi atau klasifikasi.

Hubungan antara Suhu dengan Sales

karena variabel weekly dan temperatur ini seperti berkumpul menjadi satu, kita bisa bilang kedua ini memiliki hubungan. Karena memiliki hubungan, nanti akan kita gunakan dalam klasifikasi atau regresi.

weekly sales vs fuel

## [1] 1553977866
## [1] 4429090359
## [1] 754150762

dampak holiday terhadap pendapatan penjualan per minggu


Beberapa hari libur berdampak negatif pada penjualan. Disini kita perlu cari tahu liburan yang memiliki penjualan yang lebih tinggi daripada rata-rata penjualan di hari tidak liburan untuk semua toko

# Beberapa hari libur berdampak negatif pada penjualan. Disini kita perlu cari tahu liburan yang memiliki penjualan yang lebih tinggi daripada rata-rata penjualan di hari tidak liburan untuk semua toko 

SuperBowl <- c("12-02-2010", "11-02-2011", "10-02-2012")
LaborDay <- c("10-09-2010", "09-09-2011", "07-09-2012")
ThanksGiving <- c("26-11-2010", "25-11-2011", "23-11-2012")
Christmas <- c("31-12-2010", "30-12-2011", "28-12-2012")

Holiday_Date <- data.frame(SuperBowl,LaborDay,ThanksGiving,Christmas)

Walmart$Date <- as.factor(Walmart$Date)

penjualan_holiday <- Walmart %>%
  mutate(Holiday = case_when(Date %in% SuperBowl ~ "Super Bowl",
                             Date %in% LaborDay ~ "Labor Day",
                             Date %in% ThanksGiving ~ "Thanksgiving",
                             Date %in% Christmas ~ "Christmas",
                             TRUE ~ "Non-Holiday"))
penjualan_holiday %>%
  select(Weekly_Sales,Holiday) %>%
  group_by(Holiday) %>%
  summarise(average_sales = mean(Weekly_Sales)) %>%
  arrange(desc(average_sales))
penjualan_holiday
# christmas dan labor day memiliki dampak negatif pada penjualan di mana thanksgiving dan SuperBowl memiliki dampak positif pada penjualan

# memeriksa dampak negatif berdasarkan tanggal holiday dan tanggal non holiday
# filter data holiday dan cari mean per-minggu nya

Holiday_date <- dplyr::filter(penjualan_holiday , Holiday_Flag ==1)
Holiday_Date_Sales<-summarise(group_by(Holiday_date,Date),mean(Weekly_Sales))

# kalkulasi mean penjualan Mingguan untuk non-holiday
mean_penjualan_nonHoliday <- mean(dplyr::filter(penjualan_holiday,Holiday_Flag ==0)$Weekly_Sales) 
Holiday_Date_Sales$higher_than_non_holiday <- Holiday_Date_Sales[,2] > mean_penjualan_nonHoliday
View(Holiday_Date_Sales)

# AKU CANTIKKKKKKKKK


rm(mean)
weekly_sales <- aggregate(Weekly_Sales~Date, data=Walmart,mean)
weekly_sales$Date <-as.Date(weekly_sales$Date, "%d-%m-%Y")
weekly_sales <-arrange(weekly_sales,Date)
weekly_sales$Date <-factor(weekly_sales$Date)


options(repr.plot.width = 14, repr.plot.height = 8)

cantik <- ggplot(data=weekly_sales, 
               aes(x=Date, y=Weekly_Sales, group=1)) +
  geom_line(color="blue4")+
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))+
  scale_x_discrete(breaks = NULL)+
  scale_y_continuous(labels = label_number(suffix = " M", scale = 1e-6))+
  theme(plot.title = element_text(hjust = 0.5))+
  xlab("Week (per-Minggu)") + ylab("Mean Sales of Week")



cantik +
  ggtitle('DAMPAK CHRISTMAS DAY')+
  geom_point(aes(x = factor("2010-12-31"), y = 898500.4), color = "red", size = 2) +
  geom_point(aes(x = factor("2011-12-30"), y = 1023165.8), color = "red", size = 2) +
  geom_hline(aes(yintercept = mean_penjualan_nonHoliday), linetype="longdash")+
  theme(axis.text.x=element_blank(),
        axis.ticks.x=element_blank())

cantik + 
  ggtitle('DAMPAK LABOUR DAY')+
  geom_point(aes(x = factor("2010-09-10"), y = 1014097.7), color = "red", size = 2) +
  geom_point(aes(x = factor("2011-09-09"), y = 1039182.8), color = "red", size = 2) +
  geom_point(aes(x = factor("2012-09-07"), y =  1074001.3), color = "red", size = 2) +
  geom_hline(aes(yintercept = mean_penjualan_nonHoliday), linetype="longdash")+
  theme(axis.text.x=element_blank(),
        axis.ticks.x=element_blank())

cantik + 
  ggtitle('DAMPAK THANKS GIVING')+
  geom_point(aes(x = factor("2010-11-26"), y =  1462689.0), color = "red", size = 2) +
  geom_point(aes(x = factor("2011-11-25"), y = 1479857.9), color = "red", size = 2) +
  geom_hline(aes(yintercept = mean_penjualan_nonHoliday), linetype="longdash")+
  theme(axis.text.x=element_blank(),
        axis.ticks.x=element_blank())

cantik + 
  ggtitle('DAMPAK SUPER BOWL')+
  geom_point(aes(x = factor("2010-02-12"), y =  1074148.4), color = "red", size = 2) +
  geom_point(aes(x = factor("2011-02-11"), y = 1051915.4), color = "red", size = 2) +
  geom_point(aes(x = factor("2012-02-10"), y = 1111320.2), color = "red", size = 2) +
  geom_hline(aes(yintercept = mean_penjualan_nonHoliday), linetype="longdash")+
  theme(axis.text.x=element_blank(),
        axis.ticks.x=element_blank())


Pada langkah ini, kita ingin mengetahui apakah Holiday (hari libur) memiliki dampak yang positif terhadap penjualan mingguan jika dibandingkan dengan Non Holiday? Atau justru Holiday ada yang memiliki dampak yang negatif terhadap penjualan mingguannya?
Nah, dari grafik yang telah kita rancang di atas, kita dapat menyimpulkan beberapa hal. Bisa kita lihat terdapat 2 Holiday yang memiliki dampak negatif, yaitu Christmas dan Labour Day. Hal ini dapat kita liat pada grafik bahwa terdapat titik merah dibawah garis yang menunjukkan nilai negatif. Hal ini dapat disimpulkan bahwa Christmas dan Labour Day berdampak negatif atau dapat kita katakan bahwa justru hari libur pada hari tersebut tidak menghasilkan penjualan mingguan lebih dibandingkan hari biasa atau hari Non Holiday. Seharusnya, hari libur justru memiliki penjualan mingguan yang lebih besar dibanding dengan hari biasa. Akan tetapi, Christmas dan Labour Day tidak memiliki dampak terhadap penghasilan penjualan.
Hal ini mungkin bisa disebabkan karena orang-orang lebih cenderung suka membeli sesuatu sebelum bulan Christmas, karena pada bulan desember terjadi musim Winter yang mungkin juga orang-orang lebih suka untuk dirumah saja dibandingkan harus menghabiskan waktu berbelanja.

Dampak dari Holiday berdasarkan nilai Mean

Build Regression models to predict the sales w.r.t single & multiple features.

Single Regression

Temperature vs weekly


Step pertama tentuin model regresi dan tentuin variable target dan parameter prediksi.
Pada step ini kita menggunakan model linear regresi untuk menentukan hubungan variable. Setelah itu, kita tentukan variable tagret yaitu Weekly_Sales dan parameter prediksi yaitu Temperature. Disini kita ingin mencari apakah kenaikan atau penurunan suhu mempengaruhi total penjualan?.

#tes
x = Walmart$Temperature
y = Walmart$Weekly_Sales

plot(x,y)
a = lm(Weekly_Sales~Temperature, data = Walmart)
abline(a)

summary(a)
## 
## Call:
## lm(formula = Weekly_Sales ~ Temperature, data = Walmart)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -871164 -488496  -91696  386226 2713005 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 1165406.0    24139.0  48.279  < 2e-16 ***
## Temperature   -1952.4      380.7  -5.128 3.01e-07 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 563300 on 6433 degrees of freedom
## Multiple R-squared:  0.004072,   Adjusted R-squared:  0.003917 
## F-statistic:  26.3 on 1 and 6433 DF,  p-value: 3.008e-07


Dengan menggunakan model linear regresi diketahui bahwa hubungan Weekly_Sales vs Temperature adalah negatif (dapat dilihat pada plot). Lalu, didapat juga bahwa intercept dari Weekly_Sales yaitu 1165406.
Atau untuk mengetahui adanya hubungan antara Weekly_Sales dengan Temperature dapat dilihat dari p-value = 3.008e-07 yang dimana nilai tersebut lebih kecil dari nilai alpha = 0.005 yang artinya H0 ditolak atau kedua variable memiliki hubungan.

pl <- slice_sample(Walmart, n=30)


ggplot(pl, aes(y = Temperature, x = Weekly_Sales)) +
  geom_point() +
  geom_vline(xintercept = 1165406, linetype = "dotted") +
  theme(text = element_text(12))+coord_flip()

knn <- pl %>%
  mutate(diff = abs(1165406 - Weekly_Sales)) %>%
  arrange(diff) %>%
  slice(1:5)
knn
predict = knn %>%
  summarise(predicted = mean(Weekly_Sales))
predict
ggplot(pl, aes(x = Temperature, y = Weekly_Sales)) +
  geom_point()+
  geom_point(aes(x =  mean(knn$Temperature), y =1165406 ), color = "red") +
  geom_vline(xintercept = mean(knn$Temperature) , linetype = "dotted") +
  theme(text = element_text(12))


Setelah itu, kita mengambil 30 sample untuk mengeksplor data dengan visualisasi. menggunakan scatter plot dengan intercept 1165406. Lalu, kita tentukan jarak terdekat dengan menggunakan nilai intercept dikurang dengan variable Weekly_Sales. Selanjutnya, kita slice 5 jarak terdekat dengan titik potong.
Setelah itu, kita predict dari ke 5 jarak tersebut dengan mencari rata-rata didapat nilai prediksinya adalah 1132373.

Model KNN Regresion


Step selanjutnya kita atur model knn regresi dengan membagi data terlebih dahulu menjadi data train dan data test.
Setelah itu, untuk mengatur model knn regresi kita gunakan set_engine dan set_mode lalu kita buat rentang untuk nilai k yaitu dari 1 sampai 200 dengan perbedaan 3 nilai. Selanjutnya, kita filter metricnya untuk mengambil jenis rmse saja.

walmart_split <- initial_split(Walmart, prop = 0.75, strata = Weekly_Sales)
walmart_train <- training(walmart_split)
walmart_test <- testing(walmart_split)


# cross-validation to choose K
w_recipe = recipe(Weekly_Sales~Temperature, data = Walmart)|>
  step_scale(all_predictors())|>
  step_center(all_predictors())


w_spec <- nearest_neighbor(weight_func = "rectangular", 
                              neighbors = tune()) |>
  set_engine("kknn") |>
  set_mode("regression")

w_vfold <- vfold_cv(walmart_train, v = 5, strata = Temperature)

w_wkflw <- workflow() |>
  add_recipe(w_recipe) |>
  add_model(w_spec)

w_wkflw
## == Workflow ====================================================================
## Preprocessor: Recipe
## Model: nearest_neighbor()
## 
## -- Preprocessor ----------------------------------------------------------------
## 2 Recipe Steps
## 
## * step_scale()
## * step_center()
## 
## -- Model -----------------------------------------------------------------------
## K-Nearest Neighbor Model Specification (regression)
## 
## Main Arguments:
##   neighbors = tune()
##   weight_func = rectangular
## 
## Computational engine: kknn
gridvals <- tibble(neighbors = seq(from = 1, to = 200, by =3))

w_results <- w_wkflw |>
  tune_grid(resamples = w_vfold, grid = gridvals) |>
  collect_metrics() |>
  dplyr::filter(.metric == "rmse")
w_results


Selanjutnya, untuk mempermudah mengetahui nilai k dapat kita plot dengan nilai k berdasarkan rata-rata.

Selanjutnya, kita dapat memilih nilai k dengan mencari berdasarkan rata-rata terkecil.

w_min <- w_results |>
  dplyr::filter(mean == min(mean))

w_min


Dengan kodingan diatas kita mendapatkan nilai k dengan rata-rata terkecil yaitu k = 199.

## [1] "nilai RMSPE yang terkecil adalah saat K = 199"


selanjutnya kita lakukan evaluasi data lebih lanjut, yang awalnya kita hanya menggunakan 30 sample untuk mencari nilai k, sekarang kita gunakan seluruh data untuk mempredict lebih lanjut apakah data training yang kita gunakan sudah sesuai.
Dalam mempredict data kita gunakan function metrics untuk mengetahui summary yang berkaitan dengan regresi tersebut.

#### Evaluating 
kmin = w_min |> pull(neighbors)

w_spec <- nearest_neighbor(weight_func = "rectangular", neighbors = kmin) |>
  set_engine("kknn") |>
  set_mode("regression")

w_fit <- workflow() |>
  add_recipe(w_recipe) |>
  add_model(w_spec) |>
  fit(data = walmart_train)

w_summary <- w_fit |>
  predict(walmart_test) |>
  bind_cols(walmart_test) |>
  metrics(truth = Temperature, estimate = .pred) |>
  dplyr::filter(.metric == 'rmse')

w_summary
## [1] "test model yang dibuat oleh RMSPE sebesar 1053989 . prediksi awal yang tadi kita cari adalah 1132373 ."


Didapat hasil evaluasi menghasilkan nilai estimasi sebesar 1053989 yang dimana nilai tersebut memiliki prediksi atau perkiraan yang hampir sama dengan cross validation diatas yaitu 1132373.
Maka, nilai k = 199 cocok dengan model data yang kita gunakan.

w_preds = tibble(Temperature = seq(from = 0, to =100 , by = 1))

w_preds <- w_fit |>
  predict(w_preds) |>
  bind_cols(w_preds)


Setelah itu, kita buat visualisasinya dengan nilai k yang sudah didapat dari hasil cross validation.

Multi Regression


Unemployment vs Temperature vs weekly sales, ~Season

x = Walmart$Weekly_Sales
y = Walmart$Unemployment

plot(x,y)
abline(lm(y~x))

lm(y~x)
## 
## Call:
## lm(formula = y ~ x)
## 
## Coefficients:
## (Intercept)            x  
##   8.369e+00   -3.529e-07
summary(lm(y~x))
## 
## Call:
## lm(formula = y ~ x)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -3.9409 -1.1313 -0.0544  0.6424  6.6594 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  8.369e+00  4.901e-02 170.751   <2e-16 ***
## x           -3.529e-07  4.121e-08  -8.564   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.865 on 6433 degrees of freedom
## Multiple R-squared:  0.01127,    Adjusted R-squared:  0.01112 
## F-statistic: 73.35 on 1 and 6433 DF,  p-value: < 2.2e-16


Kali ini kita ingin melakukan pemodelan prediksi multiple regresi. Yang pertama kita lakukan adalah melihat hubungan antara Weekly_Sales dan Unemployment pada data Walmart. Hal ini kita lakukan untuk memudahkan kita dalam menentukan suatu prediksi dan hasil prediksi apa yang kita inginkan. Pada langkah ini, kita lakukan untuk melihat hubungan antara kedua variabel nya adalah dengan menggunakan scatter plot. Kita perlu memplot variabel Unemployment pada sumbu x (sebagai prediktor) dan variabel Weekly Sales di sumbu y (sebagai targetnya).
Pada langkah ini kita juga ingin melihat hasil summary dari 2 variable yang kita ambil untuk diprediksi.


Dari grafik di atas, dapat kita simpulkan bahwa jika angka pengangguran atau Unemployment kecil, maka penjualan mingguan atau Weekly Sales nya cenderung akan meningkat. Sebaliknya, jika Unemployment meningkat, maka Weekly_Sales nya cenderung menurun. Akan tetapi, dalam hal ini, apakah tingkat Unemployment saja cukup untuk memprediksi adanya tingkat Weekly Sales nya? Jelas hal ini belum terlalu akurat. Atau bisa dibilang belum cukup. Mungkin saja apakah Temperature juga sangat berpengaruh terhadap meningkatnya Weekly Sales. Hal ini dapat mungkin terjadi. untuk dapat mengetahui nya, kita akan melakukan sebuah prediksi. Lebih tepatnya dengan Multiple Regression.
Kita akan memprediksi apakah tingkat Unemployment dan Temperature (suhu) berpengaruh terhadap peningkatan penjualan mingguannya? Mari kita lihat pada langkah setelah ini.

walm_recipe <- recipe(Weekly_Sales ~ Temperature + Unemployment, data = Walmart) |>
  step_scale(all_predictors()) |>
  step_center(all_predictors())
walm_spec <- nearest_neighbor(weight_func = "rectangular",
                              neighbors = tune()) |>
  set_engine("kknn") |>
  set_mode("regression")


Kita akan membangun spesifikasi model baru dan resep untuk analisis. Perhatikan bahwa kita menggunakan rumus Weekly_Sales ~ Temperature + Unemployment untuk menunjukkan bahwa kita memiliki dua prediktor, dan mengatur neighbor = tune() untuk memberitahu tidymodels untuk menyetel jumlah tetangga atau titik. Terdapat 1 outcome dan 2 predictors.

Selanjutnya, kita akan menggunakan validasi silang 5 kali lipat untuk memilih jumlah tetangga melalui RMSPE minimum:

gridvals <- tibble(neighbors = seq(1,200))
walm_multi <- workflow() |>
  add_recipe(walm_recipe) |>
  add_model(walm_spec) |>
  tune_grid(w_vfold, grid = gridvals) |>
  collect_metrics() |>
  dplyr::filter(.metric == "rmse") |>
  dplyr::filter(mean == min(mean))
walm_k <- walm_multi |>
  pull(neighbors)
walm_multi

Di sini kita melihat kalau nilai RMSPE yang terkecil dari validasi silang terjadi Ketika K = 35. Jika kita ingin membandingkan model regresi KNN multivariabel ini dengan model dengan hanya prediktor tunggal sebagai bagian dari proses penyetelan model.
Pada pemodelan multiiple regresi ini kita mendapatkan K=35.

walm_spec <- nearest_neighbor(weight_func = "rectangular", 
                              neighbors = walm_k) |>
  set_engine("kknn") |>
  set_mode("regression")
knn_mult_fit <- workflow() |>
  add_recipe(walm_recipe) |>
  add_model(walm_spec) |>
  fit(data = walmart_train)
knn_mult_preds <- knn_mult_fit |>
  predict(walmart_test) |>
  bind_cols(walmart_test)
knn_mult_mets <- metrics(knn_mult_preds, truth = Weekly_Sales, estimate = .pred) |>
  dplyr::filter(.metric == "rmse")
knn_mult_mets


Ketika kami melakukan regresi KNN pada kumpulan data yang sama, dan juga menambahkan Temperature sebagai prediktor, kami memperoleh kesalahan tes RMSPE sebesar 535662.4.


Agar kita dapat melihat gambarannya lebih rinci, kita dapat membuat 3D plot. Disini kita menggunakan library plotly untuk membuatnya. Disini kita memplot variable Unemployment sebagai sb. x, Weekly_Sales sebagai sb. y dan Temperature sebagai sb. z. Dari grafik dapat kita simpulkan bahwa Unemployment dapat berpengaruh karena adanya Temperature yang terjadi. Maka dari itu, semakin tinggi Unemployment, maka Weekly Sales nya semakin rendah.

Build Classification models to predict the sales w.r.t single &; multiple features.

Single Classification

Season ~ CPI, unemployment

Hal yang pertama yang akan kita lakukan adalah melihat data dan membuat prediksi sebagai levels. Pada cara kali ini kita akan menggunakan cara manual dan cara k-nearest neighbor.

glimpse(Walmart)
## Rows: 6,435
## Columns: 19
## $ Store        <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ~
## $ Date         <fct> 05-02-2010, 12-02-2010, 19-02-2010, 26-02-2010, 05-03-201~
## $ Weekly_Sales <dbl> 1643691, 1641957, 1611968, 1409728, 1554807, 1439542, 147~
## $ Holiday_Flag <int> 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ~
## $ Temperature  <dbl> 42.31, 38.51, 39.93, 46.63, 46.50, 57.79, 54.58, 51.45, 6~
## $ Fuel_Price   <dbl> 2.572, 2.548, 2.514, 2.561, 2.625, 2.667, 2.720, 2.732, 2~
## $ CPI          <dbl> 211.0964, 211.2422, 211.2891, 211.3196, 211.3501, 211.380~
## $ Unemployment <dbl> 8.106, 8.106, 8.106, 8.106, 8.106, 8.106, 8.106, 8.106, 7~
## $ Month        <chr> "02", "02", "02", "02", "03", "03", "03", "03", "04", "04~
## $ Year         <chr> "2010", "2010", "2010", "2010", "2010", "2010", "2010", "~
## $ dayOfWeek    <ord> Sun, Mon, Wed, Fri, Sun, Tue, Wed, Fri, Sat, Mon, Wed, Th~
## $ TypeOfDay    <chr> "Not_Holiday", "Holiday", "Not_Holiday", "Not_Holiday", "~
## $ Season       <chr> "Winter", "Winter", "Winter", "Winter", "Spring", "Spring~
## $ Quarter      <yearqtr> 2010 Q1, 2010 Q1, 2010 Q1, 2010 Q1, 2010 Q1, 2010 Q1,~
## $ Super_Bowl   <chr> "0", "1", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0~
## $ Labour_Day   <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0~
## $ Chrismast    <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0~
## $ Thanksgiving <chr> "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0~
## $ Mon_Year     <date> 2010-02-05, 2010-02-12, 2010-02-19, 2010-02-26, 2010-03-~
Walmart <- Walmart|>
  mutate(Season = as_factor(Season))
Walmart |>
  pull(Season) |>
  levels()     
## [1] "Winter" "Spring" "Summer" "Autumn"


Plot di atas adalah plot hubungan antara CPI dan Unemployment. Kita ingin mengklasifikasikan satu titik baru yang berada pada Unemployment = 7, dan CPI = 200. Kali ini kita akan mengklasifikasikan titik tersebut dengan k yang terbaik yaitu k =1 (nanti akan ditunjukkan bagaimana cara mencari k=1). kita ingin mengetahui data tersebut kemungkinan terjadi di musim (season) apa.

x_new = 7
y_new = 200

class = Walmart |>
  select(Season, CPI, Unemployment )|>
  mutate(distance_new = sqrt((Unemployment-x_new)^2 +
                             (CPI - y_new)^2))|>
  arrange(distance_new)|>
  slice(1)
class = class%>%
  count(Season)%>%
  dplyr::filter(n == max(n))
## [1] "pada saat Unemployment =  7 dan CPI = 200 . di titik tersebut, bisa diklasifikasikan sebagai data yang berada saat Autumn"

Menggunakan KNN

menentukan K

untuk menentukan k, kita harus membuat memisahkan data menjadi data yang akan di train dan test. Yang pastinya kita mengambil data tersebut secara acak dan dipastikan datanya proporsinya sama antara data test dan data train. dari total, kita menggunakan 75% untuk untuk training, dan 25% untuk testing.


f_w_train <- Walmart|>
  select(Season, CPI, Unemployment)

f_w_split <- initial_split(f_w_train, prop = 0.75, strata = Season)
f_w_test <- testing(f_w_split)
f_w_train<- training(f_w_split)

glimpse(f_w_train)
## Rows: 4,825
## Columns: 3
## $ Season       <fct> Autumn, Autumn, Autumn, Autumn, Autumn, Autumn, Autumn, A~
## $ CPI          <dbl> 211.5312, 211.4952, 211.5225, 211.6720, 211.8137, 211.908~
## $ Unemployment <dbl> 7.787, 7.787, 7.787, 7.838, 7.838, 7.838, 7.838, 7.838, 7~
glimpse(f_w_test)
## Rows: 1,610
## Columns: 3
## $ Season       <fct> Winter, Spring, Spring, Spring, Spring, Spring, Spring, S~
## $ CPI          <dbl> 211.2422, 211.2156, 211.0180, 210.6229, 210.4391, 210.340~
## $ Unemployment <dbl> 8.106, 8.106, 8.106, 7.808, 7.808, 7.808, 7.808, 7.808, 7~
f_w_proportions <- f_w_train |>
                      group_by(Season) |>
                      summarize(n = n()) |>
                      mutate(percent = 100*n/nrow(f_w_train))

f_w_proportions


Pada proporsi diatas menunjukkan proporsi setiap season dari data train (75% dari total data)

Lalu kita akan membuat dan menyiapkan recipe dengan training data. Season ~. berarti prediktor yang dipilih adalah semua kolom kecuali Season (CPI + Unemployment). Recipe ini membantu menstandarisasi data kita.

f_w_recipe <- recipe(Season ~., data = f_w_train)|>
  step_scale(all_predictors()) |>
  step_center(all_predictors())


untuk mencari nilai K yang plaing cocok dengan data kita, kita akan melanjutkan menggunakan 5-fold cross-validation. strata ini merupakan variabel kategori untuk memastikan training dan validasi ini terdapat proporsi yang sama.

f_w_vfold <- vfold_cv(f_w_train, v = 5, strata = Season)

#parameter
f_w_spec <- nearest_neighbor(weight_func = "rectangular", 
                             neighbors = tune()) |>
  set_engine("kknn") |>
  set_mode("classification")


k_vals <- tibble(neighbors = seq(from = 1, to = 100, by = 3))

f_w_results <- workflow() |>
  add_recipe(f_w_recipe) |>
  add_model(f_w_spec) |>
  tune_grid(f_w_vfold, grid = k_vals) |>
  collect_metrics() 

accuracies <- f_w_results |>
  dplyr::filter(.metric == "accuracy")

accuracies


dari hasil di atas, kita bisa melihat berapa neighbor yang terbaik dengan akurasinya. kita akan mengambil K dengan nilai akurasinya yang paling tinggi.

accuracy_vs_k <- ggplot(accuracies, aes(x = neighbors, y = mean)) +
  geom_point() +
  geom_line() +
  labs(x = "Neighbors", y = "Accuracy Estimate") + 
  theme(text = element_text(size = 12))

accuracy_vs_k

s <- accuracies|>
  dplyr::filter(mean == max(accuracies$mean))
## [1] "k yang paling cocok dengan klasifikasi di atas adalah  1 dengan akurasi sebesar 88.62 %"

klasifikasi 1 dengan k

coding di bawah ini untuk menghitung accuries dan confusion matrics soal terakhir. k =1 dari yang sudah kita cari di atas.

f_w_spec <- nearest_neighbor(weight_func = "rectangular", neighbors = 1) |>
  set_engine("kknn") |>
  set_mode("classification")
f_w_spec
## K-Nearest Neighbor Model Specification (classification)
## 
## Main Arguments:
##   neighbors = 1
##   weight_func = rectangular
## 
## Computational engine: kknn
f_w_fit <- workflow()|>
  add_recipe(f_w_recipe)|>
  add_model(f_w_spec)|>
  fit(data = f_w_train)
f_w_fit
## == Workflow [trained] ==========================================================
## Preprocessor: Recipe
## Model: nearest_neighbor()
## 
## -- Preprocessor ----------------------------------------------------------------
## 2 Recipe Steps
## 
## * step_scale()
## * step_center()
## 
## -- Model -----------------------------------------------------------------------
## 
## Call:
## kknn::train.kknn(formula = ..y ~ ., data = data, ks = min_rows(1,     data, 5), kernel = ~"rectangular")
## 
## Type of response variable: nominal
## Minimal misclassification: 0.09720207
## Best kernel: rectangular
## Best k: 1

Multi Classification

Weekly Sales, CPI, Unemployment, dengan dayOfweek

Cara klasifikasi untuk multi variabel ini kita menggunakan cara manual.

new_x <- 2000000
new_y <- 200
new_z <- 8

class_m = Walmart |>
  select(dayOfWeek, Weekly_Sales, CPI, Unemployment) |>
  mutate(dist_from_new = sqrt((Weekly_Sales - new_x)^2 + 
                              (CPI - new_y)^2 +
                              (Unemployment - new_y)^2)) |>
  arrange(dist_from_new) |>
  slice(1:5)|>
  count(dayOfWeek)|>
  dplyr::filter(n == max(n))
## [1] "pada saat weekly sales=  2e+06 CPI = 200 dan Unemployment = 8 . di titik tersebut, bisa diklasifikasikan sebagai data yang berada di hari Sun"

Also evaluate the models & compare their respective scores like R2, RMSE, etc.

Regresion

x = Walmart$Temperature
y = Walmart$Weekly_Sales
z = Walmart$Unemployment

a = lm(y~x)
b = lm(y~x + z)

RSS <- c(crossprod(a$residuals))
MSE <- RSS / length(a$residuals)
RMSE <- sqrt(MSE)
rsq <- function(x, y) summary(lm(y~x))$r.squared
rsq <- rsq(x, y)
MAE <- mae(y, predict(a))
MAPE <- MAPE(y, predict(a))

RSSm <- c(crossprod(b$residuals))
MSEm <- RSSm / length(b$residuals)
RMSEm <- sqrt(MSEm)
rsqm <- function(x, y, z) summary(lm(y~x + z))$r.squared
rsqm <- rsqm(x, y, z)
MAEm <- mae(y, predict(b))
MAPEm <- MAPE(y, predict(b))

a
## 
## Call:
## lm(formula = y ~ x)
## 
## Coefficients:
## (Intercept)            x  
##     1165406        -1952
b
## 
## Call:
## lm(formula = y ~ x + z)
## 
## Coefficients:
## (Intercept)            x            z  
##     1388956        -1641       -30312

Kesalahan mewakili seberapa banyak model membuat kesalahan dalam prediksinya. Konsep dasar evaluasi akurasi adalah membandingkan target asli dengan yang diprediksi sesuai dengan metrik tertentu. Pada langkah ini kita akan mengevaluasi nilai error dari Temperature dengan Weekly Sales untuk single regression. Sedangkan Temperature, Weekly Sales, Unemployment untuk multiple regression.
-MAE (Mean absolute error) mewakili perbedaan antara nilai asli dan yang diprediksi yang diekstraksi dengan rata-rata perbedaan absolut atas kumpulan data.
-MSE (Mean Squared Error) mewakili perbedaan antara nilai asli dan yang diprediksi yang diekstraksi dengan kuadrat perbedaan rata-rata atas kumpulan
-RMSE (Root Mean Squared Error) adalah tingkat kesalahan oleh akar kuadrat MSE.
-R-kuadrat (Koefisien penentuan) mewakili koefisien seberapa baik nilai cocok dibandingkan dengan nilai asli.

Single Regression

## [1] "R Squared Weekly_Sales vs Temperature = 0.00407171778196404"
## [1] "RSS Weekly_Sales vs Temperature = 2040947171567264"
## [1] "MSE Weekly_Sales vs Temperature = 317163507625.06"
## [1] "RMSE Weekly_Sales vs Temperature = 563172.715625553"
## [1] "MAE Weekly_Sales vs Temperature = 469311.038798951"
## [1] "MAPE Weekly_Sales vs Temperature = 0.449407402016314"

Multi Regression

## [1] "R Squared Weekly_Sales vs Temperature vs Unemployment = 0.0141188479991632"
## [1] "RSS Weekly_Sales vs Temperature vs Unemployment = 2020357674948605"
## [1] "MSE Weekly_Sales vs Temperature vs Unemployment = 313963896650.91"
## [1] "RMSE Weekly_Sales vs Temperature vs Unemployment = 560324.813524183"
## [1] "MAE Weekly_Sales vs Temperature vs Unemployment = 469283.332252412"
## [1] "MAPE Weekly_Sales vs Temperature vs Unemployment = 0.448217493638212"

Classification

Untuk mengevaluasi model klasifikasi kita, kita bisa menggunakan akurasi, confusion matriks, presisi, dan F1 score.
### Single

### prediction
f_w_test_prediction <- predict(f_w_fit, f_w_test) |>
  bind_cols(f_w_test)
f_w_test_prediction
# accuracy
accuracy = f_w_test_prediction|>
  metrics(truth = Season, estimate = .pred_class)|>
  dplyr::filter(.metric == "accuracy")

# Confution Matrics
confusion <- f_w_test_prediction|>
  conf_mat(truth = Season, estimate = .pred_class)

cm = matrix(c(299,14,1,10,16,402,14,1,2,22,422,21,21,1,13,351), nrow = 4, byrow = TRUE)

TP = cm[1,1]+cm[2,2]+cm[3,3]+cm[4,4]
FP = cm[2,1]+cm[3,1]+cm[4,1]+cm[3,2]+cm[4,2]+cm[4,3]
TN = 0
FN = cm[1,2]+cm[1,3]+cm[1,4]+cm[2,3]+cm[2,4]+cm[3,4]

Precision = (TP / (TP+FP)) 
Recall    = (TP / (TP+FN)) 


F1_score  = 2*((Precision * Recall)/ (Precision+Recall))
## [1] "Single Classification"
## [1] "akurasi dari klasifikasi adalah  0.92"
##           Truth
## Prediction Winter Spring Summer Autumn
##     Winter    299     14      1     10
##     Spring     16    402     14      1
##     Summer      2     22    422     21
##     Autumn     21      1     13    351
## [1] "Precision adalah 0.951581665590704"
## [1] "F1 Scorenya adalah 95.59 %"