1. Pendahuluan

Airbnb merupakan salah satu platform penyewaan properti jangka pendek yang berkembang pesat di berbagai kota besar dunia, termasuk New York City. Dalam platform ini, terdapat berbagai jenis properti yang ditawarkan, seperti entire home/apartment, private room, dan shared room, yang masing-masing memiliki karakteristik dan segmen pasar yang berbeda.

Memahami faktor-faktor yang mempengaruhi jenis properti yang ditawarkan menjadi penting, baik dari sisi analisis data maupun perspektif bisnis. Informasi seperti harga, lokasi, jumlah ulasan, serta ketersediaan properti diduga memiliki hubungan dengan tipe kamar yang disediakan oleh host.

Pada penelitian ini, digunakan metode Multinomial Logistic Regression untuk memodelkan hubungan antara karakteristik listing dengan tipe kamar (room_type) sebagai variabel target. Metode ini dipilih karena mampu menangani variabel dependen kategorikal dengan lebih dari dua kelas yang tidak memiliki urutan (non-ordinal).

Tujuan dari analisis ini adalah:

  1. Mengidentifikasi karakteristik utama yang membedakan tipe kamar Airbnb di New York City

  2. Membangun model klasifikasi untuk memprediksi tipe kamar berdasarkan fitur listing

  3. Mengevaluasi performa model dalam mengklasifikasikan berbagai tipe kamar

  4. Menyediakan dasar analisis yang dapat digunakan untuk memahami pola pasar Airbnb

Melalui pendekatan ini, diharapkan dapat diperoleh pemahaman yang lebih baik mengenai bagaimana karakteristik listing mempengaruhi jenis properti yang ditawarkan.

2. Load Library

packages <- c(
  "tidyverse",
  "nnet",
  "scales",
  "knitr"
)

installed_packages <- rownames(installed.packages())
for (pkg in packages) {
  if (!(pkg %in% installed_packages)) {
    install.packages(pkg, dependencies = TRUE)
  }
}

library(tidyverse)
library(nnet)
library(scales)
library(knitr)

3. Load Dataset

airbnb <- read.csv("AB_NYC_2019.csv", stringsAsFactors = FALSE)

4. Data Understanding

4.1 Struktur Dataset

dim(airbnb)
[1] 48895    16
str(airbnb)
'data.frame':   48895 obs. of  16 variables:
 $ id                            : int  2539 2595 3647 3831 5022 5099 5121 5178 5203 5238 ...
 $ name                          : chr  "Clean & quiet apt home by the park" "Skylit Midtown Castle" "THE VILLAGE OF HARLEM....NEW YORK !" "Cozy Entire Floor of Brownstone" ...
 $ host_id                       : int  2787 2845 4632 4869 7192 7322 7356 8967 7490 7549 ...
 $ host_name                     : chr  "John" "Jennifer" "Elisabeth" "LisaRoxanne" ...
 $ neighbourhood_group           : chr  "Brooklyn" "Manhattan" "Manhattan" "Brooklyn" ...
 $ neighbourhood                 : chr  "Kensington" "Midtown" "Harlem" "Clinton Hill" ...
 $ latitude                      : num  40.6 40.8 40.8 40.7 40.8 ...
 $ longitude                     : num  -74 -74 -73.9 -74 -73.9 ...
 $ room_type                     : chr  "Private room" "Entire home/apt" "Private room" "Entire home/apt" ...
 $ price                         : int  149 225 150 89 80 200 60 79 79 150 ...
 $ minimum_nights                : int  1 1 3 1 10 3 45 2 2 1 ...
 $ number_of_reviews             : int  9 45 0 270 9 74 49 430 118 160 ...
 $ last_review                   : chr  "2018-10-19" "2019-05-21" "" "2019-07-05" ...
 $ reviews_per_month             : num  0.21 0.38 NA 4.64 0.1 0.59 0.4 3.47 0.99 1.33 ...
 $ calculated_host_listings_count: int  6 2 1 1 1 1 1 1 1 4 ...
 $ availability_365              : int  365 355 365 194 0 129 0 220 0 188 ...

Berdasarkan hasil eksplorasi awal, dataset Airbnb New York memiliki 48.895 baris dan 16 variabel, yang menunjukkan jumlah observasi yang cukup besar untuk analisis dan pemodelan.

Secara umum, tipe data dalam dataset terdiri dari:

  • Numerik (int, num) seperti price, minimum_nights, number_of_reviews, dan availability_365

  • Kategorikal (chr) seperti neighbourhood_group, neighbourhood, dan room_type

  • Teks bebas seperti name dan host_name

Variabel room_type akan digunakan sebagai target dalam analisis karena merupakan variabel kategorikal dengan lebih dari dua kelas, sehingga sesuai untuk metode multinomial logistic regression.

Selain itu, terdapat beberapa variabel yang perlu diperhatikan pada tahap preprocessing, seperti:

  • reviews_per_month yang mengandung nilai kosong (NA)

  • last_review yang berupa tanggal namun masih dalam format karakter

  • Variabel identitas seperti id dan host_id yang tidak relevan untuk pemodelan

Secara keseluruhan, dataset ini memiliki kombinasi variabel numerik dan kategorikal yang cukup lengkap untuk membangun model klasifikasi serta menggali insight terkait karakteristik listing Airbnb.

4.2 Preview Dataset

head(airbnb) %>%
  kable()
id name host_id host_name neighbourhood_group neighbourhood latitude longitude room_type price minimum_nights number_of_reviews last_review reviews_per_month calculated_host_listings_count availability_365
2539 Clean & quiet apt home by the park 2787 John Brooklyn Kensington 40.64749 -73.97237 Private room 149 1 9 2018-10-19 0.21 6 365
2595 Skylit Midtown Castle 2845 Jennifer Manhattan Midtown 40.75362 -73.98377 Entire home/apt 225 1 45 2019-05-21 0.38 2 355
3647 THE VILLAGE OF HARLEM….NEW YORK ! 4632 Elisabeth Manhattan Harlem 40.80902 -73.94190 Private room 150 3 0 NA 1 365
3831 Cozy Entire Floor of Brownstone 4869 LisaRoxanne Brooklyn Clinton Hill 40.68514 -73.95976 Entire home/apt 89 1 270 2019-07-05 4.64 1 194
5022 Entire Apt: Spacious Studio/Loft by central park 7192 Laura Manhattan East Harlem 40.79851 -73.94399 Entire home/apt 80 10 9 2018-11-19 0.10 1 0
5099 Large Cozy 1 BR Apartment In Midtown East 7322 Chris Manhattan Murray Hill 40.74767 -73.97500 Entire home/apt 200 3 74 2019-06-22 0.59 1 129

Dari beberapa baris awal dataset, terlihat bahwa listing Airbnb memiliki variasi yang cukup jelas dalam hal harga, lokasi, dan tipe kamar, yang mengindikasikan adanya segmentasi pasar yang berbeda.

Listing di wilayah seperti Manhattan cenderung memiliki harga lebih tinggi dibandingkan Brooklyn, serta lebih banyak didominasi oleh tipe Entire home/apt. Sementara itu, tipe Private room muncul sebagai alternatif dengan harga yang lebih rendah.

Selain itu, terdapat indikasi bahwa tidak semua listing memiliki aktivitas yang sama, terlihat dari perbedaan jumlah review dan availability. Beberapa listing memiliki banyak review dan ketersediaan terbatas, yang dapat mengindikasikan tingkat permintaan yang tinggi.

Adanya nilai kosong pada reviews_per_month juga menunjukkan bahwa sebagian listing belum memiliki review, yang dapat merepresentasikan listing baru atau kurang diminati.

Secara keseluruhan, preview dataset sudah menunjukkan adanya hubungan potensial antara harga, lokasi, aktivitas listing, dan tipe kamar, yang relevan untuk dianalisis lebih lanjut menggunakan model klasifikasi.

4.3 Ringkasan Statistik

summary(airbnb)
       id               name              host_id           host_name        
 Min.   :    2539   Length:48895       Min.   :     2438   Length:48895      
 1st Qu.: 9471945   Class :character   1st Qu.:  7822033   Class :character  
 Median :19677284   Mode  :character   Median : 30793816   Mode  :character  
 Mean   :19017143                      Mean   : 67620011                     
 3rd Qu.:29152178                      3rd Qu.:107434423                     
 Max.   :36487245                      Max.   :274321313                     
                                                                             
 neighbourhood_group neighbourhood         latitude       longitude     
 Length:48895        Length:48895       Min.   :40.50   Min.   :-74.24  
 Class :character    Class :character   1st Qu.:40.69   1st Qu.:-73.98  
 Mode  :character    Mode  :character   Median :40.72   Median :-73.96  
                                        Mean   :40.73   Mean   :-73.95  
                                        3rd Qu.:40.76   3rd Qu.:-73.94  
                                        Max.   :40.91   Max.   :-73.71  
                                                                        
  room_type             price         minimum_nights    number_of_reviews
 Length:48895       Min.   :    0.0   Min.   :   1.00   Min.   :  0.00   
 Class :character   1st Qu.:   69.0   1st Qu.:   1.00   1st Qu.:  1.00   
 Mode  :character   Median :  106.0   Median :   3.00   Median :  5.00   
                    Mean   :  152.7   Mean   :   7.03   Mean   : 23.27   
                    3rd Qu.:  175.0   3rd Qu.:   5.00   3rd Qu.: 24.00   
                    Max.   :10000.0   Max.   :1250.00   Max.   :629.00   
                                                                         
 last_review        reviews_per_month calculated_host_listings_count
 Length:48895       Min.   : 0.010    Min.   :  1.000               
 Class :character   1st Qu.: 0.190    1st Qu.:  1.000               
 Mode  :character   Median : 0.720    Median :  1.000               
                    Mean   : 1.373    Mean   :  7.144               
                    3rd Qu.: 2.020    3rd Qu.:  2.000               
                    Max.   :58.500    Max.   :327.000               
                    NA's   :10052                                   
 availability_365
 Min.   :  0.0   
 1st Qu.:  0.0   
 Median : 45.0   
 Mean   :112.8   
 3rd Qu.:227.0   
 Max.   :365.0   
                 

