1. Variable Analysis

The variable city is qualitative on a nominal scale, as it identifies the city associated with each observation without any natural ordering.

The variable year is quantitative and continuous, but in this analysis it is treated as a qualitative ordinal variable, since the years represent distinct time periods with a natural chronological ordering.

The variable month is qualitative and nominal with a cyclical structure. Although it is coded numerically from 1 to 12, these values identify categories corresponding to the different months of the year and have a cyclical structure: December and January, for example, are consecutive months even though they are coded as 12 and 1, respectively.

The variables sales and listings are quantitative and discrete, as they represent counts and therefore take integer values. volume, median price, and months inventory are instead quantitative and continuous. All continuous quantitative variables are measured on a ratio scale, since an absolute zero is defined and ratios between values are meaningful.

The variables city, year, and month are mainly used as grouping variables and temporal dimensions for analysing the other variables. In particular, city allows us to compare the different local markets, while year and month allow us to study the temporal evolution and the seasonal component of the phenomenon.

For quantitative variables, measures of position, variability, and shape can be calculated. The Gini index can instead be used to assess distributional heterogeneity, both with respect to the variable city and with respect to classes constructed from a quantitative variable.

Temporal evolution can be represented using line charts, while bar charts are useful for comparing mean values across cities. The distributions of quantitative variables can finally be represented using boxplots.

2. Measures of Position, Variability, and Shape

Measures of Position

texas <- read.csv('realestate_texas.csv', sep = ',') 
attach(texas)
variables <- texas[, c("sales", "volume", "median_price",
                                         "listings", "months_inventory")]

ind.pos <- data.frame(
  Min = sapply(variables, min),
  First_quartile = sapply(variables, quantile, probs=0.25),
  Median = sapply(variables, median),
  Mean = sapply(variables, mean),
  Third_quartile = sapply(variables, quantile, probs=0.75),
  Max = sapply(variables, max)
)

rownames(ind.pos) <- c(
  "`sales`",
  "`volume`",
  "`median price`",
  "`listings`",
  "`months inventory`"
)

knitr::kable(
  ind.pos,
  digits = 2,
  col.names = c("", "Min", "First quartile",
                "Median", "Mean", "Third quartile", "Max"),
  align = c("l", "r", "r", "r", "r", "r", "r"))
Min First quartile Median Mean Third quartile Max
sales 79.00 127.00 175.50 192.29 247.00 423.00
volume 8.17 17.66 27.06 31.01 40.89 83.55
median price 73800.00 117300.00 134500.00 132665.42 150050.00 180000.00
listings 743.00 1026.50 1618.50 1738.02 2056.00 3296.00
months inventory 3.40 7.80 8.95 9.19 10.95 14.90

Measures of Variability

CV<-function(x){
  return(sd(x)/mean(x)*100)
}

ind.var <- data.frame(
  Standard_deviation = sapply(variables, sd),
  Coefficient_of_variation = sapply(variables, CV)
)

rownames(ind.var) <- c(
  "`sales`",
  "`volume`",
  "`median price`",
  "`listings`",
  "`months inventory`"
)

knitr::kable(
  ind.var,
  digits = 2,
  col.names = c("", "Standard deviation", "Coefficient of variation"),
  align = c("c", "c"))
Standard deviation Coefficient of variation
sales 79.65 41.42
volume 16.65 53.71
median price 22662.15 17.08
listings 752.71 43.31
months inventory 2.30 25.06

Measures of Shape

library(moments)

correct_kurt <- function(x){
  return(kurtosis(x)-3)
}

ind.for <- data.frame(
  Fisher_Index = sapply(variables, skewness),
  Kurtosis = sapply(variables, correct_kurt)
)

rownames(ind.for) <- c(
  "`sales`",
  "`volume`",
  "`median price`",
  "`listings`",
  "`months inventory`"
)

knitr::kable(
  ind.for, 
  digits = 3,
  col.names = c("", "Fisher index", "Kurtosis"),
  align = c("c", "c"))
Fisher index Kurtosis
sales 0.718 -0.313
volume 0.885 0.177
median price -0.365 -0.623
listings 0.649 -0.792
months inventory 0.041 -0.174

Looking at the results obtained, we can make several observations.

The variables median price and months inventory have very similar means and medians, suggesting that their distributions are particularly symmetric. Looking at the measures of shape, we can see that this is indeed the case, especially for months inventory.

