Descrizione del progetto

L’azienda Texas Realty Insights desidera analizzare le tendenze del mercato immobiliare nello stato del Texas, sfruttando i dati storici relativi alle vendite di immobili.
L’obiettivo è fornire insight statistici e visivi che supportino le decisioni strategiche di vendita e ottimizzazione delle inserzioni immobiliari.
Obiettivi del progetto: • Identificare e interpretare i trend storici delle vendite immobiliari in Texas.
• Valutare l’efficacia delle strategie di marketing delle inserzioni immobiliari.
• Offrire una rappresentazione grafica dei dati che evidenzi la distribuzione dei prezzi e delle vendite tra città, mesi e anni.

Valore Aggiunto

L’analisi statistica proposta permetterà a Texas Realty Insights di ottimizzare le loro strategie di mercato, identificando città con opportunità di crescita e valutando l’efficacia delle inserzioni immobiliari nel tempo.
Grazie a una visione chiara e strutturata dei dati, l’azienda potrà prendere decisioni basate su informazioni concrete, migliorando la gestione delle vendite immobiliari in Texas.
Dataset: “Real Estate Texas.csv”
Il dataset contiene le seguenti variabili:
- city: città di riferimento
- year: anno di riferimento
- month: mese di riferimento
- sales: numero totale di vendite
- volume: valore totale delle vendite (in milioni di dollari)
- median_price: prezzo mediano di vendita (in dollari)
- listings: numero totale di annunci attivi
- months_inventory: quantità di tempo necessaria per vendere tutte le inserzioni correnti, espresso in mesi

Steps del progetto

  1. Analisi delle variabili
    Identifica e descrivi il tipo di variabili statistiche presenti nel dataset. Valuta come gestire le variabili che sottintendono una dimensione tempo e commenta sul tipo di analisi che può essere condotta su ciascuna variabile.
  2. Indici di posizione, variabilità e forma
    Calcola Indici di posizione, variabilità e forma per tutte le variabili per le quali ha senso farlo, per le altre crea una distribuzione di frequenza. Infine, commenta tutto brevemente.
  3. Identificazione delle variabili con maggiore variabilità e asimmetria
    Determina: - Qual è la variabile con la più alta variabilità - Qual è la variabile con la distribuzione più asimmetrica Spiega come sei giunto a queste conclusioni e fornisci considerazioni statistiche.
  4. Creazione di classi per una variabile quantitativa
    Seleziona una variabile quantitativa (es. sales o median_price) e suddividila in classi. Crea una distribuzione di frequenze e rappresenta i dati con un grafico a barre. Calcola l’indice di eterogeneità Gini e discuti i risultati.
  5. Calcolo della probabilità
    Qual è la probabilità che, presa una riga a caso di questo dataset, essa riporti la città “Beaumont”? E la probabilità che riporti il mese di Luglio? E la probabilità che riporti il mese di dicembre 2012?
  6. Creazione di nuove variabili
    • Crea una nuova colonna che calcoli il prezzo medio degli immobili utilizzando le variabili disponibili. • Prova a creare una colonna che misuri l’efficacia degli annunci di vendita. Commenta e discuti i risultati.
  7. Analisi condizionata
    Usa il pacchetto dplyr o il linguaggio base di R per effettuare analisi statistiche condizionate per città, anno e mese. Genera dei summary (media, deviazione standard) e rappresenta graficamente i risultati.
  8. Creazione di visualizzazioni con ggplot2
    Utilizza ggplot2 per creare grafici personalizzati. Assicurati di esplorare: - Boxplot per confrontare la distribuzione del prezzo mediano tra le città. - Grafici a barre per confrontare il totale delle vendite per mese e città. - Line charts per confrontare l’andamento delle vendite in periodi storici differenti.
  9. Conclusioni
    Fornisci una sintesi dei risultati ottenuti, facendo riferimento alle principali tendenze emerse e fornendo raccomandazioni basate sull’analisi. Questo non è un progetto di programmazione, ma di statistica, e ci si aspetta di leggere commenti e considerazioni statistiche per i vari passaggi e risultati.

Import data from CSV

dataset <- read.csv("/home/denis/Desktop/realestate_texas.csv",sep=",")

