econmethods 3.0.5.6__tar.gz → 3.0.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: econmethods
3
- Version: 3.0.5.6
3
+ Version: 3.0.6
4
4
  Summary: A python package implementing various econometrical tests and estimators
5
5
  Home-page: https://github.com/NaturionBG/econmethods
6
6
  Author: NaturionBG
@@ -188,7 +188,7 @@ class CipsTest:
188
188
  pass
189
189
 
190
190
 
191
- class HausmanOneWay:
191
+ class Hausman:
192
192
  '''
193
193
  Implementation of the Hausman procedure to test whether it is more feasible to used random effects against fixed effects.
194
194
  -
@@ -217,68 +217,77 @@ class HausmanOneWay:
217
217
  - Via instance.verdict() prints the verdict of the Hausman test according to the given parameters.
218
218
  '''
219
219
  def __init__(self, data: pd.DataFrame, force_GLS: bool = False, level: int = 5) -> None:
220
- self.__df = data
221
- self.__exog = len(data.columns[3:])
222
- self.__l =[]
223
- self.__fgls = force_GLS
224
- for i in range(1, self.__exog+1):
225
- self.__l.append(f'x{i}')
226
- self.__df.columns = ['SpUnit', 'time', 'target'] + self.__l
227
- self.__alpha = level/100
228
- self.__RE = 'GLS'
229
- self.__T = len(self.__df.time.unique())
230
- self.__N = len(self.__df.SpUnit.unique())
231
-
232
-
220
+ self.__df = data
221
+ self.__exog = len(data.columns[3:])
222
+ self.__l = []
223
+ self.__fgls = force_GLS
224
+ for i in range(1, self.__exog+1):
225
+ self.__l.append(f'x{i}')
226
+ self.__df.columns = ['SpUnit', 'time', 'target'] + self.__l
227
+ self.__alpha = level/100
228
+ self.__RE = 'GLS'
229
+ self.__T = len(self.__df.time.unique())
230
+ self.__N = len(self.__df.SpUnit.unique())
231
+
233
232
  def build_FE(self) -> pd.DataFrame:
234
- fe = self.__df.copy(deep=True)
235
- for i, unit in enumerate(self.__df.SpUnit.unique()):
236
- fe.loc[:, f'd{i}'] = np.where(fe.SpUnit == unit, 1, 0)
237
- return fe.iloc[:, 2:]
238
-
239
- def build_GLS(self, w_err: float) -> pd.DataFrame | None:
240
- re = self.__df.groupby('SpUnit')[self.__df.columns[2:]].mean()
241
- temp = sm.OLS(re.iloc[:, 0], sm.add_constant(re.iloc[:, 1:])).fit()
242
- sigma2 = temp.ssr / temp.df_resid
243
- sigma_u = sigma2 - w_err/self.__T
244
- if sigma_u <= 0:
245
- sigma_u = 0
246
- elif sigma_u > 0:
247
- if not self.__fgls:
248
- self.__RE = 'REML'
249
- return None
250
- sig = np.full((self.__T, self.__T), sigma_u)
251
- np.fill_diagonal(sig, sigma_u+w_err)
252
- matrix = np.kron(np.eye(self.__N), sig)
253
- return matrix
254
-
255
-
256
-
233
+ fe = self.__df.copy(deep=True)
234
+ for i, unit in enumerate(self.__df.SpUnit.unique()):
235
+ fe.loc[:, f'd{i}'] = np.where(fe.SpUnit == unit, 1, 0)
236
+ return fe.iloc[:, 2:]
237
+
238
+ def build_GLS(self, w_err: float) -> np.ndarray | None:
239
+ re = self.__df.groupby('SpUnit')[self.__df.columns[2:]].mean()
240
+ temp = sm.OLS(re.iloc[:, 0], sm.add_constant(re.iloc[:, 1:])).fit()
241
+ sigma2 = temp.ssr / temp.df_resid
242
+ sigma_u = sigma2 - w_err / self.__T
243
+ if sigma_u <= 0:
244
+ sigma_u = 0
245
+ elif sigma_u > 0:
246
+ if not self.__fgls:
247
+ self.__RE = 'MLE'
248
+ return None
249
+ sig = np.full((self.__T, self.__T), sigma_u)
250
+ np.fill_diagonal(sig, sigma_u + w_err)
251
+ matrix = np.kron(np.eye(self.__N), sig)
252
+ return matrix
253
+
257
254
  def estimate(self) -> float:
258
255
  fe_df = self.build_FE()
259
- Chi = 0
260
256
  fe_res = sm.OLS(fe_df.iloc[:, 0], fe_df.iloc[:, 1:]).fit()
261
257
  matrix = self.build_GLS(fe_res.mse_resid)
262
258
  if matrix is not None:
