Background


Data historis suatu perusahaan yang diolah dengan baik, dapat memberi peluang baru agar perusahaan tersebut bisa beroperasi dengan lebih optimal. Hal tersebut yang ingin dicapai oleh perusahaan pesan-antar makanan, yakni ingin mengoptimasi aktivitas penjualan dan pelayanan mereka. Perusahaan ini memiliki banyak cabang di beberapa kota dan mempunyai data historis yang mencatat seluruh aktivitas pesanan dalam pola mingguan. Data diperoleh dari Kaggle : https://www.kaggle.com/ghoshsaptarshi/av-genpact-hack-dec2018?select=train.csv sebagai bagian dari Machine Learning Hackathon yang diselenggarakan oleh Analytics Vidhya & Genpact pada Desember 2018.

Setidaknya ada 4 data yang disediakan untuk dieksplor dan dibuat model machine learning: train, test, mealinfo, dan fcenter. Keempatnya bisa diolah masalah utama yang ingin dipecahkan, yaitu memprediksi jumlah penjualan selama 10 minggu mendatang (minggu ke 146 hingga 155). Uniknya dalam dataset yang tersedia, tidak ada variabel yang secara langsung mencatat historis waktu pada tiap observasi. Informasi waktu (mingguan), tercatat dalam bentuk urutan minggu kesekian. Ini adalah salah satu hal yang menarik, apakah pendekatan machine learning forecasting mampu membaca tipe dataset seperti ini? Atau perlu menggunakan model lain?

Eksplorasi dataset secara mendalam bisa memberi informasi penting terkait perlu tidaknya sebuah menu dipromosikan melaui email atau platform digital. Di sisi lain, hasil prediksi jumlah pesanan (variabel : num_orders) dari pemodelan machine learning akan digunakan untuk mengoptimasi rencana persediaan bahan makanan dan penempatan pekerja untuk tiap cabang pesan-antar.


Dataset:

Train

Data train menyimpan data historik terkait aktivitas delivery untuk semua cabang. Adanya data train adalah supaya model machine learning yang nanti dibuat bisa mempelajari banyak data.

Keterangan data train:

  1. id: unique ID
  2. week: week number
  3. center_id: unique ID for fulfillment center
  4. meal_id: unique ID for meal
  5. checkout_price: Final price including discount, taxes and delivery charges
  6. base_price: Base price of the meal
  7. emailer_for_promotion: Email sent for promotion
  8. homepage_featured: Meal featured at homepage
  9. num_orders: Orders count (target)

Dimensi data:

## [1] 456548      9

Test

Data test punya variabel yang sama dengan train, hanya berbeda di variabel target yang nantinya perlu diisi dengan hasil prediksi menggunakan machine learning.

Keterangan data test:

  1. id: unique ID
  2. week: week number
  3. center_id: unique ID for fulfillment center
  4. meal_id: unique ID for meal
  5. checkout_price: Final price including discount, taxes and delivery charges
  6. base_price: Base price of the meal
  7. emailer_for_promotion: Email sent for promotion
  8. homepage_featured: Meal featured at homepage

Dimensi data:

## [1] 32573     8

Meal Info

Data mealinfo mencatat seluruh informasi tentang makanan yang disajikan untuk kemudian diantar ke tempat tujuan.

Keterangan data mealinfo:

  1. meal_id: unique ID for meal
  2. category: type of meal (beverages/snacks/soup/etc)
  3. cuisine: meal cuisine (Indian/Italian/etc)

Dimensi data:

## [1] 51  3

Fulfilment Center Info

Data fcenter mencatat informasi dari setiap cabang yang melayani suatu pesanan.

Keterangan data fcenter:

  1. center_id: unique ID for fulfillment center
  2. city_code: unique code for city
  3. region_code: unique code for region
  4. center_type: anonymized center type
  5. op_area: area of operation (in km^2) Dimensi data:
## [1] 77  5

Preprocessing Data

Pada tahap ini, kita melakukan:

  • Data cleansing, melihat dan menyesuaikan tipe data, cek NA/missing value, dan duplicated value.
  • Data merging , menggabungkan beberapa dataset agar bisa dieksplorasi dan diolah lebih jauh.

