1. Introduction

This analysis explores historical real estate market data from selected cities in Texas. The main objective is to describe the distribution and variability of key market indicators, investigate differences across cities and time periods, and identify relevant patterns in sales, prices, listings, and market inventory.

Each observation represents the real estate market of a specific city in a specific month and year.


2. Data Preparation

2.1 Setup

2.2 Dataset Import

real_estate <- read.csv("realestate_texas.csv")

The dataset contains 240 observations and 8 original variables.

dim(real_estate)
## [1] 240   8
str(real_estate)
## 'data.frame':    240 obs. of  8 variables:
##  $ city            : chr  "Beaumont" "Beaumont" "Beaumont" "Beaumont" ...
##  $ year            : int  2010 2010 2010 2010 2010 2010 2010 2010 2010 2010 ...
##  $ month           : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ sales           : int  83 108 182 200 202 189 164 174 124 150 ...
##  $ volume          : num  14.2 17.7 28.7 26.8 28.8 ...
##  $ median_price    : num  163800 138200 122400 123200 123100 ...
##  $ listings        : int  1533 1586 1689 1708 1771 1803 1857 1830 1829 1779 ...
##  $ months_inventory: num  9.5 10 10.6 10.6 10.9 11.1 11.7 11.6 11.7 11.5 ...

The observations cover four Texas cities over the period from 2010 to 2014.

2.3 Variable Preparation

The variable city is converted into a factor because it represents a nominal categorical variable.

real_estate$city <- factor(real_estate$city)

A new ordered categorical variable is also created for the month names. This will be useful for graphical representations and seasonal analyses, while the original numeric month variable is preserved for temporal operations.

real_estate$month_name <- factor(
  real_estate$month,
  levels = 1:12,
  labels = month.name,
  ordered = TRUE
)

3. Data Quality Checks

Before performing the statistical analysis, the dataset was checked for missing values, duplicated observations, and evident inconsistencies.

# Check for missing values
colSums(is.na(real_estate))
##             city             year            month            sales 
##                0                0                0                0 
##           volume     median_price         listings months_inventory 
##                0                0                0                0 
##       month_name 
##                0
# Inspect the cities included in the dataset
unique(real_estate$city)
## [1] Beaumont              Bryan-College Station Tyler                
## [4] Wichita Falls        
## Levels: Beaumont Bryan-College Station Tyler Wichita Falls
# Check for duplicated city-year-month observations
any(duplicated(real_estate[c("city", "year", "month")]))
## [1] FALSE
# Check temporal ranges
range(real_estate$month)
## [1]  1 12
range(real_estate$year)
## [1] 2010 2014
# Check minimum values of quantitative variables
sapply(
  real_estate[c(
    "sales",
    "volume",
    "median_price",
    "listings",
    "months_inventory"
  )],
  min
)
##            sales           volume     median_price         listings 
##           79.000            8.166        73800.000          743.000 
## months_inventory 
##            3.400

No missing values were detected in the dataset. In addition, no duplicated observations were found for the combination of city, year, and month. The month variable ranges correctly from 1 to 12, while the dataset covers the period from 2010 to 2014.

All quantitative variables show positive minimum values, with no evident impossible or structurally inconsistent observations. Overall, the dataset appears suitable for the subsequent statistical analysis.


4. Variable Classification

variable <- c(
  "city",
  "year",
  "month",
  "sales",
  "volume",
  "median_price",
  "listings",
  "months_inventory"
)

description <- c(
  "reference city",
  "reference year",
  "reference month",
  "total number of sales",
  "total sales volume (USD millions)",
  "median sale price (USD)",
  "total number of active listings",
  "estimated number of months required to sell the current inventory"
)

statistical_type <- c(
  "qualitative nominal",
  "quantitative discrete, temporal",
  "qualitative ordinal, temporal and cyclical",
  "quantitative discrete",
  "quantitative continuous",
  "quantitative continuous",
  "quantitative discrete",
  "quantitative continuous"
)

suitable_analysis <- c(
  "Frequencies, proportions, Gini heterogeneity index",
  "Temporal range, grouping and trend analysis",
  "Frequencies, proportions and seasonal analysis",
  "Position, variability and shape measures",
  "Position, variability and shape measures",
  "Position, variability and shape measures",
  "Position, variability and shape measures",
  "Position, variability and shape measures"
)

variable_classification <- data.frame(
  Variable = variable,
  Description = description,
  Statistical_Type = statistical_type,
  Suitable_Analysis = suitable_analysis
)

knitr::kable(variable_classification)
Variable Description Statistical_Type Suitable_Analysis
city reference city qualitative nominal Frequencies, proportions, Gini heterogeneity index
year reference year quantitative discrete, temporal Temporal range, grouping and trend analysis
month reference month qualitative ordinal, temporal and cyclical Frequencies, proportions and seasonal analysis
sales total number of sales quantitative discrete Position, variability and shape measures
volume total sales volume (USD millions) quantitative continuous Position, variability and shape measures
median_price median sale price (USD) quantitative continuous Position, variability and shape measures
listings total number of active listings quantitative discrete Position, variability and shape measures
months_inventory estimated number of months required to sell the current inventory quantitative continuous Position, variability and shape measures

year is a quantitative discrete variable with a temporal dimension. In this analysis, it will mainly be used to group observations across different periods and to investigate trends over time.

month is an ordinal categorical variable with a cyclical temporal structure. The natural order of the months will be preserved, taking into account that December is followed by January of the subsequent year. This variable will also be useful for investigating possible seasonal patterns in the real estate market.


5. Descriptive Statistics

5.1 Helper Functions

Coefficient of Variation

The coefficient of variation is used to measure relative variability and allows comparisons between quantitative variables measured on different scales or in different units.

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

Normalized Gini Heterogeneity Index

The normalized Gini heterogeneity index is used to measure how evenly observations are distributed across the categories of a qualitative variable.

gini.index <- function(x){
  ni <- table(x)        # Absolute frequencies
  fi <- ni/length(x)    # Relative frequencies
  fi2 <- fi^2           # Squared relative frequencies
  J <- length(ni)       # Number of categories
  
  gini <- 1-sum(fi2)    # Raw Gini heterogeneity index
  gini.normalized <- gini / ((J - 1) / J) # Normalized Gini index
  
  return(gini.normalized)
}

Quantitative Summary Statistics Function

The following function calculates the main measures of position, variability, and distribution shape for a quantitative variable.

summary_stats_quant_var <- function(x) {
  c(
    Mean = mean(x),
    Median = median(x),
    Q1 = unname(quantile(x, 0.25)),
    Q3 = unname(quantile(x, 0.75)),
    Min = min(x),
    Max = max(x),
    Range = max(x) - min(x),
    Variance = var(x),
    SD = sd(x),
    IQR = IQR(x),
    CV = cv(x),
    Skewness = skewness(x),
    Excess_Kurtosis = kurtosis(x) - 3
  )
}

5.2 Quantitative Variables

The main quantitative variables considered in the descriptive analysis are:

quantitative_vars <- c(
  "sales",
  "volume",
  "median_price",
  "listings",
  "months_inventory"
)

For each variable, measures of position, variability, skewness, and kurtosis will be considered.

5.2.1 Sales

