-
Notifications
You must be signed in to change notification settings - Fork 0
/
ProyectoFinal.qmd
324 lines (241 loc) · 12.6 KB
/
ProyectoFinal.qmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
---
format: html
editor: visual
---
Vasmos a cargar el dataset de AirBnB descargado de [aquí](https://public.opendatasoft.com/explore/dataset/airbnb-listings/export/?disjunctive.host_verifications&disjunctive.amenities&disjunctive.features&q=Madrid&dataChart=eyJxdWVyaWVzIjpbeyJjaGFydHMiOlt7InR5cGUiOiJjb2x1bW4iLCJmdW5jIjoiQ09VTlQiLCJ5QXhpcyI6Imhvc3RfbGlzdGluZ3NfY291bnQiLCJzY2llbnRpZmljRGlzcGxheSI6dHJ1ZSwiY29sb3IiOiJyYW5nZS1jdXN0b20ifV0sInhBeGlzIjoiY2l0eSIsIm1heHBvaW50cyI6IiIsInRpbWVzY2FsZSI6IiIsInNvcnQiOiIiLCJzZXJpZXNCcmVha2Rvd24iOiJyb29tX3R5cGUiLCJjb25maWciOnsiZGF0YXNldCI6ImFpcmJuYi1saXN0aW5ncyIsIm9wdGlvbnMiOnsiZGlzanVuY3RpdmUuaG9zdF92ZXJpZmljYXRpb25zIjp0cnVlLCJkaXNqdW5jdGl2ZS5hbWVuaXRpZXMiOnRydWUsImRpc2p1bmN0aXZlLmZlYXR1cmVzIjp0cnVlfX19XSwidGltZXNjYWxlIjoiIiwiZGlzcGxheUxlZ2VuZCI6dHJ1ZSwiYWxpZ25Nb250aCI6dHJ1ZX0%3D&location=16,41.38377,2.15774&basemap=jawg.streets)
![](descargar.png)
```{r}
airbnb<-read.csv('airbnb-listings.csv',sep = ';')
options(repr.plot.height=4,repr.plot.width=6,repr.plot.res = 300)
library(dplyr)
```
1. Vamos a quedarnos con las columnas de mayor interés: 'City','Room.Type','Neighbourhood','Accommodates','Bathrooms','Bedrooms','Beds','Price','Square.Feet','Guests.Included','Extra.People','Review.Scores.Rating','Latitude', 'Longitude' Nos quedarmos solo con las entradas de Madrid para Room.Type=="Entire home/apt" y cuyo barrio (Neighbourhood) no está vacio '' Podemos eliminar las siguientes columnas que ya no son necesarias: "Room.Type",'City' Llama a nuevo dataframe df_madrid.
```{r}
head(airbnb)
```
```{r}
df_madrid <- airbnb[airbnb$Room.Type == "Entire home/apt" & airbnb$Neighbourhood != '' & airbnb$City == "Madrid",
c("Neighbourhood", "Accommodates", "Bathrooms", "Bedrooms", "Beds", "Price", "Square.Feet", "Guests.Included", "Extra.People", "Review.Scores.Rating", "Latitude", "Longitude")]
head(df_madrid)
```
------------------------------------------------------------------------
2. Crea una nueva columna llamada Square.Meters a partir de Square.Feet. Recuerda que un pie cuadrado son 0.092903 metros cuadrados.
```{r}
df_madrid$Square.Meters <- df_madrid$Square.Feet * 0.092903
df_madrid[, c("Square.Feet", "Square.Meters")]
head(df_madrid)
```
------------------------------------------------------------------------
3. ¿Que porcentaje de los apartamentos no muestran los metros cuadrados? Es decir, ¿cuantos tienen NA en Square.Meters?
```{r}
entire_home_NA <- sum(is.na(df_madrid$Square.Meters))
porcent <- (entire_home_NA / nrow(df_madrid)) * 100
cat(porcent)
```
------------------------------------------------------------------------
4. De todos los apartamentos que tienen un valor de metros cuadrados diferente de NA ¿Que porcentaje de los apartamentos tienen 0 metros cuadrados?
```{r}
entire_home_real <-entire_home_NA
home_cero <-sum(df_madrid$Square.Meters ==0 & !is.na(df_madrid$Square.Meters))
porcent_real <- (home_cero / entire_home_real) *100
cat(porcent_real)
```
------------------------------------------------------------------------
5. Reemplazar todos los 0m\^2 por NA
```{r}
df_madrid$Square.Meters[df_madrid$Square.Meters == '' | df_madrid$Square.Meters == 0] <- NA
cat(df_madrid$Square.Meters)
```
------------------------------------------------------------------------
Hay muchos NAs, vamos a intentar crear un modelo que nos prediga cuantos son los metros cuadrados en función del resto de variables para tratar de rellenar esos NA. Pero **antes de crear el modelo** vamos a hacer: \* pintar el histograma de los metros cuadrados y ver si tenemos que filtrar algún elemento más. \* crear una variable sintética nueva basada en la similitud entre barrios que usaremos en nuestro modelo.
6. Pinta el histograma de los metros cuadrados y ver si tenemos que filtrar algún elemento más
```{r}
library(ggplot2)
ggplot(df_madrid, aes(x = Square.Meters)) +
geom_histogram(binwidth = 10, fill = 'red', color = "white") +
labs(title = "Histograma de Metros Cuadrados", x = "Metros Cuadrados", y = "")
```
------------------------------------------------------------------------
7. Asigna el valor NA a la columna Square.Meters de los apartamentos que tengan menos de 20 m\^2
```{r}
df_madrid$Square.Meters[df_madrid$Square.Meters < 20] <- NA
cat(df_madrid$Square.Meters)
```
------------------------------------------------------------------------
8. Existen varios Barrios que todas sus entradas de Square.Meters son NA, vamos a eliminar del dataset todos los pisos que pertenecen a estos barrios.
```{r}
library(dplyr)
df_madrid_Neighbourhood<- unique(df_madrid$Neighbourhood)
Neighbourhood_0 <- character(0)
for (Neighbourhood in df_madrid_Neighbourhood) {
df_madrid_barrio <- df_madrid[df_madrid$Neighbourhood == Neighbourhood, ]
df_na <- all(is.na(df_madrid_barrio$Square.Meters))
if (df_na) {
Neighbourhood_0 <- c(Neighbourhood_0, Neighbourhood)
}
}
df_madrid <- df_madrid[!df_madrid$Neighbourhood %in% Neighbourhood_0, ]
summary(df_madrid)
```
------------------------------------------------------------------------
El barrio parece ser un indicador importante para los metros cuadrados de un apartamento.
Vamos a agrupar los barrios por metros cuadrados. Podemos usar una matriz de similaridad de Tukey tal y como hicimos en el curso de estadística:
```{r}
tky<-TukeyHSD(aov( formula=Square.Meters~Neighbourhood, data=df_madrid ))
tky.result<-data.frame(tky$Neighbourhood)
cn <-sort(unique(df_madrid$Neighbourhood))
resm <- matrix(NA, length(cn),length(cn))
rownames(resm) <- cn
colnames(resm) <- cn
resm[lower.tri(resm) ] <- round(tky.result$p.adj,4)
resm[upper.tri(resm) ] <- t(resm)[upper.tri(resm)]
diag(resm) <- 1
library(ggplot2)
library(reshape2)
dfResm <- melt(resm)
ggplot(dfResm, aes(x=Var1, y=Var2, fill=value))+
geom_tile(colour = "black")+
scale_fill_gradient(low = "white",high = "steelblue")+
ylab("Neighbourhood")+xlab("Neighbourhood")+theme_bw()+
theme(axis.text.x = element_text(angle = 90, hjust = 1),legend.position="none")
```
9. Usando como variable de distancia: 1-resm Dibuja un dendrograma de los diferentes barrios.
```{r}
library(factoextra)
distancia <- as.dist(1 - resm)
clust_madrid <- hclust(distancia, method = "complete")
dendrogram <- as.dendrogram(clust_madrid)
fviz_dend(clust_madrid, cex = 0.8, lwd = 0.8, k = 38,
rect = TRUE,
k_colors = "jco",
rect_border = "jco",
rect_fill = TRUE,
ggtheme = theme_gray())
```
------------------------------------------------------------------------
10. ¿Que punto de corte sería el aconsejable?, ¿cuantos clusters aparecen?
El punto de corte sería 0.1. Hay 38 , uno por cada barrio.
------------------------------------------------------------------------
11. Vamos a crear una nueva columna en el dataframe df_madrid con un nuevo identificador marcado por los clusters obtenidos. Esta columna la llamaremos neighb_id
```{r}
cluster <- cutree(clust_madrid, k = 38)
df_madrid_cluster <- data.frame(Neighbourhood = unique(df_madrid$Neighbourhood), neighb_id = cluster)
df_madrid <- merge(df_madrid, df_madrid_cluster , by = "Neighbourhood", all.x = TRUE)
head(df_madrid)
```
------------------------------------------------------------------------
12. Vamos a crear dos grupos, uno test y otro train.
```{r}
set.seed(42)
idx<-sample(1:nrow(df_madrid),nrow(df_madrid)*0.7)
train.df<-df_madrid[idx,]
test.df<-df_madrid[-idx,]
train.df <- train.df |> select(!c(Neighbourhood,Square.Feet))
test.df <- test.df |> select(!c(Neighbourhood,Square.Feet))
cat("Número de valores:", nrow(train.df), "\n")
cat("Número de valores de datos de prueba:", nrow(test.df), "\n")
```
------------------------------------------------------------------------
13. Tratamos de predecir los metros cuadrados en función del resto de columnas del dataframe.
```{r}
summary(train.df)
cor(train.df[,c("Accommodates","Square.Meters","Bathrooms","Bedrooms","Beds","Price","Guests.Included","Extra.People")], use ="pairwise.complete.obs")
```
```{r}
modelo1 <- lm(Square.Meters ~ Accommodates + Bathrooms + Bedrooms + Beds + Price + Guests.Included + Extra.People + Review.Scores.Rating + Latitude + Longitude , data = train.df)
summary(modelo1)
modelo2 <- lm(Square.Meters ~ Accommodates + Bedrooms + Price, data = train.df)
summary(modelo2)
```
------------------------------------------------------------------------
14. Mirad el histograma de los residuos sobre el conjunto de test para evaluar la calidad de vuestro modelo
```{r}
residuo1 <- residuals(modelo1, newdata = test.df)
residuo2 <- residuals(modelo2, newdata = test.df)
library(ggplot2)
ggplot(data.frame(residuo = residuo1), aes(x = residuo)) +
geom_histogram(binwidth = 1, fill = 'blue', color = "black", alpha = 0.5) +
labs(title = "Histograma de residuos de modelo1", x = "Residuos", y = "")
ggplot(data.frame(residuo = residuo2), aes(x = residuo)) +
geom_histogram(binwidth = 1, fill = 'darkgreen', color = "black", alpha = 0.5) +
labs(title = "Histograma de residuos de modelo2", x = "Residuos", y = "")
```
------------------------------------------------------------------------
15. Si tuvieramos un anuncio de un apartamento para 6 personas (Accommodates), con 1 baño, con un precio de 80€/noche y 3 habitaciones en el barrio de Sol, con 3 camas y un review de 80. ¿Cuantos metros cuadrados tendría? Si tu modelo necesita algúna variable adicional puedes inventartela dentro del rango de valores del dataset. ¿Como varía sus metros cuadrados con cada habitación adicional?
```{r}
df_anuncio <- data.frame(
Accommodates=6, Bathrooms=1, Bedrooms=3, Beds= 3,
Price=80, Guests.Included=3, Review.Scores.Rating = 80,
Extra.People=1, Latitude=mean(df_madrid$Latitude,na.rm = TRUE), Longitude=-mean(df_madrid$Longitude,na.rm = TRUE), neighb_id = "1")
metros_estimados_mod1 <- predict(modelo1, df_anuncio)
paste("Metros cuadrados apartamento con modelo1:", metros_estimados_mod1)
metros_habitacion_adicional <- (modelo1$coefficients["Bedrooms"])
paste("Metros por habitación adicionalcon modelo1:", metros_habitacion_adicional)
metros_estimados_mod2 <- predict(modelo2, df_anuncio)
paste("Metros cuadrados apartamento con modelo2:", metros_estimados_mod2)
metros_habitacion_adicional <- (modelo2$coefficients["Bedrooms"])
paste("Metros por habitación adicionalcon modelo2:",metros_habitacion_adicional)
```
------------------------------------------------------------------------
16. Rellenar los Square.Meters con valor NA con el estimado con el modelo anterior.
```{r}
df_madrid_nuevo <- df_madrid
df_madrid_nuevo[is.na(df_madrid_nuevo$Square.Meters),"Square.Meters"] <- predict(modelo1, (df_madrid[is.na(df_madrid$Square.Meters),]))
head(df_madrid_nuevo)
```
------------------------------------------------------------------------
17. Usar PCA para encontrar el apartamento más cercano a uno dado. Este algoritmo nos ayudaría a dado un apartamento que el algoritmo nos devolvería los 5 apartamentos más similares.
Crearemos una función tal que le pasemos un apartamento con los siguientes datos: \* Accommodates \* Bathrooms \* Bedrooms \* Beds \* Price \* Guests.Included \* Extra.People \* Review.Scores.Rating \* Latitude \* Longitude \* Square.Meters
## y nos devuelva los 5 más similares de:
```{r}
df_madrid_data <- df_madrid[, c("Accommodates", "Bathrooms", "Bedrooms", "Beds", "Price", "Guests.Included", "Extra.People", "Review.Scores.Rating", "Latitude", "Longitude", "Square.Meters")]
df_madrid_data <- na.omit(df_madrid_data) # Asegurar que no haya NAs
# Aplicar PCA
pr_madrid <- prcomp(df_madrid_data, center = FALSE, scale = FALSE)
pr_madrid
```
```{r}
# Función para encontrar los apartamentos más cercanos
find_similar_apartments <- function(apartment, pr_madrid, df_madrid_data) {
apartment_pca <- predict(pr_madrid, newdata = apartment)
distances <- apply(pr_madrid$x, 1, function(x) sqrt(sum((x - apartment_pca)^2)))
closest_indices <- order(distances)[1:5]
return(df_madrid[closest_indices, ])
}
```
```{r}
# Ejemplo
given_apartment <- data.frame(
Accommodates = 3,
Bathrooms = 1,
Bedrooms = 2,
Beds = 2,
Price = 100,
Guests.Included = 2,
Extra.People = 20,
Review.Scores.Rating = 80,
Latitude = 40.42,
Longitude = -3.7038,
Square.Meters = 70
)
similar_apartments <- find_similar_apartments(given_apartment, pr_madrid, df_madrid_data)
print(similar_apartments)
```
```{r}
# Ejemplo 2
given_apartment2 <- data.frame(
Accommodates = 3,
Bathrooms = 1,
Bedrooms = 2,
Beds = 2,
Price = 80,
Guests.Included = 2,
Extra.People = 2,
Review.Scores.Rating = 60,
Latitude = 40.42,
Longitude = -3.7038,
Square.Meters = 40
)
similar_apartments2 <- find_similar_apartments(given_apartment2, pr_madrid, df_madrid_data)
print(similar_apartments2)
```