Data Cleansing

Train

Data Structure
## Rows: 456,548
## Columns: 9
## $ id                    <int> 1379560, 1466964, 1346989, 1338232, 1448490, ...
## $ week                  <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
## $ center_id             <int> 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 5...
## $ meal_id               <int> 1885, 1993, 2539, 2139, 2631, 1248, 1778, 106...
## $ checkout_price        <dbl> 136.83, 136.83, 134.86, 339.50, 243.50, 251.2...
## $ base_price            <dbl> 152.29, 135.83, 135.86, 437.53, 242.50, 252.2...
## $ emailer_for_promotion <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ...
## $ homepage_featured     <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, ...
## $ num_orders            <int> 177, 270, 189, 54, 40, 28, 190, 391, 472, 676...
Transforming Data Type
## Rows: 456,548
## Columns: 9
## $ id                    <fct> 1379560, 1466964, 1346989, 1338232, 1448490, ...
## $ week                  <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
## $ center_id             <fct> 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 5...
## $ meal_id               <fct> 1885, 1993, 2539, 2139, 2631, 1248, 1778, 106...
## $ checkout_price        <dbl> 136.83, 136.83, 134.86, 339.50, 243.50, 251.2...
## $ base_price            <dbl> 152.29, 135.83, 135.86, 437.53, 242.50, 252.2...
## $ emailer_for_promotion <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ...
## $ homepage_featured     <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, ...
## $ num_orders            <int> 177, 270, 189, 54, 40, 28, 190, 391, 472, 676...
Missing Value
##                    id                  week             center_id 
##                     0                     0                     0 
##               meal_id        checkout_price            base_price 
##                     0                     0                     0 
## emailer_for_promotion     homepage_featured            num_orders 
##                     0                     0                     0
Tidak ada missing value pada data train.
Duplicated

Tidak ada duplicated value pada data train.

Test

Data Structure
## Rows: 32,573
## Columns: 8
## $ id                    <int> 1028232, 1127204, 1212707, 1082698, 1400926, ...
## $ week                  <int> 146, 146, 146, 146, 146, 146, 146, 146, 146, ...
## $ center_id             <int> 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 5...
## $ meal_id               <int> 1885, 1993, 2539, 2631, 1248, 1778, 1062, 270...
## $ checkout_price        <dbl> 158.11, 160.11, 157.14, 162.02, 163.93, 190.1...
## $ base_price            <dbl> 159.11, 159.11, 159.14, 162.02, 163.93, 190.1...
## $ emailer_for_promotion <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
## $ homepage_featured     <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ...
Transforming Data Type
## Rows: 32,573
## Columns: 8
## $ id                    <fct> 1028232, 1127204, 1212707, 1082698, 1400926, ...
## $ week                  <int> 146, 146, 146, 146, 146, 146, 146, 146, 146, ...
## $ center_id             <fct> 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 5...
## $ meal_id               <fct> 1885, 1993, 2539, 2631, 1248, 1778, 1062, 270...
## $ checkout_price        <dbl> 158.11, 160.11, 157.14, 162.02, 163.93, 190.1...
## $ base_price            <dbl> 159.11, 159.11, 159.14, 162.02, 163.93, 190.1...
## $ emailer_for_promotion <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
## $ homepage_featured     <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ...
Missing Value
##                    id                  week             center_id 
##                     0                     0                     0 
##               meal_id        checkout_price            base_price 
##                     0                     0                     0 
## emailer_for_promotion     homepage_featured 
##                     0                     0
Tidak ada missing value pada data test.
Duplicated

Tidak ada duplicated value pada data test.

Meal Info

Data Structure
## Rows: 51
## Columns: 3
## $ meal_id  <int> 1885, 1993, 2539, 1248, 2631, 1311, 1062, 1778, 1803, 1198...
## $ category <chr> "Beverages", "Beverages", "Beverages", "Beverages", "Bever...
## $ cuisine  <chr> "Thai", "Thai", "Thai", "Indian", "Indian", "Thai", "Itali...
Transforming Data Type
## Rows: 51
## Columns: 3
## $ meal_id  <fct> 1885, 1993, 2539, 1248, 2631, 1311, 1062, 1778, 1803, 1198...
## $ category <fct> Beverages, Beverages, Beverages, Beverages, Beverages, Ext...
## $ cuisine  <fct> Thai, Thai, Thai, Indian, Indian, Thai, Italian, Italian, ...
Missing Value
##  meal_id category  cuisine 
##        0        0        0