mean(real_estate$sales)
## [1] 192.2917
median(real_estate$sales)
## [1] 175.5
quantile(
  real_estate$sales,
  probs = c(0.25, 0.75)
)
## 25% 75% 
## 127 247
min(real_estate$sales)
## [1] 79
max(real_estate$sales)
## [1] 423
sales_range <- max(real_estate$sales) -
  min(real_estate$sales)

sales_range
## [1] 344
IQR(real_estate$sales)
## [1] 120
var(real_estate$sales)
## [1] 6344.3
sd(real_estate$sales)
## [1] 79.65111
cv(real_estate$sales)
## [1] 41.42203
skewness(real_estate$sales)
## [1] 0.718104
# Excess kurtosis
kurtosis(real_estate$sales) - 3
## [1] -0.3131764

The number of sales ranges from 79 to 423, with a mean of approximately 192.29 and a median of 175.5. The mean is higher than the median, which is consistent with the positive skewness observed in the distribution.

The central 50% of the observations lies between 127 and 247 sales, resulting in an interquartile range of 120. The standard deviation is approximately 79.65 sales, while the coefficient of variation is approximately 41.42%, indicating substantial variability relative to the average level of sales.

The skewness coefficient is approximately 0.72, suggesting a moderately right-skewed distribution. This indicates that some relatively high sales observations extend the upper tail and pull the mean above the median.

The excess kurtosis is approximately -0.31. The distribution can therefore be described as mildly platykurtic relative to a normal distribution, suggesting slightly lighter tails and a less pronounced tendency toward extreme observations.

5.2.2 Volume

mean(real_estate$volume)
## [1] 31.00519
median(real_estate$volume)
## [1] 27.0625
quantile(
  real_estate$volume,
  probs = c(0.25, 0.75)
)
##     25%     75% 
## 17.6595 40.8930
min(real_estate$volume)
## [1] 8.166
max(real_estate$volume)
## [1] 83.547
volume_range <- max(real_estate$volume) -
  min(real_estate$volume)

volume_range
## [1] 75.381
IQR(real_estate$volume)
## [1] 23.2335
var(real_estate$volume)
## [1] 277.2707
sd(real_estate$volume)
## [1] 16.65145
cv(real_estate$volume)
## [1] 53.70536
skewness(real_estate$volume)
## [1] 0.884742
# Excess kurtosis
kurtosis(real_estate$volume) - 3
## [1] 0.176987

The total sales volume ranges from USD 8.17 million to USD 83.55 million, with a mean of approximately USD 31.01 million and a median of USD 27.06 million. The mean is higher than the median, which is consistent with the positive skewness observed in the distribution.

The central 50% of observations lies between USD 17.66 million and USD 40.89 million, resulting in an interquartile range of approximately USD 23.23 million. The standard deviation is approximately USD 16.65 million, while the coefficient of variation is approximately 53.70%, indicating substantial variability relative to the average sales volume.

The skewness coefficient is approximately 0.88, suggesting a moderately right-skewed distribution. Some observations with relatively high sales volumes extend the upper tail and pull the mean above the median.

The excess kurtosis is approximately 0.18, which is close to zero. Therefore, the distribution can be considered approximately mesokurtic, with only a very slight tendency toward heavier tails than a normal distribution.

5.2.3 Median Price

mean(real_estate$median_price)
## [1] 132665.4
median(real_estate$median_price)
## [1] 134500
quantile(
  real_estate$median_price,
  probs = c(0.25, 0.75)
)
##    25%    75% 
## 117300 150050
min(real_estate$median_price)
## [1] 73800
max(real_estate$median_price)
## [1] 180000
median_price_range <- max(real_estate$median_price) -
  min(real_estate$median_price)

median_price_range
## [1] 106200
IQR(real_estate$median_price)
## [1] 32750
var(real_estate$median_price)
## [1] 513572983
sd(real_estate$median_price)
## [1] 22662.15
cv(real_estate$median_price)
## [1] 17.08218
skewness(real_estate$median_price)
## [1] -0.3645529
# Excess kurtosis
kurtosis(real_estate$median_price) - 3
## [1] -0.6229618

The median sale price ranges from USD 73,800 to USD 180,000, with a mean of approximately USD 132,665 and a median of USD 134,500. The mean is slightly lower than the median, which is consistent with the negative skewness observed in the distribution.

The central 50% of observations lies between USD 117,300 and USD 150,050, resulting in an interquartile range of USD 32,750. The standard deviation is approximately USD 22,662, while the coefficient of variation is approximately 17.08%. Compared with sales and total sales volume, median price therefore shows substantially lower relative variability.

The skewness coefficient is approximately -0.36, indicating a mildly left-skewed distribution. Some relatively low median-price observations extend the lower tail and contribute to pulling the mean slightly below the median.

The excess kurtosis is approximately -0.62, suggesting a mildly platykurtic distribution, with somewhat lighter tails than a normal distribution.

5.2.4 Listings

mean(real_estate$listings)
## [1] 1738.021
median(real_estate$listings)
## [1] 1618.5
quantile(
  real_estate$listings,
  probs = c(0.25, 0.75)
)
##    25%    75% 
## 1026.5 2056.0
min(real_estate$listings)
## [1] 743
max(real_estate$listings)
## [1] 3296
listings_range <- max(real_estate$listings) -
  min(real_estate$listings)

listings_range
## [1] 2553
IQR(real_estate$listings)
## [1] 1029.5
var(real_estate$listings)
## [1] 566569
sd(real_estate$listings)
## [1] 752.7078
cv(real_estate$listings)
## [1] 43.30833
skewness(real_estate$listings)
## [1] 0.6494982
# Excess kurtosis
kurtosis(real_estate$listings) - 3
## [1] -0.79179

The total number of active listings ranges from 743 to 3296, with a mean of approximately 1738.02 and a median of 1618.5. The mean is higher than the median, which is consistent with the positive skewness observed in the distribution.

The central 50% of observations lies between 1026.5 and 2056.0, resulting in an interquartile range of 1029.5. The standard deviation is approximately 752.71 listings, while the coefficient of variation is approximately 43.31%, indicating substantial relative variability in the number of active listings.

The skewness coefficient is approximately 0.65, suggesting a moderately right-skewed distribution. Some observations with relatively high numbers of listings extend the upper tail and pull the mean above the median.

The excess kurtosis is approximately -0.79, indicating a platykurtic distribution with lighter tails than a normal distribution.

5.2.5 Months Inventory

mean(real_estate$months_inventory)
## [1] 9.1925
median(real_estate$months_inventory)
## [1] 8.95
quantile(
  real_estate$months_inventory,
  probs = c(0.25, 0.75)
)
##   25%   75% 
##  7.80 10.95
min(real_estate$months_inventory)
## [1] 3.4
max(real_estate$months_inventory)
## [1] 14.9
months_inventory_range <- max(real_estate$months_inventory) -
  min(real_estate$months_inventory)

months_inventory_range
## [1] 11.5
IQR(real_estate$months_inventory)
## [1] 3.15
var(real_estate$months_inventory)
## [1] 5.306889
sd(real_estate$months_inventory)
## [1] 2.303669
cv(real_estate$months_inventory)
## [1] 25.06031
skewness(real_estate$months_inventory)
## [1] 0.04097527
# Excess kurtosis
kurtosis(real_estate$months_inventory) - 3
## [1] -0.1744475

