Ulasan Kasus

Data yang digunakan dalam analsis R ini didapatkan dari situs Kaggle, berisi data pemesanan penerbangan yang diperoleh dari situs web “Ease My Trip”. Selanjutnya, saya akan menganalisis pola harga tiket penerbangan dengan fokus pada identifikasi harga ekstrem (outlier) dan faktor-faktor yang memengaruhinya. Selanjutnya, sebaran harga juga akan diperiksa untuk memahami apakah distribusinya normal atau condong ke satu sisi (skewed), sehingga pendekatan analisis yang digunakan dapat lebih sesuai dengan karakteristik datanya.

# Memasukkan data ke data frame bernama data_penerbangan
data_penerbangan <- read.csv("D:/Documents/Downloads/archive/Clean_Dataset.csv", 
                             colClasses = c("X" = "NULL"))    
# Menampilkan beberapa data awal dari data_penerbangan
head(data_penerbangan)
##    airline  flight source_city departure_time stops  arrival_time
## 1 SpiceJet SG-8709       Delhi        Evening  zero         Night
## 2 SpiceJet SG-8157       Delhi  Early_Morning  zero       Morning
## 3  AirAsia  I5-764       Delhi  Early_Morning  zero Early_Morning
## 4  Vistara  UK-995       Delhi        Morning  zero     Afternoon
## 5  Vistara  UK-963       Delhi        Morning  zero       Morning
## 6  Vistara  UK-945       Delhi        Morning  zero     Afternoon
##   destination_city   class duration days_left price
## 1           Mumbai Economy     2.17         1  5953
## 2           Mumbai Economy     2.33         1  5953
## 3           Mumbai Economy     2.17         1  5956
## 4           Mumbai Economy     2.25         1  5955
## 5           Mumbai Economy     2.33         1  5955
## 6           Mumbai Economy     2.33         1  5955
str(data_penerbangan)          # untuk melihat tipe data setiap variabel
## 'data.frame':    300153 obs. of  11 variables:
##  $ airline         : chr  "SpiceJet" "SpiceJet" "AirAsia" "Vistara" ...
##  $ flight          : chr  "SG-8709" "SG-8157" "I5-764" "UK-995" ...
##  $ source_city     : chr  "Delhi" "Delhi" "Delhi" "Delhi" ...
##  $ departure_time  : chr  "Evening" "Early_Morning" "Early_Morning" "Morning" ...
##  $ stops           : chr  "zero" "zero" "zero" "zero" ...
##  $ arrival_time    : chr  "Night" "Morning" "Early_Morning" "Afternoon" ...
##  $ destination_city: chr  "Mumbai" "Mumbai" "Mumbai" "Mumbai" ...
##  $ class           : chr  "Economy" "Economy" "Economy" "Economy" ...
##  $ duration        : num  2.17 2.33 2.17 2.25 2.33 2.33 2.08 2.17 2.17 2.25 ...
##  $ days_left       : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ price           : int  5953 5953 5956 5955 5955 5955 6060 6060 5954 5954 ...
sum(is.na(data_penerbangan))   # untuk mengecek apakah ada missing value pada tiap variabel
## [1] 0

Melakukan Eksplorasi Awal Dengan Statistika Deskriptif

library(dplyr)   # Memasukkan library yang diperlukan
## Warning: package 'dplyr' was built under R version 4.4.2
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
# Menentukan ukuran pemusatan untuk masing-masing variabel
ukuran_pemusatan <- list(
  airline = names(which.max(table(data_penerbangan$airline))),  # Modus untuk data kategorik
  flight = names(which.max(table(data_penerbangan$flight))),  # Modus untuk data kategorik
  source_city = names(which.max(table(data_penerbangan$source_city))),  # Modus untuk data kategorik
  departure_time = names(which.max(table(data_penerbangan$departure_time))),  # Modus untuk data kategorik
  stops = names(which.max(table(data_penerbangan$stops))),  # Modus untuk data kategorik
  arrival_time = names(which.max(table(data_penerbangan$arrival_time))),  # Modus untuk data kategorik
  destination_city = names(which.max(table(data_penerbangan$destination_city))),  # Modus untuk data kategorik
  class = names(which.max(table(data_penerbangan$class))),  # Modus untuk data kategorik
  duration = mean(data_penerbangan$duration, na.rm = TRUE),  # Mean untuk data numerik
  days_left = median(data_penerbangan$days_left, na.rm = TRUE),  # Median untuk data integer
  price = mean(data_penerbangan$price, na.rm = TRUE)  # Mean untuk data numerik
)