Tidak ada missing value pada data mealinfo.

Duplicated

Tidak ada duplicated value pada data mealinfo.

Fulfilment Center Info

Data Structure
## Rows: 77
## Columns: 5
## $ center_id   <int> 11, 13, 124, 66, 94, 64, 129, 139, 88, 143, 101, 86, 32...
## $ city_code   <int> 679, 590, 590, 648, 632, 553, 593, 693, 526, 562, 699, ...
## $ region_code <int> 56, 56, 56, 34, 34, 77, 77, 34, 34, 77, 85, 85, 34, 77,...
## $ center_type <chr> "TYPE_A", "TYPE_B", "TYPE_C", "TYPE_A", "TYPE_C", "TYPE...
## $ op_area     <dbl> 3.7, 6.7, 4.0, 4.1, 3.6, 4.4, 3.9, 2.8, 4.1, 3.8, 2.8, ...
Transforming Data Type
## Rows: 77
## Columns: 5
## $ center_id   <int> 11, 13, 124, 66, 94, 64, 129, 139, 88, 143, 101, 86, 32...
## $ city_code   <int> 679, 590, 590, 648, 632, 553, 593, 693, 526, 562, 699, ...
## $ region_code <int> 56, 56, 56, 34, 34, 77, 77, 34, 34, 77, 85, 85, 34, 77,...
## $ center_type <chr> "TYPE_A", "TYPE_B", "TYPE_C", "TYPE_A", "TYPE_C", "TYPE...
## $ op_area     <dbl> 3.7, 6.7, 4.0, 4.1, 3.6, 4.4, 3.9, 2.8, 4.1, 3.8, 2.8, ...
Missing Value
##   center_id   city_code region_code center_type     op_area 
##           0           0           0           0           0

Tidak ada missing value pada data fcenter.

Duplicated

Tidak ada duplicated value pada data fcenter.



Data Merging : datatrain

Kita perlu menggabungkan (merge) beberapa dataset yang disediakan menjadi satu data tabular yang siap diproses. Data train dan test masing-masing akan digabung dengan mealinfo (berdasarkan meal_id) dan fcenter (berdasarkan center_id).

Data Structure
## Rows: 456,548
## Columns: 15
## $ center_id             <fct> 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 1...
## $ meal_id               <fct> 2707, 1525, 1311, 2581, 1207, 2704, 1445, 230...
## $ id                    <fct> 1347181, 1016940, 1378864, 1223760, 1260561, ...
## $ week                  <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
## $ checkout_price        <dbl> 196.00, 243.50, 174.66, 581.03, 322.07, 243.5...
## $ base_price            <dbl> 196.00, 281.33, 173.66, 610.13, 382.18, 281.3...
## $ emailer_for_promotion <fct> 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, ...
## $ homepage_featured     <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
## $ num_orders            <int> 1350, 824, 595, 485, 769, 473, 175, 323, 717,...
## $ category              <fct> Beverages, Other Snacks, Extras, Pizza, Bever...
## $ cuisine               <fct> Italian, Thai, Thai, Continental, Continental...
## $ city_code             <int> 590, 590, 590, 590, 590, 590, 590, 590, 590, ...
## $ region_code           <int> 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 5...
## $ center_type           <chr> "TYPE_B", "TYPE_B", "TYPE_B", "TYPE_B", "TYPE...
## $ op_area               <dbl> 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, ...
Transforming Data Type
## Rows: 456,548
## Columns: 15
## $ center_id             <fct> 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 1...
## $ meal_id               <fct> 2707, 1525, 1311, 2581, 1207, 2704, 1445, 230...
## $ id                    <fct> 1347181, 1016940, 1378864, 1223760, 1260561, ...
## $ week                  <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
## $ checkout_price        <dbl> 196.00, 243.50, 174.66, 581.03, 322.07, 243.5...
## $ base_price            <dbl> 196.00, 281.33, 173.66, 610.13, 382.18, 281.3...
## $ emailer_for_promotion <fct> 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, ...
## $ homepage_featured     <fct> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ...
## $ num_orders            <int> 1350, 824, 595, 485, 769, 473, 175, 323, 717,...
## $ category              <fct> Beverages, Other Snacks, Extras, Pizza, Bever...
## $ cuisine               <fct> Italian, Thai, Thai, Continental, Continental...
## $ city_code             <fct> 590, 590, 590, 590, 590, 590, 590, 590, 590, ...
## $ region_code           <fct> 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 5...
## $ center_type           <chr> "TYPE_B", "TYPE_B", "TYPE_B", "TYPE_B", "TYPE...
## $ op_area               <dbl> 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, 6.3, ...
Missing Value
##             center_id               meal_id                    id 
##                     0                     0                     0 
##                  week        checkout_price            base_price 
##                     0                     0                     0 
## emailer_for_promotion     homepage_featured            num_orders 
##                     0                     0                     0 
##              category               cuisine             city_code 
##                     0                     0                     0 
##           region_code           center_type               op_area 
##                     0                     0                     0
Check Outliers