Statistik deskriptif menunjukkan bahwa beberapa variabel dalam dataset memiliki distribusi yang tidak merata dan mengandung nilai ekstrem, yang berpotensi mempengaruhi hasil analisis.

Variabel price memiliki perbedaan yang cukup jauh antara median (106) dan nilai maksimum (10.000), yang mengindikasikan adanya outlier ekstrem serta distribusi yang condong ke kanan (right-skewed). Hal ini menunjukkan bahwa sebagian kecil listing berada pada segmen harga sangat tinggi, sementara mayoritas berada pada rentang harga menengah ke bawah.

Pada minimum_nights, mayoritas listing memiliki nilai rendah (median 3 malam), namun terdapat nilai maksimum hingga 1.250 malam. Ini menunjukkan adanya ketidakwajaran pada sebagian data, yang kemungkinan tidak merepresentasikan pola umum penyewaan jangka pendek.

Variabel number_of_reviews juga menunjukkan distribusi yang lebar, dengan median hanya 5 tetapi maksimum mencapai 629. Hal ini mengindikasikan bahwa hanya sebagian kecil listing yang sangat populer, sementara sebagian besar memiliki aktivitas review yang rendah.

Selain itu, reviews_per_month memiliki jumlah missing value yang cukup besar (10.052 data), yang menunjukkan bahwa banyak listing belum memiliki aktivitas review. Ini dapat merepresentasikan listing baru atau listing dengan tingkat permintaan rendah.

Variabel availability_365 menunjukkan variasi yang tinggi, dengan median 45 hari tetapi rata-rata lebih tinggi (112 hari). Hal ini mengindikasikan bahwa sebagian listing memiliki ketersediaan tinggi, sementara sebagian lainnya sangat terbatas atau bahkan tidak tersedia sama sekali.

Terakhir, calculated_host_listings_count menunjukkan bahwa sebagian besar host hanya memiliki satu listing, namun terdapat nilai maksimum hingga 327, yang mengindikasikan adanya host profesional dengan banyak properti.

4.4 Cek Missing Value

missing_value <- airbnb %>%
  summarise(across(everything(), ~ sum(is.na(.)))) %>%
  pivot_longer(
    cols = everything(),
    names_to = "column",
    values_to = "missing_count"
  ) %>%
  mutate(
    missing_percentage = round(missing_count / nrow(airbnb) * 100, 2)
  ) %>%
  arrange(desc(missing_count))

missing_value %>%
  kable()
column missing_count missing_percentage
reviews_per_month 10052 20.56
id 0 0.00
name 0 0.00
host_id 0 0.00
host_name 0 0.00
neighbourhood_group 0 0.00
neighbourhood 0 0.00
latitude 0 0.00
longitude 0 0.00
room_type 0 0.00
price 0 0.00
minimum_nights 0 0.00
number_of_reviews 0 0.00
last_review 0 0.00
calculated_host_listings_count 0 0.00
availability_365 0 0.00

Dataset secara umum tergolong bersih, karena hampir seluruh variabel tidak memiliki missing value. Namun, terdapat satu variabel yang cukup signifikan yaitu reviews_per_month dengan sekitar 20,56% data hilang.

Missing value pada variabel ini kemungkinan besar tidak bersifat acak, melainkan menunjukkan bahwa listing tersebut belum memiliki review. Hal ini justru memberikan informasi tambahan mengenai aktivitas atau popularitas listing.

Dengan demikian, reviews_per_month tetap relevan untuk analisis, tetapi memerlukan penanganan khusus pada tahap preprocessing agar tidak menghilangkan informasi penting dari data.

4.5 Cek Duplikasi

duplicate_count <- sum(duplicated(airbnb))
duplicate_count
[1] 0

Tidak ada Data Duplikat yang ditemukan pada Dataset.

4.6 Distribusi Target room_type

room_type_distribution <- airbnb %>%
  count(room_type) %>%
  mutate(
    percentage = round(n / sum(n) * 100, 2)
  ) %>%
  arrange(desc(n))

room_type_distribution %>%
  kable()
room_type n percentage
Entire home/apt 25409 51.97
Private room 22326 45.66
Shared room 1160 2.37
ggplot(room_type_distribution, aes(x = reorder(room_type, -n), y = n)) +
  geom_col() +
  geom_text(aes(label = paste0(percentage, "%")), vjust = -0.3) +
  labs(
    title = "Distribusi Tipe Kamar Airbnb",
    x = "Room Type",
    y = "Jumlah Listing"
  ) +
  theme_minimal()

Distribusi tipe kamar menunjukkan bahwa pasar Airbnb di New York didominasi oleh Entire home/apt (51,97%) dan Private room (45,66%), sementara Shared room hanya mencakup sebagian kecil (2,37%).

Hal ini mengindikasikan bahwa mayoritas host menawarkan properti dengan tingkat privasi lebih tinggi, serta menunjukkan bahwa Shared room merupakan segmen pasar yang sangat kecil.

Selain itu, distribusi ini juga menunjukkan adanya ketidakseimbangan kelas (class imbalance) yang perlu diperhatikan dalam pemodelan, karena dapat mempengaruhi kemampuan model dalam mengenali kategori minoritas.

5. Data Preprocessing

5.1 Memilih Kolom yang Relevan

Kolom identifier dan teks bebas seperti id, name, host_name, dan last_review tidak digunakan langsung dalam model.

airbnb_selected <- airbnb %>%
  select(
    neighbourhood_group,
    neighbourhood,
    latitude,
    longitude,
    room_type,
    price,
    minimum_nights,
    number_of_reviews,
    reviews_per_month,
    calculated_host_listings_count,
    availability_365
  )

5.2 Menangani Missing Value

Missing value pada reviews_per_month diisi dengan 0 karena listing tanpa review tidak memiliki nilai review per bulan.

airbnb_clean <- airbnb_selected %>%
  mutate(
    reviews_per_month = ifelse(is.na(reviews_per_month), 0, reviews_per_month)
  )

5.3 Membersihkan Harga dan Outlier Dasar

Data dengan harga 0 dihapus karena tidak realistis. Harga di atas 500 dan minimum nights di atas 30 juga dibatasi agar model tidak terlalu dipengaruhi outlier ekstrem.

airbnb_clean <- airbnb_clean %>%
  filter(
    price > 0,
    price <= 500,
    minimum_nights <= 30,
    availability_365 >= 0,
    availability_365 <= 365
  )

5.4 Mengubah Tipe Data Kategorikal

airbnb_clean <- airbnb_clean %>%
  mutate(
    room_type = factor(room_type),
    neighbourhood_group = factor(neighbourhood_group),
    neighbourhood = factor(neighbourhood)
  )

5.5 Cek Dataset Setelah Preprocessing

dim(airbnb_clean)
[1] 47125    11
summary(airbnb_clean)
    neighbourhood_group            neighbourhood      latitude    
 Bronx        : 1070    Williamsburg      : 3817   Min.   :40.50  
 Brooklyn     :19623    Bedford-Stuyvesant: 3644   1st Qu.:40.69  
 Manhattan    :20484    Harlem            : 2586   Median :40.72  
 Queens       : 5585    Bushwick          : 2434   Mean   :40.73  
 Staten Island:  363    Hell's Kitchen    : 1869   3rd Qu.:40.76  
                        Upper West Side   : 1857   Max.   :40.91  
                        (Other)           :30918                  
   longitude                room_type         price       minimum_nights  
 Min.   :-74.24   Entire home/apt:24029   Min.   : 10.0   Min.   : 1.000  
 1st Qu.:-73.98   Private room   :21963   1st Qu.: 68.0   1st Qu.: 1.000  
 Median :-73.96   Shared room    : 1133   Median :100.0   Median : 2.000  
 Mean   :-73.95                           Mean   :131.5   Mean   : 5.567  
 3rd Qu.:-73.94                           3rd Qu.:172.0   3rd Qu.: 5.000  
 Max.   :-73.71                           Max.   :500.0   Max.   :30.000  
                                                                          
 number_of_reviews reviews_per_month calculated_host_listings_count
 Min.   :  0.00    Min.   : 0.000    Min.   :  1.000               
 1st Qu.:  1.00    1st Qu.: 0.050    1st Qu.:  1.000               
 Median :  5.00    Median : 0.390    Median :  1.000               
 Mean   : 23.73    Mean   : 1.112    Mean   :  7.078               
 3rd Qu.: 24.00    3rd Qu.: 1.630    3rd Qu.:  2.000               
 Max.   :629.00    Max.   :58.500    Max.   :327.000               
                                                                   
 availability_365
 Min.   :  0.0   
 1st Qu.:  0.0   
 Median : 41.0   
 Mean   :110.2   
 3rd Qu.:219.0   
 Max.   :365.0   
                 
