bargaining_data <- read.csv("selected_bargaining_data.csv")
#Outliers Function
exclude_outliers <- function(x, threshold = 3) {
  z_scores <- abs(scale(x))
  x[z_scores > threshold] <- NA
  x
}

# Property Age
property_age_summary <- bargaining_data %>%
  group_by(event_id) %>%
  summarize(
    property_age = ifelse(all(is.na(year_built)), NA, 2024 - max(year_built, na.rm = TRUE))
  ) %>%
  filter(!is.na(property_age)) %>%
  summarize(
    Mean = mean(property_age, na.rm = TRUE),
    Std.Dev. = sd(property_age, na.rm = TRUE),
    Min = min(property_age, na.rm = TRUE),
    Median = median(property_age, na.rm = TRUE),
    Max = max(property_age, na.rm = TRUE)
  )

# Number of Buyers
number_of_buyers_summary <- bargaining_data %>%
  group_by(event_id) %>%
  summarize(number_of_buyers = sum(!is.na(buyer_id))) %>%
  mutate(number_of_buyers = exclude_outliers(number_of_buyers)) %>%
  summarize(
    Mean = mean(number_of_buyers, na.rm = TRUE),
    Std.Dev. = sd(number_of_buyers, na.rm = TRUE),
    Min = min(number_of_buyers, na.rm = TRUE),
    Median = median(number_of_buyers, na.rm = TRUE),
    Max = max(number_of_buyers, na.rm = TRUE)
  )

# Number of Revisions
number_of_revisions_summary <- bargaining_data %>%
  group_by(event_id) %>%
  summarize(
    number_of_revisions = sum(action == "seller_revise" | is.na(action), na.rm = TRUE)
  ) %>%
  mutate(
    number_of_revisions = exclude_outliers(number_of_revisions)
  ) %>%
  summarize(
    Mean = mean(number_of_revisions, na.rm = TRUE),
    Std.Dev. = sd(number_of_revisions, na.rm = TRUE),
    Min = min(number_of_revisions, na.rm = TRUE),
    Median = median(number_of_revisions, na.rm = TRUE),
    Max = max(number_of_revisions, na.rm = TRUE)
  )

# Duration Until Off-Market (Days)
bargaining_data <- bargaining_data %>%
  mutate(
    listing_date = ymd_hm(listing_date),
    off_market_date = ymd(off_market_date)
  )

duration_days <- bargaining_data %>%
  group_by(event_id) %>%
  summarize(duration_days = as.numeric(
    difftime(max(off_market_date, na.rm = TRUE), min(listing_date, na.rm = TRUE), units = "days"))) %>%
  filter(duration_days >= 0)
  
  

duration_days_summary <- duration_days %>%
  mutate(duration_days = exclude_outliers(duration_days)) %>%
  summarize(  
    Mean = mean(duration_days, na.rm = TRUE),
    Std.Dev. = sd(duration_days, na.rm = TRUE),
    Min = min(duration_days, na.rm = TRUE),
    Median = median(duration_days, na.rm = TRUE),
    Max = max(duration_days, na.rm = TRUE)
  )

# Sales Price
de_sales_price <- bargaining_data %>%
  distinct(de_sales_price, event_id) %>%
  mutate(de_sales_price = exclude_outliers(de_sales_price)) 

sales_price_summary <- bargaining_data %>%
  summarize(
    Mean = mean(de_sales_price, na.rm = TRUE),
    Std.Dev. = sd(de_sales_price, na.rm = TRUE),
    Min = min(de_sales_price, na.rm = TRUE),
    Median = median(de_sales_price, na.rm = TRUE),
    Max = max(de_sales_price, na.rm = TRUE)
  )

#Make Summary Table
summary_combined <- bind_rows(
  property_age_summary %>%
    mutate(Variable = "Property Age"),
  number_of_buyers_summary %>%
    mutate(Variable = "Buyer Represented by the Platform"),
  number_of_revisions_summary %>%
    mutate(Variable = "Revisions"),
  duration_days_summary %>%
    mutate(Variable = "Duration Until Off-Market (Days)"),
  sales_price_summary %>%
    mutate(Variable = "Sales Price")
)

summary_combined <- summary_combined %>%
  select(Variable, Mean, Std.Dev., Min, Median, Max) %>%
  mutate(across(where(is.numeric), ~round(., 0))) %>%
  mutate(across(where(is.numeric), ~format(., scientific = FALSE)))