str(dataset)
## '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 ...
dim(dataset)
## [1] 240   8
head(dataset)
##       city year month sales volume median_price listings months_inventory
## 1 Beaumont 2010     1    83 14.162       163800     1533              9.5
## 2 Beaumont 2010     2   108 17.690       138200     1586             10.0
## 3 Beaumont 2010     3   182 28.701       122400     1689             10.6
## 4 Beaumont 2010     4   200 26.819       123200     1708             10.6
## 5 Beaumont 2010     5   202 28.833       123100     1771             10.9
## 6 Beaumont 2010     6   189 27.219       122800     1803             11.1
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)
library(moments)

attach(dataset)

1. Variables Analysis

Types of Variables and possible Analysis:

city: nominal qualitative variable —-> groups comparison (location differences…)
year: discrete quantitative variable representing the temporal dimension —-> temporal analysis (historical trends, market cycles…)
month: cyclic temporal ordinal variable —-> temporal analysis (seasonality and recurring patterns during the year)
sales: discrete quantitative variable —-> descriptive statistics in relation to temporal and spatial comparison
volume: continuous quantitative variable —-> descriptive statistics in relation to temporal and spatial comparison
median_price: continuous quantitative variable —-> descriptive statistics in relation to temporal and spatial comparison
listings: discrete quantitative variable —-> descriptive statistics in relation to temporal and spatial comparison
months_inventory: continuous quantitative variable —-> selling velocity indicator (information on market availability and request)


2. Indices of Position, Variability and Shape

Indices of position

summary(dataset[c("sales","volume","median_price","listings","months_inventory")])
##      sales           volume        median_price       listings   
##  Min.   : 79.0   Min.   : 8.166   Min.   : 73800   Min.   : 743  
##  1st Qu.:127.0   1st Qu.:17.660   1st Qu.:117300   1st Qu.:1026  
##  Median :175.5   Median :27.062   Median :134500   Median :1618  
##  Mean   :192.3   Mean   :31.005   Mean   :132665   Mean   :1738  
##  3rd Qu.:247.0   3rd Qu.:40.893   3rd Qu.:150050   3rd Qu.:2056  
##  Max.   :423.0   Max.   :83.547   Max.   :180000   Max.   :3296  
##  months_inventory
##  Min.   : 3.400  
##  1st Qu.: 7.800  
##  Median : 8.950  
##  Mean   : 9.193  
##  3rd Qu.:10.950  
##  Max.   :14.900
mean_vector <- sapply(dataset[c("sales","volume","median_price","listings","months_inventory")],mean)
mean_vector
##            sales           volume     median_price         listings 
##        192.29167         31.00519     132665.41667       1738.02083 
## months_inventory 
##          9.19250

Indices of Variability

std_dev_vector <- sapply(dataset[c("sales","volume","median_price","listings","months_inventory")],sd)
std_dev_vector
##            sales           volume     median_price         listings 
##        79.651111        16.651447     22662.148687       752.707756 
## months_inventory 
##         2.303669
cv_vector <- std_dev_vector/mean_vector*100
cv_vector
##            sales           volume     median_price         listings 
##         41.42203         53.70536         17.08218         43.30833 
## months_inventory 
##         25.06031

Indices of Shape

skewness_vector <- sapply(dataset[c("sales","volume","median_price","listings","months_inventory")],skewness)
skewness_vector
##            sales           volume     median_price         listings 
##       0.71810402       0.88474203      -0.36455288       0.64949823 
## months_inventory 
##       0.04097527
kurtosis_vector <- sapply(dataset[c("sales","volume","median_price","listings","months_inventory")],kurtosis)-3
kurtosis_vector
##            sales           volume     median_price         listings 
##       -0.3131764        0.1769870       -0.6229618       -0.7917900 
## months_inventory 
##       -0.1744475

Sales: great variability, slightly positive skewness (righteous asymmetry) and negative kurtosis
Volume: greatest variability, positive skewness (righteous asymmetry) and positive kurtosis
Median_price: little variability, slightly negative skewness (almost symmetric) and negative kurtosis
Listings: great variability, slightly positive skewness (righteous asymmetry) and negative kurtosis
Months_inventory: great variability, slightly positive skewness (practically symmetric) and negative kurtosis


3. Greater Variability and Asymmetry Variables Identification

In order to determine the variable with greater variability, it is necessary to compare the coefficients of variation.
The variable with the greatest variability is “volume”.
In order to determine the variable with the greatest skewness, it is necessary to compare the skewness indexes.
The variable with the greatest skewness is “volume”.
It is possible to observe that “volume” shows a distribution with great variability and, therefore, a large dispersion around the mean value.
The positive skewness indicates that most observations are concentrated at relatively low values, while a smaller number of observations with very high values produce a long right tail.


