econmethods 0.0.1__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.
- econmethods-0.0.1/PKG-INFO +30 -0
- econmethods-0.0.1/README.md +10 -0
- econmethods-0.0.1/econmethods/__init__.py +1 -0
- econmethods-0.0.1/econmethods/econmethods.py +177 -0
- econmethods-0.0.1/econmethods.egg-info/PKG-INFO +30 -0
- econmethods-0.0.1/econmethods.egg-info/SOURCES.txt +9 -0
- econmethods-0.0.1/econmethods.egg-info/dependency_links.txt +1 -0
- econmethods-0.0.1/econmethods.egg-info/requires.txt +4 -0
- econmethods-0.0.1/econmethods.egg-info/top_level.txt +1 -0
- econmethods-0.0.1/setup.cfg +4 -0
- econmethods-0.0.1/setup.py +22 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: econmethods
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A python package implementing various econometrical tests and estimators
|
|
5
|
+
Home-page: https://github.com/NaturionBG/econmethods
|
|
6
|
+
Author: NaturionBG
|
|
7
|
+
Author-email: 7aegorsheryshev@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Requires-Dist: statsmodels>=0.14.5
|
|
10
|
+
Requires-Dist: numpy>=2.3.5
|
|
11
|
+
Requires-Dist: pandas>=2.3.3
|
|
12
|
+
Requires-Dist: scipy>=1.16.3
|
|
13
|
+
Dynamic: author
|
|
14
|
+
Dynamic: author-email
|
|
15
|
+
Dynamic: description
|
|
16
|
+
Dynamic: home-page
|
|
17
|
+
Dynamic: license
|
|
18
|
+
Dynamic: requires-dist
|
|
19
|
+
Dynamic: summary
|
|
20
|
+
|
|
21
|
+
* econmethods
|
|
22
|
+
|
|
23
|
+
A library made specifically for an econometrics project.
|
|
24
|
+
Contains implementations of various estimators and tests.
|
|
25
|
+
|
|
26
|
+
The library is not made by a professional, hence, the implemented methods may require a very scecific data struture.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
'''sh
|
|
30
|
+
pip install econmethods
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
* econmethods
|
|
2
|
+
|
|
3
|
+
A library made specifically for an econometrics project.
|
|
4
|
+
Contains implementations of various estimators and tests.
|
|
5
|
+
|
|
6
|
+
The library is not made by a professional, hence, the implemented methods may require a very scecific data struture.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
'''sh
|
|
10
|
+
pip install econmethods
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from econmethods import *
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import statsmodels.api as sm
|
|
4
|
+
from itertools import product
|
|
5
|
+
import scipy.stats as sc
|
|
6
|
+
from math import floor
|
|
7
|
+
|
|
8
|
+
class CipsTest:
|
|
9
|
+
'''
|
|
10
|
+
Implementation of the standard Cross-Sectionally Augmented Dickey-Fuller
|
|
11
|
+
precedure to test for non-stationarity I(1) in panel data. Works only with a linear trend.
|
|
12
|
+
----
|
|
13
|
+
The hypotheses are as follows:
|
|
14
|
+
- *H0*: The Target variable is I(1)
|
|
15
|
+
- *H1*: The Target variable is I(0)\n
|
|
16
|
+
PARAMETERS:
|
|
17
|
+
----------
|
|
18
|
+
------
|
|
19
|
+
- *df*: A standart Pandas DataFrame containing panelized data. \n
|
|
20
|
+
Ensure that the DataFrame contains the following columns in this exact order: \n
|
|
21
|
+
0 - a column of spatial units. Must contain homogenous data, e.g. only countries, companies, regions, etc. \n
|
|
22
|
+
1 - temporal column. Must contain homogenous data, e.g. only years, months, quarters, etc. \n
|
|
23
|
+
2 - target variable. Must not contain NaN Values. An Error will be raised otherwise. \n
|
|
24
|
+
|
|
25
|
+
- *T*: Your Temporal window. Will be used to determine the test critical value.
|
|
26
|
+
- *N*: Your Spatial window. Will be used to determine the test critical value.
|
|
27
|
+
|
|
28
|
+
- *trend*: State whether your ADF model has a trend or not. Will be used to determine the test critical value.
|
|
29
|
+
|
|
30
|
+
- *poly_trend*: State whether your target variable has a ditinct polynomial trend. \n
|
|
31
|
+
If a value bigger than 1 is entered, the test will detrend the target variable to get a robust result.
|
|
32
|
+
|
|
33
|
+
- *intercept*: State whether ADF model has an intercept or not. Will be used to determine the test critical value.
|
|
34
|
+
|
|
35
|
+
- *n_lags*: Determine the maximum amount of lags in the Augmented Dickey-Fuller regression.
|
|
36
|
+
the test will choose the best lag amount from 1 to n_lags based on AIC (Akaike Information Criterion)
|
|
37
|
+
|
|
38
|
+
- *level*: Value of significance to conduct the test at (in %%). Only 5 and 1% are allowed.
|
|
39
|
+
-----------------------------
|
|
40
|
+
RETURNS:
|
|
41
|
+
--
|
|
42
|
+
via instance.verdict() -> None: Prints the verdict of the test based on the parameters set by the user.
|
|
43
|
+
'''
|
|
44
|
+
def __init__(self, df: pd.DataFrame, T: int, N: int, trend: bool = False, poly_trend: int = 1, intercept: bool = False, n_lags: int = 2, level: int = 5) -> None:
|
|
45
|
+
CipsTest.__build_tables()
|
|
46
|
+
self.__df = df
|
|
47
|
+
self.__L = 1
|
|
48
|
+
self.__T = T
|
|
49
|
+
self.__N = N
|
|
50
|
+
self.__trend = trend
|
|
51
|
+
self.__C = intercept
|
|
52
|
+
self.__n_lags = n_lags
|
|
53
|
+
if self.__n_lags > floor(self.__T/5):
|
|
54
|
+
self.__n_lags = floor(self.__T/5)
|
|
55
|
+
if self.__n_lags < 1:
|
|
56
|
+
self.__n_lags = 1
|
|
57
|
+
self.__alpha = level/100
|
|
58
|
+
self.__df = self.__df.rename(columns={self.__df.columns[0]:'SpUnit', self.__df.columns[1]:'time', self.__df.columns[2]:'target'})
|
|
59
|
+
self.__df.target = np.log(self.__df.target)
|
|
60
|
+
self.__poly = poly_trend
|
|
61
|
+
if self.__trend:
|
|
62
|
+
if self.__poly > 1:
|
|
63
|
+
self.__df = self.detrend()
|
|
64
|
+
self.__trend = False
|
|
65
|
+
self.verify()
|
|
66
|
+
self.__table = self.get_table()
|
|
67
|
+
self.__CADF_Crit = self.get_critical_value()
|
|
68
|
+
self.__CADF = self.estimate()
|
|
69
|
+
|
|
70
|
+
def verify(self) -> None:
|
|
71
|
+
if self.__df.target.isnull().sum() > 0:
|
|
72
|
+
raise TypeError('Values in Target must NOT be NaN!')
|
|
73
|
+
if self.__alpha != 0.01 and self.__alpha != 0.05:
|
|
74
|
+
raise ValueError('The Significance Level must be either 1 or 5!')
|
|
75
|
+
if self.__poly < 1:
|
|
76
|
+
raise ValueError('The Polynomial Power Cannot be lesser than 1!')
|
|
77
|
+
|
|
78
|
+
@classmethod
|
|
79
|
+
def __build_tables(cls) -> None:
|
|
80
|
+
cls.NTNC_1P = pd.read_excel('CADF_Crit_Values.xlsx', sheet_name='NTNC_1P', index_col=0)
|
|
81
|
+
cls.NTNC_5P = pd.read_excel('CADF_Crit_Values.xlsx', sheet_name='NTNC_5P', index_col=0)
|
|
82
|
+
cls.NTC_1P = pd.read_excel('CADF_Crit_Values.xlsx', sheet_name='NTC_1P', index_col=0)
|
|
83
|
+
cls.NTC_5P = pd.read_excel('CADF_Crit_Values.xlsx', sheet_name='NTC_5P', index_col=0)
|
|
84
|
+
cls.TC_1P = pd.read_excel('CADF_Crit_Values.xlsx', sheet_name='TC_1P', index_col=0)
|
|
85
|
+
cls.TC_5P = pd.read_excel('CADF_Crit_Values.xlsx', sheet_name='TC_5P', index_col=0)
|
|
86
|
+
|
|
87
|
+
def get_table(self) -> pd.DataFrame:
|
|
88
|
+
if not self.__trend and not self.__C:
|
|
89
|
+
if self.__alpha == 0.01:
|
|
90
|
+
return CipsTest.NTNC_1P
|
|
91
|
+
else:
|
|
92
|
+
return CipsTest.NTNC_5P
|
|
93
|
+
if not self.__trend and self.__C:
|
|
94
|
+
if self.__alpha == 0.01:
|
|
95
|
+
return CipsTest.NTC_1P
|
|
96
|
+
else:
|
|
97
|
+
return CipsTest.NTC_5P
|
|
98
|
+
if self.__trend and self.__C:
|
|
99
|
+
if self.__alpha == 0.01:
|
|
100
|
+
return CipsTest.TC_1P
|
|
101
|
+
else:
|
|
102
|
+
return CipsTest.TC_5P
|
|
103
|
+
|
|
104
|
+
def get_critical_value(self) -> float:
|
|
105
|
+
dct = {}
|
|
106
|
+
for arr in product(self.__table.index, self.__table.index):
|
|
107
|
+
lst = np.array(arr)
|
|
108
|
+
dt = np.array([self.__T, self.__N])
|
|
109
|
+
dct[arr] = np.sqrt(np.sum((dt-lst)**2))
|
|
110
|
+
return self.__table.loc[min(dct, key=dct.get)]
|
|
111
|
+
|
|
112
|
+
def detrend(self) -> pd.DataFrame:
|
|
113
|
+
lst = []
|
|
114
|
+
for unit in self.__df.SpUnit.unique():
|
|
115
|
+
subdf = self.__df[self.__df.SpUnit == unit]
|
|
116
|
+
for i in range(1, self.__poly+1):
|
|
117
|
+
subdf.insert(3, f't^{i}', np.linspace(1, len(subdf), len(subdf))**i)
|
|
118
|
+
diff = subdf['target'].copy() - sm.OLS(subdf['target'], sm.add_constant(subdf.iloc[:, 3:])).fit().predict(sm.add_constant(subdf.iloc[:, 3:]))
|
|
119
|
+
subdf.loc[:, 'target'] = diff
|
|
120
|
+
lst.append(subdf.iloc[:, :3])
|
|
121
|
+
return pd.concat(lst, axis=0)
|
|
122
|
+
|
|
123
|
+
def build_regressions(self, lags: int) -> list[pd.DataFrame]:
|
|
124
|
+
lst = []
|
|
125
|
+
for unit in self.__df.SpUnit.unique():
|
|
126
|
+
subdf = self.__df[self.__df.SpUnit == unit]
|
|
127
|
+
if self.__trend:
|
|
128
|
+
subdf.insert(2, 't', np.linspace(1, len(subdf), len(subdf)))
|
|
129
|
+
subdf = pd.concat([subdf, subdf.target.shift(periods=range(1, lags+1))], axis=1)
|
|
130
|
+
subdf['cs_avg'] = self.__df.groupby(['time'])['target'].mean().values
|
|
131
|
+
subdf = pd.concat([subdf, subdf.cs_avg.shift(periods=range(1, lags+1))], axis=1)
|
|
132
|
+
subdf.insert(3, 'target_diff', subdf.target - subdf.target_1)
|
|
133
|
+
subdf['cs_avg_diff'] = subdf.cs_avg - subdf.cs_avg_1
|
|
134
|
+
subdf = pd.concat([subdf, subdf.cs_avg_diff.shift(periods=range(1, lags+1))], axis=1)
|
|
135
|
+
subdf = pd.concat([subdf, subdf.target_diff.shift(periods=range(1, lags+1))], axis=1)
|
|
136
|
+
if self.__trend:
|
|
137
|
+
base = ['target_diff', 't', 'target_1', 'cs_avg_1', 'cs_avg_diff']
|
|
138
|
+
else:
|
|
139
|
+
base = ['target_diff', 'target_1', 'cs_avg_1', 'cs_avg_diff']
|
|
140
|
+
additional = []
|
|
141
|
+
for i in range(1, lags+1):
|
|
142
|
+
additional.append(f'target_diff_{i}')
|
|
143
|
+
additional.append(f'cs_avg_diff_{i}')
|
|
144
|
+
subdf=(subdf.loc[:, base+additional]).iloc[self.__n_lags+1:, :]
|
|
145
|
+
lst.append(subdf)
|
|
146
|
+
return lst
|
|
147
|
+
|
|
148
|
+
def estimate(self) -> float:
|
|
149
|
+
CADF_stat = None
|
|
150
|
+
best_aic = np.inf
|
|
151
|
+
for l in range(1, self.__n_lags+1):
|
|
152
|
+
aic = []
|
|
153
|
+
lst1 = self.build_regressions(l)
|
|
154
|
+
CADF = []
|
|
155
|
+
for frame in lst1:
|
|
156
|
+
if self.__C:
|
|
157
|
+
res = sm.OLS(frame.iloc[:, 0], sm.add_constant(frame.iloc[:, 1:])).fit()
|
|
158
|
+
else:
|
|
159
|
+
res = sm.OLS(frame.iloc[:, 0], frame.iloc[:, 1:]).fit()
|
|
160
|
+
CADF.append(res.tvalues['target_1'])
|
|
161
|
+
aic.append(res.aic)
|
|
162
|
+
if len(np.unique(np.array(CADF))) != 1:
|
|
163
|
+
CADF = np.array(CADF).mean()
|
|
164
|
+
if np.array(aic).mean() < best_aic:
|
|
165
|
+
CADF_stat = CADF
|
|
166
|
+
best_aic = np.array(aic).mean()
|
|
167
|
+
self.__L = l
|
|
168
|
+
return CADF_stat
|
|
169
|
+
|
|
170
|
+
def verdict(self) -> None:
|
|
171
|
+
if self.__CADF < self.__CADF_Crit:
|
|
172
|
+
print(f'{self.__CADF} < {self.__CADF_Crit}\n Your target variable is I(0) according to the CIPS test\n Significance level : {self.__alpha*100}%. \n Selected lag amount: {self.__L}')
|
|
173
|
+
else:
|
|
174
|
+
print(f'{self.__CADF} > {self.__CADF_Crit}\n Your target variable is I(1) according to the CIPS test\n significance level: {self.__alpha*100}%. \n Selected lag amount: {self.__L}')
|
|
175
|
+
|
|
176
|
+
def __del__(self) -> None:
|
|
177
|
+
pass
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: econmethods
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A python package implementing various econometrical tests and estimators
|
|
5
|
+
Home-page: https://github.com/NaturionBG/econmethods
|
|
6
|
+
Author: NaturionBG
|
|
7
|
+
Author-email: 7aegorsheryshev@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Requires-Dist: statsmodels>=0.14.5
|
|
10
|
+
Requires-Dist: numpy>=2.3.5
|
|
11
|
+
Requires-Dist: pandas>=2.3.3
|
|
12
|
+
Requires-Dist: scipy>=1.16.3
|
|
13
|
+
Dynamic: author
|
|
14
|
+
Dynamic: author-email
|
|
15
|
+
Dynamic: description
|
|
16
|
+
Dynamic: home-page
|
|
17
|
+
Dynamic: license
|
|
18
|
+
Dynamic: requires-dist
|
|
19
|
+
Dynamic: summary
|
|
20
|
+
|
|
21
|
+
* econmethods
|
|
22
|
+
|
|
23
|
+
A library made specifically for an econometrics project.
|
|
24
|
+
Contains implementations of various estimators and tests.
|
|
25
|
+
|
|
26
|
+
The library is not made by a professional, hence, the implemented methods may require a very scecific data struture.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
'''sh
|
|
30
|
+
pip install econmethods
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
econmethods
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from setuptools import find_packages, setup
|
|
2
|
+
|
|
3
|
+
with open('README.md', 'r') as f:
|
|
4
|
+
long_desc = f.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name = 'econmethods',
|
|
8
|
+
version = '0.0.1',
|
|
9
|
+
description='A python package implementing various econometrical tests and estimators',
|
|
10
|
+
packages = find_packages(),
|
|
11
|
+
long_description=long_desc,
|
|
12
|
+
url = 'https://github.com/NaturionBG/econmethods',
|
|
13
|
+
author = 'NaturionBG',
|
|
14
|
+
author_email='7aegorsheryshev@gmail.com',
|
|
15
|
+
license='MIT',
|
|
16
|
+
install_requires=[
|
|
17
|
+
'statsmodels >= 0.14.5',
|
|
18
|
+
'numpy >= 2.3.5',
|
|
19
|
+
'pandas >= 2.3.3',
|
|
20
|
+
'scipy >= 1.16.3'
|
|
21
|
+
],
|
|
22
|
+
)
|