The coefficient of variation allows us to compare the relative dispersion of the different variables. We can therefore state that volume has the highest relative variability, while median price has the lowest relative variability.

All variables except median price have positively skewed distributions, as indicated by the sign of the Fisher index. Regarding kurtosis, the distribution of volume is leptokurtic, while all the others are platykurtic.

3. Identifying the Variables with the Highest Variability and Skewness

The variable with the highest variability is volume, because it has the highest coefficient of variation. volume is also the most asymmetric variable, with positive skewness, since it has the highest absolute value of the Fisher skewness index.

4. Creating Classes for a Quantitative Variable

We divide the variable sales into classes. We choose the number of classes using Sturges’ rule:

N <- round(1+log(length(sales), base = 2))
N
## [1] 9

Therefore, the number of classes is equal to 9.

The table below reports absolute and relative frequencies:

freq_ass<-table(sales_cl)
freq_rel<-table(sales_cl)/length(sales)
distr_frq_sales_cl<-cbind(freq_ass,freq_rel)

knitr::kable(
  distr_frq_sales_cl,
  digits = 2,
  col.names = c("Classes", "Absolute frequency", "Relative frequency"),
  align = c("c", "c"))
Classes Absolute frequency Relative frequency
(78,116] 45 0.19
(116,155] 50 0.21
(155,193] 46 0.19
(193,231] 27 0.11
(231,270] 23 0.10
(270,308] 26 0.11
(308,346] 10 0.04
(346,385] 9 0.04
(385,423] 4 0.02

For greater clarity, we now represent the absolute frequencies with a bar chart.

ggplot(data=texas)+
  geom_bar(aes(x=sales_cl),
           stat='count',
           col='black',
           fill='blue')+
  labs(title = 'Distribution of monthly sales classes',
       x='Sales classes',
       y='Absolute frequencies')+
  theme_classic()

gini.index<-function(x){
  ni=table(x)
  fi=ni/length(x)
  fi2=fi^2
  J=length(table(x))
  gini=1-sum(fi2)
  gini.norm=gini/((J-1)/J)
  return(gini.norm)
}

paste("The Gini index is", round(gini.index(sales_cl), digits = 3))
## [1] "The Gini index is 0.954"

The heterogeneity index is very high, indicating a relatively even distribution of the number of sales across the different classes.

5. Creating New Variables

We create a new variable representing the average property price by dividing total sales volume by the number of sales: mean price = volume/sales x 1,000,000, since volume is expressed in millions of dollars. We then measure listing effectiveness by introducing a variable that gives the number of sales per listing: efficacy = sales/listings.

To comment on and analyse these new variables, we can ask, for example, how their mean values vary across the different cities.

texas %>%
  group_by(city) %>%
  summarise(
    mean_price = mean(mean_price),
    efficacy = mean(listings_efficacy)
  )%>%
  knitr::kable(
    digits = 3,
    col.names = c("City", "Mean price", "Listing effectiveness"),
    align = c("l", "r", "r"))
City Mean price Listing effectiveness
Beaumont 146640.4 0.106
Bryan-College Station 183534.3 0.147
Tyler 167676.8 0.093
Wichita Falls 119430.0 0.128

The table shows that, over the 2010–2014 period, Bryan-College Station had the highest prices and the highest listing effectiveness, while Wichita Falls had the lowest prices and Tyler had the lowest listing effectiveness.

We now calculate the mean values of the variables over the five years considered.

texas %>%
  group_by(year) %>%
  summarise(
    mean_price = mean(mean_price),
    efficacy = mean(listings_efficacy)
  )%>%
  knitr::kable(
    digits = 3,
    col.names = c("Year", "Mean price", "Listing effectiveness"),
    align = c("l", "r", "r"))
Year Mean price Listing effectiveness
2010 150188.6 0.100
2011 148250.6 0.093
2012 150898.7 0.110
2013 158705.2 0.135
2014 163558.7 0.157

We can therefore observe that, overall across the four cities considered, both mean prices and listing effectiveness appear to have increased over the five years analysed, especially in 2013 and 2014.

6. Conditional Analysis

We use the dplyr package to perform conditional statistical analyses by city, year, and month. The results are also represented graphically.

6.1 Total Number of Sales

