1. Data Preparation
main_path <- "C:/Users/吳聿絜/Desktop/Empirical IO"
setwd(main_path)
data <- read.csv("data.csv")
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(tidyr)
library(fixest)
## Warning: package 'fixest' was built under R version 4.5.3
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.5.3
library(modelsummary)
## Warning: package 'modelsummary' was built under R version 4.5.3
library(gt)
## Warning: package 'gt' was built under R version 4.5.3
annual_data <- data %>%
group_by(food_type, year) %>%
summarise(
poison = first(poison),
price_mean = mean(price_index, na.rm = TRUE),
price_sd = sd(price_index, na.rm = TRUE),
price_cv = sd(price_index, na.rm = TRUE) / mean(price_index, na.rm = TRUE),
price_max = max(price_index, na.rm = TRUE),
price_min = min(price_index, na.rm = TRUE),
.groups = "drop"
) %>%
arrange(food_type, year) %>%
group_by(food_type) %>%
mutate(lag_poison = lag(poison, 1)) %>%
ungroup()
3. Regression Models
3.1 Overall Panel Fixed Effects Model
model_overall <- feols(
price_mean ~ lag_poison | food_type + year,
data = annual_data
)
## NOTE: 7 observations removed because of NA values (RHS: 7).
summary(model_overall)
## OLS estimation, Dep. Var.: price_mean
## Observations: 63
## Fixed-effects: food_type: 7, year: 9
## Standard-errors: IID
## Estimate Std. Error t value Pr(>|t|)
## lag_poison 0.210296 0.288818 0.728124 0.47015
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## RMSE: 4.66869 Adj. R2: 0.707219
## Within R2: 0.011154
3.2 Cross-Category Substitution Models
Seafood model
model_seafood <- lm(
price_mean_水產品 ~ lag_poison_水產品 +
lag_poison_肉類及其加工品 +
lag_poison_水產加工品,
data = wide_df
)
summary(model_seafood)
##
## Call:
## lm(formula = price_mean_水產品 ~ lag_poison_水產品 + lag_poison_肉類及其加工品 +
## lag_poison_水產加工品, data = wide_df)
##
## Residuals:
## 2 3 4 5 6 7 8 9 10
## 2.2100 -7.4335 -4.6607 -1.4983 0.4764 2.9326 3.6756 5.3726 -1.0748
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 99.879617 3.564533 28.020 1.08e-06 ***
## lag_poison_水產品 -0.841810 0.384409 -2.190 0.0801 .
## lag_poison_肉類及其加工品 3.008674 0.806195 3.732 0.0135 *
## lag_poison_水產加工品 0.007099 1.019316 0.007 0.9947
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 5.224 on 5 degrees of freedom
## (1 observation deleted due to missingness)
## Multiple R-squared: 0.7371, Adjusted R-squared: 0.5793
## F-statistic: 4.672 on 3 and 5 DF, p-value: 0.06505
Vegetable model
model_vegetable <- lm(
price_mean_蔬果類 ~ lag_poison_蔬果類 +
lag_poison_穀類,
data = wide_df
)
summary(model_vegetable)
##
## Call:
## lm(formula = price_mean_蔬果類 ~ lag_poison_蔬果類 + lag_poison_穀類,
## data = wide_df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -15.509 -5.870 -3.331 7.411 14.241
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 91.8580 9.1053 10.088 5.51e-05 ***
## lag_poison_蔬果類 0.4021 1.8543 0.217 0.836
## lag_poison_穀類 5.1059 3.4640 1.474 0.191
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 10.98 on 6 degrees of freedom
## (1 observation deleted due to missingness)
## Multiple R-squared: 0.3023, Adjusted R-squared: 0.06971
## F-statistic: 1.3 on 2 and 6 DF, p-value: 0.3397
Meat model
model_meat <- lm(
price_mean_肉類及其加工品 ~ lag_poison_肉類及其加工品 +
lag_poison_蛋類 +
lag_poison_乳類,
data = wide_df
)
summary(model_meat)
##
## Call:
## lm(formula = price_mean_肉類及其加工品 ~ lag_poison_肉類及其加工品 +
## lag_poison_蛋類 + lag_poison_乳類, data = wide_df)
##
## Residuals:
## 2 3 4 5 6 7 8 9
## -3.5498 -12.0478 1.7530 1.1361 0.3169 2.6842 5.3239 4.5419
## 10
## -0.1585
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 95.3486 3.6101 26.412 1.45e-06 ***
## lag_poison_肉類及其加工品 3.8328 1.3382 2.864 0.0352 *
## lag_poison_蛋類 -5.9394 3.0296 -1.960 0.1072
## lag_poison_乳類 0.5009 5.0913 0.098 0.9255
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 6.609 on 5 degrees of freedom
## (1 observation deleted due to missingness)
## Multiple R-squared: 0.7342, Adjusted R-squared: 0.5748
## F-statistic: 4.604 on 3 and 5 DF, p-value: 0.06673
4. Visualization
4.1 Overall trend
ggplot(annual_data, aes(x = poison, y = price_mean)) +
geom_point(aes(color = food_type), size = 3, alpha = 0.7) +
geom_smooth(method = "lm", color = "black", linetype = "dashed") +
theme_minimal() +
labs(
title = "Food Price vs Food Poisoning",
x = "Poisoning Cases",
y = "Price Index",
color = "Food Type"
)
## `geom_smooth()` using formula = 'y ~ x'