# Menampilkan hasil ukuran pemusatan
print(ukuran_pemusatan)
## $airline
## [1] "Vistara"
## 
## $flight
## [1] "UK-706"
## 
## $source_city
## [1] "Delhi"
## 
## $departure_time
## [1] "Morning"
## 
## $stops
## [1] "one"
## 
## $arrival_time
## [1] "Night"
## 
## $destination_city
## [1] "Mumbai"
## 
## $class
## [1] "Economy"
## 
## $duration
## [1] 12.22102
## 
## $days_left
## [1] 26
## 
## $price
## [1] 20889.66

Berdasarkan hasil analisis ukuran pemusatan data di atas, mayoritas penerbangan dalam berasal dari Delhi dan menuju Mumbai, dengan maskapai yang paling sering dipakai adalah Vistara dengan nomor penerbangan yang paling umum adalah UK-706. Waktu keberangkatan yang paling sering terjadi adalah pagi hari, sementara waktu kedatangan yang dominan adalah malam hari. Sebagian besar penerbangan memiliki satu kali transit dan kelas penerbangan yang paling umum adalah ekonomi. Untuk variabel numerik, rata-rata durasi penerbangan adalah 12,22 jam, dengan jumlah hari tersisa sebelum keberangkatan memiliki nilai median 26 hari, serta harga tiket rata-rata sebesar 20.889,66 INR.

Memvisualisasikan Sebaran Data

# Membuat histogram untuk mengecek distribusi sebaran Harga tiket
hist (data_penerbangan$price,
      main = "Distribusi Harga Tiket",
      xlab = "Harga (INR)",
      col = 'skyblue')

Histogram “Distribusi Harga Tiket” di atas menunjukkan bahwa harga tiket pesawat memiliki distribusi right-skewed (menjulur ke kanan), di mana mayoritas harga tiket berada di kisaran 0 - 20.000 INR. Namun, terdapat beberapa kelompok harga yang lebih tinggi, bahkan hingga lebih dari 80.000 INR, yang kemungkinan besar merupakan outlier atau tiket kelas premium. Pola ini mengindikasikan adanya variasi harga yang cukup besar, yang mungkin dipengaruhi oleh beberapa faktor seperti maskapai, kelas penerbangan, jumlah hari sebelum keberangkatan, dan rute penerbangan.Selanjutnya akan diperiksa keberadaan nilai ekstrim pada kolom Harga di data_penerbangan.

# Load library yang diperlukan
library(ggplot2) 
## Warning: package 'ggplot2' was built under R version 4.4.2
# Boxplot dengan highlight pencilan
ggplot(data_penerbangan, aes(y = price)) +
  geom_boxplot(fill = "lightgreen", outlier.color = "red", outlier.shape = 16, outlier.size = 3) +
  labs(title = "Boxplot Harga Tiket", y = "Harga (INR)") +
  theme_minimal()

Boxplot di atas menunjukkan “Distribusi Harga Tiket” dalam satuan INR. Dari visualisasi ini, terlihat bahwa mayoritas data harga tiket berada pada rentang yang relatif rendah, dengan median harga berada di bagian bawah kotak. Namun, terdapat banyak outlier di bagian atas (harga tinggi), yang menunjukkan adanya tiket dengan harga jauh lebih mahal dibandingkan mayoritas tiket lainnya. Hal ini dapat mengindikasikan bahwa sebagian kecil tiket dijual dengan harga premium atau terdapat variasi harga yang signifikan,