The months inventory ranges from 3.4 to 14.9 months, with a mean of approximately 9.19 months and a median of 8.95 months. The mean and median are very close, which is consistent with the near-zero skewness observed in the distribution.

The central 50% of observations lies between 7.80 and 10.95 months, resulting in an interquartile range of 3.15 months. The standard deviation is approximately 2.30 months, while the coefficient of variation is approximately 25.06%, indicating moderate relative dispersion around the average inventory level.

The skewness coefficient is approximately 0.04, suggesting an approximately symmetric distribution, with no relevant evidence of asymmetry.

The excess kurtosis is approximately -0.17, which is close to zero. Therefore, the distribution can be considered approximately mesokurtic, with only a very slight tendency toward lighter tails than a normal distribution.

5.3 Categorical and Temporal Variables

For categorical and temporal variables, absolute and relative frequency distributions will be considered. For city, the Gini heterogeneity index will also be calculated to assess how evenly the observations are distributed across the different cities.

The categorical and temporal variables considered in this section are city, year, and month.

5.3.1 Variable City

5.3.1.1 Frequency Table
abs_freq_city <- table(real_estate$city)
rel_freq_city <- prop.table(abs_freq_city)


city_frequency <- data.frame(
  City = names(abs_freq_city),
  Frequency = as.vector(abs_freq_city),
  Percentage = round(as.vector(rel_freq_city) * 100, 2)
)

knitr::kable(
  city_frequency,
  col.names = c(
    "City",
    "Absolute Frequency",
    "Relative Frequency (%)"
  ),
  caption = "Frequency Distribution by City"
)
Frequency Distribution by City
City Absolute Frequency Relative Frequency (%)
Beaumont 60 25
Bryan-College Station 60 25
Tyler 60 25
Wichita Falls 60 25
5.3.1.2 Gini Heterogeneity Index

The normalized Gini heterogeneity index is used to assess how evenly observations are distributed across the categories of a qualitative variable.

gini_city <- gini.index(real_estate$city)
gini_city
## [1] 1

The normalized Gini heterogeneity index for city is equal to 1, indicating maximum heterogeneity in the distribution of observations across cities. This result reflects the perfectly balanced structure of the dataset, with the same number of observations for each city.

5.3.2 Variable Year

5.3.2.1 Frequency Table
abs_freq_year <- table(real_estate$year)
rel_freq_year <- prop.table(abs_freq_year)

year_frequency <- data.frame(
  Year = names(abs_freq_year),
  Frequency = as.vector(abs_freq_year),
  Percentage = round(as.vector(rel_freq_year) * 100, 2)
)

knitr::kable(
  year_frequency,
  col.names = c(
    "Year",
    "Absolute Frequency",
    "Relative Frequency (%)"
  ),
  caption = "Frequency Distribution by Year"
)
Frequency Distribution by Year
Year Absolute Frequency Relative Frequency (%)
2010 48 20
2011 48 20
2012 48 20
2013 48 20
2014 48 20

Each year contains 48 observations, corresponding to 20% of the total dataset. This indicates that the dataset is evenly distributed across the period from 2010 to 2014, with each year receiving the same representation. Therefore, comparisons across years are not affected by differences in the number of observations available for each year.

5.3.3 Variable Month

5.3.3.1 Frequency Table
abs_freq_month <- table(real_estate$month_name)
rel_freq_month <- prop.table(abs_freq_month)

month_frequency <- data.frame(
  Month = names(abs_freq_month),
  Frequency = as.vector(abs_freq_month),
  Percentage = round(as.vector(rel_freq_month) * 100, 2)
)

knitr::kable(
  month_frequency,
  col.names = c(
    "Month",
    "Absolute Frequency",
    "Relative Frequency (%)"
  ),
  caption = "Frequency Distribution by Month"
)
Frequency Distribution by Month
Month Absolute Frequency Relative Frequency (%)
January 20 8.33
February 20 8.33
March 20 8.33
April 20 8.33
May 20 8.33
June 20 8.33
July 20 8.33
August 20 8.33
September 20 8.33
October 20 8.33
November 20 8.33
December 20 8.33

Each month contains 20 observations, corresponding to approximately 8.33% of the total dataset. This indicates that the dataset is evenly distributed across the twelve months of the year. Such a balanced monthly structure is particularly useful for seasonal comparisons, since no month is over- or under-represented. Since month is treated as an ordered categorical variable with a cyclical temporal structure, the natural sequence from January to December will be preserved in subsequent analyses and visualizations.

5.4 Overall Comparison of Quantitative Variables

To provide an overall comparison of the quantitative variables, the main measures of position, variability, and distribution shape are summarized in the following table. This allows the statistical characteristics of sales, volume, median_price, listings, and months_inventory to be compared directly.

descriptive_stats <- t(
  sapply(
    real_estate[quantitative_vars],
    summary_stats_quant_var
  )
)

knitr::kable(
  descriptive_stats,
  digits = 2,
  format.args = list(
    scientific = FALSE,
    big.mark = ","
  ),
  caption = "Descriptive Statistics for Quantitative Variables"
)
Descriptive Statistics for Quantitative Variables
Mean Median Q1 Q3 Min Max Range Variance SD IQR CV Skewness Excess_Kurtosis
sales 192.29 175.50 127.00 247.00 79.00 423.00 344.00 6,344.30 79.65 120.00 41.42 0.72 -0.31
volume 31.01 27.06 17.66 40.89 8.17 83.55 75.38 277.27 16.65 23.23 53.71 0.88 0.18
median_price 132,665.42 134,500.00 117,300.00 150,050.00 73,800.00 180,000.00 106,200.00 513,572,983.09 22,662.15 32,750.00 17.08 -0.36 -0.62
listings 1,738.02 1,618.50 1,026.50 2,056.00 743.00 3,296.00 2,553.00 566,568.97 752.71 1,029.50 43.31 0.65 -0.79
months_inventory 9.19 8.95 7.80 10.95 3.40 14.90 11.50 5.31 2.30 3.15 25.06 0.04 -0.17

The descriptive statistics reveal relevant differences in the behavior of the quantitative variables. In terms of relative variability, volume shows the highest coefficient of variation (53.71%), followed by listings (43.31%) and sales (41.42%), while median_price is comparatively more stable, with the lowest coefficient of variation (17.08%).

Regarding distribution shape, sales, volume, and listings show moderate positive skewness, indicating a tendency toward relatively high values in the right tail. Conversely, median_price presents mild negative skewness, while months_inventory is approximately symmetric. The relationship between mean and median is consistent with these skewness patterns.

In terms of kurtosis, sales, median_price, and listings show negative excess kurtosis, indicating somewhat lighter tails than a normal distribution. volume and months_inventory have excess kurtosis values close to zero, suggesting distributions that are approximately mesokurtic.

6. Variability and Asymmetry Analysis

6.1 Variable with the Highest Relative Variability

Since the quantitative variables are measured on different scales and in different units, the coefficient of variation (CV) is used to compare their relative variability. Unlike the standard deviation, the CV expresses dispersion relative to the mean and therefore allows a more meaningful comparison across variables.

descriptive_stats[, "CV"]
##            sales           volume     median_price         listings 
##         41.42203         53.70536         17.08218         43.30833 
## months_inventory 
##         25.06031