4.2 By food type
ggplot(annual_data, aes(x = poison, y = price_mean, color = food_type)) +
geom_point(size = 3, alpha = 0.7) +
geom_smooth(method = "lm", se = FALSE) +
theme_minimal() +
labs(
title = "Price Impact by Food Type",
x = "Poisoning Cases",
y = "Price Index"
)
## `geom_smooth()` using formula = 'y ~ x'

5. Regression Table (GT Output)
names(model_overall$coefficients) <- c("Lag Poison (Overall)")
names(model_seafood$coefficients) <- c(
"(Intercept)",
"Self Shock (Seafood)",
"Meat Substitute Shock",
"Processed Seafood Shock"
)
names(model_vegetable$coefficients) <- c(
"(Intercept)",
"Self Shock (Vegetable)",
"Grain Substitute Shock"
)
names(model_meat$coefficients) <- c(
"(Intercept)",
"Self Shock (Meat)",
"Egg Shock",
"Dairy Shock"
)
models_list <- list(
"Overall FE" = model_overall,
"Seafood" = model_seafood,
"Vegetable" = model_vegetable,
"Meat" = model_meat
)
coef_order <- c(
"Lag Poison (Overall)",
"Self Shock (Seafood)",
"Self Shock (Vegetable)",
"Self Shock (Meat)",
"Meat Substitute Shock",
"Processed Seafood Shock",
"Grain Substitute Shock",
"Egg Shock",
"Dairy Shock",
"(Intercept)"
)
table <- modelsummary(
models_list,
output = "gt",
stars = c('*' = .1, '**' = .05, '***' = .01)
)
table
| |
Overall FE |
Seafood |
Vegetable |
Meat |
| Lag Poison (Overall) |
0.210 |
|
|
|
|
(0.289) |
|
|
|
| (Intercept) |
|
99.880*** |
91.858*** |
95.349*** |
|
|
(3.565) |
(9.105) |
(3.610) |
| Self Shock (Seafood) |
|
-0.842* |
|
|
|
|
(0.384) |
|
|
| Meat Substitute Shock |
|
3.009** |
|
|
|
|
(0.806) |
|
|
| Processed Seafood Shock |
|
0.007 |
|
|
|
|
(1.019) |
|
|
| Self Shock (Vegetable) |
|
|
0.402 |
|
|
|
|
(1.854) |
|
| Grain Substitute Shock |
|
|
5.106 |
|
|
|
|
(3.464) |
|
| Self Shock (Meat) |
|
|
|
3.833** |
|
|
|
|
(1.338) |
| Egg Shock |
|
|
|
-5.939 |
|
|
|
|
(3.030) |
| Dairy Shock |
|
|
|
0.501 |
|
|
|
|
(5.091) |
| Num.Obs. |
63 |
9 |
9 |
9 |
| R2 |
0.778 |
0.737 |
0.302 |
0.734 |
| R2 Adj. |
0.707 |
0.579 |
0.070 |
0.575 |
| R2 Within |
0.011 |
|
|
|
| R2 Within Adj. |
-0.010 |
|
|
|
| AIC |
404.9 |
60.0 |
73.0 |
64.2 |
| BIC |
439.2 |
61.0 |
73.8 |
65.2 |
| Log.Lik. |
|
-25.005 |
-32.509 |
-27.122 |
| F |
|
4.672 |
1.300 |
4.604 |
| RMSE |
4.67 |
3.89 |
8.96 |
4.93 |
| FE: food_type |
X |
|
|
|
| FE: year |
X |
|
|
|
| * p < 0.1, ** p < 0.05, *** p < 0.01 |