diff --git a/coverage.xml b/coverage.xml index 68435763..a1cbc19b 100644 --- a/coverage.xml +++ b/coverage.xml @@ -1,12 +1,12 @@ - - + + C:\Users\alexa\Documents\pyfixest\pyfixest - + @@ -14,40 +14,29 @@ - - - - + + + - + + - - - - - - - - - - - - - + + - + @@ -57,7 +46,7 @@ - + @@ -71,143 +60,147 @@ - - - - - + + + + + + - - - - - + + + + + - - - - - - + + + + + + - - - - + + + + + - - - + + - + - - + + - - - - + + + + + - - - + + - - - + + + - + - + + - - + + - - + - + - - - + + + + - + - - + - + - + + - + - - - + - - + + + + - - - - - - + + + + + + - - - - - - + + + - + - + - + + + + + + - + @@ -232,21 +225,21 @@ - - - - - - - + + + + + + + - - - + + + - - + + @@ -266,8 +259,8 @@ - - + + @@ -310,7 +303,7 @@ - + @@ -322,124 +315,124 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - + + + - - - - - + + + + + + - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + - + - - - - - - + + + + + + + - + - - - - - - - - - - + + + + + + + + + + - - + - + @@ -456,69 +449,72 @@ - - - - - + + + + - + - + - - - - - + + + + + + - - - - + + + - - - - - - - + + + + + + + - + - - - + + + + - - - - - - - - + + + + + + + + + - - - - - - - + + + + + + + + + @@ -561,7 +557,7 @@ - + @@ -982,7 +978,7 @@ - + @@ -1039,7 +1035,7 @@ - + @@ -1048,131 +1044,165 @@ - - - - + + + + + + - - + - + + + + - - + + - - - + + + - + - - + - - - - - + + + + + - - + + + - - + + - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - + + + + + + - - + + - - - - + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1359,95 +1389,95 @@ - - - - - - - - - - + + + + + - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + - + + + + + + - - - + - - - - - - - - - + - - + + + + - + + + + + + + + + + + + + + + @@ -1565,7 +1595,7 @@ - + @@ -1594,25 +1624,18 @@ - - - - - - - + - + + + - - - + - @@ -1620,6 +1643,7 @@ + @@ -1627,902 +1651,919 @@ - + + + + - + - - - - + + - - + + - + + + - + - - - + + + - - - - + + + + + + + - - - - - - - + + + + - - - - - - + + + + - - - - - - + + + + + + + + - - - - - - - - - - + + + + + + + + - + + + + + - - - - - - - - + + + + - + + + + + + - - - - - - + + + - - + + - - - - - + + + + - - - - + + + + - - + + + + + - - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - + + - - - + + + + + + - - - - - - + + + + - - + + + + - - - - + - + + - - + - - - - - - - + + + + + + + - - - - - - - + + + + + + + + - + + + + - - - - - - - - - - - - - + + + + + + + + + + - - + - + - - - - - - + + + + + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - + + - + - - - - - + + - + + - - + + + + - + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - + + + - + - - - - - - - + + + + + + + + + - + - - - + + - - + - - - + + - - - - + - + + + + + + + + + + + - - - - - - - - + - + + + + + - + - - - - - - - - - - - - - - + + + + + + + + + + - - + + + - - - - - - + + + + + + - - - - - + - - + - - - - - - - - - - + + + + + + + + + + + + + + + + + - + - - - - - - - + + + + - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - + - + + - - - - - - - - - - - - + - - - + + + + + + + + + + + + + + + + + + - - + + + + - + + - - + + - - + - + - - + + - - - - - - - - - - - - - - - - - - + + - - - + - + - - + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - + + + + + + - + + + + + - - + + + + + - - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - + + - - + - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3120,88 +3161,124 @@ - + - + - - - + + + - + - - + + - - - + + + - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3419,7 +3496,7 @@ - + @@ -3429,512 +3506,525 @@ - + + - + - + - - - + + - - - - - + + + + + + - + - - - - - - - - - - - + + + + + + + + + + - - + + - - + + + - + - + - + - + - + - - + + - - - - - - - - - + + + + + + + + + - + - + - - + + - - + - - - + + + - - - - - - - - - - - + + + + + + + + + + + + - - - + + + - + - - - - - + + + + + - - - + + - + + - - - - - + + + + - - + + + - + - + - - - - + + + + - - + + - - - + + + - - - - + + + + - - - + + - - - - - - + + + + + + + - + - - - + + + - - + - - - - - - - + + + + + + + + - + - - - - - - + + - + - + + + + - + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + - - + - + - - + - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + + - - - - - - - + + + + + + + + + - - + - - - + + + + + + + + + + + + - - - - - - - - + + - - - - - - - - - - + + + + + + + + + - - - + + - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - - - - - - - - - - + + - + + + - - + - + + - - + + + + + - - - + - + + + - - - - + + - - - - - - - - - - + + + + + + + + + + - - + + - - - - - - + + + + + + + + - - + + + - - - - - - + + + + + + + + + + + + + + + + @@ -3973,7 +4063,7 @@ - + @@ -4066,7 +4156,7 @@ - + @@ -4129,10 +4219,10 @@ - - + - + + @@ -4197,54 +4287,54 @@ + + + - - - + + + - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + diff --git a/pyfixest/did/did.py b/pyfixest/did/did.py index f7e6a6ba..e8c40c85 100644 --- a/pyfixest/did/did.py +++ b/pyfixest/did/did.py @@ -1,6 +1,7 @@ from abc import ABC, abstractmethod from typing import Optional +import numpy as np import pandas as pd @@ -17,14 +18,12 @@ class DID(ABC): idname : str The name of the identifier variable. tname : str - Variable name for calendar period. Must be an integer in the format - YYYYMMDDHHMMSS, i.e. it must be possible to compare two dates via '>'. - Datetime variables are currently not accepted. + Variable name for calendar period. Must be a numeric (int or float) and + of the same data type as the gname variable. gname : str - unit-specific time of initial treatment. Must be an integer in the format - YYYYMMDDHHMMSS, i.e. it must be possible to compare two dates via '>'. - Datetime variables are currently not accepted. Never treated units must - have a value of 0. + unit-specific time of initial treatment. Must be an numeric (int or float) + and of the same data type as the tname variable. More concretely, needs to be + included in the values of tname. Values of 0 are considered as never treated. xfml : str The formula for the covariates. att : str @@ -66,9 +65,8 @@ def __init__( "float32", ]: raise ValueError( - f"""The variable {self._tname} must be of a numeric type, and more - specifically, in the format YYYYMMDDHHMMSS. I.e. either 2012, 2013, - etc. or 201201, 201202, 201203 etc.""" + f"""The variable {self._tname} must be of a numeric type, + but it is of type {self._data[self._tname].dtype}.""" ) if self._data[self._gname].dtype not in [ "int64", @@ -78,11 +76,31 @@ def __init__( "float32", ]: raise ValueError( - f"""The variable {self._tname} must be of a numeric type, and more - specifically, in the format YYYYMMDDHHMMSS. I.e. either 2012, 2013, - etc. or 201201, 201202, 201203 etc.""" + f"""The variable {self._tname} must be of a numeric type, but it is + of type {self._data[self._gname].dtype}. + """ ) + # check if gname is included in tname values + self._tname_unique = self._data[self._tname].unique() + self._gname_unique = self._data[self._gname].unique() + + if np.isin(0, self._tname_unique).any(): + raise ValueError( + f"""The value 0 was found in the 'tname' variable {self._tname}. + This value is reserved for never treated groups and cannot be used as a treatment period. + """ + ) + + allowed_g_values = [*self._tname_unique.tolist(), 0] + for gval in self._gname_unique: + if gval not in allowed_g_values: + raise ValueError( + f"""The variable {gval} was found in the 'gname' variable {self._gname} but not in 'tname' {self._tname}. + All values of 'gname' must be included in 'tname' or be equal to 0 (for never treated groups). + """ + ) + # create a treatment variable self._data["ATT"] = (self._data[self._tname] >= self._data[self._gname]) * ( self._data[self._gname] > 0 diff --git a/pyfixest/did/did2s.py b/pyfixest/did/did2s.py index 72c4b6af..595011df 100644 --- a/pyfixest/did/did2s.py +++ b/pyfixest/did/did2s.py @@ -28,14 +28,12 @@ class DID2S(DID): idname : str The name of the identifier variable. tname : str - Variable name for calendar period. Must be an integer in the format - YYYYMMDDHHMMSS, i.e. it must be possible to compare two dates via '>'. - Datetime variables are currently not accepted. + Variable name for calendar period. Must be numeric (ints or float). + Needs to be of the same data type as the gname variable. gname : str - unit-specific time of initial treatment. Must be an integer in the format - YYYYMMDDHHMMSS, i.e. it must be possible to compare two dates via '>'. - Datetime variables are currently not accepted. Never treated units - must have a value of 0. + unit-specific time of initial treatment. Must be numeric (ints or float). + Needs to be of the same data type as the tname variable. More concretely, + needs to be included in the values of tname. Values of 0 are considered as never treated. xfml : str The formula for the covariates. att : str diff --git a/pyfixest/did/lpdid.py b/pyfixest/did/lpdid.py index 3feb7e32..697ab27f 100644 --- a/pyfixest/did/lpdid.py +++ b/pyfixest/did/lpdid.py @@ -23,9 +23,12 @@ class LPDID(DID): idname : str The name of the identifier variable. tname : str - The name of the time variable. + The name of the time variable. Needs to be a numeric (int or float) and + of the same data type as the gname variable. gname : str - The name of the group variable. + The name of the group variable. Needs to be a numeric (int or float) and + of the same data type as the tname variable. More concretely, needs to be + included in the values of tname. Values of 0 are considered as never treated. xfml : str The transformation to apply to the data. att : str diff --git a/pyfixest/did/twfe.py b/pyfixest/did/twfe.py index eb4aa4c3..1aaf4650 100644 --- a/pyfixest/did/twfe.py +++ b/pyfixest/did/twfe.py @@ -23,14 +23,12 @@ class TWFE(DID): idname: str The name of the id variable. tname: str - Variable name for calendar period. Must be an integer in the format - YYYYMMDDHHMMSS, i.e. it must be possible to compare two dates via '>'. - Datetime variables are currently not accepted. + Variable name for calendar period. Must be a numeric (int or float) and + of the same data type as the gname variable. gname: str - Unit-specific time of initial treatment. Must be an integer in the format - YYYYMMDDHHMMSS, i.e. it must be possible to compare two dates via '>'. - Datetime variables are currently not accepted. Never treated units - must have a value of 0. + Unit-specific time of initial treatment. Must be an numeric (int or float) + and of the same data type as the tname variable. More concretely, needs to be + included in the values of tname. Values of 0 are considered as never treated. xfml: str The formula for the covariates. att: bool diff --git a/tests/test_errors.py b/tests/test_errors.py index fec8d865..e3299c68 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -720,3 +720,53 @@ def test_gelbach_errors(): pf.fepois("Y ~ X1", data=dt).decompose( param="X1", combine_covariates={"g1": ["x21"]} ) + + +def test_did_errors(): + df_het = pd.read_csv("pyfixest/did/data/df_het.csv") + df_het["g"][0] = 111111 + + # gname not in tname + with pytest.raises(ValueError): + pf.lpdid( + df_het, + yname="dep_var", + idname="unit", + tname="year", + gname="g", + vcov={"CRV1": "state"}, + pre_window=-20, + post_window=20, + att=False, + ) + + df_het.at[0, "g"] = 2010 + df_het.at[0, "year"] = 0 + + # 0 in tname (reserved for never treated) + with pytest.raises(ValueError): + pf.lpdid( + df_het, + yname="dep_var", + idname="unit", + tname="year", + gname="g", + vcov={"CRV1": "state"}, + pre_window=-20, + post_window=20, + att=False, + ) + + df_het.at[0, "year"] = 0.0 + with pytest.raises(ValueError): + pf.lpdid( + df_het, + yname="dep_var", + idname="unit", + tname="year", + gname="g", + vcov={"CRV1": "state"}, + pre_window=-20, + post_window=20, + att=False, + )