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.
@@ -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,9 @@
1
+ README.md
2
+ setup.py
3
+ econmethods/__init__.py
4
+ econmethods/econmethods.py
5
+ econmethods.egg-info/PKG-INFO
6
+ econmethods.egg-info/SOURCES.txt
7
+ econmethods.egg-info/dependency_links.txt
8
+ econmethods.egg-info/requires.txt
9
+ econmethods.egg-info/top_level.txt
@@ -0,0 +1,4 @@
1
+ statsmodels>=0.14.5
2
+ numpy>=2.3.5
3
+ pandas>=2.3.3
4
+ scipy>=1.16.3
@@ -0,0 +1 @@
1
+ econmethods
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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
+ )