easyresearch 0.1.0__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.
Files changed (41) hide show
  1. easyresearch-0.1.0/LICENSE +21 -0
  2. easyresearch-0.1.0/PKG-INFO +198 -0
  3. easyresearch-0.1.0/README.md +161 -0
  4. easyresearch-0.1.0/pyproject.toml +49 -0
  5. easyresearch-0.1.0/setup.cfg +4 -0
  6. easyresearch-0.1.0/src/easyresearch/__init__.py +28 -0
  7. easyresearch-0.1.0/src/easyresearch/__main__.py +3 -0
  8. easyresearch-0.1.0/src/easyresearch/cli.py +165 -0
  9. easyresearch-0.1.0/src/easyresearch/common/__init__.py +1 -0
  10. easyresearch-0.1.0/src/easyresearch/common/hassanat.py +70 -0
  11. easyresearch-0.1.0/src/easyresearch/common/output.py +156 -0
  12. easyresearch-0.1.0/src/easyresearch/common/references.py +235 -0
  13. easyresearch-0.1.0/src/easyresearch/regression/__init__.py +12 -0
  14. easyresearch-0.1.0/src/easyresearch/regression/analysis.py +371 -0
  15. easyresearch-0.1.0/src/easyresearch/regression/data.py +114 -0
  16. easyresearch-0.1.0/src/easyresearch/regression/evaluation.py +298 -0
  17. easyresearch-0.1.0/src/easyresearch/regression/figures.py +190 -0
  18. easyresearch-0.1.0/src/easyresearch/regression/models.py +124 -0
  19. easyresearch-0.1.0/src/easyresearch/regression/report.py +316 -0
  20. easyresearch-0.1.0/src/easyresearch/timeseries/__init__.py +4 -0
  21. easyresearch-0.1.0/src/easyresearch/timeseries/classify.py +430 -0
  22. easyresearch-0.1.0/src/easyresearch/timeseries/data.py +224 -0
  23. easyresearch-0.1.0/src/easyresearch/timeseries/deep.py +208 -0
  24. easyresearch-0.1.0/src/easyresearch/timeseries/evaluation.py +242 -0
  25. easyresearch-0.1.0/src/easyresearch/timeseries/figures.py +209 -0
  26. easyresearch-0.1.0/src/easyresearch/timeseries/forecast.py +302 -0
  27. easyresearch-0.1.0/src/easyresearch/timeseries/models.py +257 -0
  28. easyresearch-0.1.0/src/easyresearch/timeseries/report.py +268 -0
  29. easyresearch-0.1.0/src/easyresearch/timeseries/signal_data.py +146 -0
  30. easyresearch-0.1.0/src/easyresearch/timeseries/signal_models.py +379 -0
  31. easyresearch-0.1.0/src/easyresearch.egg-info/PKG-INFO +198 -0
  32. easyresearch-0.1.0/src/easyresearch.egg-info/SOURCES.txt +39 -0
  33. easyresearch-0.1.0/src/easyresearch.egg-info/dependency_links.txt +1 -0
  34. easyresearch-0.1.0/src/easyresearch.egg-info/entry_points.txt +2 -0
  35. easyresearch-0.1.0/src/easyresearch.egg-info/requires.txt +16 -0
  36. easyresearch-0.1.0/src/easyresearch.egg-info/top_level.txt +1 -0
  37. easyresearch-0.1.0/tests/test_evaluation_integrity.py +226 -0
  38. easyresearch-0.1.0/tests/test_models_save.py +64 -0
  39. easyresearch-0.1.0/tests/test_research_references.py +54 -0
  40. easyresearch-0.1.0/tests/test_signals_and_regression.py +125 -0
  41. easyresearch-0.1.0/tests/test_timeseries.py +160 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ahmad Hassanat
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,198 @@
1
+ Metadata-Version: 2.4
2
+ Name: easyresearch
3
+ Version: 0.1.0
4
+ Summary: Machine learning without programming: regression, time-series forecasting and signal classification cores, with honest evaluation and plain-language reports.
5
+ Author-email: Ahmad Hassanat <ahmad.hassanat@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/ahmadhassant/easyresearch
8
+ Project-URL: Issues, https://github.com/ahmadhassant/easyresearch/issues
9
+ Project-URL: Changelog, https://github.com/ahmadhassant/easyresearch/blob/main/CHANGELOG.md
10
+ Keywords: machine learning,regression,forecasting,time series,no-code
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Operating System :: OS Independent
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: easyclassifier<0.9,>=0.8.2
23
+ Requires-Dist: pandas>=1.5
24
+ Requires-Dist: numpy>=1.23
25
+ Requires-Dist: scikit-learn>=1.2
26
+ Requires-Dist: matplotlib>=3.6
27
+ Requires-Dist: joblib>=1.1
28
+ Requires-Dist: openpyxl>=3.0.10
29
+ Requires-Dist: statsmodels>=0.14
30
+ Requires-Dist: torch>=2.2
31
+ Provides-Extra: full
32
+ Requires-Dist: xgboost>=2; extra == "full"
33
+ Requires-Dist: lightgbm>=4; extra == "full"
34
+ Provides-Extra: test
35
+ Requires-Dist: pytest>=7; extra == "test"
36
+ Dynamic: license-file
37
+
38
+ # EasyResearch
39
+
40
+ [![tests](https://github.com/ahmadhassant/easyresearch/actions/workflows/tests.yml/badge.svg)](https://github.com/ahmadhassant/easyresearch/actions/workflows/tests.yml)
41
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/ahmadhassant/easyresearch/blob/main/LICENSE)
42
+
43
+ Machine learning without programming: analysis cores for researchers who do
44
+ not code. They follow the rules of
45
+ [EasyClassifier](https://github.com/ahmadhassant/easyclassifier):
46
+
47
+ * every step that learns from data uses training data only;
48
+ * models use their authors' default settings with fixed random seeds (no
49
+ tuning), so results are reproducible;
50
+ * when several models are compared, the selected one gets a separate,
51
+ honest final score;
52
+ * every run writes a plain-language report with a Methods paragraph,
53
+ figures, tables, predictions, the trained model, citations and a log.
54
+
55
+ The cores have no user interaction (settings in, results out), so a terminal
56
+ wizard, the desktop application or a web server can all drive them.
57
+
58
+ This repository holds:
59
+
60
+ | Folder | What it is |
61
+ |---|---|
62
+ | `src/easyresearch`, `tests` | the analysis cores and their tests (`pip install easyresearch`) |
63
+ | `desktop` | **EasyResearch Desktop**, a Windows application that runs classification, regression, forecasting and signal classification without code ([README](https://github.com/ahmadhassant/easyresearch/blob/main/desktop/README.md)) |
64
+ | `benchmarks` | correctness and honesty benchmarks, with all results |
65
+ | `docs` | development guide, release plan, publishing steps |
66
+ | `papers` | the EasyResearch paper |
67
+
68
+ | Core | Task | Status |
69
+ |---|---|---|
70
+ | Classification | predict a category from a table | EasyClassifier 0.8.2 |
71
+ | `easyresearch.regression` | predict a number from a table | ready |
72
+ | `easyresearch.timeseries` – forecasting | forecast one series | ready |
73
+ | `easyresearch.timeseries` – signals | classify recordings (ECG, EEG, sensors) | ready (one channel) |
74
+
75
+ ## Install and run
76
+
77
+ **Windows, without Python:** download `EasyResearchDesktop-0.1.0-setup.exe`
78
+ from the [Releases page](https://github.com/ahmadhassant/easyresearch/releases)
79
+ and run it. It installs EasyResearch Desktop with its own Python and every
80
+ package it needs; no administrator rights are required. Windows may show
81
+ "Windows protected your PC" because the program is not code-signed: choose
82
+ **More info**, then **Run anyway**.
83
+
84
+ **Python (any system):**
85
+
86
+ ```bash
87
+ pip install easyresearch # installs EasyClassifier, PyTorch and statsmodels
88
+ easyresearch forecast --demo
89
+ easyresearch forecast sales.csv --value Sales --horizon 12
90
+ easyresearch regress houses.xlsx --target Price
91
+ easyresearch signals ECG200_TRAIN.tsv
92
+ easyresearch models forecast # list models; * = default fast set
93
+ ```
94
+
95
+ Add `--models all`, or a list such as `--models ets,lstm,nbeats`, to choose
96
+ models. Results go to a new folder in `./Results` (or `--out`). Deep models
97
+ use a GPU automatically when PyTorch finds one.
98
+
99
+ Figures: `--figures residuals,comparison` draws only the named figures (the
100
+ default is the task's usual set), `--figure-theme` chooses colour-blind safe
101
+ (default), greyscale or high-contrast colours, and `--figure-format png+pdf`
102
+ or `png+svg` adds vector files for journals.
103
+
104
+ ## Forecasting
105
+
106
+ * **Data:** a CSV/Excel table with a date column (detected automatically)
107
+ and the value to forecast. Hourly, daily, business-daily, weekly, monthly,
108
+ quarterly and yearly series are recognised; the season length follows
109
+ (24, 7, 5, 52, 12, 4, none). Repeated time points are averaged; missing
110
+ points are filled with the **last known value** (never a later one).
111
+ Without a date column, rows are taken in order with no season.
112
+ * **Models:** reference rules (naive, seasonal naive) are always included.
113
+ Statistical: exponential smoothing (damped trend, seasonal) and Theta.
114
+ Machine learning on the last *L* values: Ridge, Random Forest, Gradient
115
+ Boosting, KNN with the Hassanat distance. Deep (PyTorch): MLP, LSTM, GRU,
116
+ TCN, N-BEATS, Transformer. Default set: ETS, Theta, Ridge, Random Forest
117
+ (deep models are optional because each takes minutes).
118
+ * **Honest evaluation:** never shuffled. Models are compared at up to five
119
+ rolling origins before a final period (the last ~20%); the selected model
120
+ is then scored in the final period, which played no part in choosing it,
121
+ retrained before each origin. The automatic horizon is the usual one for
122
+ the time unit, shortened (with a note) when the series is too short to
123
+ evaluate it honestly; a series too short for any horizon is refused with
124
+ the number of values it needs.
125
+ * **Measures:** MASE (used to choose, by default), MAE, RMSE, sMAPE and
126
+ **MHSP** (mean Hassanat similarity percentage) – any of MASE, RMSE, MAE or
127
+ MHSP can choose the model (`--metric mhsp`).
128
+ * **Outputs:** the future forecast with an 80% band (its coverage in the
129
+ final period is checked and reported), final-period forecasts, comparison
130
+ table, five figures, report, trained model, `settings.json` (what was
131
+ asked and what was used) and `versions.txt` (the software used).
132
+
133
+ ### MHSP
134
+
135
+ For each prediction, the Hassanat similarity between actual *a* and
136
+ forecast *f* is (1 + min(a, f)) / (1 + max(a, f)), with the signed form
137
+ (1 + min + |min|) / (1 + max + |min|) when the smaller value is negative.
138
+ MHSP is 100 × the mean of these similarities (100% = perfect), computed on
139
+ the values as they are. It is also reported by the regression core. Reference:
140
+ Hassanat, A. B., et al. (2024). A novel outlier-robust accuracy measure for
141
+ machine learning regression using a non-convex distance metric. *Mathematics*,
142
+ 12(22), 3623. https://doi.org/10.3390/math12223623
143
+
144
+ ## Signal classification (ECG, EEG, sensors)
145
+
146
+ * **Data:** one recording per row – a CSV/Excel table with a label column and
147
+ the signal values in the other numeric columns, or UCR/UEA archive files
148
+ (`.tsv`/`.txt`, label first). Gaps inside a recording are filled from its
149
+ own neighbouring values.
150
+ * **Models:** KNN with the Hassanat distance (each recording scaled to 0–1),
151
+ ROCKET (10,000 random convolution kernels), signal features + Random
152
+ Forest, and deep FCN, ResNet, InceptionTime and LSTM.
153
+ * **Evaluation:** EasyClassifier's own – stratified cross-validation to
154
+ compare; nested cross-validation for the final score (up to 2,000
155
+ recordings, without deep networks) or an untouched stratified 20% test set
156
+ (larger data, or when deep networks are compared, because they take
157
+ minutes each on a normal computer).
158
+ * The demo (`--demo`) uses **synthetic** heartbeats for trying the tool; it
159
+ is not patient data.
160
+ * Not yet: several channels per recording (multichannel EEG) and long
161
+ recordings to be cut into windows.
162
+
163
+ ## Regression
164
+
165
+ See the EasyResearch Desktop README for details: linear and ridge regression,
166
+ decision tree, random forest, gradient boosting, SVR, KNN with the Hassanat
167
+ distance and a neural network; R², RMSE, MAE, median absolute error, MAPE
168
+ and MHSP against the reference of always predicting the average.
169
+ XGBoost and LightGBM are added when installed (`pip install -e ".[full]"`).
170
+
171
+ ## Development
172
+
173
+ ```bash
174
+ pip install -e ".[test]"
175
+ python -m pytest tests
176
+ ```
177
+
178
+ From the repository root, `python tools/run_all_tests.py` runs every suite
179
+ (these cores and the desktop adapters); see `docs/DEVELOPMENT.md`.
180
+ `benchmarks/easyresearch_benchmarks.py` measures accuracy, run time, memory
181
+ and agreement with reference implementations, and
182
+ `benchmarks/easyresearch_honesty.py` measures whether the reported scores are
183
+ honest, against data that is never touched (results in
184
+ `benchmarks/results/easyresearch_honesty`).
185
+
186
+ The tests include a check that no forecasting model – statistical, machine
187
+ learning or deep – changes its forecast when every value after the forecast
188
+ origin is changed.
189
+
190
+ ## Citing
191
+
192
+ If you use EasyResearch in published work, please cite it (GitHub's "Cite
193
+ this repository" button uses `CITATION.cff`); every run also writes the exact
194
+ references for the methods it used to `citations.txt`.
195
+
196
+ ## Licence
197
+
198
+ MIT. Ahmad Hassanat.
@@ -0,0 +1,161 @@
1
+ # EasyResearch
2
+
3
+ [![tests](https://github.com/ahmadhassant/easyresearch/actions/workflows/tests.yml/badge.svg)](https://github.com/ahmadhassant/easyresearch/actions/workflows/tests.yml)
4
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/ahmadhassant/easyresearch/blob/main/LICENSE)
5
+
6
+ Machine learning without programming: analysis cores for researchers who do
7
+ not code. They follow the rules of
8
+ [EasyClassifier](https://github.com/ahmadhassant/easyclassifier):
9
+
10
+ * every step that learns from data uses training data only;
11
+ * models use their authors' default settings with fixed random seeds (no
12
+ tuning), so results are reproducible;
13
+ * when several models are compared, the selected one gets a separate,
14
+ honest final score;
15
+ * every run writes a plain-language report with a Methods paragraph,
16
+ figures, tables, predictions, the trained model, citations and a log.
17
+
18
+ The cores have no user interaction (settings in, results out), so a terminal
19
+ wizard, the desktop application or a web server can all drive them.
20
+
21
+ This repository holds:
22
+
23
+ | Folder | What it is |
24
+ |---|---|
25
+ | `src/easyresearch`, `tests` | the analysis cores and their tests (`pip install easyresearch`) |
26
+ | `desktop` | **EasyResearch Desktop**, a Windows application that runs classification, regression, forecasting and signal classification without code ([README](https://github.com/ahmadhassant/easyresearch/blob/main/desktop/README.md)) |
27
+ | `benchmarks` | correctness and honesty benchmarks, with all results |
28
+ | `docs` | development guide, release plan, publishing steps |
29
+ | `papers` | the EasyResearch paper |
30
+
31
+ | Core | Task | Status |
32
+ |---|---|---|
33
+ | Classification | predict a category from a table | EasyClassifier 0.8.2 |
34
+ | `easyresearch.regression` | predict a number from a table | ready |
35
+ | `easyresearch.timeseries` – forecasting | forecast one series | ready |
36
+ | `easyresearch.timeseries` – signals | classify recordings (ECG, EEG, sensors) | ready (one channel) |
37
+
38
+ ## Install and run
39
+
40
+ **Windows, without Python:** download `EasyResearchDesktop-0.1.0-setup.exe`
41
+ from the [Releases page](https://github.com/ahmadhassant/easyresearch/releases)
42
+ and run it. It installs EasyResearch Desktop with its own Python and every
43
+ package it needs; no administrator rights are required. Windows may show
44
+ "Windows protected your PC" because the program is not code-signed: choose
45
+ **More info**, then **Run anyway**.
46
+
47
+ **Python (any system):**
48
+
49
+ ```bash
50
+ pip install easyresearch # installs EasyClassifier, PyTorch and statsmodels
51
+ easyresearch forecast --demo
52
+ easyresearch forecast sales.csv --value Sales --horizon 12
53
+ easyresearch regress houses.xlsx --target Price
54
+ easyresearch signals ECG200_TRAIN.tsv
55
+ easyresearch models forecast # list models; * = default fast set
56
+ ```
57
+
58
+ Add `--models all`, or a list such as `--models ets,lstm,nbeats`, to choose
59
+ models. Results go to a new folder in `./Results` (or `--out`). Deep models
60
+ use a GPU automatically when PyTorch finds one.
61
+
62
+ Figures: `--figures residuals,comparison` draws only the named figures (the
63
+ default is the task's usual set), `--figure-theme` chooses colour-blind safe
64
+ (default), greyscale or high-contrast colours, and `--figure-format png+pdf`
65
+ or `png+svg` adds vector files for journals.
66
+
67
+ ## Forecasting
68
+
69
+ * **Data:** a CSV/Excel table with a date column (detected automatically)
70
+ and the value to forecast. Hourly, daily, business-daily, weekly, monthly,
71
+ quarterly and yearly series are recognised; the season length follows
72
+ (24, 7, 5, 52, 12, 4, none). Repeated time points are averaged; missing
73
+ points are filled with the **last known value** (never a later one).
74
+ Without a date column, rows are taken in order with no season.
75
+ * **Models:** reference rules (naive, seasonal naive) are always included.
76
+ Statistical: exponential smoothing (damped trend, seasonal) and Theta.
77
+ Machine learning on the last *L* values: Ridge, Random Forest, Gradient
78
+ Boosting, KNN with the Hassanat distance. Deep (PyTorch): MLP, LSTM, GRU,
79
+ TCN, N-BEATS, Transformer. Default set: ETS, Theta, Ridge, Random Forest
80
+ (deep models are optional because each takes minutes).
81
+ * **Honest evaluation:** never shuffled. Models are compared at up to five
82
+ rolling origins before a final period (the last ~20%); the selected model
83
+ is then scored in the final period, which played no part in choosing it,
84
+ retrained before each origin. The automatic horizon is the usual one for
85
+ the time unit, shortened (with a note) when the series is too short to
86
+ evaluate it honestly; a series too short for any horizon is refused with
87
+ the number of values it needs.
88
+ * **Measures:** MASE (used to choose, by default), MAE, RMSE, sMAPE and
89
+ **MHSP** (mean Hassanat similarity percentage) – any of MASE, RMSE, MAE or
90
+ MHSP can choose the model (`--metric mhsp`).
91
+ * **Outputs:** the future forecast with an 80% band (its coverage in the
92
+ final period is checked and reported), final-period forecasts, comparison
93
+ table, five figures, report, trained model, `settings.json` (what was
94
+ asked and what was used) and `versions.txt` (the software used).
95
+
96
+ ### MHSP
97
+
98
+ For each prediction, the Hassanat similarity between actual *a* and
99
+ forecast *f* is (1 + min(a, f)) / (1 + max(a, f)), with the signed form
100
+ (1 + min + |min|) / (1 + max + |min|) when the smaller value is negative.
101
+ MHSP is 100 × the mean of these similarities (100% = perfect), computed on
102
+ the values as they are. It is also reported by the regression core. Reference:
103
+ Hassanat, A. B., et al. (2024). A novel outlier-robust accuracy measure for
104
+ machine learning regression using a non-convex distance metric. *Mathematics*,
105
+ 12(22), 3623. https://doi.org/10.3390/math12223623
106
+
107
+ ## Signal classification (ECG, EEG, sensors)
108
+
109
+ * **Data:** one recording per row – a CSV/Excel table with a label column and
110
+ the signal values in the other numeric columns, or UCR/UEA archive files
111
+ (`.tsv`/`.txt`, label first). Gaps inside a recording are filled from its
112
+ own neighbouring values.
113
+ * **Models:** KNN with the Hassanat distance (each recording scaled to 0–1),
114
+ ROCKET (10,000 random convolution kernels), signal features + Random
115
+ Forest, and deep FCN, ResNet, InceptionTime and LSTM.
116
+ * **Evaluation:** EasyClassifier's own – stratified cross-validation to
117
+ compare; nested cross-validation for the final score (up to 2,000
118
+ recordings, without deep networks) or an untouched stratified 20% test set
119
+ (larger data, or when deep networks are compared, because they take
120
+ minutes each on a normal computer).
121
+ * The demo (`--demo`) uses **synthetic** heartbeats for trying the tool; it
122
+ is not patient data.
123
+ * Not yet: several channels per recording (multichannel EEG) and long
124
+ recordings to be cut into windows.
125
+
126
+ ## Regression
127
+
128
+ See the EasyResearch Desktop README for details: linear and ridge regression,
129
+ decision tree, random forest, gradient boosting, SVR, KNN with the Hassanat
130
+ distance and a neural network; R², RMSE, MAE, median absolute error, MAPE
131
+ and MHSP against the reference of always predicting the average.
132
+ XGBoost and LightGBM are added when installed (`pip install -e ".[full]"`).
133
+
134
+ ## Development
135
+
136
+ ```bash
137
+ pip install -e ".[test]"
138
+ python -m pytest tests
139
+ ```
140
+
141
+ From the repository root, `python tools/run_all_tests.py` runs every suite
142
+ (these cores and the desktop adapters); see `docs/DEVELOPMENT.md`.
143
+ `benchmarks/easyresearch_benchmarks.py` measures accuracy, run time, memory
144
+ and agreement with reference implementations, and
145
+ `benchmarks/easyresearch_honesty.py` measures whether the reported scores are
146
+ honest, against data that is never touched (results in
147
+ `benchmarks/results/easyresearch_honesty`).
148
+
149
+ The tests include a check that no forecasting model – statistical, machine
150
+ learning or deep – changes its forecast when every value after the forecast
151
+ origin is changed.
152
+
153
+ ## Citing
154
+
155
+ If you use EasyResearch in published work, please cite it (GitHub's "Cite
156
+ this repository" button uses `CITATION.cff`); every run also writes the exact
157
+ references for the methods it used to `citations.txt`.
158
+
159
+ ## Licence
160
+
161
+ MIT. Ahmad Hassanat.
@@ -0,0 +1,49 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "easyresearch"
7
+ version = "0.1.0"
8
+ description = "Machine learning without programming: regression, time-series forecasting and signal classification cores, with honest evaluation and plain-language reports."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ authors = [{ name = "Ahmad Hassanat", email = "ahmad.hassanat@gmail.com" }]
13
+ keywords = ["machine learning", "regression", "forecasting", "time series", "no-code"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Science/Research",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Operating System :: OS Independent",
23
+ ]
24
+ dependencies = [
25
+ "easyclassifier>=0.8.2,<0.9",
26
+ "pandas>=1.5",
27
+ "numpy>=1.23",
28
+ "scikit-learn>=1.2",
29
+ "matplotlib>=3.6",
30
+ "joblib>=1.1",
31
+ "openpyxl>=3.0.10",
32
+ "statsmodels>=0.14",
33
+ "torch>=2.2",
34
+ ]
35
+
36
+ [project.optional-dependencies]
37
+ full = ["xgboost>=2", "lightgbm>=4"]
38
+ test = ["pytest>=7"]
39
+
40
+ [project.urls]
41
+ Homepage = "https://github.com/ahmadhassant/easyresearch"
42
+ Issues = "https://github.com/ahmadhassant/easyresearch/issues"
43
+ Changelog = "https://github.com/ahmadhassant/easyresearch/blob/main/CHANGELOG.md"
44
+
45
+ [project.scripts]
46
+ easyresearch = "easyresearch.cli:main"
47
+
48
+ [tool.setuptools.packages.find]
49
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,28 @@
1
+ """EasyResearch - machine learning without programming.
2
+
3
+ Analysis cores that share EasyClassifier's rules (leakage-free preparation,
4
+ default parameters with fixed seeds, honest final scores, plain-language
5
+ reports):
6
+
7
+ * ``easyresearch.regression`` - predict a number from a table
8
+ * ``easyresearch.timeseries`` - forecast a series; classify recordings
9
+ (ECG, EEG, sensor signals)
10
+ * classification is provided by the EasyClassifier package (0.8.2)
11
+
12
+ The cores have no user interaction: settings go in, results and files come
13
+ out, so a terminal wizard, the desktop application or a web server can drive
14
+ them in the same way.
15
+ """
16
+
17
+ __version__ = "0.1.0"
18
+ __author__ = "Ahmad Hassanat"
19
+
20
+ CITATION = (
21
+ "Hassanat, A. B. A. (2026). EasyResearch: Machine Learning without "
22
+ "Programming (Version {version}) [Software]. "
23
+ "https://github.com/ahmadhassant/easyresearch".format(version=__version__)
24
+ )
25
+ EASYCLASSIFIER_CITATION = (
26
+ "Hassanat, A. B. A. (2026). EasyClassifier: Machine Learning without "
27
+ "Programming (Version 0.8.2) [Software]. Zenodo. "
28
+ "https://doi.org/10.5281/zenodo.23122901")
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())
@@ -0,0 +1,165 @@
1
+ """Command line for the EasyResearch cores (no programming needed beyond one
2
+ command). Examples::
3
+
4
+ easyresearch forecast sales.csv --value Sales --horizon 12
5
+ easyresearch forecast --demo
6
+ easyresearch regress houses.xlsx --target Price
7
+ easyresearch signals ECG200_TRAIN.tsv --label label
8
+ easyresearch models forecast # list the available models
9
+ easyresearch regress --demo --figures residuals,comparison --figure-format png+pdf
10
+
11
+ Results are written to a new folder inside ./Results (or --out).
12
+ A terminal wizard and the desktop/web interfaces will drive the same cores.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import argparse
18
+ import os
19
+ import sys
20
+ from pathlib import Path
21
+
22
+ from . import __version__
23
+
24
+
25
+ def _models(arg, registry):
26
+ if not arg:
27
+ return None
28
+ if arg == "all":
29
+ return [k for k, s in registry.items() if getattr(s, "available", True)]
30
+ return [m.strip() for m in arg.split(",") if m.strip()]
31
+
32
+
33
+ def _figure_settings(st, a):
34
+ """Figure colours, file formats and the figures to draw (default: the
35
+ task's usual set)."""
36
+ st.figure_theme, st.figure_format = a.figure_theme, a.figure_format
37
+ if a.figures:
38
+ st.figure_keys = [k.strip() for k in a.figures.split(",") if k.strip()]
39
+ return st
40
+
41
+
42
+ def main(argv=None) -> int:
43
+ from easyclassifier.figures import DEFAULT_THEME, FORMATS, THEMES
44
+ p = argparse.ArgumentParser(prog="easyresearch",
45
+ description="Machine learning without "
46
+ "programming - analysis cores.")
47
+ p.add_argument("--version", action="version",
48
+ version=f"EasyResearch {__version__}")
49
+ sub = p.add_subparsers(dest="task", required=True)
50
+
51
+ for name, help_ in (("forecast", "forecast one time series"),
52
+ ("regress", "predict a number from a table"),
53
+ ("signals", "classify recordings (ECG, EEG, ...)")):
54
+ s = sub.add_parser(name, help=help_)
55
+ s.add_argument("data", nargs="?", help="CSV, Excel or UCR .tsv file")
56
+ s.add_argument("--demo", action="store_true",
57
+ help="use the built-in example data")
58
+ s.add_argument("--models", help="comma-separated model ids, or 'all'"
59
+ " (default: the fast set)")
60
+ s.add_argument("--out", default=".", help="folder for Results/")
61
+ s.add_argument("--no-figures", action="store_true")
62
+ s.add_argument("--figures", help="comma-separated figure names "
63
+ "(default: the usual set; see the report's list)")
64
+ s.add_argument("--figure-theme", default=DEFAULT_THEME,
65
+ choices=list(THEMES), help="figure colours")
66
+ s.add_argument("--figure-format", default="png", choices=list(FORMATS),
67
+ help="figure files: png, png+pdf or png+svg")
68
+ if name == "forecast":
69
+ s.add_argument("--value", help="column to forecast")
70
+ s.add_argument("--time", help="date/time column (auto-detected)")
71
+ s.add_argument("--horizon", default="auto",
72
+ help="steps ahead (default: automatic)")
73
+ s.add_argument("--metric", default="mase",
74
+ choices=["mase", "rmse", "mae", "mhsp"],
75
+ help="measure used to choose the model")
76
+ elif name == "regress":
77
+ s.add_argument("--target", help="numeric column to predict")
78
+ else:
79
+ s.add_argument("--label", help="column holding the class")
80
+ lm = sub.add_parser("models", help="list the models of a task")
81
+ lm.add_argument("which", choices=["forecast", "regress", "signals"])
82
+ a = p.parse_args(argv)
83
+
84
+ if a.task == "models":
85
+ if a.which == "forecast":
86
+ from .timeseries.models import build_registry
87
+ elif a.which == "regress":
88
+ from .regression.models import build_registry
89
+ else:
90
+ from .timeseries.signal_models import build_registry
91
+ for k, s in build_registry().items():
92
+ mark = "*" if getattr(s, "default_selected", False) else " "
93
+ print(f" {mark} {k:20s} {s.name}")
94
+ print("\n * = in the default (fast) set")
95
+ return 0
96
+
97
+ if not a.demo and not a.data:
98
+ p.error("give a data file or --demo")
99
+ out = os.path.abspath(a.out)
100
+ try:
101
+ if a.task == "forecast":
102
+ from .timeseries import ForecastSettings, run_forecast
103
+ from .timeseries import data as td
104
+ from .timeseries.models import build_registry
105
+ df = td.load_demo() if a.demo else _load(a.data)
106
+ value = a.value or ("CO2_ppm" if a.demo else td.suggest_value(df))
107
+ st = ForecastSettings(time_column=a.time, figures=not a.no_figures,
108
+ selection_metric=a.metric,
109
+ horizon=a.horizon if a.horizon == "auto"
110
+ else int(a.horizon))
111
+ st.models = _models(a.models, build_registry()) or st.models
112
+ _figure_settings(st, a)
113
+ r = run_forecast(df, value, st, out,
114
+ td.DEMO_NAME if a.demo else Path(a.data).name,
115
+ "demo_co2" if a.demo else Path(a.data).stem,
116
+ td.DEMO_CITATION if a.demo else "")
117
+ head = f"Selected: {r['best'].name}"
118
+ elif a.task == "regress":
119
+ from .regression import Settings, run_analysis
120
+ from .regression import data as rd
121
+ from .regression.models import build_registry
122
+ df = rd.load_demo() if a.demo else _load(a.data)
123
+ target = a.target or rd.suggest_target(df)
124
+ reg = build_registry()
125
+ models = _models(a.models, reg) or [
126
+ k for k, s in reg.items() if s.default_selected]
127
+ st = _figure_settings(Settings(models=models,
128
+ figures=not a.no_figures), a)
129
+ r = run_analysis(df, target, st, out, rd.DEMO_NAME if a.demo else
130
+ Path(a.data).name, "demo_diabetes" if a.demo
131
+ else Path(a.data).stem,
132
+ rd.DEMO_CITATION if a.demo else "")
133
+ head = f"Selected: {r['best'].name}"
134
+ else:
135
+ from .timeseries import signal_data as sd
136
+ from .timeseries.classify import (SignalSettings,
137
+ run_signal_classification)
138
+ from .timeseries.signal_models import build_registry
139
+ df = sd.load_demo() if a.demo else sd.load_table(a.data)
140
+ label = a.label or sd.suggest_label(df)
141
+ st = SignalSettings(figures=not a.no_figures)
142
+ st.models = _models(a.models, build_registry()) or st.models
143
+ _figure_settings(st, a)
144
+ r = run_signal_classification(
145
+ df, label, st, out, sd.DEMO_NAME if a.demo else
146
+ Path(a.data).name, "demo_heartbeats" if a.demo
147
+ else Path(a.data).stem)
148
+ head = f"Selected: {r['best'].classifier_name}"
149
+ except (ValueError, RuntimeError, FileNotFoundError) as exc:
150
+ print(f"\nCould not run the analysis: {exc}", file=sys.stderr)
151
+ return 1
152
+ print("\n" + head)
153
+ for line in r["summary"]:
154
+ print(" " + line)
155
+ print(f"\nAll results: {r['out']}")
156
+ return 0
157
+
158
+
159
+ def _load(path):
160
+ from easyclassifier.dataset import clean_path, load_csv
161
+ return load_csv(clean_path(path))
162
+
163
+
164
+ if __name__ == "__main__":
165
+ raise SystemExit(main())
@@ -0,0 +1 @@
1
+ """Pieces shared by all EasyResearch cores."""