AntVal
AntVal

Reputation: 665

2-way FE model gives "empty model" in R

I am trying to run a 2-way fixed effect model in R, using plm. I am trying to get the treatment effect of an event on municipalities votes on referenda.

I would like to run the model with municipality and referenda fixed effects. Each row or unit is a pair of municipality*referendum.

I am trying to fit the model using the following:

model_2fe <- plm(vote.ant.immig ~ pre.post, data = clean.df, effect = "twoways", index = c("municipality.code", "ref.code")) 

And I keep on getting the following:

Error in plm.fit(data, model, effect, random.method, random.models, random.dfcor, : empty model

If it helps: pre.post is a factor indicating treatment condition (1,0), vote.ant.immig is a numeric object, municipality.code is a factor, as is ref.code.

Could anyone help me? Thanks!

Upvotes: 2

Views: 1710

Answers (3)

ctde
ctde

Reputation: 91

I found this post useful so I'll contribute what information I can, but it's really a summary of the vignette which should guide anyone using plm. Note, you don't include a provided the input for model in your plm() which is obviously problematic.

Given (as you've written),

#note, no model input for plm()
model_2fe <- plm(vote.ant.immig ~ pre.post,
                 data = clean.df, 
                 effect = "twoways", 
                 index = c("municipality.code", "ref.code")) 

we ought to proceed step-by-step and ensure that we fit the necessary format of 'p...' for plm():

pform <- pFormula(vote.ant.immig ~ pre.post)
#then make the pdata.frame 
pclean.df <- pdata.frame(clean.df,index = c("municipalitycode", "refcode"))
#then make the df with necessary variables for/from pform (the formula) 
pmf.clean.df <- model.frame(pclean.df,pform)
#then make the design/model matrix "e.g., by expanding factors to a set of dummy variables (depending on the contrasts) and expanding interactions similarly" (quote from ?model.matrix).
pmodmat.fe <- model.matrix(pform,data=pmf.clean.df,  model = "within",effect = "twoways") 
#then check for linear dependence
detect.lindep(pmodmat.fe)
#lastly, run the regression with fixed effects 
mod.fe <- plm(pform,
               data=pclean.df, 
               model="within",
               effects="twoways")

For me, when I used this in a personal application it was beneficial to index in pdata.frame since I could save a lot of time.

Upvotes: 1

Otto K&#228;ssi
Otto K&#228;ssi

Reputation: 3083

Another way to accomplish what @Helix123 discusses above, is to create a new dummy variable for municipality x referendum fixed effects.

clean.df$muni_x_ref <- factor(paste(clean.df$municipality, clean.df$refcode, sep='X'))

Then you can tabulate prepost with your new muni_x_ref variable. First few lines below. You see that you have only one realisation of your independent variable for each of the municipality x referendum fixed effects. Your fe's and independent variable are fully collinear, and there is no variation to estimate your model. I believe you need to rethink what you want to estimate.

 table(clean.df$muni_x_refcode, df$prepost)


                            0 1
  AdlikonX5240              1 0
  AdlikonX5250              1 0
  AdlikonX5320              1 0
  AdlikonX5470              1 0
  AdlikonX5521              1 0
  AdlikonX5522              1 0
  AdlikonX5710              1 0
  AdlikonX5800              0 1
  AdlikonX5880              0 1
  AdlikonX5970              0 1
  AdlikonX6040              0 1
  AdlikonX6090              0 1
  Aeugst am AlbisX5240      1 0
  Aeugst am AlbisX5250      1 0
  Aeugst am AlbisX5320      1 0
  Aeugst am AlbisX5470      1 0
  Aeugst am AlbisX5521      1 0
  Aeugst am AlbisX5522      1 0
  Aeugst am AlbisX5710      1 0
  Aeugst am AlbisX5800      0 1
  Aeugst am AlbisX5880      0 1
  Aeugst am AlbisX5970      0 1
  Aeugst am AlbisX6040      0 1
  Aeugst am AlbisX6090      0 1
  Affoltern am AlbisX5240   1 0
  Affoltern am AlbisX5250   1 0
  Affoltern am AlbisX5320   1 0
  Affoltern am AlbisX5470   1 0
  Affoltern am AlbisX5521   1 0
  Affoltern am AlbisX5522   1 0
  Affoltern am AlbisX5710   1 0 ....

Upvotes: 2

Helix123
Helix123

Reputation: 3687

Using the hints in ?plm::detect.lindep you can see what the data look like after two-way fixed effect transformation. Here are some lines of code to get you there:

dat <- pdata.frame(<inputdata>, index = c("municipalitycode", "refcode"))

fml <- voteantimmig ~ prepost
mf <- model.frame(dat, fml)
modmat_2FE <- model.matrix(mf, model = "within", effect = "twoways")
all(abs(modmat_2FE) < 0.0000000000001) # TRUE
## look at your transformed data in modmat_2FE -> all zero -> empty model

## Analyse why this is the case, per individual, per time period:
modmat_FEi <- model.matrix(mf, model = "within", effect = "individual")
all(abs(modmat_FEi) < 0.0000000000001) # FALSE
## look at your transformed data in modmat_FEi
unique(modmat_FEi) # not so many different values
## look at your transformed data in modmat_FEi with individual and time index next to it: 
modmat_FEiindexes <- cbind(modmat_FEi, dat$municipalitycode, dat$refcode)
## => not much variation left within each individual. 

modmat_FEt <- model.matrix(mf, model = "within", effect = "time")
all(abs(modmat_FEt) < 0.0000000000001) # TRUE
## look at your transformed data in modmat_FEt -> all zero

Upvotes: 2

Related Questions