Based on the coefficient of variation, volume shows the highest relative variability, with a CV of 53.71%. This indicates that total sales volume is the quantitative variable that varies the most relative to its mean among those considered.

6.2 Variable with the Highest Asymmetry

To compare the degree of asymmetry across the quantitative variables, the absolute value of skewness is considered. This allows the magnitude of asymmetry to be assessed independently of its direction.

abs(descriptive_stats[, "Skewness"])
##            sales           volume     median_price         listings 
##       0.71810402       0.88474203       0.36455288       0.64949823 
## months_inventory 
##       0.04097527

Among the variables analyzed, volume shows the highest absolute skewness, with a value of approximately 0.88. Since the skewness is positive, the distribution is moderately right-skewed, indicating the presence of relatively high sales-volume observations in the upper tail.

7. Grouped Frequency Distribution and Gini Heterogeneity

In this section, a quantitative variable is grouped into classes in order to construct a frequency distribution and analyze how observations are distributed across the resulting intervals. The grouped distribution will then be represented graphically, and the normalized Gini heterogeneity index will be calculated to assess the degree of heterogeneity across the classes.

The variable sales is selected for this analysis. This variable represents the total number of property sales and is characterized by a sufficiently wide range of observed values, from 79 to 423, making it suitable for grouping into meaningful and interpretable classes.

7.1 Definition of the Number of Classes

Before constructing the grouped frequency distribution, it is necessary to determine an appropriate number of classes. Rather than selecting the number of intervals arbitrarily, Sturges’ rule is used as a statistical criterion based on the sample size.

n <- nrow(real_estate)    # Number of observations

k <- 1 + 3.322 * log10(n) # Sturges' rule for the number of classes
k
## [1] 8.907062
k_rounded <- round(k)     # Number of classes used in the analysis
k_rounded
## [1] 9

Sturges’ rule suggests approximately 8.91 classes. Therefore, the number of classes is rounded to 9.

7.2 Definition of Class Width

Once the number of classes has been established, the theoretical class width is obtained by dividing the range of sales by the number of classes.

sales_range <- max(real_estate$sales) - min(real_estate$sales)  # Range of sales

class_width <- sales_range / k_rounded                          # Theoretical class width
class_width
## [1] 38.22222

The theoretical class width is approximately 38.22 sales. To obtain more readable and interpretable intervals, the class width is rounded to 40 sales.

sales_breaks <- seq(
  from = 79,       # Minimum observed value
  to = 439,        # Upper boundary covering the maximum observed value
  by = 40          # Selected class width
)

sales_breaks
##  [1]  79 119 159 199 239 279 319 359 399 439

7.3 Construction of the Sales Classes

Based on the selected class width of 40 sales, nine equally spaced intervals are constructed. The class boundaries extend slightly beyond the maximum observed value in order to preserve equal class widths.

sales_labels <- c(
  "79-118",
  "119-158",
  "159-198",
  "199-238",
  "239-278",
  "279-318",
  "319-358",
  "359-398",
  "399-438"
)

real_estate$sales_class <- cut(
  real_estate$sales,
  breaks = sales_breaks,
  labels = sales_labels,
  right = FALSE,
  include.lowest = TRUE
)

7.4 Grouped Frequency Distribution

The grouped frequency distribution of sales is constructed using the nine previously defined classes. Both absolute and relative frequencies are reported in order to examine how the observations are distributed across the different sales intervals.

abs_freq_sales_class <- table(real_estate$sales_class)       # Absolute frequencies
rel_freq_sales_class <- prop.table(abs_freq_sales_class)     # Relative frequencies

sales_class_frequency <- data.frame(
  Sales_Class = names(abs_freq_sales_class),
  Frequency = as.vector(abs_freq_sales_class),
  Percentage = as.vector(rel_freq_sales_class) * 100
)

# Preserve the natural order of the sales classes
sales_class_frequency$Sales_Class <- factor(
  sales_class_frequency$Sales_Class,
  levels = sales_labels,
  ordered = TRUE
)

knitr::kable(
  sales_class_frequency,
  digits = 2,
  col.names = c(
    "Sales Class",
    "Absolute Frequency",
    "Relative Frequency (%)"
  ),
  caption = "Grouped Frequency Distribution of Sales"
)
Grouped Frequency Distribution of Sales
Sales Class Absolute Frequency Relative Frequency (%)
79-118 46 19.17
119-158 51 21.25
159-198 50 20.83
199-238 27 11.25
239-278 23 9.58
279-318 23 9.58
319-358 11 4.58
359-398 6 2.50
399-438 3 1.25

The grouped frequency distribution shows that most observations are concentrated in the lower and intermediate sales classes, while the frequency progressively decreases for higher sales values. This pattern suggests a positively skewed distribution, with a longer right tail. This result is consistent with the previously calculated skewness of approximately 0.72, indicating moderate right-skewness.

7.5 Bar Chart of the Grouped Sales Distribution

The grouped frequency distribution is represented through a bar chart to provide a visual overview of how the observations are distributed across the different sales classes.

ggplot(
  sales_class_frequency,
  aes(x = Sales_Class, y = Frequency)
) +
  geom_col() +
  labs(
    title = "Grouped Frequency Distribution of Sales",
    x = "Sales Class",
    y = "Absolute Frequency"
  ) +
  theme_minimal()

7.6 Gini Heterogeneity Index of Sales Classes

The normalized Gini heterogeneity index is calculated on the grouped sales variable to assess how evenly the observations are distributed across the nine sales classes.

gini_sales_class <- gini.index(real_estate$sales_class)

gini_sales_class
## [1] 0.9458984

The normalized Gini heterogeneity index for the grouped sales variable is approximately 0.946. This relatively high value indicates that the observations are distributed across several sales classes rather than being concentrated in only one or a few intervals.

Although the first three classes contain a large share of the observations, the remaining observations are still spread across the other classes. Therefore, the distribution shows a high degree of heterogeneity across the nine intervals.

This result should not be confused with the positive skewness previously observed for sales. The skewness describes the shape and direction of the distribution, while the Gini heterogeneity index measures how evenly observations are distributed across the defined classes. For this reason, a distribution can be moderately right-skewed and still present a high Gini heterogeneity index.

8. Empirical Probability Analysis

Empirical probabilities are estimated using the relative frequency of the events observed in the dataset. Considering each city-year-month observation as a statistical unit, the probability of an event is calculated as the proportion of observations satisfying the specified condition over the total number of observations.

prob_beaumont <- mean(real_estate$city == "Beaumont")
prob_july <- mean(real_estate$month == 7)

prob_december_2012 <- mean(
  real_estate$year == 2012 &
  real_estate$month == 12
)

prob_beaumont
## [1] 0.25
prob_july
## [1] 0.08333333
prob_december_2012
## [1] 0.01666667

8.1 Probability of Beaumont

The empirical probability that a randomly selected observation refers to Beaumont is 0.25, or 25%. This result is consistent with the balanced structure of the dataset, since Beaumont accounts for 60 of the 240 observations.

8.2 Probability of July

The empirical probability that a randomly selected observation refers to July is approximately 0.0833, or 8.33%. Each month contains 20 observations out of a total of 240.

8.3 Probability of December 2012

The empirical probability that a randomly selected observation refers specifically to December 2012 is approximately 0.0167, or 1.67%. There are four observations corresponding to this period, one for each city, out of the 240 observations in the dataset.