airbnb_clean %>%
  count(room_type) %>%
  mutate(percentage = round(n / sum(n) * 100, 2)) %>%
  kable()
room_type n percentage
Entire home/apt 24029 50.99
Private room 21963 46.61
Shared room 1133 2.40

Setelah preprocessing, jumlah data berkurang menjadi 47.125 observasi dengan 11 variabel, yang menunjukkan bahwa proses pembersihan data telah menghilangkan sebagian data yang tidak relevan atau tidak valid.

Distribusi variabel menunjukkan bahwa nilai ekstrem pada price dan minimum_nights telah berhasil dikendalikan (maksimum price menjadi 500 dan minimum_nights menjadi 30), sehingga data menjadi lebih representatif untuk analisis.

Rata-rata harga berada di sekitar 131, yang lebih mendekati nilai median, mengindikasikan bahwa distribusi harga menjadi lebih stabil dibanding sebelumnya. Variabel lain seperti number_of_reviews, reviews_per_month, dan availability_365 tetap menunjukkan variasi yang cukup luas, sehingga masih memiliki potensi sebagai fitur pembeda dalam model.

Distribusi target room_type setelah preprocessing tidak mengalami perubahan signifikan, di mana Entire home/apt (50,99%) dan Private room (46,61%) tetap mendominasi, sementara Shared room (2,40%) tetap menjadi kelas minoritas. Hal ini menunjukkan bahwa class imbalance masih menjadi karakteristik utama dataset.

6. Feature Engineering

6.1 Membuat Fitur Baru

Fitur baru yang dibuat:

  • price_log: transformasi log dari harga
  • has_review: penanda apakah listing memiliki review atau tidak
  • host_type: penanda host individu atau host dengan banyak listing
  • availability_category: kategori tingkat ketersediaan listing
airbnb_featured <- airbnb_clean %>%
  mutate(
    price_log = log(price),
    has_review = ifelse(number_of_reviews > 0, "Has review", "No review"),
    host_type = ifelse(
      calculated_host_listings_count > 1,
      "Multi-listing host",
      "Single-listing host"
    ),
    availability_category = case_when(
      availability_365 == 0 ~ "Unavailable",
      availability_365 <= 90 ~ "Low availability",
      availability_365 <= 180 ~ "Medium availability",
      TRUE ~ "High availability"
    ),
    has_review = factor(has_review),
    host_type = factor(host_type),
    availability_category = factor(
      availability_category,
      levels = c(
        "Unavailable",
        "Low availability",
        "Medium availability",
        "High availability"
      )
    )
  )

6.2 Cek Hasil Feature Engineering

airbnb_featured %>%
  select(
    room_type,
    price,
    price_log,
    number_of_reviews,
    reviews_per_month,
    has_review,
    calculated_host_listings_count,
    host_type,
    availability_365,
    availability_category
  ) %>%
  head() %>%
  kable()
room_type price price_log number_of_reviews reviews_per_month has_review calculated_host_listings_count host_type availability_365 availability_category
Private room 149 5.003946 9 0.21 Has review 6 Multi-listing host 365 High availability
Entire home/apt 225 5.416100 45 0.38 Has review 2 Multi-listing host 355 High availability
Private room 150 5.010635 0 0.00 No review 1 Single-listing host 365 High availability
Entire home/apt 89 4.488636 270 4.64 Has review 1 Single-listing host 194 High availability
Entire home/apt 80 4.382027 9 0.10 Has review 1 Single-listing host 0 Unavailable
Entire home/apt 200 5.298317 74 0.59 Has review 1 Single-listing host 129 Medium availability

Hasil feature engineering menunjukkan bahwa variabel tambahan berhasil memperkaya informasi dalam dataset dan membantu menangkap pola yang lebih jelas antar listing.

Transformasi price_log membuat perbedaan harga menjadi lebih stabil, sehingga variasi antar listing tidak terlalu dipengaruhi oleh nilai ekstrem. Selain itu, fitur has_review memberikan indikasi bahwa sebagian besar listing sudah memiliki aktivitas review, sementara sebagian kecil belum memiliki review sama sekali.

Dari sisi host, fitur host_type menunjukkan adanya perbedaan antara host individu dan host dengan banyak listing, yang berpotensi mencerminkan perbedaan strategi pengelolaan properti.

Sementara itu, kategorisasi availability_365 menjadi availability_category membantu mengelompokkan listing berdasarkan tingkat ketersediaannya, yang dapat digunakan untuk mengidentifikasi apakah suatu listing cenderung sering tersedia atau jarang tersedia.

Secara keseluruhan, fitur-fitur baru ini membantu merepresentasikan karakteristik listing secara lebih informatif, sehingga berpotensi meningkatkan kemampuan model dalam membedakan tipe kamar.

7. Exploratory Data Analysis

7.1 Distribusi Room Type Setelah Preprocessing

airbnb_featured %>%
  count(room_type) %>%
  mutate(percentage = n / sum(n)) %>%
  ggplot(aes(x = reorder(room_type, -n), y = n)) +
  geom_col() +
  geom_text(aes(label = percent(percentage, accuracy = 0.01)), vjust = -0.3) +
  labs(
    title = "Distribusi Room Type Setelah Preprocessing",
    x = "Room Type",
    y = "Jumlah Listing"
  ) +
  theme_minimal()

Distribusi tipe kamar setelah preprocessing menunjukkan bahwa Entire home/apt (50,99%) dan Private room (46,61%) tetap mendominasi pasar, sementara Shared room hanya mencakup sebagian kecil (2,40%).

Hal ini mengindikasikan bahwa preferensi pasar cenderung mengarah pada tingkat privasi yang lebih tinggi. Selain itu, ketimpangan distribusi ini menunjukkan bahwa model kemungkinan akan lebih mudah mengenali dua kelas utama, namun berpotensi mengalami kesulitan dalam mengklasifikasikan Shared room sebagai kelas minoritas.

7.2 Distribusi Neighbourhood Group

airbnb_featured %>%
  count(neighbourhood_group) %>%
  mutate(percentage = n / sum(n)) %>%
  ggplot(aes(x = reorder(neighbourhood_group, -n), y = n)) +
  geom_col() +
  geom_text(aes(label = percent(percentage, accuracy = 0.01)), vjust = -0.3) +
  labs(
    title = "Distribusi Listing Berdasarkan Neighbourhood Group",
    x = "Neighbourhood Group",
    y = "Jumlah Listing"
  ) +
  theme_minimal()

Distribusi listing berdasarkan wilayah menunjukkan bahwa pasar Airbnb di New York sangat terkonsentrasi di Manhattan (43,47%) dan Brooklyn (41,64%), yang secara bersama-sama mencakup sebagian besar listing.

Wilayah lain seperti Queens (11,85%), Bronx (2,27%), dan Staten Island (0,77%) memiliki proporsi yang jauh lebih kecil, menunjukkan bahwa aktivitas Airbnb tidak merata secara geografis.

Hal ini mengindikasikan bahwa lokasi berpotensi menjadi faktor penting dalam menentukan karakteristik listing, termasuk tipe kamar, harga, dan tingkat aktivitas, sehingga relevan untuk digunakan sebagai fitur dalam model klasifikasi.

7.3 Room Type Berdasarkan Neighbourhood Group

airbnb_featured %>%
  count(neighbourhood_group, room_type) %>%
  group_by(neighbourhood_group) %>%
  mutate(percentage = n / sum(n)) %>%
  ungroup() %>%
  ggplot(aes(x = neighbourhood_group, y = percentage, fill = room_type)) +
  geom_col(position = "fill") +
  scale_y_continuous(labels = percent_format()) +
  labs(
    title = "Proporsi Room Type Berdasarkan Neighbourhood Group",
    x = "Neighbourhood Group",
    y = "Proporsi",
    fill = "Room Type"
  ) +
  theme_minimal()

Proporsi tipe kamar menunjukkan adanya perbedaan karakteristik listing antar wilayah. Manhattan memiliki proporsi Entire home/apt yang lebih dominan dibanding wilayah lain, menunjukkan kecenderungan pasar premium di area tersebut. Sebaliknya, wilayah seperti Bronx dan Queens memiliki proporsi Private room yang lebih tinggi, mengindikasikan segmen pasar yang lebih terjangkau.

Sementara itu, Shared room memiliki proporsi yang sangat kecil di seluruh wilayah, menunjukkan bahwa tipe ini bukan merupakan pilihan utama di hampir semua area. Secara keseluruhan, pola ini menegaskan bahwa lokasi berpengaruh terhadap jenis properti yang ditawarkan.

7.4 Harga Berdasarkan Room Type

ggplot(airbnb_featured, aes(x = room_type, y = price)) +
  geom_boxplot(outlier.alpha = 0.2) +
  labs(
    title = "Distribusi Harga Berdasarkan Room Type",
    x = "Room Type",
    y = "Harga"
  ) +
  theme_minimal()

