-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathReport_code.Rmd
More file actions
347 lines (244 loc) · 15.2 KB
/
Copy pathReport_code.Rmd
File metadata and controls
347 lines (244 loc) · 15.2 KB
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
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
---
title: "Thumbtack Data Analysis & Visualization"
author: "Jong Ha Lee"
date: "2/1/2017"
output:
html_document: default
pdf_document: default
---
```{r global_options, include=FALSE}
knitr::opts_chunk$set(fig.width=8, fig.height=6, echo = F, results = 'hide',
warning = F)
setwd("~/Documents/Jobs/Job Applications/Thumbtack")
library(ggplot2)
library(dplyr)
library(grid)
library(gridExtra)
```
```{r data}
#First, reading the two datasets:
quotes <- read.csv("quotes.csv", stringsAsFactors = F)
visitors <- read.csv("visitors.csv", stringsAsFactors = F)
```
----
##1. Visitors and Conversion Rate
\
###a) How does the number of visitors change over time?
```{r 1a_dataprepare}
#First, converting session_date column to Date object types:
visitors$session_date <- as.Date(visitors$session_date, format = "%m/%d")
```
Line Graph of Number of Visitors over time:
```{r 1a_graph}
ggplot_1 <- ggplot(data = visitors, aes(x = session_date))
ggplot_1 +
geom_line(stat = 'count') +
labs(x = "Date (Year 2016)", y = "Number of visitors") +
ggtitle("Number of Visitors over Time")
```
Quick analysis shows that there is some sort of periodic activity in the number of visitors, especially on a weekly basis. Let's take August 7th for example:
```{r 1a_weekday, results = 'markup'}
weekdays(as.Date('07-08-2016', '%d-%m-%Y'))
```
It looks like August 7th, 2016 is a Sunday - thus we can see that the number of visitors is highest at the beginning of the week (Monday), and diminishes as it approaches the weekend.
\
###b) % of Visitors submitting project request
First, checking whether there are data quality issues (having values besides 0 or 1):
```{r 1b_datacheck, results = 'markup'}
table(visitors$sent_request)
```
Looks okay, calculating % of Visitors submitting Project Requests:
```{r 1b, results = 'markup'}
sum(visitors$sent_request) / nrow(visitors) * 100
```
It looks like around 56.9 percent of visitors submit a request.
\
###c) Category and Device Influences
\
#### Visitors: Categorical Influences
```{r 1c_visitors_cat}
ggplot_1 +
geom_line(stat = 'count', aes(color = category_name)) +
facet_grid(category_name ~.) +
guides(color = F) +
labs(x = "Date (Year 2016)", y = "Number of visitors") +
ggtitle("Number of Visitors Over Time, Separated by Category")
```
Looking at the categories, first we notice that there are a lot more requests for Moving help, and thus will contribute to the overall number of visitors trend more in comparison to Cleaning help. Secondly, we can see that the overall trend we saw - decreasing number of visitors as the week go by - is prevalent in both categories. However, we also notice that the trend is more prevalent in the Moving category, with around 50% drops from the start of the week (Monday), to the end of the week (Sunday). In contrast, House Cleaning shows a slightly less degree of a drop, of around 33%.
\
#### Visitors: Device Influences
```{r 1c_visitors_device}
ggplot_1 +
geom_line(stat = 'count', aes(color = device)) +
facet_grid(device ~.) +
guides(color = F) +
labs(x = "Date (Year 2016)", y = "Number of visitors") +
ggtitle("Number of Visitors Over Time, Separated by Device")
```
Looking at the number of visitors over time, separated by device, we can see an analogous trend here. A lot more visitors come through the desktop interface as compared to the mobile application; furthermore, the degree of drop is much larger in the desktop area in comparison to the mobile area.
\
#### Visitors: Combined Influences
```{r 1c_combined}
ggplot_1 +
geom_line(stat = 'count') +
facet_grid(device ~ category_name) +
labs(x = "Date (Year 2016)", y = "Number of visitors") +
ggtitle("Number of Visitors Over Time, Separated by Device")
```
Finally, looking at the combination of visitors and devices, we can see that desktop visitors, in need of Moving help, 1) possesses the most number of customers, and 2) clearly shows the diminishing trend we described earlier.
\
I hypothesize that more people tend towards the Desktop application mainly because for these help activities - especially moving - people wish to be thorough and not miss a detail in hiring a professional. These activities are a hassle for people, and they wish to avoid more hassle in the logistics of getting professional help (e.g. missing move-out date because they missed a small detail in putting in a request). Thus, since Desktop provides a more holistic view and can save details easily, I believe people, especially in need of help in these two categories, tend more towards the Desktop application.
As for the diminishing trend from weekday to weekend, I believe it is due to the fact that people want the professionals to come in during weekends to help them, because it may be a hassle to talk and let in the professionals into the house during working days. Thus, assuming the request -> quote -> agreement process takes around 4-5 days, it may seem reasonable that most people submit requests on Monday, when professionals are back to work from the weekend checking requests, and also gives ample time to walk through the process of getting professionals on board.
\
####Percent Visitors: Category
```{r 1c_percent_cat, results = 'markup'}
table(visitors$category_name) / nrow(visitors) * 100
```
This discrepancy may be due to the fact that house cleaning requests are relatively constant over seasons/months, but moving may happen more frequently during summer seasons (July - August) especially for college students. We may need to look at overall moving trends in America to see whether there is seasonality in the data.
\
####Percent Visitors: Device
```{r 1c_percent_dev, results = 'markup'}
table(visitors$device) / nrow(visitors) * 100
```
\
####Percent Visitors: Combined
```{r 1c_percent_comb, results = 'markup'}
table(visitors$device, visitors$category_name) / nrow(visitors) * 100
```
As explained before, the large discrepency in the proportion of number of visitors in need of Local Moving Help by device may be explained by the fact that these customers want to be more thorough by using a Desktop interface. In contrast, there is little discrepency in the House Cleaning category between the two devices.
\
\
----
##2. Quotes Per Request
\
###a) Distribution of Number of Quotes per Request
```{r 2a_reshape}
#Reshaping data to only include 1 row per request_id, with
#a new column showing how many quote ids there were for that request:
grouped <-
quotes %>% group_by(., request_id) %>%
dplyr::summarise(., num_quotes = n_distinct(quote_id))
```
A Histogram of Number of Quotes Per Request:
```{r 2a_dist_quotes}
ggplot2 <- ggplot(data = grouped, aes(x = num_quotes))
ggplot2 +
geom_histogram(bins = length(unique(grouped$num_quotes))) +
labs(x = "Number of Quotes", y = "Count of Requests") +
ggtitle("Distribution of Number of Quotes Per Request")
```
Five-number summary of Quotes per Request:
```{r 2a_fivenumber, results = 'markup'}
summary(grouped$num_quotes)
```
Mean and Standard Deviation of Quotes per Request:
```{r 2a_musd, results = 'markup'}
mean(grouped$num_quotes)
sd(grouped$num_quotes)
```
Based on the histogram, we can see that the distribution of number of quotes per request is skewed to the right; most of the requests only receive 1-2 quotes, with only a few receiving 5, and very rarely 6 quotes per request.
\
###b) Factors Contributing to Distribution
I postulate that it is due to the category, how_far for Moving, and num_bedrooms/num_bathrooms for Cleaning. The further you have to move, the higher price you can charge, and thus more quotes for that request. Similar logic applies for cleaning for number of rooms to clean.
Before analysis, we note that not all the request_ids in visitors are in quotes dataset:
```{r join_out, echo = T, results = 'markup'}
table(visitors[visitors$sent_request == 1, ]$request_id %in% grouped$request_id)
```
We will only deal with visitors data which have request_ids in the quotes dataset, meaning only requests that have received quotes after sending it in; we are making this selective process because our question is trying to understand what factors contribute to some requests getting more *quotes* than others, and with my postulation, we definitely need the visitors' request data as well.
\
```{r joining}
#Continuing with the joining process of the two datasets:
joined <- dplyr::left_join(grouped,
visitors[visitors$sent_request == 1, ], by = "request_id")
```
```{r function}
data_out <- function(data, g){
output <-
data %>% dplyr::group_by_(., g) %>%
dplyr::summarize(., avg_quotes = sum(num_quotes) / length(num_quotes))
return(output)
}
plot_out <- function(d, x1, y1 = "avg_quotes"){
plot_graph <-
ggplot(data = d,
aes_string(x = x1, y = y1, fill = x1)) +
guides(fill = F) +
geom_bar(stat = 'identity') + ggtitle(paste("Average Quotes by", x1))
return(plot_graph)
}
```
```{r 2b_save_gg}
#Separated by Category
cat_data <- data_out(joined, "category_name")
p1 <- plot_out(cat_data, "category_name")
#Separated by How_Far for Moving
far_data <- data_out(joined, "how_far")
p2 <- plot_out(far_data[far_data$how_far != "", ], "how_far") + coord_flip()
#Separated by num_bathrooms for Cleaning
bath_data <- data_out(joined, "num_bathrooms")
p3 <- plot_out(bath_data[bath_data$num_bathrooms != "", ], "num_bathrooms") + coord_flip()
#Separated by num_bedrooms for Cleaning
bed_data <- data_out(joined, "num_bedrooms")
p4 <- plot_out(bed_data[bed_data$num_bedrooms != "", ], "num_bedrooms") + coord_flip()
```
Plotting bar charts separated by category, and separated by distance for Moving requests:
```{r 2b_plot_gg1}
grid.arrange(p1, p2, ncol = 2)
```
We can see that Moving on average receives more quotes than house cleaning. This may be due to 1) attracting more professionals perhaps due to the higher price they can charge to help moving, or 2) simply more professionals are into Moving, regardless of reason.
Also, we can see that for the Moving Requests, the further the distance is, the more quotes a Moving request receives. This may be due to the fact that compared to the inconvenience and cost a professional burdens due to a longer distance, the revenue it receives is still more attractive than that of the shorter distance Moving requests.
\
Next, plotting graphs separated by number of bedrooms and number of bathrooms for Cleaning requests:
```{r 2b_plot_gg2}
grid.arrange(p3, p4, nrow = 2)
```
As for Cleaning Requests, we can also see a similar trend: the larger the bathroom and bedrooms are, the more quotes the Cleaning requests receive. Again similar logic applies - larger the surface area to clean, the more revenue.
Thus, we conclude that in general, the amount of work correlates positively with the amount of quotes received in both moving and cleaning requests, due to one main reason: potentially increased revenue.
\
\
----
##3. Job Value
\
###a) Distribution of Prices
Note that there is missing data for the quote_prices for some quotes. We will omit these data for now, as there is no reasonable method to predict these missing quote prices.
```{r 1a_prices_dist}
#First creating a joined dataframe to get categories
pdata_joined <- left_join(quotes, visitors[ ,c("category_name","request_id")],
by = "request_id")
#To have a reaonable visualization of the density plot
outlier_limit <-
IQR(na.omit(pdata_joined$quote_price)) * 1.5 +
summary(pdata_joined$quote_price)[5]
ggplot(data = pdata_joined[!is.na(pdata_joined$quote_price), ]) +
geom_density(aes(x = quote_price, fill = category_name), alpha = 0.5) +
xlim(0, outlier_limit) +
ggtitle("Distributions of Quote Prices separated by Category") +
theme(legend.position = "bottom")
```
Though the prices are discrete variables, looking at the density plots we can see that Quote Prices for Moving requests are relatively normally distributed in contrast to the Quote Prices for Cleaning requests, which are skewed to the right. This may be due to Cleaning requests with many bedrooms and bathrooms, which may mean a higher economic class and hence the consumer's willingness to pay may be much higher than normal, creating an outlier in quote price charged.
Also to note is that the mean of quote prices for moving is larger than that of house cleaning, mainly because Moving on average costs more for a professional to conduct than cleaning.
\
###b) Charging Prices by Thumbtack
For Cleaning Requests, I believe Thumbtack should charge pros a proportion of their quote price. We clearly saw that the distribution of quote prices pros charge for requests vary greatly, and is quite unstable. Thus, instead of charging a flat fee per quote, I believe the pricing strategy should also vary to make sure professionals cannot take advantage of Thumbtack, nor are treated with unfair prices based on the requests that come in for Cleaning. This proportion may be a 3% quoting fee.
In contrast, we can see that the quote prices for Moving requests are somewhat normally distributed, with less outliers and thus variability than that of Cleaning requests - the quote prices are relatively more stable. Thus, perhaps for Cleaning requests a flat fee per month may be a better option. This will enable professionals to quote different ranges of prices within a stable distribution we see here, and on average will be a fair price compared to the quotes received. This price per month may be calculated as:
```{r price_calculation, echo = T, results = 'markup'}
#Assuming we have a month's worth of quoting data for professionals:
hired <-
pdata_joined %>% group_by(., pro_id) %>%
filter(., hired == 1) %>% summarise(., num_hired = n())
hired <- mean(hired$num_hired)
#So per pro, get number of times hired per month (if quote got hired, that means he got hired) -> and get the mean of number of hired
#avg hired * avg price quoted * 0.03
move_price <- hired * mean(na.omit(pdata_joined$quote_price)) * 0.03
move_price
```
\
\
----
##4. Further Explanation
\
###a) How Elastic is the Supply of Professionals?
We saw previously that the number of requests diminishes as the weekday moves into the weekend. Do the number of professionals active (submitting quotes) follow that trend? Or rather, is it that the number of professionals is relatively fixed, but the number of quotes from pre-existing professionals simply increase? We would be interested in doing this analysis because we can flexibly alter pricing strategies based on number of professionals and the quotes they are submitting.
\
###b) How many requests do not hire a professional - in other words, how many requests do not reach the final match between quotes/professionals and customers?
Something to notice is that some of the requests actually do not eventually hire a professional, even when many professionals are quoting for the request. We could examine which kind of requests especially show this trend, and this exploratory data analysis may lead leeways recognizing a disequilibrium in the market, suggesting better quoting strategies to professionals, and potentially asking customers for their reasons for not hiring a professional.