263
- re_res = sm.GLS(self.__df.iloc[:, 2], sm.add_constant(self.__df.iloc[:, 3:]), matrix).fit()
259
+ re_res = sm.GLS(self.__df.iloc[:, 2], sm.add_constant(self.__df.iloc[:, 3:]), matrix).fit()
264
260
  else:
265
- re_res = sm.MixedLM(self.__df['target'], sm.add_constant(self.__df[self.__l]), groups=self.__df.SpUnit).fit(reml = True, maxiter=100_00)
266
- for b_fe, b_re, var_fe, var_re in zip(fe_res.params[1:], re_res.params[1:], fe_res.bse[1:]**2, re_res.bse[1:]**2):
267
- Chi += (b_fe - b_re)**2 / (var_fe - var_re)
268
-
269
- return Chi
270
-
271
- def verdict(self) -> None:
272
- Chi = self.estimate()
273
- ch2 = sc.chi2(self.__exog)
274
- p = ch2.sf(Chi)
275
- if p < self.__alpha:
276
- print(f'P-Value: {p} < Alpha: {self.__alpha}. \n According to the Hausman test, you should use the FE (Fixed Effects) model. \n RE estimator: {self.__RE}')
261
+ re_res = sm.MixedLM(self.__df['target'], sm.add_constant(self.__df[self.__l]), groups=self.__df.SpUnit).fit(reml=False, maxiter=100_00)
262
+ x_names = self.__l
263
+ fe_params = fe_res.params
264
+ fe_cov = fe_res.cov_params()
265
+ fe_params_x = fe_params[x_names]
266
+ fe_cov_x = fe_cov.loc[x_names, x_names].values
267
+ re_params = re_res.params
268
+ re_cov = re_res.cov_params()
269
+ if 'const' in re_params.index:
270
+ re_params_x = re_params[x_names]
271
+ re_cov_x = re_cov.loc[x_names, x_names].values
277
272
  else:
278
- print(f'P-Value: {p} > Alpha: {self.__alpha}. \n According to the Hausman test, you should use the RE (Random Effects) model. \n RE estimator: {self.__RE}')
279
-
280
- def __del__(self) -> None:
281
- pass
273
+ re_params_x = re_params[x_names]
274
+ re_cov_x = re_cov.loc[x_names, x_names].values
275
+ d = fe_params_x - re_params_x
276
+ V = fe_cov_x - re_cov_x
277
+ try:
278
+ chi2 = d.T @ np.linalg.inv(V) @ d
279
+ except np.linalg.LinAlgError:
280
+ chi2 = d.T @ np.linalg.pinv(V) @ d
281
+ return chi2
282
+
283
+ def verdict(self) -> None:
284
+ Chi = self.estimate()
285
+ ch2 = sc.chi2(self.__exog)
286
+ p = ch2.sf(Chi)
287
+ if p < self.__alpha:
288
+ print(f'P-Value: {p} < Alpha: {self.__alpha}. \n According to the Hausman test, you should use the FE (Fixed Effects) model. \n RE estimator: {self.__RE}')
289
+ else:
290
+ print(f'P-Value: {p} > Alpha: {self.__alpha}. \n According to the Hausman test, you should use the RE (Random Effects) model. \n RE estimator: {self.__RE}')
282
291
 
283
292
  class FECM:
284
293
  '''
@@ -649,7 +658,7 @@ class FECM:
649
658
  def __del__(self) -> None:
650
659
  pass
651
660
 
652
- class CDTwoWay:
661
+ class CDTest:
653
662
  '''
654
663
  Implementation of the CD test to validate/reject cross-sectional dependence.
655
664
  Hypotheses:
@@ -0,0 +1,3 @@
1
+ from .Lib import CipsTest, HausmanOneWay, FECM, CDTwoWay, SlopeHomogeneityF
2
+
3
+ __all__ = ['CipsTest', 'Hausman', 'FECM', 'CDTest', 'SlopeHomogeneityF']
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: econmethods
3
- Version: 3.0.5.6
3
+ Version: 3.0.6
4
4
  Summary: A python package implementing various econometrical tests and estimators
5
5
  Home-page: https://github.com/NaturionBG/econmethods
6
6
  Author: NaturionBG
@@ -5,7 +5,7 @@ with open('README.md', 'r') as f:
5
5
 
6
6
  setup(
7
7
  name = 'econmethods',
8
- version = 'v3.0.5.6',
8
+ version = 'v3.0.6',
9
9
  description='A python package implementing various econometrical tests and estimators',
10
10
  packages = find_packages(),
11
11
  long_description=long_desc,
@@ -1,3 +0,0 @@
1
- from .Lib import CipsTest, HausmanOneWay, FECM, CDTwoWay, SlopeHomogeneityF
2
-
3
- __all__ = ['CipsTest', 'HausmanOneWay', 'FECM', 'CDTwoWay', 'SlopeHomogeneityF']
File without changes
File without changes