Distribusi harga menunjukkan perbedaan yang jelas antar tipe kamar. Entire home/apt memiliki rentang harga paling tinggi dengan median yang jauh di atas tipe lainnya, menandakan posisi sebagai segmen premium. Private room berada pada rentang harga menengah, sedangkan Shared room merupakan segmen dengan harga paling rendah.

Selain itu, terlihat bahwa variasi harga pada Entire home/apt jauh lebih lebar dibanding tipe lainnya, yang menunjukkan adanya perbedaan kualitas dan fasilitas yang lebih beragam dalam kategori ini.

Secara keseluruhan, harga menjadi faktor pembeda utama antar tipe kamar, yang memperkuat relevansinya sebagai fitur penting dalam model klasifikasi.

airbnb_featured %>%
  group_by(room_type) %>%
  summarise(
    count = n(),
    mean_price = round(mean(price), 2),
    median_price = median(price),
    min_price = min(price),
    max_price = max(price),
    .groups = "drop"
  ) %>%
  arrange(desc(median_price)) %>%
  kable()
room_type count mean_price median_price min_price max_price
Entire home/apt 24029 180.06 159 10 500
Private room 21963 81.87 70 10 500
Shared room 1133 63.78 45 10 500

Ringkasan statistik menunjukkan perbedaan harga yang konsisten antar tipe kamar. Entire home/apt memiliki rata-rata dan median harga tertinggi (mean ≈ 180, median 159), diikuti oleh Private room (median 70), dan Shared room (median 45).

Hal ini mempertegas bahwa setiap tipe kamar merepresentasikan segmen pasar yang berbeda, dengan Entire home/apt sebagai segmen premium dan Shared room sebagai segmen paling terjangkau. Selain itu, kesamaan nilai maksimum (500) menunjukkan bahwa batas harga atas telah dikendalikan pada tahap preprocessing.

7.5 Harga Berdasarkan Neighbourhood Group

ggplot(airbnb_featured, aes(x = neighbourhood_group, y = price)) +
  geom_boxplot(outlier.alpha = 0.2) +
  labs(
    title = "Distribusi Harga Berdasarkan Neighbourhood Group",
    x = "Neighbourhood Group",
    y = "Harga"
  ) +
  theme_minimal()

Distribusi harga antar wilayah menunjukkan bahwa Manhattan memiliki rentang dan median harga tertinggi dibandingkan wilayah lain, dengan variasi harga yang juga lebih lebar. Brooklyn berada di posisi kedua, sementara Queens, Staten Island, dan Bronx cenderung memiliki harga yang lebih rendah.

Hal ini menunjukkan bahwa lokasi memiliki pengaruh kuat terhadap harga listing, di mana wilayah pusat kota cenderung memiliki harga lebih tinggi dibandingkan wilayah pinggiran.

airbnb_featured %>%
  group_by(neighbourhood_group) %>%
  summarise(
    count = n(),
    mean_price = round(mean(price), 2),
    median_price = median(price),
    min_price = min(price),
    max_price = max(price),
    .groups = "drop"
  ) %>%
  arrange(desc(median_price)) %>%
  kable()
neighbourhood_group count mean_price median_price min_price max_price
Manhattan 20484 163.30 145 10 500
Brooklyn 19623 112.70 90 10 500
Queens 5585 93.03 75 10 500
Staten Island 363 91.43 75 13 450
Bronx 1070 81.98 65 10 500

Ringkasan statistik memperkuat pola pada visualisasi, di mana Manhattan memiliki median harga tertinggi (145), diikuti Brooklyn (90), Queens dan Staten Island (75), serta Bronx (65).

Perbedaan ini mengindikasikan adanya segmentasi harga berdasarkan wilayah, di mana Manhattan berperan sebagai pusat pasar premium, sementara wilayah lain cenderung melayani segmen menengah hingga bawah.

Secara keseluruhan, harga dipengaruhi oleh kombinasi tipe kamar dan lokasi, sehingga kedua variabel ini menjadi faktor kunci dalam analisis dan pemodelan.

7.6 Median Harga Berdasarkan Room Type dan Neighbourhood Group

airbnb_featured %>%
  group_by(neighbourhood_group, room_type) %>%
  summarise(
    median_price = median(price),
    count = n(),
    .groups = "drop"
  ) %>%
  ggplot(aes(x = neighbourhood_group, y = median_price, fill = room_type)) +
  geom_col(position = "dodge") +
  labs(
    title = "Median Harga Berdasarkan Room Type dan Neighbourhood Group",
    x = "Neighbourhood Group",
    y = "Median Harga",
    fill = "Room Type"
  ) +
  theme_minimal()

Median harga menunjukkan pola yang konsisten di seluruh wilayah, di mana Entire home/apt selalu memiliki harga tertinggi, diikuti Private room, dan Shared room sebagai yang paling rendah.

Manhattan menonjol sebagai wilayah dengan median harga tertinggi di semua tipe kamar, menegaskan posisinya sebagai pusat pasar premium. Sementara itu, wilayah seperti Bronx dan Staten Island memiliki median harga yang lebih rendah di semua tipe, menunjukkan segmentasi pasar yang lebih terjangkau.

Hal ini menunjukkan bahwa harga dipengaruhi oleh kombinasi tipe kamar dan lokasi, dengan pola yang relatif konsisten di seluruh wilayah.

7.7 Availability Berdasarkan Room Type

ggplot(airbnb_featured, aes(x = room_type, y = availability_365)) +
  geom_boxplot(outlier.alpha = 0.2) +
  labs(
    title = "Availability 365 Berdasarkan Room Type",
    x = "Room Type",
    y = "Availability 365"
  ) +
  theme_minimal()

Distribusi availability menunjukkan bahwa Shared room memiliki tingkat ketersediaan yang lebih tinggi dibandingkan tipe kamar lainnya, dengan median yang lebih besar dan variasi yang lebih lebar.

Sebaliknya, Entire home/apt dan Private room cenderung memiliki availability yang lebih rendah, yang dapat mengindikasikan bahwa kedua tipe ini lebih sering terisi atau memiliki tingkat permintaan yang lebih tinggi.

airbnb_featured %>%
  group_by(room_type) %>%
  summarise(
    count = n(),
    mean_availability = round(mean(availability_365), 2),
    median_availability = median(availability_365),
    .groups = "drop"
  ) %>%
  kable()
room_type count mean_availability median_availability
Entire home/apt 24029 107.76 36
Private room 21963 110.15 43
Shared room 1133 162.31 90

Ringkasan statistik memperkuat temuan visualisasi, di mana Shared room memiliki rata-rata dan median availability tertinggi (mean ≈ 162, median 90), diikuti oleh Private room dan Entire home/apt yang memiliki nilai lebih rendah.

Hal ini mengindikasikan bahwa Shared room cenderung lebih sering tersedia, yang bisa mencerminkan tingkat permintaan yang lebih rendah atau preferensi pasar yang lebih kecil terhadap tipe ini.

Secara keseluruhan, availability memberikan gambaran tambahan mengenai dinamika permintaan antar tipe kamar, yang dapat menjadi faktor penting dalam analisis dan pemodelan.

7.8 Review Berdasarkan Room Type

ggplot(airbnb_featured, aes(x = room_type, y = number_of_reviews)) +
  geom_boxplot(outlier.alpha = 0.2) +
  labs(
    title = "Jumlah Review Berdasarkan Room Type",
    x = "Room Type",
    y = "Number of Reviews"
  ) +
  theme_minimal()

Distribusi jumlah review menunjukkan bahwa Entire home/apt dan Private room memiliki pola yang relatif mirip, dengan variasi review yang cukup luas dan banyak outlier pada nilai tinggi. Hal ini mengindikasikan bahwa kedua tipe kamar memiliki tingkat aktivitas dan popularitas yang lebih tinggi.

Sebaliknya, Shared room cenderung memiliki jumlah review yang lebih rendah dan variasi yang lebih sempit, yang menunjukkan bahwa tipe ini kurang diminati atau memiliki aktivitas yang lebih rendah dibandingkan tipe lainnya.

airbnb_featured %>%
  group_by(room_type) %>%
  summarise(
    count = n(),
    mean_reviews = round(mean(number_of_reviews), 2),
    median_reviews = median(number_of_reviews),
    mean_reviews_per_month = round(mean(reviews_per_month), 2),
    median_reviews_per_month = median(reviews_per_month),
    .groups = "drop"
  ) %>%
  kable()
room_type count mean_reviews median_reviews mean_reviews_per_month median_reviews_per_month
Entire home/apt 24029 23.45 6 1.07 0.37
Private room 21963 24.40 5 1.16 0.42
Shared room 1133 16.95 4 1.10 0.45

Ringkasan statistik menunjukkan bahwa rata-rata jumlah review untuk Entire home/apt (23,45) dan Private room (24,40) relatif serupa, sementara Shared room lebih rendah (16,95). Median review juga mengikuti pola yang sama, di mana Shared room memiliki nilai paling kecil.

Sementara itu, nilai reviews_per_month relatif tidak jauh berbeda antar tipe kamar, yang menunjukkan bahwa frekuensi review per bulan cenderung stabil, namun total akumulasi review lebih rendah pada Shared room.

Secara keseluruhan, hasil ini mengindikasikan bahwa Entire home/apt dan Private room memiliki tingkat popularitas yang lebih tinggi dibandingkan Shared room, baik dari sisi jumlah maupun distribusi review.