sales_city <- texas %>%
  group_by(city)%>%
  summarise(media=mean(sales),
            dev.standard=sd(sales)
            )

knitr::kable(
  sales_city,
  digits = 2,
  col.names = c("City", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
City Mean Standard deviation
Beaumont 177.38 41.48
Bryan-College Station 205.97 84.98
Tyler 269.75 61.96
Wichita Falls 116.07 22.15
ggplot(sales_city, aes(x = city, y = media)) +
  geom_col(fill = 'blue') +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ), width = 0.2) +
  labs(
    x = "City",
    y = "Mean sales",
    title = "6.1.1 Mean sales by city"
  )

sales_year <- texas %>%
  group_by(year)%>%
  summarise(media=mean(sales),
            dev.standard=sd(sales))

knitr::kable(
  sales_year,
  digits = 2,
  col.names = c("Year", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
Year Mean Standard deviation
2010 168.67 60.54
2011 164.12 63.87
2012 186.15 70.91
2013 211.92 84.00
2014 230.60 95.51
ggplot(sales_year, aes(x = year, y = media)) +
  geom_line(col = 'blue') +
  geom_point() +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ),
    width = 0.1, col='red'
  ) +
  scale_x_continuous(breaks = 2010:2014) +
  labs(
    x = "Year",
    y = "Mean sales",
    title = "6.1.2 Mean sales by year"
  )

sales_month <- texas %>%
  group_by(month)%>%
  summarise(media=mean(sales),
            dev.standard=sd(sales))

knitr::kable(
  sales_month,
  digits = 2,
  col.names = c("Month", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
Month Mean Standard deviation
1 127.40 43.38
2 140.85 51.07
3 189.45 59.18
4 211.70 65.40
5 238.85 83.12
6 243.55 95.00
7 235.75 96.27
8 231.45 79.23
9 182.35 72.52
10 179.90 74.95
11 156.85 55.47
12 169.40 60.75
ggplot(sales_month, aes(x = month, y = media)) +
  geom_line(col = 'blue') +
  geom_point() +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ),
    width = 0.1, col='red'
  ) +
  scale_x_continuous(breaks = 1:12) +
  labs(
    x = "Month",
    y = "Mean sales",
    title = "6.1.3 Mean sales by month"
  )

Mean sales values differ substantially across cities, with Tyler recording the highest mean and Wichita Falls the lowest. Over time, the annual mean increases, while the monthly pattern reveals a seasonal component, with generally higher values in the summer months.

6.2 Total Sales Volume

volume_city<-texas %>%
  group_by(city)%>%
  summarise(media=mean(volume),
            dev.standard=sd(volume))

knitr::kable(
  volume_city,
  digits = 2,
  col.names = c("City", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
City Mean Standard deviation
Beaumont 26.13 6.97
Bryan-College Station 38.19 17.25
Tyler 45.77 13.11
Wichita Falls 13.93 3.24
ggplot(volume_city, aes(x = city, y = media)) +
  geom_col(fill = 'darkgreen') +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ), width = 0.2) +
  labs(
    x = "City",
    y = "Mean sales volume",
    title = "6.2.1 Mean sales volume by city"
  )

volume_year<-texas %>%
  group_by(year)%>%
  summarise(media=mean(volume),
            dev.standard=sd(volume))

knitr::kable(
  volume_year,
  digits = 2,
  col.names = c("Year", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
Year Mean Standard deviation
2010 25.68 10.80
2011 25.16 12.20
2012 29.27 14.52
2013 35.15 17.93
2014 39.77 21.19
ggplot(volume_year, aes(x = year, y = media)) +
  geom_line(col = 'darkgreen') +
  geom_point() +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ),
    width = 0.1, col='red'
  ) +
  scale_x_continuous(breaks = 2010:2014) +
  labs(
    x = "Year",
    y = "Mean sales volume",
    title = "6.2.2 Mean sales volume by year"
  )

volume_month<-texas %>%
  group_by(month)%>%
  summarise(media=mean(volume),
            dev.standard=sd(volume))