print(summary_combined)
## # A tibble: 5 × 6
##   Variable                          Mean     Std.Dev. Min      Median   Max     
##   <chr>                             <chr>    <chr>    <chr>    <chr>    <chr>   
## 1 Property Age                      "    47" "    32" "     5" "    38" "    16…
## 2 Buyer Represented by the Platform "     3" "     1" "     2" "     2" "      …
## 3 Revisions                         "     1" "     1" "     0" "     0" "      …
## 4 Duration Until Off-Market (Days)  "    42" "    50" "     1" "    21" "    23…
## 5 Sales Price                       "469988" "249385" "104335" "411423" "156179…
state_name <- read.csv("cbsa2fipsxw.csv")
bargaining_data <- bargaining_data %>%
  mutate(state_fips = ifelse(nchar(censustract) == 11,
                             substr(censustract, 1, 2),
                             substr(censustract, 1, 1)))

state_names <- state_name %>%
  mutate(fipsstatecode = as.character(fipsstatecode))

bargaining_data <- left_join(bargaining_data, state_names, by = c("state_fips" = "fipsstatecode"))
## Warning in left_join(bargaining_data, state_names, by = c(state_fips = "fipsstatecode")): Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 1 of `x` matches multiple rows in `y`.
## ℹ Row 365 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship =
##   "many-to-many"` to silence this warning.
library(ggplot2)
library(plotly)
## Warning: 程辑包'plotly'是用R版本4.3.3 来建造的
## 
## 载入程辑包:'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
us_states <- map_data("state")

#Number of Properties in Each State & Legend Showing Distribution of Counts
property_count <- bargaining_data %>%
  group_by(statename) %>%
  summarize(property_count = n_distinct(property_id))
bargaining_data <- left_join(bargaining_data, property_count, by = "statename")

property_count
## # A tibble: 28 × 2
##    statename            property_count
##    <chr>                         <int>
##  1 Arizona                           7
##  2 Arkansas                          1
##  3 California                       51
##  4 Colorado                          5
##  5 District of Columbia              6
##  6 Florida                           5
##  7 Georgia                           2
##  8 Illinois                         12
##  9 Maryland                         11
## 10 Massachusetts                    16
## # ℹ 18 more rows
#gglot
p1 <- ggplot(us_states)+
  geom_polygon(aes(x=long, y=lat, group = group), fill="white", color ="black")+ 
  geom_point(data=bargaining_data, 
             aes(x=property_longitude, y=property_latitude, color=property_count, size=property_count), na.rm=T)+ 
  scale_color_gradient(low = "green", high="darkblue")+
  scale_size_continuous(range=c(1,4))+
  coord_fixed(1.2)+
  theme_void() +
  ggtitle("Number of Properties in Each State & Distribution of Counts")

ggplotly(p1)
property_age <- bargaining_data %>%
  group_by(event_id) %>%
  summarize(
    property_age = ifelse(all(is.na(year_built)), NA, 2024 - max(year_built, na.rm = TRUE))
  ) %>%
  distinct()

bargaining_data <- bargaining_data %>%
  left_join(property_age, by = "event_id")

#exclude outliers
bargaining_data_1 <- bargaining_data %>%
  mutate(de_sales_price = exclude_outliers(de_sales_price))

bargaining_data_1 <- bargaining_data %>%
  filter(!is.na(de_sales_price) & !is.na(property_age)) %>%
  mutate(de_sales_price = log(de_sales_price)) %>%
  select(event_id, property_age, de_sales_price)

# univariate regression
library(readxl)

lm_property_age = lm(de_sales_price~property_age, data = bargaining_data_1)
plot(bargaining_data_1$property_age, bargaining_data_1$de_sales_price, pch = 16, col = "blue", xlab = "Property Age", ylab = "Sales Price")
abline(lm_property_age)

summary(lm_property_age)
## 
## Call:
## lm(formula = de_sales_price ~ property_age, data = bargaining_data_1)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -1.28317 -0.31453  0.02626  0.23440  1.40076 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  1.278e+01  5.575e-03 2292.47   <2e-16 ***
## property_age 1.298e-03  1.141e-04   11.37   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.4767 on 20778 degrees of freedom
## Multiple R-squared:  0.006185,   Adjusted R-squared:  0.006138 
## F-statistic: 129.3 on 1 and 20778 DF,  p-value: < 2.2e-16
r_squared <- summary(lm_property_age)$r.squared
library(dplyr)

# Assume bargaining_data, duration_days, and de_sales_price are available
original_listing <- bargaining_data %>%
  distinct(event_id, de_original_list_price) %>%
  select(event_id, de_original_list_price)

duration_price <- merge(duration_days, original_listing, by = "event_id", all.x = TRUE)