7.9 Host Type Berdasarkan Room Type

airbnb_featured %>%
  count(host_type, room_type) %>%
  group_by(host_type) %>%
  mutate(percentage = n / sum(n)) %>%
  ungroup() %>%
  ggplot(aes(x = host_type, y = percentage, fill = room_type)) +
  geom_col(position = "fill") +
  scale_y_continuous(labels = percent_format()) +
  labs(
    title = "Proporsi Room Type Berdasarkan Host Type",
    x = "Host Type",
    y = "Proporsi",
    fill = "Room Type"
  ) +
  theme_minimal()

Proporsi tipe kamar menunjukkan perbedaan pola antara multi-listing host dan single-listing host. Single-listing host cenderung lebih banyak menawarkan Entire home/apt, yang mengindikasikan bahwa host individu lebih fokus pada penyewaan satu properti secara penuh.

Sebaliknya, multi-listing host memiliki proporsi Private room yang lebih tinggi, yang dapat menunjukkan strategi pemanfaatan properti secara lebih maksimal dengan membagi ruang menjadi beberapa unit sewa.

Selain itu, Shared room tetap memiliki proporsi yang sangat kecil pada kedua tipe host, sehingga bukan menjadi fokus utama baik bagi host individu maupun host dengan banyak listing.

Secara keseluruhan, tipe host berpengaruh terhadap jenis properti yang ditawarkan, yang mencerminkan perbedaan strategi antara host individu dan host yang bersifat lebih profesional.

8. Persiapan Data Modeling

8.1 Memilih Variabel untuk Model

model_data <- airbnb_featured %>%
  select(
    room_type,
    price_log,
    minimum_nights,
    number_of_reviews,
    reviews_per_month,
    availability_365,
    calculated_host_listings_count,
    neighbourhood_group,
    has_review,
    host_type
  ) %>%
  drop_na()

8.2 Menentukan Baseline Class

Entire home/apt dijadikan baseline class agar kategori lain dibandingkan terhadap tipe kamar tersebut.

model_data <- model_data %>%
  mutate(
    room_type = relevel(room_type, ref = "Entire home/apt")
  )

levels(model_data$room_type)
[1] "Entire home/apt" "Private room"    "Shared room"    

8.3 Train-Test Split dengan Stratifikasi Manual

set.seed(123)

model_data <- model_data %>%
  mutate(row_id = row_number())

train_data <- model_data %>%
  group_by(room_type) %>%
  slice_sample(prop = 0.8) %>%
  ungroup()

test_data <- model_data %>%
  anti_join(train_data %>% select(row_id), by = "row_id")

train_data <- train_data %>% select(-row_id)
test_data <- test_data %>% select(-row_id)

8.4 Cek Distribusi Target pada Train dan Test

train_distribution <- train_data %>%
  count(room_type) %>%
  mutate(dataset = "Train", percentage = round(n / sum(n) * 100, 2))

test_distribution <- test_data %>%
  count(room_type) %>%
  mutate(dataset = "Test", percentage = round(n / sum(n) * 100, 2))

bind_rows(train_distribution, test_distribution) %>%
  select(dataset, room_type, n, percentage) %>%
  kable()
dataset room_type n percentage
Train Entire home/apt 19223 50.99
Train Private room 17570 46.61
Train Shared room 906 2.40
Test Entire home/apt 4806 50.99
Test Private room 4393 46.61
Test Shared room 227 2.41

8.5 Scaling Variabel Numerik

Scaling dilakukan berdasarkan data train, lalu parameter yang sama diterapkan ke data test.

numeric_features <- c(
  "price_log",
  "minimum_nights",
  "number_of_reviews",
  "reviews_per_month",
  "availability_365",
  "calculated_host_listings_count"
)

train_scaled <- train_data
test_scaled <- test_data

for (feature in numeric_features) {
  feature_mean <- mean(train_data[[feature]], na.rm = TRUE)
  feature_sd <- sd(train_data[[feature]], na.rm = TRUE)
  
  train_scaled[[paste0(feature, "_scaled")]] <-
    (train_data[[feature]] - feature_mean) / feature_sd
  
  test_scaled[[paste0(feature, "_scaled")]] <-
    (test_data[[feature]] - feature_mean) / feature_sd
}

9. Model Multinomial Logistic Regression

9.1 Membuat Model

model_mlr <- multinom(
  room_type ~ price_log_scaled +
    minimum_nights_scaled +
    number_of_reviews_scaled +
    reviews_per_month_scaled +
    availability_365_scaled +
    calculated_host_listings_count_scaled +
    neighbourhood_group +
    has_review +
    host_type,
  data = train_scaled,
  trace = FALSE,
  maxit = 1000
)

9.2 Ringkasan Model

summary(model_mlr)
Call:
multinom(formula = room_type ~ price_log_scaled + minimum_nights_scaled + 
    number_of_reviews_scaled + reviews_per_month_scaled + availability_365_scaled + 
    calculated_host_listings_count_scaled + neighbourhood_group + 
    has_review + host_type, data = train_scaled, trace = FALSE, 
    maxit = 1000)

Coefficients:
             (Intercept) price_log_scaled minimum_nights_scaled
Private room  -0.6014959        -2.532744            -0.7432779
Shared room   -5.0427167        -3.921299            -1.0726314
             number_of_reviews_scaled reviews_per_month_scaled
Private room               -0.1029116               -0.1312467
Shared room                -0.4037619               -0.1201316
             availability_365_scaled calculated_host_listings_count_scaled
Private room               0.3739803                            -0.2926392
Shared room                0.7574062                            -0.3817620
             neighbourhood_groupBrooklyn neighbourhood_groupManhattan
Private room                   0.7738773                     1.630794
Shared room                    0.6297354                     2.610177
             neighbourhood_groupQueens neighbourhood_groupStaten Island
Private room                 0.5135096                       -0.3930781
Shared room                  0.4547215                       -1.4555719
             has_reviewNo review host_typeSingle-listing host
Private room           0.7676896                    -1.151296
Shared room            1.3008241                    -1.866626

Std. Errors:
             (Intercept) price_log_scaled minimum_nights_scaled
Private room   0.1040987       0.02659128            0.01976861
Shared room    0.2164355       0.06237398            0.04954272
             number_of_reviews_scaled reviews_per_month_scaled
Private room               0.01829897               0.01979634
Shared room                0.06181354               0.04916213
             availability_365_scaled calculated_host_listings_count_scaled
Private room              0.01796892                            0.03838575
Shared room               0.03974803                            0.13593256
             neighbourhood_groupBrooklyn neighbourhood_groupManhattan
Private room                   0.1029745                    0.1050315
Shared room                    0.2006997                    0.2051609
             neighbourhood_groupQueens neighbourhood_groupStaten Island
Private room                 0.1085086                        0.1929548
Shared room                  0.2113996                        0.4913421
             has_reviewNo review host_typeSingle-listing host
Private room          0.04159171                   0.03646961
Shared room           0.09899310                   0.08932657

Residual Deviance: 34488.02 
AIC: 34540.02 

Model menggunakan Entire home/apt sebagai kategori acuan, sehingga seluruh koefisien menunjukkan perbandingan peluang terhadap kategori tersebut.

Variabel price_log_scaled memiliki koefisien negatif pada Private room dan Shared room. Hal ini menunjukkan bahwa semakin tinggi harga, semakin kecil kemungkinan suatu listing termasuk ke dalam dua kategori tersebut, dan semakin besar kecenderungannya menjadi Entire home/apt. Dengan kata lain, harga merupakan pembeda utama antara segmen premium dan non-premium.

Variabel minimum_nights_scaled juga menunjukkan hubungan negatif, yang mengindikasikan bahwa listing dengan minimum malam yang lebih tinggi cenderung bukan Private room atau Shared room, melainkan lebih dekat dengan karakteristik Entire home/apt.

Variabel yang berkaitan dengan popularitas, yaitu number_of_reviews_scaled dan reviews_per_month_scaled, memiliki koefisien negatif. Hal ini menunjukkan bahwa listing dengan aktivitas review yang tinggi lebih cenderung merupakan Entire home/apt, yang dapat diinterpretasikan sebagai indikasi bahwa properti penuh lebih diminati atau lebih sering dipesan.

Sebaliknya, availability_365_scaled memiliki koefisien positif, yang berarti semakin tinggi ketersediaan suatu listing, semakin besar kemungkinan listing tersebut termasuk ke dalam Private room atau Shared room. Hal ini mengindikasikan bahwa listing yang sering tersedia cenderung memiliki tingkat permintaan yang lebih rendah dibandingkan Entire home/apt.

Variabel calculated_host_listings_count_scaled menunjukkan kecenderungan negatif, yang mengindikasikan bahwa host dengan banyak listing lebih terkait dengan tipe Entire home/apt. Hal ini dapat mencerminkan bahwa host yang lebih profesional cenderung mengelola properti secara penuh.

Dari sisi lokasi, variabel neighbourhood_group menunjukkan bahwa wilayah seperti Manhattan, Brooklyn, dan Queens memiliki pengaruh yang berbeda terhadap peluang tipe kamar. Secara umum, lokasi menjadi faktor penting yang membedakan karakteristik listing.