knitr::kable(
  volume_month,
  digits = 2,
  col.names = c("Month", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
Month Mean Standard deviation
1 19.00 8.37
2 21.65 10.09
3 29.38 12.02
4 33.30 14.52
5 39.70 19.02
6 41.30 21.08
7 39.12 21.41
8 38.01 18.05
9 29.60 15.22
10 29.08 15.13
11 24.81 11.15
12 27.09 12.57
ggplot(volume_month, aes(x = month, y = media)) +
  geom_line(col = 'darkgreen') +
  geom_point() +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ),
    width = 0.1, col='red'
  ) +
  scale_x_continuous(breaks = 1:12) +
  labs(
    x = "Month",
    y = "Mean sales volume",
    title = "6.2.3 Mean sales volume by month"
  )

The pattern of total sales volume is consistent with that observed for sales: Tyler has the highest values on average, while Wichita Falls has the lowest. Here too, an increase is observed over the period considered, together with marked variability across months.

6.3 Total Number of Active Listings

list_city<-texas %>%
  group_by(city)%>%
  summarise(media=mean(listings),
            dev.standard=sd(listings))

knitr::kable(
  list_city,
  digits = 2,
  col.names = c("City", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
City Mean Standard deviation
Beaumont 1679.32 91.13
Bryan-College Station 1458.13 252.53
Tyler 2905.05 226.75
Wichita Falls 909.58 73.76
ggplot(list_city, aes(x = city, y = media)) +
  geom_col(fill = 'orange') +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ), width = 0.2) +
  labs(
    x = "City",
    y = "Mean listings",
    title = "6.3.1 Mean number of listings by city"
  )

list_year<-texas %>%
  group_by(year)%>%
  summarise(media=mean(listings),
            dev.standard=sd(listings))

knitr::kable(
  list_year,
  digits = 2,
  col.names = c("Year", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
Year Mean Standard deviation
2010 1826.00 785.02
2011 1849.65 780.38
2012 1776.81 738.45
2013 1677.60 743.52
2014 1560.04 706.71
ggplot(list_year, aes(x = year, y = media)) +
  geom_line(col = 'orange') +
  geom_point() +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ),
    width = 0.1, col='red'
  ) +
  scale_x_continuous(breaks = 2010:2014) +
  labs(
    x = "Year",
    y = "Mean listings",
    title = "6.3.2 Mean number of listings by year"
  )

list_month<-texas %>%
  group_by(month)%>%
  summarise(media=mean(listings),
            dev.standard=sd(listings))

knitr::kable(
  list_month,
  digits = 2,
  col.names = c("Month", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
Month Mean Standard deviation
1 1647.05 704.61
2 1692.50 711.20
3 1756.70 727.35
4 1825.70 770.43
5 1823.85 790.22
6 1833.25 811.63
7 1821.20 826.72
8 1786.30 815.87
9 1748.90 802.66
10 1710.35 779.16
11 1652.70 741.25
12 1557.75 692.57
ggplot(list_month, aes(x = month, y = media)) +
  geom_line(col = 'orange') +
  geom_point() +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ),
    width = 0.1, col='red'
  ) +
  scale_x_continuous(breaks = 1:12) +
  labs(
    x = "Month",
    y = "Mean listings",
    title = "6.3.3 Mean number of listings by month"
  )

Regarding the number of active listings, Bryan-College Station has lower mean values than the other cities. Over time, the annual mean decreases over the period considered, while the monthly pattern shows proportionally smaller variations than those observed for sales and volume.

6.4 Months of Inventory

invent_city<-texas %>%
  group_by(city)%>%
  summarise(media=mean(months_inventory),
            dev.standard=sd(months_inventory))

knitr::kable(
  invent_city,
  digits = 2,
  col.names = c("City", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
City Mean Standard deviation
Beaumont 9.97 1.65
Bryan-College Station 7.66 2.25
Tyler 11.32 1.89
Wichita Falls 7.82 0.78
ggplot(invent_city, aes(x = city, y = media)) +
  geom_col(fill = 'purple') +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ), width = 0.2) +
  labs(
    x = "City",
    y = "Mean months of inventory",
    title = "6.4.1 Mean months of inventory by city"
  )

invent_year<-texas %>%
  group_by(year)%>%
  summarise(media=mean(months_inventory),
            dev.standard=sd(months_inventory))