# Load library
library(moments)

# Hitung skewness dan kurtosis
skewness_value <- skewness(data_penerbangan$price, na.rm = TRUE)
kurtosis_value <- kurtosis(data_penerbangan$price, na.rm = TRUE)

# Print hasil
cat("Skewness:", skewness_value, "\n")
## Skewness: 1.061372
cat("Kurtosis:", kurtosis_value, "\n")
## Kurtosis: 2.603694

Berdasarkan nilai skewness sebesar 1.061372 > 0, distribusi harga tiket penerbangan menunjukkan kemenjuluran ke kanan (right-skewed), yang berarti mayoritas harga tiket cenderung berada di kisaran yang lebih rendah, sementara ada sejumlah kecil tiket dengan harga yang jauh lebih tinggi. Hal ini sejalan dengan visualisasi histogram sebelumnya, di mana sebagian besar tiket berkumpul di rentang harga rendah, tetapi terdapat ekor panjang ke arah harga yang lebih mahal. Sementara itu, nilai kurtosis 2.603694 < 3, menunjukkan bahwa distribusi harga tiket memiliki puncak yang lebih rendah dibandingkan distribusi normal (mesokurtik), tetapi tidak terlalu ekstrem. Kondisi ini mengindikasikan adanya variasi harga yang cukup besar.

Memeriksa Sebaran Data

#Membuat QQ plot untuk memeriksa apakah data mengikuti distribusi normal
qqnorm(data_penerbangan$price, main="QQ Plot Harga Tiket", col="blue")
qqline(data_penerbangan$price, col="red", lwd=2)

Berdasarkan QQ Plot Harga Tiket, terlihat bahwa distribusi harga tiket menyimpang secara signifikan dari distribusi normal. Pada bagian ekor kiri dan kanan, titik-titik data jauh dari garis referensi (garis merah), menunjukkan adanya skewness positif yang cukup kuat, sebagaimana juga terlihat pada histogram sebelumnya. Selain itu, terdapat banyak titik yang berada di luar pola garis normal, yang mengindikasikan keberadaan outlier pada harga tiket. Dengan demikian, pendekatan analisis yang lebih robust dapat dilakukan.

Mendeteksi Harga Tiket Yang Termasuk Pencilan

median_value <- median(data_penerbangan$price)   # Menghitung median
mad_value <- median(abs(data_penerbangan$price - median_value))    # Menghitung MAD (Median Absolute Deviation)
z_robust <- 0.6745 * (data_penerbangan$price - median_value) / mad_value    # Menghitung robust Z-score dengan faktor 0.6745
outliers <- data_penerbangan$price[abs(z_robust) > 3.5]    # Menentukan pencilan (|z_robust| > 3.5)
head(outliers)   # Menampilkan beberapa data pencilan
## [1] 29580 29160 29580 29580 31260 28058
summary(outliers)  # Melihat ringkasan dari data Outliers
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   27828   45883   53743   53912   60508  123071

Harga tiket yang termasuk kategori outlier memiliki rentang yang cukup besar, mulai dari INR 27.828 hingga INR 123.071. Nah, selanjutnya saya tertarik untuk melihat variabel mana saja yang memiliki kontribusi terbesar terhadap harga tiket yang termasuk outliers (selanjutnya akan disebut sebagai tiket dengan harga mahal).

Mencari Variabel dengan Outliers Terbanyak