9. Creation of New Variables

Two additional indicators are derived from the available variables in order to provide further insight into the real estate market: an estimated average property price and a measure of listing effectiveness.

9.1 Average Property Price

The variable avg_property_price is calculated as the total sales volume, converted from millions of USD to USD, divided by the number of sales. This provides an estimate of the average transaction value per property sold for each city-year-month observation.

real_estate$avg_property_price <- 
  (real_estate$volume * 1000000) / real_estate$sales
summary(real_estate$avg_property_price)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   97010  132939  156588  154320  173915  213234

The estimated avg_property_price ranges from approximately $97,010 to $213,234, with a mean of about $154,320 and a median of approximately $156,588. These values represent the average transaction value per property sold and should not be confused with median_price, which describes the central position of sale prices rather than their arithmetic average.

9.2 Listing Effectiveness

The variable listing_effectiveness is created to compare the number of sales with the number of active listings. It is expressed as a percentage and provides an indication of sales performance relative to the active listing stock. This indicator should be interpreted as a descriptive proxy for sales activity relative to active listings, rather than as a direct measure of marketing effectiveness.

real_estate$listing_effectiveness <- 
  (real_estate$sales / real_estate$listings) * 100
summary(real_estate$listing_effectiveness)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   5.014   8.980  10.963  11.874  13.492  38.713

The listing_effectiveness indicator ranges from approximately 5.01% to 38.71%, with a mean of 11.87% and a median of 10.96%. The central 50% of the observations lies between approximately 8.98% and 13.49%.

These results indicate that the relationship between monthly sales and active listings varies substantially across city-year-month observations. Higher values of listing_effectiveness indicate stronger sales activity relative to the active listing stock, while lower values indicate weaker relative sales performance. However, the indicator should not be interpreted as the exact percentage of listed properties that were sold, since sales and listings represent different market flows and stocks.

10. Conditional Analysis

The analysis is extended by conditioning selected quantitative variables on city, year, and month. Group-specific means and standard deviations are calculated to identify geographical differences, temporal trends, and possible seasonal patterns in the Texas real estate market.

10.1 Conditional Analysis by City

sales_by_city <- real_estate %>%
  group_by(city) %>%
  summarise(
    Mean_Sales = mean(sales),
    SD_Sales = sd(sales)
  )

knitr::kable(
  sales_by_city,
  digits = 2,
  col.names = c(
    "City",
    "Mean Sales",
    "SD Sales"
  ),
  caption = "Mean and Standard Deviation of Sales by City"
)
Mean and Standard Deviation of Sales by City
City Mean Sales SD Sales
Beaumont 177.38 41.48
Bryan-College Station 205.97 84.98
Tyler 269.75 61.96
Wichita Falls 116.07 22.15

The conditional analysis by city reveals clear differences in sales activity across the four real estate markets. Tyler records the highest average number of sales, with approximately 269.75 sales per month, followed by Bryan-College Station (205.97) and Beaumont (177.38). Wichita Falls shows the lowest average, with approximately 116.07 sales per month.

In terms of absolute variability, Bryan-College Station presents the highest standard deviation (84.98), indicating greater fluctuations in monthly sales over the observed period. In contrast, Wichita Falls has the lowest standard deviation (22.15), suggesting comparatively more stable monthly sales.

10.2 Conditional Analysis by Year

The analysis is conditioned on year to examine how the central level and variability of property prices change over time. For each year, the mean and standard deviation of median_price are calculated.

median_price_by_year <- real_estate %>%
  group_by(year) %>%
  summarise(
    Mean_Median_Price = mean(median_price),
    SD_Median_Price = sd(median_price)
  )

knitr::kable(
  median_price_by_year,
  digits = 2,
  format.args = list(
    scientific = FALSE,
    big.mark = ","
  ),
  col.names = c(
    "Year",
    "Mean Median Price",
    "SD Median Price"
  ),
  caption = "Mean and Standard Deviation of Median Price by Year"
)
Mean and Standard Deviation of Median Price by Year
Year Mean Median Price SD Median Price
2,010 130,191.7 21,821.76
2,011 127,854.2 21,317.80
2,012 130,077.1 21,431.52
2,013 135,722.9 21,708.08
2,014 139,481.2 25,625.41

The conditional analysis by year shows a slight decline in the average median_price between 2010 and 2011, followed by a gradual increase over the subsequent years. The average median price rises from approximately $127,854 in 2011 to $139,481 in 2014, suggesting an upward price trend toward the end of the observed period.

The standard deviation remains relatively stable between 2010 and 2013, at around $21,000–$22,000, but increases to approximately $25,625 in 2014. This suggests greater dispersion in median prices across cities and months during the final year of the dataset.

10.3 Conditional Analysis by Month

The analysis is conditioned on month to investigate possible seasonal patterns in sales activity. For each month, the mean and standard deviation of sales are calculated across all cities and years.

sales_by_month <- real_estate %>%
  group_by(month_name) %>%
  summarise(
    Mean_Sales = mean(sales),
    SD_Sales = sd(sales)
  )

knitr::kable(
  sales_by_month,
  digits = 2,
  col.names = c(
    "Month",
    "Mean Sales",
    "SD Sales"
  ),
  caption = "Mean and Standard Deviation of Sales by Month"
)
Mean and Standard Deviation of Sales by Month
Month Mean Sales SD Sales
January 127.40 43.38
February 140.85 51.07
March 189.45 59.18
April 211.70 65.40
May 238.85 83.12
June 243.55 95.00
July 235.75 96.27
August 231.45 79.23
September 182.35 72.52
October 179.90 74.95
November 156.85 55.47
December 169.40 60.75

The conditional analysis by month suggests a clear seasonal pattern in sales activity. Average sales increase substantially from the winter months into spring, reaching their highest level in June with approximately 243.55 sales. Sales remain relatively high throughout the summer and then decline during the autumn months. January records the lowest average sales level, with approximately 127.40 sales. A slight increase is observed again in December compared with November.

This pattern supports the cyclical interpretation of month, as sales activity appears to follow a recurring annual structure characterized by stronger activity during spring and summer and weaker activity during autumn and winter.

The standard deviation also tends to be higher during the most active months. In particular, June and July show standard deviations of approximately 95–96 sales, compared with 43.38 in January. This suggests that sales activity is not only higher during the summer period, but also more variable across cities and years.

10.4 Deeper Analysis of Monthly Sales Variability

The previous monthly analysis showed that the months with the highest average sales also tend to present greater variability. To investigate this pattern further, monthly sales are analyzed jointly with city and year in order to assess whether the observed variability is associated with geographical differences, temporal differences, or both.

10.4.1 Monthly Sales by City

To investigate whether the higher variability observed during the most active months is associated with geographical differences, the analysis is further conditioned on both month and city.

For each month-city combination, the mean and standard deviation of sales are calculated across the five years included in the dataset. This makes it possible to assess whether the seasonal pattern is shared across all cities or whether specific local markets contribute more strongly to the variability observed at the monthly level.

sales_by_month_city <- real_estate %>%
  group_by(month_name, city) %>%
  summarise(
    Mean_Sales = mean(sales),
    SD_Sales = sd(sales),
    .groups = "drop"
  )