4. Class Creation for a Quantitative Variable

Variable “Sales” in Classes

sales_cl <- cut(sales,breaks=seq(70,430,10),right=TRUE,include.lowest=TRUE)
n <- dim(dataset)[1]
dist_freq_sales <- as.data.frame(cbind(ni=table(sales_cl),
                                       fi=table(sales_cl)/n,
                                       Ni=cumsum(table(sales_cl)),
                                       Fi=cumsum(table(sales_cl))/n))
dist_freq_sales$classes <- rownames(dist_freq_sales)
dist_freq_sales$classes <- factor(dist_freq_sales$classes, levels=unique(dist_freq_sales$classes))

Mode of the variable “Sales” in Classes

moda_sales_cl <- names(table(sales_cl)) [table(sales_cl)==max(table(sales_cl))]

Barplot of “Sales_cl”

ggplot(data=dist_freq_sales)+
  geom_col(aes(x=classes,y=ni),
           col="black",
           fill="red")+
  labs(title="Frequency Distribution of Sales divided in Classes",
       x="sales [classes]",
       y="frequency")+
  scale_y_continuous(breaks=seq(0,20,5))+
  theme_dark(base_size = 15)+
  theme(axis.text.x=element_text(size=10,angle=80, hjust=1))

Gini Heterogeneity Index

Gini Index is usually applied to nominal qualitative variables. It is possible to apply it to a quantitative variable divided in classes, but it’s not the best option.

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)
}
gini_index(sales_cl) 
## [1] 0.9846786

The normalized Gini index is very close to one, having a value of 0.98. It indicates a highly heterogeneous distribution.
No single class dominates the frequency distribution.


5. Probability Calculation

Probability Theory

x <- table(city)
pBeaumont <- x["Beaumont"]/n
y <- table(month)
pLuglio <- y["7"]/n
z <- table(month,year)
pDicembre12 <- z["12","2012"]/n
pBeaumont
## Beaumont 
##     0.25
pLuglio
##          7 
## 0.08333333
pDicembre12
## [1] 0.01666667

Randomly selecting one observation from the data-set, the probability to extract the city Beaumont is 0.25.
The probability to extract July is about 0.083 and the probability to extract December 2012 is approximately 0.017.


6. Creation of new Variables

dataset["average_price"] <- volume*(10^6)/sales

df_avg_price_cy <- dataset %>%
  group_by(city,year) %>%
  summarise(average_avg_price_cy = mean(average_price),
            std_dev_avg_price_cy = sd(average_price))
## `summarise()` has regrouped the output.
## ℹ Summaries were computed grouped by city and year.
## ℹ Output is grouped by city.
## ℹ Use `summarise(.groups = "drop_last")` to silence this message.
## ℹ Use `summarise(.by = c(city, year))` for per-operation grouping
##   (`?dplyr::dplyr_by`) instead.
dataset["listing_efficiency"] <- sales/listings

df_efficiency_cy <- dataset %>%
  group_by(city,year) %>%
  summarise(average_efficiency_cy = mean(listing_efficiency),
            std_dev_efficiency_cy = sd(listing_efficiency))
## `summarise()` has regrouped the output.
## ℹ Summaries were computed grouped by city and year.
## ℹ Output is grouped by city.
## ℹ Use `summarise(.groups = "drop_last")` to silence this message.
## ℹ Use `summarise(.by = c(city, year))` for per-operation grouping
##   (`?dplyr::dplyr_by`) instead.
ggplot(data=df_efficiency_cy,aes(x=year,y=average_efficiency_cy,color=city))+
  geom_line()+
  geom_point(size=3)+
  labs(title="Average Efficiency by Year and City",
       x="Year",
       y="Average Efficiency")+
  scale_y_continuous(breaks=seq(0.003,0.01,0.0005))+
  theme_minimal()+
  theme(plot.title = element_text(hjust=.5))

ggplot(dataset, aes(x=months_inventory,y=listing_efficiency,color=city))+
  geom_point(size=3)+
  labs(title="Relation between Months Inventory and Listing Efficiency",
       x="Months Inventory",
       y="Listing Efficiency")+
  theme_minimal()+
  theme(plot.title = element_text(hjust=.5))