Variabel has_review menunjukkan bahwa listing tanpa review lebih cenderung termasuk ke dalam Private room atau Shared room, yang dapat mengindikasikan listing baru atau kurang populer. Sementara itu, variabel host_type menunjukkan bahwa single-listing host lebih cenderung memiliki Entire home/apt, yang mencerminkan kecenderungan host individu untuk menyewakan satu properti secara penuh.

Secara keseluruhan, model menunjukkan bahwa harga, availability, aktivitas review, dan lokasi merupakan faktor utama yang membedakan tipe kamar. Listing dengan harga tinggi, banyak review, dan availability rendah cenderung termasuk dalam Entire home/apt, sedangkan listing dengan harga lebih rendah dan availability tinggi lebih cenderung termasuk dalam Private room atau Shared room.

9.3 AIC Model

AIC(model_mlr)
[1] 34540.02

Nilai AIC sebesar 34540.02 menunjukkan tingkat kecocokan model dengan mempertimbangkan kompleksitasnya. Nilai ini digunakan sebagai acuan untuk membandingkan model, di mana model dengan nilai AIC lebih kecil dianggap lebih baik. Dalam konteks ini, nilai AIC berfungsi sebagai baseline jika nantinya dilakukan pengembangan atau perbandingan dengan model lain.

9.4 Pseudo R-Squared McFadden

null_model <- multinom(
  room_type ~ 1,
  data = train_scaled,
  trace = FALSE,
  maxit = 1000
)

pseudo_r2_mcfadden <- 1 - as.numeric(logLik(model_mlr) / logLik(null_model))
pseudo_r2_mcfadden
[1] 0.4201498

Nilai Pseudo R-Squared McFadden sebesar 0.420 menunjukkan bahwa model memiliki kemampuan yang cukup baik dalam menjelaskan variasi pada data. Secara umum, nilai di atas 0.2 sudah dianggap baik untuk model logistik, sehingga nilai ini mengindikasikan bahwa model mampu menangkap hubungan yang cukup kuat antara variabel prediktor dan tipe kamar.

10. Prediksi dan Evaluasi Model

10.1 Prediksi pada Data Test

pred_class <- predict(model_mlr, newdata = test_scaled, type = "class")
pred_prob <- predict(model_mlr, newdata = test_scaled, type = "probs")

prediction_result <- test_scaled %>%
  select(room_type) %>%
  mutate(predicted_room_type = pred_class)

head(prediction_result) %>%
  kable()
room_type predicted_room_type
Entire home/apt Entire home/apt
Private room Private room
Entire home/apt Entire home/apt
Private room Private room
Entire home/apt Private room
Private room Private room

Hasil prediksi awal menunjukkan bahwa model mampu mengklasifikasikan sebagian besar data dengan benar. Namun, terlihat bahwa masih terdapat beberapa kesalahan klasifikasi, khususnya ketika model memprediksi Entire home/apt sebagai Private room.

10.2 Confusion Matrix

conf_matrix <- table(
  Actual = prediction_result$room_type,
  Predicted = prediction_result$predicted_room_type
)

conf_matrix
                 Predicted
Actual            Entire home/apt Private room Shared room
  Entire home/apt            4112          694           0
  Private room                692         3697           4
  Shared room                  16          205           6

10.3 Visualisasi Confusion Matrix

conf_matrix_df <- as.data.frame(conf_matrix)

conf_matrix_df %>%
  ggplot(aes(x = Predicted, y = Actual, fill = Freq)) +
  geom_tile() +
  geom_text(aes(label = Freq)) +
  labs(
    title = "Confusion Matrix Multinomial Logistic Regression",
    x = "Predicted Class",
    y = "Actual Class",
    fill = "Jumlah"
  ) +
  theme_minimal()

Confusion matrix menunjukkan bahwa model memiliki performa yang cukup baik dalam mengklasifikasikan Entire home/apt dan Private room. Sebagian besar data pada kedua kategori ini berhasil diprediksi dengan benar, meskipun masih terdapat kesalahan antar keduanya.

Sebaliknya, performa model pada kategori Shared room sangat rendah. Dari total data aktual, hanya sebagian kecil yang berhasil diprediksi dengan benar, sementara sebagian besar diklasifikasikan sebagai Private room. Hal ini menunjukkan bahwa model mengalami kesulitan dalam membedakan Shared room dari kategori lainnya.

Secara keseluruhan, model cenderung bias terhadap kelas mayoritas dan kurang mampu menangkap pola pada kelas minoritas. Hal ini kemungkinan disebabkan oleh ketidakseimbangan distribusi data, di mana jumlah Shared room jauh lebih sedikit dibandingkan kategori lainnya.

10.4 Accuracy

accuracy <- mean(prediction_result$room_type == prediction_result$predicted_room_type)
accuracy
[1] 0.8290898

Model menghasilkan accuracy sebesar 0.829, yang menunjukkan bahwa sekitar 82,9% prediksi yang dilakukan sudah sesuai dengan nilai aktual. Nilai ini tergolong cukup tinggi dan mengindikasikan bahwa model mampu menangkap pola dalam data dengan baik.

10.5 Baseline Accuracy

Baseline accuracy dihitung dengan cara selalu memprediksi kelas mayoritas dari data train.

majority_class <- train_scaled %>%
  count(room_type) %>%
  arrange(desc(n)) %>%
  slice(1) %>%
  pull(room_type)

baseline_accuracy <- mean(test_scaled$room_type == majority_class)
baseline_accuracy
[1] 0.5098663

Jika dibandingkan dengan baseline accuracy sebesar 0.509, yang hanya memprediksi kelas mayoritas, terlihat bahwa model memberikan peningkatan performa yang signifikan. Hal ini menunjukkan bahwa model tidak sekadar mengikuti distribusi kelas, tetapi benar-benar memanfaatkan informasi dari fitur untuk melakukan klasifikasi.

10.6 Precision, Recall, dan F1-Score per Class

actual <- prediction_result$room_type
predicted <- prediction_result$predicted_room_type
classes <- levels(actual)

metrics_per_class <- map_dfr(classes, function(cls) {
  tp <- sum(actual == cls & predicted == cls)
  fp <- sum(actual != cls & predicted == cls)
  fn <- sum(actual == cls & predicted != cls)
  tn <- sum(actual != cls & predicted != cls)
  
  precision <- ifelse((tp + fp) == 0, NA, tp / (tp + fp))
  recall <- ifelse((tp + fn) == 0, NA, tp / (tp + fn))
  f1_score <- ifelse(
    is.na(precision) | is.na(recall) | (precision + recall) == 0,
    NA,
    2 * precision * recall / (precision + recall)
  )
  
  tibble(
    class = cls,
    support = sum(actual == cls),
    precision = round(precision, 4),
    recall = round(recall, 4),
    f1_score = round(f1_score, 4)
  )
})

metrics_per_class %>%
  kable()
class support precision recall f1_score
Entire home/apt 4806 0.8531 0.8556 0.8544
Private room 4393 0.8044 0.8416 0.8226
Shared room 227 0.6000 0.0264 0.0506

Model menunjukkan performa yang baik pada kelas Entire home/apt dan Private room, dengan nilai precision, recall, dan F1-score yang relatif tinggi (di atas 0.80). Hal ini menunjukkan bahwa model mampu mengenali kedua kelas mayoritas tersebut dengan cukup akurat dan konsisten.

Sebaliknya, performa pada kelas Shared room sangat rendah, terutama pada nilai recall (0.0264) dan F1-score (0.0506). Ini menunjukkan bahwa sebagian besar data Shared room gagal dikenali oleh model dan cenderung diklasifikasikan ke kelas lain.

Perbedaan performa ini mengindikasikan bahwa model masih bias terhadap kelas mayoritas dan kesulitan dalam mempelajari pola pada kelas minoritas. Hal ini sejalan dengan kondisi distribusi data yang tidak seimbang, di mana jumlah Shared room jauh lebih sedikit dibandingkan kelas lainnya.

11. Interpretasi Koefisien Model

11.1 Membuat Tabel Koefisien, P-Value, dan Odds Ratio

Catatan: Pada nnet::multinom, p-value dihitung manual menggunakan z-value.

model_summary <- summary(model_mlr)

coef_matrix <- model_summary$coefficients
se_matrix <- model_summary$standard.errors

coef_long <- as.data.frame(coef_matrix) %>%
  rownames_to_column("target_class") %>%
  pivot_longer(
    cols = -target_class,
    names_to = "feature",
    values_to = "coefficient"
  )

se_long <- as.data.frame(se_matrix) %>%
  rownames_to_column("target_class") %>%
  pivot_longer(
    cols = -target_class,
    names_to = "feature",
    values_to = "std_error"
  )

coefficient_table <- coef_long %>%
  left_join(se_long, by = c("target_class", "feature")) %>%
  mutate(
    z_value = coefficient / std_error,
    p_value = 2 * (1 - pnorm(abs(z_value))),
    odds_ratio = exp(coefficient)
  ) %>%
  mutate(
    coefficient = round(coefficient, 4),
    std_error = round(std_error, 4),
    z_value = round(z_value, 4),
    p_value = round(p_value, 4),
    odds_ratio = round(odds_ratio, 4)
  )

coefficient_table %>%
  kable()
