refs-mcc 1.0.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.
@@ -0,0 +1,2 @@
1
+ include requirements.txt
2
+ recursive-include src *.py
@@ -0,0 +1,73 @@
1
+ Metadata-Version: 2.4
2
+ Name: refs-mcc
3
+ Version: 1.0.0
4
+ Summary: Recursive Ensemble Feature Selection using Matthews Correlation Coefficient
5
+ Author: Alejandro Lopez-Rincon, Alberto Tonda, Brigitta Varga
6
+ Author-email: Alejandro Lopez-Rincon <alejandrolopezrn@gmail.com>
7
+ License: MIT
8
+ Project-URL: source, https://github.com/steppenwolf0/REFS-MCC/
9
+ Project-URL: tracker, https://github.com/steppenwolf0/REFS-MCC/issues
10
+ Keywords: feature-selection,matthews-correlation-coefficient,bioinformatics,machine-learning,ensemble-learning
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: Implementation :: CPython
22
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ Requires-Dist: joblib>=1.5.3
26
+ Requires-Dist: matplotlib>=3.10.8
27
+ Requires-Dist: numpy>=2.4.1
28
+ Requires-Dist: pandas>=2.3.3
29
+ Requires-Dist: scikit-learn>=1.8.0
30
+ Requires-Dist: scipy>=1.17.0
31
+ Requires-Dist: statsmodels>=0.14.6
32
+ Provides-Extra: dev
33
+ Requires-Dist: pytest>=7.0; extra == "dev"
34
+
35
+ # REFS-MCC
36
+ Recursive Ensemble Feauture Selection using Matthews Correlation Coefficient
37
+
38
+ --------------------------------------------------------------------
39
+ Installation
40
+
41
+ ```bash
42
+ pip install refs-mcc
43
+ ```
44
+
45
+ After installation it can be used as the following (using the default parameters):
46
+ ```python
47
+ from refs_mcc import REFS_MCC
48
+ REFS_MCC().run()
49
+ ```
50
+
51
+ Or from CLI. For more information, run:
52
+ ```bash
53
+ refs-mcc --help
54
+ ```
55
+
56
+ --------------------------------------------------------------------
57
+ Input
58
+
59
+ Next to the folder where the code is executed from, a `data` folder needs to be present with the following files:
60
+ - `data_0.csv`
61
+ - `features_0.csv`
62
+ - `ids.csv`
63
+ - `labels.csv`
64
+
65
+ --------------------------------------------------------------------
66
+ Output
67
+
68
+ The following folders and files will be created:
69
+ - run folders (`run0`, `run1`, ..., `run{n-1}`, where n is the selected number of total runs, 10 by default)
70
+ - `best` folder
71
+ - `sumFig.pdf` & `sumFig.png`
72
+
73
+ --------------------------------------------------------------------
@@ -0,0 +1,25 @@
1
+ # REFS-MCC
2
+ Recursive Ensemble Feauture Selection using Matthews Correlation Coefficient
3
+
4
+ --------------------------------------------------------------------
5
+ Instructions
6
+
7
+ - From the src folder run the refs-mcc (the default parameters are: 10 threads, 10 folds and 10 total runs):
8
+ ```bash
9
+ python refs_mcc.py
10
+ ```
11
+
12
+ - For the full list of command line args:
13
+ ```bash
14
+ python refs_mcc.py --help
15
+ ```
16
+
17
+ --------------------------------------------------------------------
18
+ Output
19
+
20
+ The following folders and files will be created:
21
+ - run folders (`run0`, `run1`, ..., `run{n-1}`, where n is the selected number of total runs, 10 by default)
22
+ - `best` folder
23
+ - `sumFig.pdf` & `sumFig.png`
24
+
25
+ --------------------------------------------------------------------
@@ -0,0 +1,39 @@
1
+ # REFS-MCC
2
+ Recursive Ensemble Feauture Selection using Matthews Correlation Coefficient
3
+
4
+ --------------------------------------------------------------------
5
+ Installation
6
+
7
+ ```bash
8
+ pip install refs-mcc
9
+ ```
10
+
11
+ After installation it can be used as the following (using the default parameters):
12
+ ```python
13
+ from refs_mcc import REFS_MCC
14
+ REFS_MCC().run()
15
+ ```
16
+
17
+ Or from CLI. For more information, run:
18
+ ```bash
19
+ refs-mcc --help
20
+ ```
21
+
22
+ --------------------------------------------------------------------
23
+ Input
24
+
25
+ Next to the folder where the code is executed from, a `data` folder needs to be present with the following files:
26
+ - `data_0.csv`
27
+ - `features_0.csv`
28
+ - `ids.csv`
29
+ - `labels.csv`
30
+
31
+ --------------------------------------------------------------------
32
+ Output
33
+
34
+ The following folders and files will be created:
35
+ - run folders (`run0`, `run1`, ..., `run{n-1}`, where n is the selected number of total runs, 10 by default)
36
+ - `best` folder
37
+ - `sumFig.pdf` & `sumFig.png`
38
+
39
+ --------------------------------------------------------------------
@@ -0,0 +1,74 @@
1
+ [project]
2
+ name = "refs-mcc"
3
+ version = "1.0.0"
4
+ description = "Recursive Ensemble Feature Selection using Matthews Correlation Coefficient"
5
+ keywords = ["feature-selection", "matthews-correlation-coefficient", "bioinformatics", "machine-learning", "ensemble-learning"]
6
+ readme = "README_PYPI.md"
7
+ requires-python = ">=3.10"
8
+ authors = [
9
+ { name = "Alejandro Lopez-Rincon", email = "alejandrolopezrn@gmail.com" },
10
+ { name = "Alejandro Lopez-Rincon" },
11
+ { name = "Alberto Tonda" },
12
+ { name = "Brigitta Varga" }
13
+ ]
14
+ license = { text = "MIT" }
15
+ classifiers = [
16
+ "Development Status :: 4 - Beta",
17
+ "Intended Audience :: Science/Research",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3 :: Only",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Programming Language :: Python :: Implementation :: CPython",
27
+ "Topic :: Scientific/Engineering :: Bio-Informatics",
28
+ ]
29
+
30
+ dependencies = [
31
+ "joblib>=1.5.3",
32
+ "matplotlib>=3.10.8",
33
+ "numpy>=2.4.1",
34
+ "pandas>=2.3.3",
35
+ "scikit-learn>=1.8.0",
36
+ "scipy>=1.17.0",
37
+ "statsmodels>=0.14.6",
38
+ ]
39
+
40
+ [project.optional-dependencies]
41
+ dev = [
42
+ "pytest>=7.0",
43
+ ]
44
+
45
+ [project.scripts]
46
+ refs-mcc = "refs_mcc:main"
47
+
48
+ [project.urls]
49
+ source = "https://github.com/steppenwolf0/REFS-MCC/"
50
+ tracker = "https://github.com/steppenwolf0/REFS-MCC/issues"
51
+
52
+ [build-system]
53
+ requires = ["setuptools>=61.0", "wheel"]
54
+ build-backend = "setuptools.build_meta"
55
+
56
+ [tool.black]
57
+ line-length = 88
58
+ target-version = ["py38"]
59
+ exclude = "\\.venv|\\.git|\\.tox|build|dist"
60
+
61
+ [tool.isort]
62
+ profile = "black"
63
+
64
+ [tool.pytest.ini_options]
65
+ minversion = "6.0"
66
+ addopts = "-q"
67
+ testpaths = ["tests"]
68
+
69
+ [tool.flake8]
70
+ max-line-length = 88
71
+ extend-ignore = ["E203"]
72
+
73
+ [tool.check-manifest]
74
+ ignore = ["data/*", "old/*"]
@@ -0,0 +1,67 @@
1
+ aiohappyeyeballs==2.6.2
2
+ aiohttp==3.14.1
3
+ aiosignal==1.4.0
4
+ alembic==1.18.1
5
+ attrs==26.1.0
6
+ Boruta==0.4.3
7
+ catboost==1.2.10
8
+ certifi==2026.2.25
9
+ charset-normalizer==3.4.5
10
+ cloudpickle==3.1.2
11
+ cma==4.4.1
12
+ colorama==0.4.6
13
+ colorlog==6.10.1
14
+ contourpy==1.3.3
15
+ cycler==0.12.1
16
+ filelock==3.29.4
17
+ fonttools==4.61.1
18
+ frozenlist==1.8.0
19
+ fsspec==2026.6.0
20
+ graphviz==0.21
21
+ greenlet==3.3.1
22
+ idna==3.11
23
+ Jinja2==3.1.6
24
+ joblib==1.5.3
25
+ kiwisolver==1.4.9
26
+ llvmlite==0.47.0
27
+ lxml==6.0.2
28
+ Mako==1.3.10
29
+ MarkupSafe==3.0.3
30
+ matplotlib==3.10.8
31
+ mpmath==1.3.0
32
+ multidict==6.7.1
33
+ narwhals==2.19.0
34
+ networkx==3.6.1
35
+ numba==0.65.1
36
+ numpy==2.4.1
37
+ optuna==4.7.0
38
+ packaging==25.0
39
+ pandas==2.3.3
40
+ patsy==1.0.2
41
+ pillow==12.1.0
42
+ plotly==6.7.0
43
+ propcache==0.5.2
44
+ psutil==7.2.2
45
+ pyparsing==3.3.2
46
+ python-dateutil==2.9.0.post0
47
+ pytz==2025.2
48
+ PyYAML==6.0.3
49
+ requests==2.32.5
50
+ scikit-learn==1.8.0
51
+ scipy==1.17.0
52
+ seaborn==0.13.2
53
+ setuptools==81.0.0
54
+ shap==0.52.0
55
+ six==1.17.0
56
+ slicer==0.0.8
57
+ SQLAlchemy==2.0.46
58
+ statsmodels==0.14.6
59
+ sympy==1.14.0
60
+ threadpoolctl==3.6.0
61
+ tqdm==4.67.1
62
+ typing_extensions==4.15.0
63
+ tzdata==2025.3
64
+ urllib3==2.6.3
65
+ xgboost==3.2.0
66
+ xxhash==3.8.0
67
+ yarl==1.24.2
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,58 @@
1
+ from features import *
2
+ from reduceData import *
3
+
4
+ from joblib import Parallel, delayed
5
+ import multiprocessing
6
+ import time
7
+ import argparse
8
+
9
+ def mainRun(indexRun, numberOfFolds) :
10
+ run=indexRun
11
+ start_time = time.time()
12
+ globalAnt=0.0
13
+ globalIndex=0
14
+ globalAccuracy=0.0
15
+
16
+ X, y, biomarkerNames = loadDatasetOriginal(run)
17
+
18
+ if (int(len(X[0]))>1000):
19
+ numberOfTopFeatures = 1000
20
+ else :
21
+ numberOfTopFeatures = int(len(X[0])*0.80)
22
+
23
+ variableSize=numberOfTopFeatures;
24
+ while True:
25
+ globalAnt=globalAccuracy
26
+ globalAccuracy=featureSelection(globalIndex,variableSize, run,numberOfFolds)
27
+ print(globalAccuracy)
28
+ print(globalIndex)
29
+ print(variableSize)
30
+ size,sizereduced=reduceDataset(globalIndex, run)
31
+
32
+ if(variableSize==0):
33
+ break
34
+ variableSize=int(variableSize*0.80)
35
+
36
+ globalIndex=globalIndex + 1
37
+
38
+ elapsed_time = time.time() - start_time
39
+ print("time")
40
+ print(elapsed_time)
41
+ return
42
+
43
+ def main(threads, totalRuns, numberOfFolds) :
44
+ Parallel(n_jobs=threads, verbose=5, backend="multiprocessing")(delayed(mainRun)(i, numberOfFolds) for i in range(0,totalRuns))
45
+ return
46
+
47
+ if __name__ == "__main__" :
48
+ parser = argparse.ArgumentParser(description="Run REFS-MCC - part 1")
49
+ parser.add_argument('--threads', type=int, default=10, help='Number of threads (default: 10)')
50
+ parser.add_argument('--totalRuns', type=int, default=10, help='Total number of runs (default: 10)')
51
+ parser.add_argument('--folds', type=int, default=10, help='Number of folds (default: 10)')
52
+ args = parser.parse_args()
53
+
54
+ threads=args.threads
55
+ totalRuns=args.totalRuns
56
+ numberOfFolds=args.folds
57
+
58
+ sys.exit( main(threads, totalRuns, numberOfFolds) )
@@ -0,0 +1,227 @@
1
+ import copy
2
+ import datetime
3
+ import logging
4
+ import numpy as np
5
+ import os
6
+ import sys
7
+ import pandas as pd
8
+ import argparse
9
+
10
+ from sklearn.ensemble import AdaBoostClassifier
11
+ from sklearn.ensemble import BaggingClassifier
12
+ from sklearn.ensemble import ExtraTreesClassifier
13
+ from sklearn.ensemble import GradientBoostingClassifier
14
+ from sklearn.ensemble import RandomForestClassifier
15
+
16
+ from sklearn.linear_model import ElasticNet
17
+ from sklearn.linear_model import ElasticNetCV
18
+ from sklearn.linear_model import Lasso
19
+ from sklearn.linear_model import LassoCV
20
+ from sklearn.linear_model import LogisticRegression
21
+ from sklearn.linear_model import LogisticRegressionCV
22
+ from sklearn.linear_model import PassiveAggressiveClassifier
23
+ from sklearn.linear_model import RidgeClassifier
24
+ from sklearn.linear_model import RidgeClassifierCV
25
+ from sklearn.linear_model import SGDClassifier
26
+
27
+ from sklearn.multiclass import OneVsOneClassifier
28
+ from sklearn.multiclass import OneVsRestClassifier
29
+ from sklearn.multiclass import OutputCodeClassifier
30
+
31
+ from sklearn.naive_bayes import BernoulliNB
32
+ from sklearn.naive_bayes import GaussianNB
33
+ from sklearn.naive_bayes import MultinomialNB
34
+
35
+ from sklearn.neighbors import KNeighborsClassifier
36
+ from sklearn.neighbors import NearestCentroid
37
+ from sklearn.neighbors import RadiusNeighborsClassifier
38
+
39
+ from sklearn.svm import SVC
40
+
41
+ from sklearn.tree import DecisionTreeClassifier
42
+ from sklearn.tree import ExtraTreeClassifier
43
+ from sklearn.neural_network import MLPClassifier
44
+
45
+ # used for normalization
46
+ from sklearn.preprocessing import Normalizer
47
+ from sklearn.preprocessing import StandardScaler
48
+ from sklearn.preprocessing import MinMaxScaler
49
+ # used for cross-validation
50
+ from sklearn.model_selection import StratifiedKFold
51
+ from sklearn.metrics import roc_curve, auc
52
+ from numpy import interp
53
+ import matplotlib.pyplot as plt
54
+ from pandas import read_csv
55
+
56
+ from statsmodels.multivariate.manova import MANOVA
57
+ import statsmodels.api as sm
58
+ from scipy import stats
59
+ from sklearn.metrics import f1_score
60
+ def loadDataset() :
61
+
62
+ # data used for the predictions
63
+ dfData = read_csv("./best/data_0.csv", header=None, sep=',')
64
+ dfLabels = read_csv("./best/labels.csv", header=None)
65
+
66
+ return dfData.values, dfLabels.values.ravel() # to have it in the format that the classifiers like
67
+
68
+
69
+ def runFeatureReduce(numberOfFolds) :
70
+
71
+ # list of classifiers, selected on the basis of our previous paper "
72
+ classifierList = [
73
+
74
+ [GradientBoostingClassifier(n_estimators=300), "GradientBoostingClassifier(n_estimators=300)"],
75
+ [RandomForestClassifier(n_estimators=300), "RandomForestClassifier(n_estimators=300)"],
76
+ [LogisticRegression(solver='lbfgs',), "LogisticRegression"],
77
+ [PassiveAggressiveClassifier(),"PassiveAggressiveClassifier"],
78
+ [SGDClassifier(), "SGDClassifier"],
79
+ [SVC(kernel='linear'), "SVC(linear)"],
80
+ [RidgeClassifier(), "RidgeClassifier"],
81
+ [BaggingClassifier(n_estimators=300), "BaggingClassifier(n_estimators=300)"],
82
+ # ensemble
83
+ #[AdaBoostClassifier(), "AdaBoostClassifier"],
84
+ #[AdaBoostClassifier(n_estimators=300), "AdaBoostClassifier(n_estimators=300)"],
85
+ #[AdaBoostClassifier(n_estimators=1500), "AdaBoostClassifier(n_estimators=1500)"],
86
+ #[BaggingClassifier(), "BaggingClassifier"],
87
+
88
+ #[ExtraTreesClassifier(), "ExtraTreesClassifier"],
89
+ #[ExtraTreesClassifier(n_estimators=300), "ExtraTreesClassifier(n_estimators=300)"],
90
+ # features_importances_
91
+ #[GradientBoostingClassifier(n_estimators=300), "GradientBoostingClassifier(n_estimators=300)"],
92
+ #[GradientBoostingClassifier(n_estimators=1000), "GradientBoostingClassifier(n_estimators=1000)"],
93
+
94
+ #[RandomForestClassifier(n_estimators=300), "RandomForestClassifier(n_estimators=300)"],
95
+ #[RandomForestClassifier(n_estimators=1000), "RandomForestClassifier(n_estimators=1000)"], # features_importances_
96
+
97
+ # linear
98
+ #[ElasticNet(), "ElasticNet"],
99
+ #[ElasticNetCV(), "ElasticNetCV"],
100
+ #[Lasso(), "Lasso"],
101
+ #[LassoCV(), "LassoCV"],
102
+ # coef_
103
+ #[LogisticRegressionCV(), "LogisticRegressionCV"],
104
+ # coef_
105
+ # coef_
106
+ #[RidgeClassifierCV(), "RidgeClassifierCV"],
107
+ # coef_
108
+ # coef_, but only if the kernel is linear...the default is 'rbf', which is NOT linear
109
+
110
+ # naive Bayes
111
+ #[BernoulliNB(), "BernoulliNB"],
112
+ #[GaussianNB(), "GaussianNB"],
113
+ #[MultinomialNB(), "MultinomialNB"],
114
+
115
+ # neighbors
116
+ #[KNeighborsClassifier(), "KNeighborsClassifier"], # no way to return feature importance
117
+ # TODO this one creates issues
118
+ #[NearestCentroid(), "NearestCentroid"], # it does not have some necessary methods, apparently
119
+ #[RadiusNeighborsClassifier(), "RadiusNeighborsClassifier"],
120
+
121
+ # tree
122
+ #[DecisionTreeClassifier(), "DecisionTreeClassifier"],
123
+ #[ExtraTreeClassifier(), "ExtraTreeClassifier"],
124
+ [AdaBoostClassifier(n_estimators=300), "AdaBoostClassifier(n_estimators=300)"],
125
+ [ExtraTreesClassifier(n_estimators=300), "ExtraTreesClassifier(n_estimators=300)"],
126
+ [KNeighborsClassifier(), "KNeighborsClassifier"],
127
+ #[LassoCV(), "LassoCV"],
128
+ [MLPClassifier(), "MLPClassifier"],
129
+ [LassoCV(), "LassoCV"]
130
+ ]
131
+
132
+ # this is just a hack to check a few things
133
+ #classifierList = [
134
+ # [RandomForestClassifier(), "RandomForestClassifier"]
135
+ # ]
136
+
137
+ print("Loading dataset...")
138
+ X, y = loadDataset()
139
+
140
+ print(len(X))
141
+ print(len(X[0]))
142
+ print(len(y))
143
+
144
+
145
+ labels=np.max(y)+1
146
+ # prepare folds
147
+ skf = StratifiedKFold(n_splits=numberOfFolds, shuffle=True)
148
+ indexes = [ (training, test) for training, test in skf.split(X, y) ]
149
+
150
+ # this will be used for the top features
151
+ topFeatures = dict()
152
+
153
+ # iterate over all classifiers
154
+ classifierIndex = 0
155
+
156
+
157
+
158
+
159
+ for originalClassifier, classifierName in classifierList :
160
+
161
+ print("\nClassifier " + classifierName)
162
+ classifierPerformance = []
163
+ F1score= []
164
+
165
+ cMatrix=np.zeros((labels, labels))
166
+ # iterate over all folds
167
+
168
+ indexFold = 0
169
+
170
+ yTest=[]
171
+ yNew=[]
172
+
173
+ for train_index, test_index in indexes :
174
+
175
+ X_train, X_test = X[train_index], X[test_index]
176
+ y_train, y_test = y[train_index], y[test_index]
177
+
178
+ # let's normalize, anyway
179
+ # MinMaxScaler StandardScaler Normalizer
180
+ scaler = StandardScaler()
181
+ X_train = scaler.fit_transform(X_train)
182
+ X_test = scaler.transform(X_test)
183
+
184
+
185
+
186
+ classifier = copy.deepcopy(originalClassifier)
187
+ classifier.fit(X_train, y_train)
188
+ scoreTraining = classifier.score(X_train, y_train)
189
+ scoreTest = classifier.score(X_test, y_test)
190
+
191
+ y_new = classifier.predict(X_test)
192
+
193
+
194
+
195
+ yNew.append(y_new)
196
+ yTest.append(y_test)
197
+
198
+
199
+ for i in range(0,len(y_new)):
200
+ cMatrix[y_test[i]][round(y_new[i])]+=1
201
+ y_new[i]=round(y_new[i])
202
+
203
+ print("\ttraining: %.4f, test: %.4f" % (scoreTraining, scoreTest))
204
+ classifierPerformance.append( scoreTest )
205
+
206
+
207
+ F1scoreTest = f1_score(y_test, y_new, average='weighted')
208
+ F1score.append(F1scoreTest)
209
+
210
+ pd.DataFrame(cMatrix).to_csv("./best/cMatrix"+str(classifierIndex)+".csv", header=None, index =None)
211
+ classifierIndex+=1
212
+ line ="%s \t %.4f \t %.4f \t %.4f \t %.4f\n" % (classifierName, np.mean(classifierPerformance), np.std(classifierPerformance), np.mean(F1score), np.std(F1score))
213
+
214
+
215
+ print(line)
216
+ fo = open("./best/results.txt", 'a')
217
+ fo.write( line )
218
+ fo.close()
219
+
220
+ return
221
+
222
+ if __name__ == "__main__" :
223
+ parser = argparse.ArgumentParser(description="Run multiple classifiers based on the best run")
224
+ parser.add_argument('--folds', type=int, default=10, help='Number of folds (default: 10)')
225
+ args = parser.parse_args()
226
+
227
+ sys.exit( runFeatureReduce(args.folds) )