Unlike median_price, which represents the median transaction value, average_price is the arithmetic mean of the selling prices and may be more influenced by unusually expensive properties.
The efficiency indicator measures the proportion of active listings that resulted in actual sales..
Higher values indicate that a larger fraction of listed properties were successfully sold, suggesting stronger market demand, more effective marketing strategies or more convenient and attractive pricing.
Comparing cities over time reveals differences in market performance.
Cities with consistently high efficiency values are characterized by a faster turnover of listed properties, whereas lower efficiency values suggest that properties remain on the market longer or that demand is weaker.
Temporal changes in efficiency may also reflect broader economic conditions.
An increasing trend indicates improving market dynamics, while a decreasing trend may lead to slower sales or an excess of offer.
A higher efficiency is generally expected to correspond to a lower value of months_inventory, since a larger proportion of active listings is converted into sales in a shorter period of time.
As shown in the scatter plot, it is possible to suppose a negative association between listing_efficiency and months_inventory.


7-8. Conditioned Analysis and Graphs using GGPLOT

df_volume_c <- dataset %>%
  group_by(city) %>%
  summarise(average_volume_c = mean(volume),
            std_dev_volume_c = sd(volume),
            min_volume_C = min(volume),
            max_volume_c = max(volume))
df_volume_c
## # A tibble: 4 × 5
##   city               average_volume_c std_dev_volume_c min_volume_C max_volume_c
##   <chr>                         <dbl>            <dbl>        <dbl>        <dbl>
## 1 Beaumont                       26.1             6.97        13.5          42.0
## 2 Bryan-College Sta…             38.2            17.2         15.2          83.5
## 3 Tyler                          45.8            13.1         21.0          80.8
## 4 Wichita Falls                  13.9             3.24         8.17         20.9
df_sales_c <- dataset %>%
  group_by(city) %>%
  summarise(average_sales_c = mean(sales),
            std_dev_sales_c = sd(sales),
            min_sales_C = min(sales),
            max_sales_c = max(sales))
df_sales_c
## # A tibble: 4 × 5
##   city                  average_sales_c std_dev_sales_c min_sales_C max_sales_c
##   <chr>                           <dbl>           <dbl>       <int>       <int>
## 1 Beaumont                         177.            41.5          83         273
## 2 Bryan-College Station            206.            85.0          89         403
## 3 Tyler                            270.            62.0         143         423
## 4 Wichita Falls                    116.            22.2          79         167
df_volume_ym <- dataset %>%
  group_by(year,month) %>%
  summarise(average_volume_ym = mean(volume),
            std_dev_volume_ym = sd(volume),
            min_volume_ym = min(volume),
            max_volume_ym = max(volume))
## `summarise()` has regrouped the output.
## ℹ Summaries were computed grouped by year and month.
## ℹ Output is grouped by year.
## ℹ Use `summarise(.groups = "drop_last")` to silence this message.
## ℹ Use `summarise(.by = c(year, month))` for per-operation grouping
##   (`?dplyr::dplyr_by`) instead.
df_volume_ym
## # A tibble: 60 × 6
## # Groups:   year [5]
##     year month average_volume_ym std_dev_volume_ym min_volume_ym max_volume_ym
##    <int> <int>             <dbl>             <dbl>         <dbl>         <dbl>
##  1  2010     1              15.9              6.92          8.95          25.5
##  2  2010     2              19.2              8.54          9.38          30.1
##  3  2010     3              28.0              7.30         18.2           35.9
##  4  2010     4              33.8             13.3          19.8           49.9
##  5  2010     5              35.9             13.2          20.9           48.4
##  6  2010     6              34.5             13.6          19.2           47.5
##  7  2010     7              26.7             12.1          12.4           40.9
##  8  2010     8              28.6             10.7          15.3           39.7
##  9  2010     9              22.2              7.23         16.5           32.1
## 10  2010    10              21.8              8.07         13.6           32.1
## # ℹ 50 more rows
df_sales_ym <- dataset %>%
  group_by(year,month) %>%
  summarise(average_sales_ym = mean(sales),
            std_dev_sales_ym = sd(sales),
            min_sales_ym = min(sales),
            max_sales_ym = max(sales))