knitr::kable(
  sales_by_month_city,
  digits = 2,
  col.names = c(
    "Month",
    "City",
    "Mean Sales",
    "SD Sales"
  ),
  caption = "Mean and Standard Deviation of Sales by Month and City"
)
Mean and Standard Deviation of Sales by Month and City
Month City Mean Sales SD Sales
January Beaumont 121.6 31.25
January Bryan-College Station 118.2 27.89
January Tyler 181.4 37.19
January Wichita Falls 88.4 10.43
February Beaumont 135.4 31.95
February Bryan-College Station 125.6 27.46
February Tyler 211.6 28.89
February Wichita Falls 90.8 7.89
March Beaumont 171.0 14.87
March Bryan-College Station 189.8 49.74
March Tyler 268.4 23.22
March Wichita Falls 128.6 23.56
April Beaumont 189.6 17.74
April Bryan-College Station 236.4 49.52
April Tyler 286.8 33.36
April Wichita Falls 134.0 21.68
May Beaumont 206.8 42.61
May Bryan-College Station 301.6 46.59
May Tyler 311.2 47.64
May Wichita Falls 135.8 23.13
June Beaumont 205.0 36.03
June Bryan-College Station 319.4 44.15
June Tyler 327.0 59.85
June Wichita Falls 122.8 7.63
July Beaumont 185.4 22.93
July Bryan-College Station 306.0 95.33
July Tyler 319.0 52.42
July Wichita Falls 132.6 19.07
August Beaumont 217.4 50.64
August Bryan-College Station 262.8 62.28
August Tyler 310.8 47.52
August Wichita Falls 134.8 9.60
September Beaumont 174.0 46.89
September Bryan-College Station 158.4 35.37
September Tyler 281.4 51.68
September Wichita Falls 115.6 14.88
October Beaumont 189.2 43.97
October Bryan-College Station 151.8 46.82
October Tyler 271.8 64.46
October Wichita Falls 106.8 8.53
November Beaumont 158.6 22.80
November Bryan-College Station 143.8 29.93
November Tyler 225.2 54.37
November Wichita Falls 99.8 10.85
December Beaumont 174.6 30.11
December Bryan-College Station 157.8 34.19
December Tyler 242.4 52.91
December Wichita Falls 102.8 15.66
Graphical Representation
ggplot(
  sales_by_month_city,
  aes(
    x = month_name,
    y = Mean_Sales,
    group = city,
    color = city
  )
) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  labs(
    title = "Average Monthly Sales by City",
    subtitle = "Mean sales across the 2010–2014 period",
    x = "Month",
    y = "Mean Sales",
    color = "City"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )

The joint analysis of month and city shows that the higher variability observed during the most active months is partly associated with substantial differences across local markets. Tyler consistently records the highest or among the highest average sales levels, while Wichita Falls generally shows the lowest values. These geographical differences become particularly pronounced during spring and summer.

For example, in June, average sales range from approximately 122.8 in Wichita Falls to 327.0 in Tyler, indicating considerable dispersion across cities. Bryan-College Station also reaches a high average of 319.4 sales during the same month.

The within-city standard deviations further suggest that temporal variability differs across local markets. In particular, Bryan-College Station records a standard deviation of approximately 95.33 sales in July, whereas Wichita Falls shows a much lower value of approximately 19.07. Therefore, the higher monthly variability observed during the most active periods appears to reflect both differences between cities and, for some markets, substantial fluctuations across years.

10.4.2 Monthly Sales by Year

To investigate whether the seasonal pattern and the higher variability observed during the most active months also differ across years, the analysis is further conditioned on both month and year.

For each month-year combination, the mean and standard deviation of sales are calculated across the four cities. This allows the seasonal sales pattern to be compared across the five years and helps identify whether specific years contribute more strongly to the observed monthly variability.

sales_by_month_year <- real_estate %>%
  group_by(month_name, year) %>%
  summarise(
    Mean_Sales = mean(sales),
    SD_Sales = sd(sales),
    .groups = "drop"
  )

knitr::kable(
  sales_by_month_year,
  digits = 2,
  col.names = c(
    "Month",
    "Year",
    "Mean Sales",
    "SD Sales"
  ),
  caption = "Mean and Standard Deviation of Sales by Month and Year"
)
Mean and Standard Deviation of Sales by Month and Year
Month Year Mean Sales SD Sales
January 2010 105.25 36.61
January 2011 106.25 27.04
January 2012 124.75 29.78
January 2013 144.00 49.22
January 2014 156.75 61.35
February 2010 121.75 40.26
February 2011 117.25 44.26
February 2012 143.50 57.61
February 2013 148.25 54.90
February 2014 173.50 62.22
March 2010 188.75 43.60
March 2011 167.00 52.43
March 2012 177.75 66.69
March 2013 203.50 64.04
March 2014 210.25 85.36
April 2010 229.00 63.95
April 2011 179.00 58.65
April 2012 186.75 52.78
April 2013 219.50 74.54
April 2014 244.25 84.10
May 2010 232.75 58.84
May 2011 195.00 70.28
May 2012 220.50 90.72
May 2013 264.25 90.36
May 2014 281.75 112.16
June 2010 216.50 71.44
June 2011 221.25 93.93
June 2012 224.50 86.18
June 2013 261.25 108.22
June 2014 294.25 134.62
July 2010 178.00 62.51
July 2011 203.00 69.96
July 2012 232.00 89.81
July 2013 281.75 122.70
July 2014 284.00 122.30
August 2010 184.50 45.00
August 2011 196.50 70.28
August 2012 238.50 87.99
August 2013 276.75 92.02
August 2014 261.00 89.71
September 2010 149.50 47.20
September 2011 157.25 67.61
September 2012 176.75 78.21
September 2013 203.50 66.00
September 2014 224.75 103.54
October 2010 141.25 45.70
October 2011 148.50 57.58
October 2012 185.50 79.81
October 2013 184.50 65.98
October 2014 239.75 106.32
November 2010 125.75 31.00
November 2011 137.25 49.38
November 2012 162.50 37.24
November 2013 172.50 65.08
November 2014 186.25 84.50
December 2010 151.00 40.70
December 2011 141.25 48.25
December 2012 160.75 52.20
December 2013 183.25 64.05
December 2014 210.75 91.74
Graphical Representation
ggplot(
  sales_by_month_year,
  aes(
    x = month_name,
    y = Mean_Sales,
    group = factor(year),
    color = factor(year)
  )
) +
  geom_line(linewidth = 1) +
  geom_point(size = 2) +
  labs(
    title = "Average Monthly Sales by Year",
    subtitle = "Mean sales across the four cities",
    x = "Month",
    y = "Mean Sales",
    color = "Year"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )

The analysis by month and year suggests two main patterns. First, average sales generally increase over the observed period, with more recent years tending to show higher sales levels than earlier years.

Second, a similar seasonal pattern appears across the different years. Sales tend to increase during spring, reach higher levels around the summer months, and then decline toward the end and beginning of the year. This recurring structure suggests that the seasonal behavior of the real estate market is relatively consistent across the 2010–2014 period.

The higher standard deviations observed in some recent summer months also indicate that differences across cities become particularly pronounced during periods of stronger market activity.

11. Data Visualization with ggplot2

11.1 Median Price Distribution by City