duration_price <- duration_price %>%
  mutate(log_de_original_list_price = log(de_original_list_price))

# Check correlation between duration and original listing price
lm_listing_duration <- lm(duration_days ~ log_de_original_list_price, data = duration_price)
summary(lm_listing_duration)
## 
## Call:
## lm(formula = duration_days ~ log_de_original_list_price, data = duration_price)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -57.21 -41.63 -29.37  18.27 338.32 
## 
## Coefficients:
##                            Estimate Std. Error t value Pr(>|t|)
## (Intercept)                -148.970    124.151  -1.200    0.232
## log_de_original_list_price   15.249      9.564   1.594    0.112
## 
## Residual standard error: 66.52 on 197 degrees of freedom
## Multiple R-squared:  0.01274,    Adjusted R-squared:  0.007728 
## F-statistic: 2.542 on 1 and 197 DF,  p-value: 0.1124
# Plot duration vs. original listing price
plot(duration_price$log_de_original_list_price, duration_price$duration_days, 
     pch = 16, col = "blue", xlab = "Log Original Price", ylab = "Duration in the Market",
     main = "Duration vs. Original Listing Price")
abline(lm_listing_duration, col = "red")

listing_sales <- merge(de_sales_price, original_listing, by = "event_id", all.x = TRUE)

listing_sales <- listing_sales %>%
  mutate(log_de_sales_price = log(de_sales_price),
         log_de_original_list_price = log(de_original_list_price))

# Check correlation between sales price and original listing price
lm_listing_sales <- lm(log_de_sales_price ~ log_de_original_list_price, data = listing_sales)
summary(lm_listing_sales)
## 
## Call:
## lm(formula = log_de_sales_price ~ log_de_original_list_price, 
##     data = listing_sales)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.23647 -0.03985 -0.00427  0.02771  0.22068 
## 
## Coefficients:
##                            Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                -0.29803    0.15193  -1.962   0.0514 .  
## log_de_original_list_price  1.02252    0.01173  87.150   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.07048 on 171 degrees of freedom
##   (因为不存在,27个观察量被删除了)
## Multiple R-squared:  0.978,  Adjusted R-squared:  0.9779 
## F-statistic:  7595 on 1 and 171 DF,  p-value: < 2.2e-16
# Plot sales price vs. original listing price
plot(listing_sales$log_de_original_list_price, listing_sales$log_de_sales_price, 
     pch = 16, col = "blue", xlab = "Log Original Price", ylab = "Log Sales Price",
     main = "Sales Price vs. Original Listing Price")
abline(lm_listing_sales, col = "red")

all_data <- merge(listing_sales, duration_price, by = "event_id", all.x = TRUE)

all_data <- all_data %>%
  mutate(log_duration_days = log(duration_days))

# Multivariate regression model
lm_full_model <- lm(log_de_sales_price ~ log_de_original_list_price.x + log_duration_days, data = all_data)

summary(lm_full_model)
## 
## Call:
## lm(formula = log_de_sales_price ~ log_de_original_list_price.x + 
##     log_duration_days, data = all_data)
## 
## Residuals:
##       Min        1Q    Median        3Q       Max 
## -0.138840 -0.032394 -0.008055  0.024956  0.184768 
## 
## Coefficients:
##                               Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                  -0.262560   0.118817   -2.21   0.0285 *  
## log_de_original_list_price.x  1.026980   0.009182  111.85   <2e-16 ***
## log_duration_days            -0.032691   0.003119  -10.48   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.05509 on 170 degrees of freedom
##   (因为不存在,27个观察量被删除了)
## Multiple R-squared:  0.9866, Adjusted R-squared:  0.9865 
## F-statistic:  6269 on 2 and 170 DF,  p-value: < 2.2e-16
# Plot the relationships side-by-side
par(mfrow = c(1, 2))

# Plot 1: Sales price vs. original listing price
plot(all_data$log_de_original_list_price.x, all_data$log_de_sales_price, 
     pch = 16, col = "blue", xlab = "Original Price", ylab = "Sales Price",
     main = "Sales Price vs. Original Listing Price")
abline(lm(log_de_sales_price ~ log_de_original_list_price.x, data = all_data), col = "red")

# Plot 2: Sales price vs. duration in the market
plot(all_data$log_duration_days, all_data$log_de_sales_price, 
     pch = 17, col = "green", xlab = "Duration in the Market", ylab = "Sales Price",
     main = "Sales Price vs. Duration in the Market")
abline(lm(log_de_sales_price ~ log_duration_days, data = all_data), col = "red")

#combine
par(mfrow = c(1, 1))