## `summarise()` has regrouped the output.
## ℹ Summaries were computed grouped by year and month.
## ℹ Output is grouped by year.
## ℹ Use `summarise(.groups = "drop_last")` to silence this message.
## ℹ Use `summarise(.by = c(year, month))` for per-operation grouping
##   (`?dplyr::dplyr_by`) instead.
df_sales_ym
## # A tibble: 60 × 6
## # Groups:   year [5]
##     year month average_sales_ym std_dev_sales_ym min_sales_ym max_sales_ym
##    <int> <int>            <dbl>            <dbl>        <int>        <int>
##  1  2010     1             105.             36.6           83          160
##  2  2010     2             122.             40.3           91          181
##  3  2010     3             189.             43.6          147          250
##  4  2010     4             229              64.0          167          316
##  5  2010     5             233.             58.8          165          282
##  6  2010     6             216.             71.4          129          286
##  7  2010     7             178              62.5          104          255
##  8  2010     8             184.             45            130          238
##  9  2010     9             150.             47.2          122          220
## 10  2010    10             141.             45.7          100          202
## # ℹ 50 more rows
df_volume_cy <- dataset %>%
  group_by(city,year) %>%
  summarise(average_volume_cy = mean(volume),
            std_dev_volume_cy = sd(volume),
            min_volume_cy = min(volume),
            max_volume_cy = max(volume))
## `summarise()` has regrouped the output.
## ℹ Summaries were computed grouped by city and year.
## ℹ Output is grouped by city.
## ℹ Use `summarise(.groups = "drop_last")` to silence this message.
## ℹ Use `summarise(.by = c(city, year))` for per-operation grouping
##   (`?dplyr::dplyr_by`) instead.
df_volume_cy
## # A tibble: 20 × 6
## # Groups:   city [4]
##    city     year average_volume_cy std_dev_volume_cy min_volume_cy max_volume_cy
##    <chr>   <int>             <dbl>             <dbl>         <dbl>         <dbl>
##  1 Beaumo…  2010              22.7              4.95         14.2           28.8
##  2 Beaumo…  2011              21.1              4.30         15.5           28.5
##  3 Beaumo…  2012              24.5              4.92         13.5           31.1
##  4 Beaumo…  2013              30.3              6.44         20.3           42.0
##  5 Beaumo…  2014              32.1              7.05         18.1           41.2
##  6 Bryan-…  2010              28.7             10.8          15.2           47.5
##  7 Bryan-…  2011              28.9             10.3          15.2           47.8
##  8 Bryan-…  2012              35.4             13.5          19.8           55.4
##  9 Bryan-…  2013              45.1             19.5          19.0           76.1
## 10 Bryan-…  2014              52.8             18.0          29.5           83.5
## 11 Tyler    2010              36.3              8.39         24.4           49.9
## 12 Tyler    2011              38.6              9.41         21.0           52.3
## 13 Tyler    2012              44.0             10.2          25.4           57.4
## 14 Tyler    2013              50.3             10.3          32.1           63.0
## 15 Tyler    2014              59.6             12.8          36.9           80.8
## 16 Wichit…  2010              15.0              4.07          8.95          20.9
## 17 Wichit…  2011              12.1              2.52          8.17          15.3
## 18 Wichit…  2012              13.2              2.66          9.70          17.8
## 19 Wichit…  2013              14.9              3.11          9.67          19.1
## 20 Wichit…  2014              14.5              3.13          9.63          18.7
ggplot(df_volume_cy, aes(x=year,y=average_volume_cy,color=city))+
  geom_line()+
  geom_point(size=3)+
  labs(title="Average Volume by Year and City",
       x="Year",
       y="Average Volume")+
  scale_y_continuous(breaks=seq(10,65,5))

df_sales_cy <- dataset %>%
  group_by(city,year) %>%
  summarise(average_sales_cy = mean(sales),
            std_dev_sales_cy = sd(sales),
            min_sales_cy = min(sales),
            max_sales_cy = max(sales))
## `summarise()` has regrouped the output.
## ℹ Summaries were computed grouped by city and year.
## ℹ Output is grouped by city.
## ℹ Use `summarise(.groups = "drop_last")` to silence this message.
## ℹ Use `summarise(.by = c(city, year))` for per-operation grouping
##   (`?dplyr::dplyr_by`) instead.
ggplot(df_sales_cy, aes(x=year,y=average_sales_cy,color=city))+
  geom_line()+
  geom_point(size=3)+
  labs(title="Average Sales by Year and City",
       x="Year",
       y="Average Sales")+
  scale_y_continuous(breaks=seq(100,400,25))