ggplot(
  real_estate,
  aes(x = city, y = median_price)
) +
  geom_boxplot() +
  labs(
    title = "Distribution of Median Property Prices by City",
    x = "City",
    y = "Median Price (USD)"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 20, hjust = 1)
  )

The boxplot highlights clear differences in the distribution of median_price across the four cities. Bryan-College Station shows the highest median property prices, followed by Tyler, while Wichita Falls records the lowest central price level.

In terms of dispersion, Wichita Falls appears to have a relatively wider interquartile range, indicating greater variability in the central 50% of median prices. Bryan-College Station and Beaumont show more compact distributions, while Tyler presents an intermediate level of dispersion.

A few upper outliers are also visible for Beaumont, Bryan-College Station, and Wichita Falls, indicating some city-month-year observations with unusually high median prices compared with the typical distribution of each local market. Overall, the graph suggests that both the central price level and the degree of variability differ meaningfully across cities.

11.2 Sales Volume Distribution by City and Year

The distribution of total sales volume is compared across cities and years using boxplots. Since both geographical and temporal differences are of interest, separate panels are used for each year in order to preserve the readability of the comparison.

ggplot(
  real_estate,
  aes(x = city, y = volume, fill = city)
) +
  geom_boxplot() +
  facet_wrap(~ year) +
  labs(
    title = "Distribution of Sales Volume by City and Year",
    subtitle = "Total sales volume expressed in USD millions",
    x = NULL,
    y = "Sales Volume (USD millions)"
  ) +
  guides(fill = guide_legend(title = NULL)) +
  theme_minimal() +
  theme(
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    legend.position = "bottom"
  )

The boxplots show clear differences in the distribution of volume across both cities and years. Tyler generally records the highest sales volumes, while Wichita Falls consistently shows the lowest levels. Bryan-College Station appears to display substantial variability in several years, particularly from 2012 onward, as indicated by the wide boxes and long whiskers.

From a temporal perspective, the distributions suggest a general increase in sales volume over the observed period, especially for Tyler and Bryan-College Station. Overall, the graph highlights the presence of both geographical differences and temporal variation in total sales volume across the Texas real estate markets considered.

11.3 Monthly Total Sales by City

Total sales are aggregated by month and city in order to compare the contribution of each local market to monthly sales activity. A stacked bar chart is first used to represent absolute sales totals, followed by a normalized version to compare the relative composition across months.

monthly_sales_city <- real_estate %>%
  group_by(month_name, city) %>%
  summarise(
    Total_Sales = sum(sales),
    .groups = "drop"
  )

11.3.1 Stacked Bar Chart

ggplot(
  monthly_sales_city,
  aes(
    x = month_name,
    y = Total_Sales,
    fill = city
  )
) +
  geom_col() +
  labs(
    title = "Total Monthly Sales by City",
    subtitle = "Aggregated sales across the 2010–2014 period",
    x = "Month",
    y = "Total Sales"
  ) +
  guides(fill = guide_legend(title = NULL)) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )

The stacked bar chart confirms a clear seasonal pattern in total sales. June records the highest overall number of sales, followed by May, July, and August, while January shows the lowest total sales activity. Overall, sales increase considerably during spring, remain high throughout the summer, and decline during autumn and winter.

Tyler provides the largest contribution to total sales across all months. However, the contribution of Bryan-College Station becomes particularly substantial during the peak sales period, especially between May and July. This suggests that the increase in overall market activity during spring and summer is not driven by a single city, although the relative contribution of individual local markets differs across the year.

11.3.2 Normalized Stacked Bar Chart

A normalized stacked bar chart is used to compare the relative contribution of each city to total monthly sales. Since each monthly bar is scaled to 100%, the graph emphasizes differences in composition rather than differences in absolute sales volume.

ggplot(
  monthly_sales_city,
  aes(
    x = month_name,
    y = Total_Sales,
    fill = city
  )
) +
  geom_col(position = "fill") + # Position = "fill" to normalize the graph
  labs(
    title = "Relative Composition of Monthly Sales by City",
    subtitle = "Each bar represents 100% of monthly sales",
    x = "Month",
    y = "Share of Total Sales"
  ) +
  guides(fill = guide_legend(title = NULL)) +
  scale_y_continuous(labels = scales::percent) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )

The normalized stacked bar chart confirms the pattern observed in the previous absolute-frequency graph. Although Tyler remains one of the largest contributors to monthly sales throughout the year, the relative contribution of Bryan-College Station increases noticeably during the spring and summer months, particularly between May and July.

This indicates that the stronger contribution of Bryan-College Station during the peak season is not simply the result of an overall increase in market activity. Its share of total monthly sales also becomes larger during these months. In contrast, the relative contribution of the other cities remains more stable or decreases slightly during the same period.

Therefore, the normalized graph complements the absolute stacked bar chart by showing that both the total level of sales and the relative composition of the market change across the annual cycle.

11.3.3 Difference Between geom_bar() and geom_col()

geom_bar() and geom_col() are both used to create bar charts, but they differ in how bar heights are determined. By default, geom_bar() counts the number of observations associated with each category, while geom_col() uses values that have already been calculated and supplied through the y aesthetic.

In this analysis, geom_col() is appropriate because total sales have already been computed for each month-city combination using sum(sales).

11.3.4 Monthly Sales by City and Year

To extend the monthly sales analysis, the variable year is incorporated into the visualization. The aim is to verify whether the seasonal pattern and the relative contribution of each city remain consistent across the different years of the dataset.

Monthly sales are therefore analyzed jointly by month, city, and year. Separate panels are used for each year in order to preserve readability and avoid overcrowding the graph.

monthly_sales_city_year <- real_estate %>%
  group_by(year, month_name, city) %>%
  summarise(
    Total_Sales = sum(sales),
    .groups = "drop"
  )
ggplot(
  monthly_sales_city_year,
  aes(
    x = month_name,
    y = Total_Sales,
    fill = city
  )
) +
  geom_col() +
  facet_wrap(
    ~ year,
    scales = "free_x" # To insert months labels under each panel
  ) +
  scale_x_discrete(labels = month.abb) + # month.abb to abbreviate months names
  labs(
    title = "Monthly Sales by City and Year",
    subtitle = "Comparison of monthly sales composition across the 2010–2014 period",
    x = "Month",
    y = "Total Sales"
  ) +
  guides(fill = guide_legend(title = NULL)) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )

The year-specific stacked bar charts show that the seasonal pattern observed in the aggregated analysis is generally repeated across the 2010–2014 period. In each year, sales tend to increase from the beginning of the year toward spring and summer, before declining again during the autumn and winter months.

At the same time, the overall height of the monthly bars tends to be greater in the more recent years, particularly in 2013 and 2014. This suggests a general increase in sales activity over time alongside a relatively persistent seasonal structure.

The contribution of the individual cities also changes across months and years. Tyler remains an important contributor throughout the period, while Bryan-College Station becomes especially relevant during several spring and summer months. Overall, incorporating year confirms that both temporal growth and seasonal variation contribute to the observed sales dynamics.

11.4 Historical Trend of Listing Effectiveness

A line chart comparing monthly sales across historical years was previously presented in Section 10.4.2. The following analysis extends the historical visualization to the derived listing_effectiveness indicator in order to explore a different dimension of market behavior.

