Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
193 lines (155 sloc) 9.12 KB
---
title: Moving Penalty
author: Jens von Bergmann
date: '2018-11-28'
slug: moving-penalty
categories:
- cmhc
- Toronto
- Vancouver
- rental
tags: []
description: "What's the penalty to move f you are renting in a purpose-built rental building in Canada."
featured: 'moving-penalty-1.png'
images: ["https://doodles.mountainmath.ca/posts/2018-11-28-moving-penalty_files/figure-html/moving-penalty-1.png"]
featuredalt: ""
featuredpath: "/posts/2018-11-28-moving-penalty_files/figure-html"
linktitle: ''
type: "post"
---
[Aaron Licker](https://twitter.com/LGeospatial) asked a good question about this very interesting dataset.
{{<tweet 1067902087571230721>}}
Unfortunately it is not obvious where to get the raw data, but Keith Stewart at the Vancouver CMHC office was kind enough the share the dataset. So read on to follow my quick look at the data, or just [download it if you want to tinker yourself](/data/cmhc_average_vacant_rents/average-rents-vacant-occupied-units-2018.xlsx). (French version [here](/data/cmhc_average_vacant_rents/loyers-moyens-log-inoccup-occ-2018.xlsx)).
```{r setup, include=FALSE}
knitr::opts_chunk$set(
echo = FALSE,
message = FALSE,
warning = FALSE,
fig.width = 8,
cache = TRUE
)
library(tidyverse)
library(cmhc)
library(cancensus)
library(cansim)
library(here)
vars <- c("Bachelor", "1 Bedroom", "2 Bedroom", "3 Bedroom +", "Total")
bedroom_colors <- set_names(RColorBrewer::brewer.pal(length(vars),"Dark2"),vars)
```
```{r}
first_row <- function(data)as.character(data[1,])
cut_at_na <- function(data,column_name){
index=which(is.na(data[[column_name]])) %>% first
data[1:(index-1),]
}
h1 <- readxl::read_xlsx(here("static/data/cmhc_average_vacant_rents/average-rents-vacant-occupied-units-2018.xlsx"),skip=8) %>%
names %>%
gsub("X__\\d+","XXX",.) %>%
na_if("XXX")
h2 <- readxl::read_xlsx(here("static/data/cmhc_average_vacant_rents/average-rents-vacant-occupied-units-2018.xlsx"),skip=8) %>%
first_row
hh=tibble(h1=h1,h2=h2) %>%
fill(h1) %>%
mutate(h2=ifelse(is.na(h2),paste0(lag(h2)," Q"),h2)) %>%
mutate(h=ifelse(is.na(h1),h2,paste0(h1,";",h2)))
data <- readxl::read_xlsx(here("static/data/cmhc_average_vacant_rents/average-rents-vacant-occupied-units-2018.xlsx"),skip=10,col_names=FALSE) %>%
set_names(hh$h) %>%
cut_at_na("Zone") %>%
gather(key="Type",value="Value",setdiff(names(.),c("Zone","Year"))) %>%
mutate(Bedrooms=strsplit(Type,";") %>% map(first) %>% unlist) %>%
mutate(Series=strsplit(Type,";") %>% map(last) %>% unlist) %>%
select(-Type) %>%
mutate(CMA=ifelse(grepl(" CMA$",Zone) & !grepl(" - Remainder of CMA$",Zone),gsub(" CMA$","",Zone),NA)) %>%
fill(CMA,.direction="up") %>%
mutate(Zone=ifelse(grepl(" - Remainder of CMA$",Zone),paste0(Zone," ",CMA),Zone)) %>%
group_by(Zone,Year,Bedrooms) %>%
spread(key="Series",value="Value") %>%
ungroup %>%
mutate_at(c("Vacant Units","Occupied Units"),as.numeric) %>%
mutate(moving_penalty=`Vacant Units`-`Occupied Units`) %>%
mutate(relative_moving_penalty=moving_penalty/`Occupied Units`)
cma_data <- data %>% filter(grepl("CMA$",Zone))
```
## Moving penalty
The data is interesting because it gives an estimate of the "moving penalty", that is on average how much more rent a person that is currently renting would have to pay to move to a different purpose-built rental unit in the same CMA.
Of course the exact amount is location specific, and the CMHC estimates for the rents for "vacant" units are not very precise, especially in areas with low vacancy rates. And we don't know much about the quality and location of the vacant units. The vacancy rate varies geographically across CMAs. For example the City of Vancouver has a lower rate than the CMA average, so this will lead to the vacancy units over-sampling the outer (and less expensive) areas, so the true penalty to move in Vancouver might be higher.
Understanding some of the data caveats, here are the moving penalties by CMA.
```{r moving-penalty}
plot_data <- cma_data %>% filter(Bedrooms=="Total")
ggplot(plot_data,aes(x=reorder(CMA,relative_moving_penalty),y=relative_moving_penalty,fill=..x..)) +
geom_bar(stat="identity") +
scale_y_continuous(labels=scales::percent) +
coord_flip() +
scale_fill_viridis_c(option = "magma",guide=FALSE) +
theme_light() +
labs(title="Relative moving penalty",subtitle="(relative difference of rents for vacant to occupied units)",
x="CMA",
y="Relative moving penalty",
caption="MountainMath, CMHC Rms 2018")
```
This suggests that in Halifax people could lower their rent by almost 10% if they are willing to move, whereas in Victoria people should expect a 30% rent hike if they need to move. Again, these are only estimates, and quality and location of units can have sizable effects on this representation. It could well be that the rentals that are currently vacant in Halifax are simply not very desirable and Halifax has no need for less desirable (and cheaper) rentals.
The same cannot be said for Vancouver, where council is currently in the second day of a public hearing about strengthening renter protections in case of extensive building renovations. Renovations improve the quality of rentals, which is good for renters. But they also increase rents, which is bad for renters. On top of that, in a rent controlled environment with vacancy decontrol like in Vancouver, renters may pay a strong moving penalty that is independent of the quality of the unit and just a function of the time they have lived in their current unit. At the centre of this are "renovictions", where the landlord conducting extensive renovations that requires the termination of the leases. It is not always clear if these renovations are matter of necessity to prolong the life of the building (which is quite old in many cases), or if it primarily motivated by a combination of the desire to circumvent rent control and capture higher rents for higher quality renovated units.
Of note is that the moving penalty is generally higher in Provinces with rent control.
```{r}
vacancy_rent_table_for <- function(GeoUID){
region_params=cmhc_region_params_from_census(as.character(GeoUID))
params=cmhc_timeseries_params(table_id = cmhc_table_list["Rms Vacancy Rate Time Series"],region=region_params)
dat_vacancy <- get_cmhc(params) %>%
rename(Year=X1) %>%
mutate(Series="Vacancy rate")
params=cmhc_timeseries_params(table_id = cmhc_table_list["Rms Rent Change Time Series"],region=region_params)
dat_rent_change <- get_cmhc(params) %>%
rename(Year=X1) %>%
mutate(Series="Rent change")
dat=bind_rows(dat_vacancy,dat_rent_change) %>%
mutate(GeoUID=GeoUID)
return(dat)
}
```
To better understand this we can correlate the moving penalty with the vacancy rate that we looked at [earlier today](https://doodles.mountainmath.ca/blog/2018/11/28/vacancy-rate-and-rent-change/).
```{r}
geo_uid_lookup <- set_names(cmhc::cmhc_cma_translation_data$CMA_UID,cmhc::cmhc_cma_translation_data$NAME_EN)
cma_data <- cma_data %>% mutate(GeoUID=geo_uid_lookup[CMA])
data <- cma_data$GeoUID %>%
unique %>%
lapply(vacancy_rent_table_for) %>%
bind_rows %>%
select_if(!grepl("X\\d+",names(.))) %>%
mutate(Year=as.integer(gsub(" October$","",Year))) %>%
gather(key="Bedrooms",value="Value",vars)
full_data <- inner_join(cma_data,data,by=c("GeoUID","Year","Bedrooms"))
```
```{r}
plot_data <- full_data %>%
filter(Series=="Vacancy rate") %>%
group_by(Bedrooms) %>%
mutate(Value=Value/100)
ggplot(plot_data,aes(x=Value,y=relative_moving_penalty,color=Bedrooms)) +
geom_point() +
scale_y_continuous(labels=scales::percent) +
scale_x_continuous(labels=scales::percent) +
geom_smooth(method="lm",formula=y~x,se=FALSE) +
theme_light() +
labs(x="Vacancy rate",y="Relative moving penalty",
title="Canadian CMA moving penalty vs vacancy rate",
caption="MountainMath, CMHC Rms 2018")
```
The scatterplot with all bedroom types gets a bit messy, but things get much clearer if we correlate the variables separately by number of Bedrooms. This shows that the moving penalty anti-correlates with the vacancy rate.
To round things off, we can also look at the fixed-sample rent change. Here we expect a high pressure to raise rents in areas with a high moving penalty, which would lead to higher fixed-sample rent increases.
```{r}
plot_data <- full_data %>%
filter(Series=="Rent change") %>%
group_by(Bedrooms) %>%
mutate(Value=Value)
ggplot(plot_data,aes(x=Value,y=relative_moving_penalty,color=Bedrooms)) +
geom_point() +
scale_y_continuous(labels=scales::percent) +
scale_x_continuous(labels=scales::percent) +
geom_smooth(method="lm",formula=y~x,se=FALSE) +
theme_light() +
labs(x="Fixed-sample rent change",y="Relative moving penalty",
title="Canadian CMA moving penalty vs vacancy rate",
caption="MountainMath, CMHC Rms 2018")
```
This graph shows that fixed-sample rents indeed correlate with the moving penalty. At some point it is probably worth looking into these relationships more closely.
As always, the code for the analysis is [available on GitHub](https://github.com/mountainMath/doodles/blob/master/content/posts/2018-11-28-moving-penalty.Rmarkdown) for anyone to reproduce, adapt or appropriate for their own purposes.