ggplot(data=dataset)+
  geom_boxplot(aes(x=city, y=median_price, fill=city))+
  labs(title="Boxplot of Median Price by City",
       x="City",
       y="Median Price")+
  theme_bw(base_size = 18)+
  theme(legend.position = "none")

df_sales_cm <- dataset %>%
  group_by(city,month) %>%
  summarise(average_sales_cm = mean(sales),
            std_dev_sales_cm = sd(sales),
            min_sales_cm = min(sales),
            max_sales_cm = max(sales))
## `summarise()` has regrouped the output.
## ℹ Summaries were computed grouped by city and month.
## ℹ Output is grouped by city.
## ℹ Use `summarise(.groups = "drop_last")` to silence this message.
## ℹ Use `summarise(.by = c(city, month))` for per-operation grouping
##   (`?dplyr::dplyr_by`) instead.
ggplot(df_sales_cm, aes(x=factor(month),y=average_sales_cm,fill=city))+
  geom_col(color="black")+
  labs(title="Average Sales by Month and City",
       x="Month",
       y="Average Sales")+
  geom_text(aes(label=average_sales_cm), position= 
              position_stack(vjust=0.5),color="black",size=3)+
  scale_y_continuous(breaks=seq(0,1000,100))

ggplot(dataset, aes(x=factor(month),y=sales,fill=city))+
  geom_col(color="black")+
  facet_wrap(factor(year))+
  labs(title="Sales by Month and City",
       x="Months",
       y="Sales")+
  theme_minimal()

dataset$data <- as.Date(paste(year,month,"01", sep="-"))

ggplot(dataset, aes(x=data,y=sales,col=city))+
  geom_line(linewidth=1)+
  geom_point(size=2)+
  scale_x_date(date_labels ="%b %Y",date_breaks = "4 months")+
  labs(title="Sales Trend per City",
       x="Time (Year and Month)",
       y="Sales")+
  theme_minimal()+
  theme(axis.text.x = element_text(angle=45, hjust=1))

ggplot(dataset, aes(x=data,y=volume,col=city))+
  geom_line(linewidth=1)+
  geom_point(size=2)+
  scale_x_date(date_labels ="%b %Y",date_breaks = "4 months")+
  labs(title="Volume Trend per City",
       x="Time (Year and Month)",
       y="Volume")+
  theme_minimal()+
  theme(axis.text.x = element_text(angle=45, hjust=1))

ggplot(dataset,aes(x=factor(month),
                  y=sales,
                  fill=city))+
  geom_col(position="fill")+
  facet_wrap(~year)+
  labs(y="Proportion")+
  labs(title="Normalized Sales per Month and Year",
       x="Month",
       y="Normalized Sales")+
  theme_grey()

9. Conclusion

Price Distribution and Differences between Cities

The boxplot analysis of median prices highlights relevant differences among cities.
Some locations show higher median values, suggesting stronger housing demand or a more expensive real estate market.
The city with the highest median price values is Bryan_College Station.
This suggests that Bryan_College Station represents a higher-value real estate market compared with the other cities analyzed.
This characteristic may make the city attractive for investors, although further analysis would be required.
Other cities present lower prices, suggesting more homogeneous and accessible markets.
The city with the lowest values is Wichita Falls, suggesting a more affordable housing market.
The presence of outliers indicates that these observations may represent luxury properties or exceptional transactions and should be investigated.

Effectiveness of Listings

The efficiency indicator provides information about how effectively active listings are converted into sales.
Cities with higher efficiency values appear to have a stronger ability to transform available properties into completed transactions, suggesting higher demand or more effective pricing strategies.
This could be the case of Bryan-College Station, showing an improving efficiency along the years.
On the other hand, lower efficiency values may indicate a slower market, excessive supply or the need for improved listing strategies.
That’s the case of Wichita Falls, showing an almost steady efficiency along the years.

Strategic Recommendations

The analysis suggests that Texas Realty Insights should adopt a differentiated strategy based on city-specific characteristics.
Cities with strong sales performance and high listing efficiency represent potential opportunities for expansion, while areas with lower efficiency may require improvements in pricing strategies, property promotion and market positioning.
The statistical insights obtained from this analysis can support more informed decisions and improve the effectiveness of real estate management strategies.