The historical evolution of listing_effectiveness is analyzed to examine how sales activity relative to active listings changes across the 2010–2014 period and whether different cities follow similar or distinct patterns.

To represent the monthly observations in their correct chronological order, year and month are combined into a single time variable. Higher values of listing_effectiveness indicate stronger sales activity relative to the active listing stock, while lower values indicate weaker relative sales performance.

real_estate$date <- as.Date(
  paste(
    real_estate$year,
    real_estate$month,
    "01",
    sep = "-"
  )
)
ggplot(
  real_estate,
  aes(
    x = date,
    y = listing_effectiveness,
    color = city,
    group = city
  )
) +
  geom_line(linewidth = 0.9) +
  scale_x_date(
    date_breaks = "1 year",
    date_labels = "%Y"
  ) +
  labs(
    title = "Historical Trend of Listing Effectiveness by City",
    subtitle = "Monthly sales relative to active listings, 2010–2014",
    x = "Year",
    y = "Listing Effectiveness (%)"
  ) +
  guides(color = guide_legend(title = NULL)) +
  theme_minimal() +
  theme(
    legend.position = "bottom"
  )

The historical analysis of listing_effectiveness reveals substantial differences across cities. Bryan-College Station shows the most distinctive pattern, with increasingly pronounced peaks over the 2010–2014 period. These peaks tend to occur around the middle of the year and become particularly strong in 2013 and 2014, indicating substantially stronger sales activity relative to the active listing stock during these periods.

A recurring seasonal pattern is particularly evident for Bryan-College Station, where listing_effectiveness generally increases during the central months of the year before declining again. Tyler shows a similar but considerably more moderate pattern, with smaller fluctuations over time.

In contrast, Beaumont and Wichita Falls display more irregular short-term fluctuations, making their seasonal patterns less pronounced. Overall, the graph suggests that both geographical and temporal differences affect the relationship between sales and active listings, with Bryan-College Station showing the most substantial increase in relative sales performance over the observed period.

However, higher listing_effectiveness should not be interpreted as direct evidence that individual listings are more effective. Since the indicator is defined as the ratio between sales and listings, an increase may result from higher sales, lower active listings, or more generally from sales increasing relative to the active listing stock.

11.4.1 Follow-up Analysis: Bryan-College Station

The previous line chart showed a particularly strong increase in listing_effectiveness for Bryan-College Station, especially during the central months of the year and in the later part of the 2010–2014 period.

To better understand this pattern, sales and listings are examined separately for Bryan-College Station. Since listing_effectiveness is defined as the ratio between sales and listings, this follow-up analysis aims to assess whether the observed increase is mainly associated with higher sales activity, lower active listing stock, or a combination of both.

bryan_data <- real_estate %>%
  filter(city == "Bryan-College Station")
ggplot(
  bryan_data,
  aes(x = date, y = sales)
) +
  geom_line(linewidth = 0.9) +
  scale_x_date(
    date_breaks = "1 year",
    date_labels = "%Y"
  ) +
  labs(
    title = "Historical Sales in Bryan-College Station",
    x = "Year",
    y = "Sales"
  ) +
  theme_minimal()

ggplot(
  bryan_data,
  aes(x = date, y = listings)
) +
  geom_line(linewidth = 0.9) +
  scale_x_date(
    date_breaks = "1 year",
    date_labels = "%Y"
  ) +
  labs(
    title = "Historical Active Listings in Bryan-College Station",
    x = "Year",
    y = "Active Listings"
  ) +
  theme_minimal()

The follow-up analysis provides additional insight into the strong increase in listing_effectiveness observed for Bryan-College Station. During the earlier part of the period, sales and listings show some similarities in their seasonal movements, with both variables tending to increase during more active parts of the year.

From approximately 2013 onward, however, a clearer divergence emerges. Sales reach increasingly high seasonal peaks, while the overall level of active listings declines substantially. Although short-term seasonal fluctuations remain present in both series, their longer-term trajectories become increasingly different.

This combination helps explain the pronounced increase in listing_effectiveness. Since the indicator is calculated as the ratio between sales and listings, higher sales together with a declining active listing stock lead to substantially higher values. Therefore, the increase observed for Bryan-College Station appears to reflect both stronger sales activity and a reduction in the active listing stock.

12. Conclusions and Statistical Recommendations

12.1 Main Findings

The analysis reveals substantial geographical, temporal, and seasonal differences across the Texas real estate markets included in the dataset.

From a geographical perspective, the four cities show clearly different market profiles. Tyler records the highest average number of monthly sales, while Wichita Falls consistently shows the lowest sales activity. The analysis of property prices also reveals differences across local markets, with Bryan-College Station generally presenting higher median property prices and Wichita Falls lower price levels.

A clear seasonal pattern emerges in sales activity. Average sales increase from the beginning of the year through spring, reach their highest levels during late spring and summer, and subsequently decline during autumn and winter. June records the highest average monthly sales, while January shows the lowest. This seasonal structure is observed across multiple years, suggesting a relatively persistent annual pattern rather than an effect driven by a single period.

The temporal analysis also suggests an overall strengthening of market activity during the later years of the dataset. Average sales tend to be higher in 2013 and 2014 than in the earlier years. Similarly, the average median_price increases toward the end of the observed period, reaching its highest annual level in 2014. At the same time, the greater dispersion observed in some recent periods indicates that market developments are not uniform across cities.

Among the quantitative variables, volume presents the highest relative variability, with a coefficient of variation of approximately 53.71%, and also the greatest degree of asymmetry, with positive skewness of approximately 0.88. This indicates that total sales value varies considerably across observations and that some relatively high-volume periods contribute to the right tail of its distribution.

The analysis of the derived listing_effectiveness indicator provides additional insight into the relationship between sales activity and active listings. Bryan-College Station shows a particularly strong increase in this indicator over time, with pronounced peaks during the central months of the year, especially in 2013 and 2014. The follow-up analysis suggests that this pattern is associated with increasingly strong sales activity together with a declining level of active listings. Therefore, the increase in listing_effectiveness appears to reflect a growing level of sales relative to the active listing stock rather than direct evidence of greater effectiveness of individual property listings.

12.2 Statistical Recommendations

The results suggest that market analysis and decision-making should account for both geographical and seasonal differences rather than relying exclusively on aggregated averages across the four cities. Since cities show substantially different levels of sales, prices, variability, and inventory dynamics, city-specific indicators should be monitored separately.

The recurring seasonal pattern in sales should also be incorporated into market planning and forecasting. Comparisons between periods should account for the month of the year, since higher activity during spring and summer and lower activity during winter could otherwise be incorrectly interpreted as structural changes in market performance.

Particular attention should be given to Bryan-College Station, where the combination of stronger sales activity and declining active listings produces increasingly high values of listing_effectiveness. Monitoring both components of this indicator separately is recommended, since changes in the ratio may result from different movements in sales and listing stock.

The relatively high variability of volume also suggests that total sales value should be interpreted carefully. Period averages alone may not adequately represent the market when unusually high-volume observations are present; measures of dispersion and distribution shape should therefore be considered alongside central tendency.

Finally, the present analysis is descriptive and does not establish causal relationships. Further analysis could incorporate additional economic and market variables, such as population growth, employment conditions, mortgage rates, or other local indicators, and apply inferential or predictive methods to investigate the drivers of the patterns identified in this report.