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:
Mengidentifikasi karakteristik utama yang membedakan tipe kamar Airbnb di New York City
Membangun model klasifikasi untuk memprediksi tipe kamar berdasarkan fitur listing
Mengevaluasi performa model dalam mengklasifikasikan berbagai tipe kamar
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.
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)
airbnb <- read.csv("AB_NYC_2019.csv", stringsAsFactors = FALSE)
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.
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.
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.
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.
duplicate_count <- sum(duplicated(airbnb))
duplicate_count
[1] 0
Tidak ada Data Duplikat yang ditemukan pada Dataset.
room_typeroom_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.
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
)
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)
)
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
)
airbnb_clean <- airbnb_clean %>%
mutate(
room_type = factor(room_type),
neighbourhood_group = factor(neighbourhood_group),
neighbourhood = factor(neighbourhood)
)
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.
Fitur baru yang dibuat:
price_log: transformasi log dari hargahas_review: penanda apakah listing memiliki review atau
tidakhost_type: penanda host individu atau host dengan
banyak listingavailability_category: kategori tingkat ketersediaan
listingairbnb_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"
)
)
)
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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()
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"
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)
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 |
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
}
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
)
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.
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.
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.
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.
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
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.
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.
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.
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.
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.
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.
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.
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.
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.