target_class feature coefficient std_error z_value p_value odds_ratio
Private room (Intercept) -0.6015 0.1041 -5.7781 0.0000 0.5480
Private room price_log_scaled -2.5327 0.0266 -95.2472 0.0000 0.0794
Private room minimum_nights_scaled -0.7433 0.0198 -37.5989 0.0000 0.4756
Private room number_of_reviews_scaled -0.1029 0.0183 -5.6239 0.0000 0.9022
Private room reviews_per_month_scaled -0.1312 0.0198 -6.6298 0.0000 0.8770
Private room availability_365_scaled 0.3740 0.0180 20.8126 0.0000 1.4535
Private room calculated_host_listings_count_scaled -0.2926 0.0384 -7.6236 0.0000 0.7463
Private room neighbourhood_groupBrooklyn 0.7739 0.1030 7.5152 0.0000 2.1682
Private room neighbourhood_groupManhattan 1.6308 0.1050 15.5267 0.0000 5.1079
Private room neighbourhood_groupQueens 0.5135 0.1085 4.7324 0.0000 1.6711
Private room neighbourhood_groupStaten Island -0.3931 0.1930 -2.0372 0.0416 0.6750
Private room has_reviewNo review 0.7677 0.0416 18.4578 0.0000 2.1548
Private room host_typeSingle-listing host -1.1513 0.0365 -31.5686 0.0000 0.3162
Shared room (Intercept) -5.0427 0.2164 -23.2989 0.0000 0.0065
Shared room price_log_scaled -3.9213 0.0624 -62.8676 0.0000 0.0198
Shared room minimum_nights_scaled -1.0726 0.0495 -21.6506 0.0000 0.3421
Shared room number_of_reviews_scaled -0.4038 0.0618 -6.5319 0.0000 0.6678
Shared room reviews_per_month_scaled -0.1201 0.0492 -2.4436 0.0145 0.8868
Shared room availability_365_scaled 0.7574 0.0397 19.0552 0.0000 2.1327
Shared room calculated_host_listings_count_scaled -0.3818 0.1359 -2.8085 0.0050 0.6827
Shared room neighbourhood_groupBrooklyn 0.6297 0.2007 3.1377 0.0017 1.8771
Shared room neighbourhood_groupManhattan 2.6102 0.2052 12.7226 0.0000 13.6015
Shared room neighbourhood_groupQueens 0.4547 0.2114 2.1510 0.0315 1.5757
Shared room neighbourhood_groupStaten Island -1.4556 0.4913 -2.9624 0.0031 0.2333
Shared room has_reviewNo review 1.3008 0.0990 13.1406 0.0000 3.6723
Shared room host_typeSingle-listing host -1.8666 0.0893 -20.8966 0.0000 0.1546

Seluruh variabel dalam model memiliki nilai p-value yang sangat kecil (mendekati 0), yang menunjukkan bahwa sebagian besar fitur signifikan dalam membedakan tipe kamar dibandingkan kategori acuan (Entire home/apt).

Variabel price_log_scaled memiliki koefisien negatif besar baik pada Private room maupun Shared room, dengan odds ratio yang sangat kecil (0.079 dan 0.019). Hal ini menunjukkan bahwa peningkatan harga secara signifikan menurunkan peluang suatu listing menjadi Private room atau Shared room, sehingga memperkuat bahwa harga merupakan faktor utama yang mengarah ke Entire home/apt.

Variabel minimum_nights_scaled juga memiliki pengaruh negatif, yang menunjukkan bahwa semakin tinggi minimum malam, semakin kecil kemungkinan listing termasuk ke dalam Private room atau Shared room. Ini mengindikasikan bahwa tipe tersebut lebih identik dengan Entire home/apt.

Variabel availability_365_scaled memiliki pengaruh positif pada kedua kelas, dengan odds ratio di atas 1. Hal ini menunjukkan bahwa listing dengan availability tinggi cenderung lebih mungkin menjadi Private room atau Shared room, yang dapat diartikan sebagai indikasi permintaan yang lebih rendah dibandingkan Entire home/apt.

Variabel yang berkaitan dengan review (number_of_reviews_scaled dan reviews_per_month_scaled) memiliki pengaruh negatif, yang menunjukkan bahwa listing dengan aktivitas review yang tinggi cenderung lebih dekat ke Entire home/apt. Hal ini mengindikasikan bahwa properti penuh lebih populer atau lebih sering dipesan.

Dari sisi lokasi, neighbourhood_groupManhattan memiliki odds ratio yang sangat tinggi, terutama pada Shared room (13.60), yang menunjukkan bahwa lokasi di Manhattan secara signifikan meningkatkan peluang listing menjadi Private room atau Shared room dibandingkan baseline wilayah. Brooklyn dan Queens juga menunjukkan pengaruh positif, sementara Staten Island cenderung memiliki pengaruh negatif.

Variabel has_review menunjukkan bahwa listing tanpa review memiliki peluang lebih besar untuk menjadi Private room atau Shared room, yang mengindikasikan bahwa listing yang belum memiliki aktivitas cenderung berada di segmen non-premium.

Variabel host_typeSingle-listing host memiliki pengaruh negatif yang kuat, yang menunjukkan bahwa host individu lebih cenderung memiliki Entire home/apt dibandingkan tipe kamar lainnya. Sebaliknya, host dengan banyak listing lebih bervariasi dalam tipe kamar yang ditawarkan.

Secara keseluruhan, hasil model menunjukkan bahwa harga, availability, lokasi, dan aktivitas review merupakan faktor paling berpengaruh dalam menentukan tipe kamar. Listing dengan harga tinggi, review tinggi, dan availability rendah cenderung termasuk Entire home/apt, sedangkan listing dengan harga lebih rendah dan availability tinggi lebih cenderung termasuk Private room atau Shared room.

11.2 Koefisien Paling Berpengaruh Berdasarkan Nilai Absolut

top_coefficients <- coefficient_table %>%
  filter(feature != "(Intercept)") %>%
  mutate(abs_coefficient = abs(coefficient)) %>%
  group_by(target_class) %>%
  slice_max(abs_coefficient, n = 10) %>%
  ungroup() %>%
  arrange(target_class, desc(abs_coefficient))

top_coefficients %>%
  kable()
target_class feature coefficient std_error z_value p_value odds_ratio abs_coefficient
Private room price_log_scaled -2.5327 0.0266 -95.2472 0.0000 0.0794 2.5327
Private room neighbourhood_groupManhattan 1.6308 0.1050 15.5267 0.0000 5.1079 1.6308
Private room host_typeSingle-listing host -1.1513 0.0365 -31.5686 0.0000 0.3162 1.1513
Private room neighbourhood_groupBrooklyn 0.7739 0.1030 7.5152 0.0000 2.1682 0.7739
Private room has_reviewNo review 0.7677 0.0416 18.4578 0.0000 2.1548 0.7677
Private room minimum_nights_scaled -0.7433 0.0198 -37.5989 0.0000 0.4756 0.7433
Private room neighbourhood_groupQueens 0.5135 0.1085 4.7324 0.0000 1.6711 0.5135
Private room neighbourhood_groupStaten Island -0.3931 0.1930 -2.0372 0.0416 0.6750 0.3931
Private room availability_365_scaled 0.3740 0.0180 20.8126 0.0000 1.4535 0.3740
Private room calculated_host_listings_count_scaled -0.2926 0.0384 -7.6236 0.0000 0.7463 0.2926
Shared room price_log_scaled -3.9213 0.0624 -62.8676 0.0000 0.0198 3.9213
Shared room neighbourhood_groupManhattan 2.6102 0.2052 12.7226 0.0000 13.6015 2.6102
Shared room host_typeSingle-listing host -1.8666 0.0893 -20.8966 0.0000 0.1546 1.8666
Shared room neighbourhood_groupStaten Island -1.4556 0.4913 -2.9624 0.0031 0.2333 1.4556
Shared room has_reviewNo review 1.3008 0.0990 13.1406 0.0000 3.6723 1.3008
Shared room minimum_nights_scaled -1.0726 0.0495 -21.6506 0.0000 0.3421 1.0726
Shared room availability_365_scaled 0.7574 0.0397 19.0552 0.0000 2.1327 0.7574
Shared room neighbourhood_groupBrooklyn 0.6297 0.2007 3.1377 0.0017 1.8771 0.6297
Shared room neighbourhood_groupQueens 0.4547 0.2114 2.1510 0.0315 1.5757 0.4547
Shared room number_of_reviews_scaled -0.4038 0.0618 -6.5319 0.0000 0.6678 0.4038

Hasil model menunjukkan bahwa harga merupakan faktor paling dominan dalam membedakan tipe kamar. Peningkatan harga secara signifikan menurunkan peluang suatu listing menjadi Private room maupun Shared room, sehingga listing dengan harga tinggi cenderung berada pada kategori Entire home/apt. Hal ini menegaskan adanya segmentasi pasar yang jelas antara properti premium dan non-premium.

Dari sisi lokasi, wilayah Manhattan memberikan pengaruh yang sangat kuat terhadap peluang suatu listing menjadi Private room maupun Shared room. Hal ini menunjukkan bahwa lokasi strategis tidak hanya meningkatkan harga, tetapi juga mempengaruhi variasi tipe properti yang ditawarkan. Brooklyn dan Queens juga menunjukkan kecenderungan serupa, meskipun dengan pengaruh yang lebih moderat, sementara Staten Island cenderung memiliki peluang lebih rendah untuk kedua tipe tersebut.