knitr::kable(
  invent_year,
  digits = 2,
  col.names = c("Year", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
Year Mean Standard deviation
2010 9.97 2.08
2011 10.90 2.07
2012 9.88 1.61
2013 8.15 1.69
2014 7.06 1.75
ggplot(invent_year, aes(x = year, y = media)) +
  geom_line(col = 'purple') +
  geom_point() +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ),
    width = 0.1, col='red'
  ) +
  scale_x_continuous(breaks = 2010:2014) +
  labs(
    x = "Year",
    y = "Mean months of inventory",
    title = "6.4.2 Mean months of inventory by year"
  )

invent_month<-texas %>%
  group_by(month)%>%
  summarise(media=mean(months_inventory),
            dev.standard=sd(months_inventory))

knitr::kable(
  invent_month,
  digits = 2,
  col.names = c("Month", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
Month Mean Standard deviation
1 8.84 1.97
2 9.06 1.98
3 9.40 2.06
4 9.72 2.24
5 9.68 2.38
6 9.70 2.41
7 9.62 2.50
8 9.39 2.45
9 9.19 2.52
10 8.94 2.44
11 8.66 2.37
12 8.12 2.27
ggplot(invent_month, aes(x = month, y = media)) +
  geom_line(col = 'purple') +
  geom_point() +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ),
    width = 0.1, col='red'
  ) +
  scale_x_continuous(breaks = 1:12) +
  labs(
    x = "Month",
    y = "Mean months of inventory",
    title = "6.4.3 Mean months of inventory by month"
    )

The variable months inventory has relatively low mean values in Bryan-College Station and shows a decrease in the annual mean starting in 2011. The monthly pattern has seasonal characteristics, less pronounced than those observed for sales and volume, but more pronounced than for listings.

6.5 Median Sale Price

median_city<-texas %>%
  group_by(city)%>%
  summarise(media=mean(median_price),
            dev.standard=sd(median_price))

knitr::kable(
  median_city,
  digits = 2,
  col.names = c("City", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
City Mean Standard deviation
Beaumont 129988.3 10104.99
Bryan-College Station 157488.3 8852.24
Tyler 141441.7 9336.54
Wichita Falls 101743.3 11320.03
ggplot(median_city, aes(x = city, y = media)) +
  geom_col(fill = 'lightgreen') +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ), width = 0.2) +
  labs(
    x = "City",
    y = "Mean median price",
    title = "6.5.1 Mean median price by city"
  )

median_year<-texas %>%
  group_by(year)%>%
  summarise(media=mean(median_price),
            dev.standard=sd(median_price))

knitr::kable(
  median_year,
  digits = 2,
  col.names = c("Year", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
Year Mean Standard deviation
2010 130191.7 21821.76
2011 127854.2 21317.80
2012 130077.1 21431.52
2013 135722.9 21708.08
2014 139481.2 25625.41
ggplot(median_year, aes(x = year, y = media)) +
  geom_line(col = 'lightgreen') +
  geom_point() +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ),
    width = 0.1, col='red'
  ) +
  scale_x_continuous(breaks = 2010:2014) +
  labs(
    x = "Year",
    y = "Mean median price",
    title = "6.5.2 Mean median price by year"
  )

median_month<-texas %>%
  group_by(month)%>%
  summarise(media=mean(median_price),
            dev.standard=sd(median_price))

knitr::kable(
  median_month,
  digits = 2,
  col.names = c("Month", "Mean", "Standard deviation"),
  align = c("l", "c", "c"))
Month Mean Standard deviation
1 124250 25151.28
2 130075 22822.59
3 127415 23442.03
4 131490 21458.40
5 134485 18796.26
6 137620 19231.02
7 134750 21944.78
8 136675 22488.38
9 134040 24344.10
10 133480 26358.07
11 134305 24691.47
12 133400 22809.76
ggplot(median_month, aes(x = month, y = media)) +
  geom_line(col = 'lightgreen') +
  geom_point() +
  geom_errorbar(
    aes(
      ymin = media - dev.standard,
      ymax = media + dev.standard
    ),
    width = 0.1, col='red'
  ) +
  scale_x_continuous(breaks = 1:12) +
  labs(
    x = "Month",
    y = "Mean median price",
    title = "6.5.3 Mean median price by month"
  )

Median price has considerably higher mean values in Bryan-College Station and lower values in Wichita Falls. Over the period considered, the annual mean also increases, while the seasonal pattern appears somewhat less pronounced than in the previous cases.

7. Creating Visualisations with ggplot2