## [1] 32937

## [1] 306


Data outlier pada target variabel mencapai puluhan ribu. Untuk itu, beberapa variabel numerik–termasuk target–perlu ditransformasi menggunakan scale/log. Tampak perbedaan jumlah data outlier yang cukup signifikan setelah target variabel ditransformasi menggunakan log. Lebih jauh lagi, beberapa variabel numerik lainnya juga akan diberi perlakuan sama. Untuk sekarang sekarang kita sudah memiliki datatrain yang siap untuk diekplor dan divisualisasikan agar mendapat informasi/insight yang berguna. Berikutnya akan dibuat model machine learning supaya bisa menghasilkan prediksi yang tepat pada variabel num_orders.

Exploratory Data Analysis

Kita coba buat kolom baru yang menyimpan informasi penjualan sebagai hasil perkalian kolom checkout_price dan num_orders. Kolom sales nantinya akan diolah untuk menghasilkan visualisasi jenis makanan apa saya yang cukup diminati dan berkontribusi paling besar pada kenaikan angka penjualan.


Dari grafik di atas, kita bisa tahu rata-rata penjualan tiap minggunya (minggu ke 1-145) selalu naik turun, ada pola seasonality pada datatrain. Namun keadaan ini belum bisa diinterpretasikan lebih jauh, yang jelas rata-rata penjualan sejauh ini berada di angka 60.000 hingga 70.000 setiap minggu.

Ada 14 jenis (category) makanan yang tersedia pada datatrain, dimana Beverages adalah jenis yang paling sering dipesan oleh pembeli. Posisinya sangat unggul jauh dibanding jenis makanan lain. Keadaan ini bisa dipengaruhi karena kecenderungan orang-orang yang lebih suka mengonsumsi makanan ringan (camilan) ketimbang makanan berat. Namun dengan penjualan Beverages sebanyak lebih dari 120.000 pesanan, apakah berarti jenis makanan ini berkontribusi paling besar dalam meningkatkan angka penjualan?

Nyatanya tidak. Secara visualisasi, cukup jelas category makanan Rice Bowl membawa keuntungan paling besar dari seluruh data penjualan, yaitu sekitar 170.000. Kemudian ada Sandwich di peringkat dua dan Pizza di peringkat tiga. Sedangkan kontribusi Beveragescenderung kecil, sekitar 6.000 saja. Maka dari itu, perusahaan tetap perlu memperhatikan ketersediaan bahan bukan hanya makanan yang paling sering dipesan, tapi juga makanan yang punya angka penjualan tinggi.

Mengingat tingginya permintaan Beverages maka penting bagi perusahaan bisa memenuhi permintaan pembeli dengan baik. Walau kontribusinya tidak terlalu signifikan, Beverages bisa menjadi kunci untuk membangun kepuasan berbelanja bagi pembeli. Maka dari itu, plot di atas menjelaskan cuisine Italian dan Continental sebagai favorit pembeli yang memesan Beverages.