airline_mahal <- data_penerbangan[data_penerbangan$price >= min(outliers), "airline"] 
table(airline_mahal)    # Menghitung jumlah outlier per maskapai
## airline_mahal
## Air_India   AirAsia  GO_FIRST    Indigo  SpiceJet   Vistara 
##     30820        11        14        14         1     58603
source_city_mahal <- data_penerbangan[data_penerbangan$price >= min(outliers), "source_city"]
table(source_city_mahal)  # Menghitung jumlah outlier per asal kota keberangkatan
## source_city_mahal
## Bangalore   Chennai     Delhi Hyderabad   Kolkata    Mumbai 
##     15988     11939     17440     12225     13361     18510
departure_time_mahal <- data_penerbangan[data_penerbangan$price >= min(outliers), "departure_time"]
table(departure_time_mahal)  # Menghitung jumlah outlier waktu berangkat
## departure_time_mahal
##     Afternoon Early_Morning       Evening    Late_Night       Morning 
##         12042         19170         19907           120         21457 
##         Night 
##         16767
stops_mahal <- data_penerbangan[data_penerbangan$price >= min(outliers), "stops"]
table(stops_mahal)  # Menghitung jumlah outlier per jumlah pemberhentian
## stops_mahal
##         one two_or_more        zero 
##       84208        1111        4144
arrival_time_mahal <- data_penerbangan[data_penerbangan$price >= min(outliers), "arrival_time"]
table(arrival_time_mahal)  # Menghitung jumlah outlier per waktu tiba
## arrival_time_mahal
##     Afternoon Early_Morning       Evening    Late_Night       Morning 
##         10398          3342         25690          1780         20441 
##         Night 
##         27812
destination_city_mahal <- data_penerbangan[data_penerbangan$price >= min(outliers), "destination_city"]
table(destination_city_mahal)  # Menghitung jumlah outlier per kota tujuan
## destination_city_mahal
## Bangalore   Chennai     Delhi Hyderabad   Kolkata    Mumbai 
##     15783     12853     15545     12958     14647     17677
class_mahal <- data_penerbangan[data_penerbangan$price >= min(outliers), "class"]
table(class_mahal)  # Menghitung jumlah outlier per kelas
## class_mahal
## Business  Economy 
##    89307      156
duration <- cut(data_penerbangan$duration,
                                        breaks = seq(0, max(data_penerbangan$duration), by = 4), 
                                        include.lowest = TRUE, right = FALSE)     # Mengelompokkan durasi terbang per 4 jam
duration_mahal <- duration[data_penerbangan$price >= min(outliers)]
table(duration_mahal)  # Menghitung jumlah outlier per kelas
## duration_mahal
##   [0,4)   [4,8)  [8,12) [12,16) [16,20) [20,24) [24,28) [28,32) [32,36) [36,40) 
##    4169   11290   19047   24269   11306    9674    8547    1068      80       7 
## [40,44) [44,48] 
##       3       3
days_left <- cut(data_penerbangan$days_left,
                      breaks = seq(0, max(data_penerbangan$days_left), by = 7),
                      include.lowest = TRUE, right = FALSE)
days_left_mahal <- days_left[data_penerbangan$price >= min(outliers)]
table(days_left_mahal)  # Menghitung jumlah outlier per hari sebelum keberangkatan
## days_left_mahal
##   [0,7)  [7,14) [14,21) [21,28) [28,35) [35,42) [42,49] 
##    8359   13205   13218   13357   13380   13305   14639

Tiket penerbangan yang masuk kategori mahal didominasi oleh maskapai Vistara (58.603 tiket) dan Air India (30.820 tiket), dengan mayoritas berasal dari kelas bisnis (89.307 tiket). Tiket mahal lebih sering ditemukan pada penerbangan one-stop (84.208 tiket), dengan durasi 12-16 jam (24.269 tiket), serta paling banyak terjadi pada waktu keberangkatan pagi (21.457 tiket) dengan waktu kedatangan malam (27.812 tiket). Penerbangan dari dan menuju kota besar juga memengaruhi harga tiket, dengan Kota Mumbai sebagai kota keberangkatan (18.510 tiket) dan kota tujuan (17.677 tiket) jumlah tiket mahal terbanyak.