Variabel ketersediaan (availability) memiliki pengaruh positif, yang menunjukkan bahwa listing yang lebih sering tersedia cenderung bukan Entire home/apt. Hal ini dapat diinterpretasikan bahwa properti dengan tingkat permintaan lebih rendah, atau yang kurang sering dipesan, lebih banyak berada pada kategori Private room dan Shared room.

Dari sisi aktivitas, listing yang tidak memiliki review memiliki peluang lebih tinggi untuk masuk ke kategori Private room dan Shared room. Hal ini mengindikasikan bahwa listing yang belum memiliki reputasi atau masih baru cenderung berada pada segmen non-premium.

Variabel minimum nights dan jumlah review menunjukkan pengaruh negatif, yang berarti listing dengan durasi minimum lebih tinggi dan aktivitas review yang lebih besar cenderung merupakan Entire home/apt. Hal ini menunjukkan bahwa properti penuh lebih sering digunakan untuk penyewaan dengan durasi tertentu dan memiliki tingkat popularitas yang lebih tinggi.

Selain itu, tipe host juga berperan penting. Single-listing host cenderung memiliki peluang lebih kecil untuk menawarkan Private room atau Shared room, sehingga lebih identik dengan penyewaan properti secara penuh. Sebaliknya, host dengan banyak listing menunjukkan pola yang lebih beragam dalam tipe kamar yang ditawarkan.

Secara keseluruhan, hasil model menunjukkan bahwa harga, lokasi, availability, dan aktivitas listing merupakan faktor utama yang membentuk perbedaan tipe kamar. Listing dengan harga tinggi, aktivitas tinggi, dan availability rendah cenderung termasuk dalam Entire home/apt, sedangkan listing dengan harga lebih rendah dan availability tinggi lebih cenderung termasuk dalam Private room atau Shared room.

top_coefficients %>%
  ggplot(aes(x = reorder(feature, abs_coefficient), y = coefficient, fill = target_class)) +
  geom_col(show.legend = FALSE) +
  coord_flip() +
  facet_wrap(~ target_class, scales = "free_y") +
  labs(
    title = "Koefisien Paling Berpengaruh pada Setiap Kelas",
    x = "Feature",
    y = "Coefficient"
  ) +
  theme_minimal()

Visualisasi menunjukkan bahwa price_log_scaled merupakan variabel dengan pengaruh paling kuat pada kedua kelas (Private room dan Shared room), dengan koefisien negatif yang besar. Hal ini menegaskan bahwa semakin tinggi harga, semakin kecil kemungkinan listing termasuk ke dalam kedua kategori tersebut, dan semakin besar kecenderungannya menjadi Entire home/apt.

Pada kedua kelas, neighbourhood_groupManhattan memiliki pengaruh positif yang signifikan, terutama pada Shared room. Ini menunjukkan bahwa lokasi di Manhattan meningkatkan peluang suatu listing masuk ke kategori non-entire home, serta mencerminkan keberagaman tipe properti di wilayah tersebut.

Variabel host_typeSingle-listing host memiliki pengaruh negatif yang cukup kuat pada kedua kelas, yang menunjukkan bahwa host individu lebih cenderung menawarkan Entire home/apt dibandingkan tipe kamar lainnya.

Selain itu, has_reviewNo review memberikan pengaruh positif, yang mengindikasikan bahwa listing tanpa review lebih sering ditemukan pada Private room dan Shared room. Hal ini dapat dikaitkan dengan listing baru atau kurang populer.

Variabel minimum_nights_scaled dan number_of_reviews_scaled cenderung memiliki pengaruh negatif, yang menunjukkan bahwa listing dengan durasi minimum lebih tinggi dan jumlah review lebih banyak lebih identik dengan Entire home/apt.

Sementara itu, availability_365_scaled memiliki pengaruh positif, yang berarti listing dengan tingkat ketersediaan tinggi lebih cenderung termasuk dalam Private room atau Shared room, yang dapat diartikan sebagai indikasi permintaan yang lebih rendah.

Secara keseluruhan, visualisasi ini memperjelas bahwa harga, lokasi, tipe host, dan availability merupakan faktor paling dominan dalam membedakan tipe kamar, dengan pola yang konsisten antara kedua kelas yang dibandingkan terhadap Entire home/apt.

12. Analisis Probabilitas Prediksi

12.1 Menyimpan Probabilitas Prediksi

pred_prob_df <- as.data.frame(pred_prob)

prediction_probability <- bind_cols(
  test_scaled %>% select(room_type),
  pred_prob_df
)

head(prediction_probability) %>%
  kable()
room_type Entire home/apt Private room Shared room
Entire home/apt 0.7728180 0.2258591 0.0013230
Private room 0.3510524 0.6436387 0.0053090
Entire home/apt 0.9617140 0.0382577 0.0000283
Private room 0.0691335 0.8906860 0.0401805
Entire home/apt 0.4114565 0.5834212 0.0051223
Private room 0.0039487 0.7893095 0.2067418

Hasil probabilitas prediksi menunjukkan bahwa model umumnya memberikan probabilitas tertinggi pada kelas yang sesuai dengan nilai aktual, terutama untuk Entire home/apt dan Private room. Hal ini menunjukkan bahwa model cukup percaya diri dalam membedakan dua kelas mayoritas tersebut.

Pada beberapa kasus, terlihat adanya tumpang tindih probabilitas antara Entire home/apt dan Private room, yang menunjukkan bahwa karakteristik kedua tipe ini dalam beberapa kondisi cukup mirip sehingga model tidak selalu dapat membedakan secara tegas.

Sebaliknya, probabilitas untuk Shared room cenderung sangat kecil pada sebagian besar observasi, bahkan ketika nilai aktual bukan Shared room. Hal ini menunjukkan bahwa model jarang memberikan keyakinan tinggi terhadap kelas ini.

12.2 Rata-Rata Probabilitas Prediksi Berdasarkan Actual Class

prediction_probability %>%
  group_by(room_type) %>%
  summarise(across(where(is.numeric), mean), .groups = "drop") %>%
  kable()
room_type Entire home/apt Private room Shared room
Entire home/apt 0.7771089 0.2192502 0.0036409
Private room 0.2390351 0.7190821 0.0418829
Shared room 0.1096098 0.7462468 0.1441435

Rata-rata probabilitas memperkuat pola sebelumnya. Untuk data aktual Entire home/apt, model memberikan probabilitas tertinggi pada kelas yang sama (≈0.77), dan hal yang sama terjadi pada Private room (≈0.72). Ini menunjukkan bahwa model cukup baik dalam mengenali dua kelas utama.

Namun, pada data aktual Shared room, probabilitas tertinggi justru diberikan kepada Private room (≈0.75), sementara probabilitas untuk Shared room sendiri relatif rendah (≈0.14). Hal ini menunjukkan bahwa model cenderung salah mengklasifikasikan Shared room sebagai Private room.

Secara keseluruhan, hasil ini mengindikasikan bahwa model memiliki kemampuan yang baik dalam membedakan kelas mayoritas, tetapi masih kesulitan dalam mengenali kelas minoritas, yang konsisten dengan kondisi distribusi data yang tidak seimbang.

13. Kesimpulan

Penelitian ini menunjukkan bahwa tipe kamar Airbnb di New York sangat dipengaruhi oleh harga, lokasi, availability, dan aktivitas listing. Model multinomial logistic regression mampu menangkap hubungan tersebut dengan cukup baik, terutama untuk membedakan Entire home/apt dan Private room, meskipun masih memiliki keterbatasan dalam mengenali Shared room akibat ketidakseimbangan data.

Dari sisi bisnis, terdapat beberapa insight utama yang dapat diambil. Harga menjadi pembeda paling kuat antar segmen, di mana Entire home/apt berada pada kategori premium, sedangkan Private room dan Shared room berada pada segmen yang lebih terjangkau. Hal ini menunjukkan bahwa strategi pricing sangat menentukan positioning suatu listing di pasar.

Lokasi juga berperan penting, dengan Manhattan dan Brooklyn sebagai pusat aktivitas Airbnb yang didominasi oleh listing dengan harga lebih tinggi dan variasi tipe kamar yang lebih beragam. Hal ini mengindikasikan bahwa wilayah strategis tidak hanya meningkatkan harga, tetapi juga mempengaruhi karakteristik penawaran properti.

Dari sisi operasional, availability yang tinggi cenderung berkaitan dengan tipe kamar non-premium, yang dapat mengindikasikan tingkat permintaan yang lebih rendah. Sebaliknya, listing dengan availability rendah dan jumlah review tinggi menunjukkan tingkat okupansi yang lebih baik, sehingga dapat digunakan sebagai indikator performa listing.

Selain itu, perbedaan antara host individu dan host dengan banyak listing menunjukkan adanya dua pola bisnis yang berbeda. Host individu cenderung menyewakan properti secara penuh, sedangkan host dengan banyak listing memiliki pendekatan yang lebih beragam dalam menawarkan tipe kamar.

Secara keseluruhan, hasil ini menunjukkan bahwa pasar Airbnb memiliki segmentasi yang jelas berdasarkan harga, lokasi, dan karakteristik listing. Insight ini dapat dimanfaatkan oleh host untuk menentukan strategi penetapan harga, memilih lokasi yang optimal, serta mengelola ketersediaan properti agar lebih sesuai dengan permintaan pasar.