ggplot(data=texas)+
  geom_boxplot(aes(x=city, y=median_price), fill='lightblue')+
  labs(x='City', y='Median price', title = '7.1 Boxplot of median price by city')

texas3 <- data.frame(texas)
texas3$year <- as.character(texas$year)

Chart 7.1 highlights a clear difference in median price levels across the four cities. Bryan-College Station has the highest values, followed by Tyler, Beaumont, and finally Wichita Falls. Regarding dispersion, Wichita Falls has the widest interquartile range, while Bryan-College Station has a relatively more concentrated central distribution. There are also outliers for Beaumont, Wichita Falls, and Bryan-College Station.

ggplot(data=texas3)+
  geom_boxplot(aes(x=year, y=volume, fill=city))+
  labs(x='Years', y='Total sales volume (in millions of $)',
       title = '7.2 Boxplot of total sales volume by year and city')

Chart 7.2 shows strong variability in total sales volume, which differs across cities and years. In several years, Bryan-College Station and Tyler have wider interquartile ranges, indicating greater dispersion of monthly values, while Wichita Falls generally shows lower variability. A shift towards higher values in later years can also be observed, together with an outlier for Beaumont in 2012.

ggplot(data=texas)+
  geom_bar(aes(x=month, y=volume,
               fill=city),
           position = 'stack',
           stat='identity',
           col='black')+
  facet_wrap(year, ncol=2)+
  labs(title = '7.3 Total sales volume by month, year, and city',
       x='Months',
       y='Total sales volume (in millions of $)')+
  scale_x_continuous(breaks=1:12)+
  theme_classic()

Chart 7.3 shows the seasonal component of total sales volume and, at the same time, the contribution of the individual cities. Overall values tend to be higher in the spring and summer months and lower in the winter months. The year 2010 shows a partially different pattern, with the peak concentrated between April and June.

ggplot(data=texas)+
  geom_bar(aes(x=month, y=volume,
               fill=city),
           position = 'fill',
           stat='identity',
           col='black')+
  facet_wrap(year, ncol=2)+
  labs(title = '7.4 Normalised total sales volume by month, year, and city',
       x='Months',
       y='Percentage share of total')+
  scale_x_continuous(breaks=1:12)+
  theme_classic()

The normalisation in 7.4 makes it possible to compare the relative contribution of the different cities independently of the absolute sales volume. Tyler and Bryan-College Station generally account for the largest shares of the total volume, while Beaumont and especially Wichita Falls contribute smaller shares. The proportions are fairly stable across the years.

texas2 <- data.frame(texas)
texas2$year <- rep(seq(2010+1/24,2014+23/24,1/12),times=4)
texas2$month <- NULL

ggplot(texas2, aes(x = year, y = sales, color = city, group = city)) +
  geom_line(linewidth = 1) +
  geom_point() +
  labs(
    x = "Year",
    y = "Number of sales",
    title = "7.5 Sales trend by city"
  ) +
  scale_x_continuous(breaks = 2010:2014)

Finally, chart 7.5 shows the evolution of sales in the individual cities over the entire period considered. Beaumont, Bryan-College Station, and Tyler show an overall increasing trend, despite marked seasonal fluctuations. Wichita Falls remains at lower levels and does not show a clearly increasing or decreasing overall trend.

8. Conclusions

The analysis reveals a marked seasonal component in sales, with generally higher values in the late spring and summer months and lower values in the winter months. This pattern is present in most years, although 2010 is an exception, and it affects the individual cities to different degrees.

A second relevant feature is the strong heterogeneity among local markets. Tyler and Bryan-College Station generally show higher levels of both the number and value of sales, while Wichita Falls remains at the lowest levels. The disaggregated analysis also shows that the growth observed at the aggregate level is not uniform across all cities.

Over the period considered, the number of sales, sales volume, and median price show an overall increase starting in 2011, while the number of listings and months of inventory decrease. However, the high standard deviations observed in many analyses indicate that aggregate means do not fully represent the variability of individual markets. For this reason, analysis by city is essential for correctly interpreting the observed dynamics.

Based on the results obtained, Texas Realty Insights should take the seasonal component of sales into account when planning and interpreting data, avoiding direct comparisons between periods belonging to different seasons without considering this effect. In addition, the marked differences observed among local markets suggest complementing aggregate indicators with monitoring and analysis activities specific to each city.