Compare commits

...

6 Commits

Author SHA1 Message Date
5f8ca8f3bb Reformat test with new black version 2024-03-05 18:46:19 +01:00
Ricardo Montañana Gómez
fb8b9b344f Update README.md
update installation instructions
2024-03-05 18:18:55 +01:00
036d1ba2a7 Add separate methods to return nodes/leaves/depth 2023-11-27 10:02:14 +01:00
4de74973b8 Black format issue 2023-07-12 14:16:08 +02:00
Ricardo Montañana Gómez
28dd04b95a Update benchmark.ipynb 2023-05-13 14:44:49 +02:00
Ricardo Montañana Gómez
542bbce7db ci: ⬆️ Update ci files and badges 2023-01-15 02:18:41 +01:00
8 changed files with 86 additions and 42 deletions

View File

@@ -2,12 +2,12 @@ name: "CodeQL"
on:
push:
branches: [ master ]
branches: [master]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
branches: [master]
schedule:
- cron: '16 17 * * 3'
- cron: "16 17 * * 3"
jobs:
analyze:
@@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
language: ["python"]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
@@ -28,7 +28,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -39,7 +39,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -53,4 +53,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2

View File

@@ -16,9 +16,9 @@ jobs:
python: [3.8, "3.10"]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
- name: Install dependencies
@@ -35,7 +35,7 @@ jobs:
coverage run -m unittest -v stree.tests
coverage xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml

View File

@@ -1,7 +1,7 @@
![CI](https://github.com/Doctorado-ML/STree/workflows/CI/badge.svg)
[![CodeQL](https://github.com/Doctorado-ML/STree/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/Doctorado-ML/STree/actions/workflows/codeql-analysis.yml)
[![codecov](https://codecov.io/gh/doctorado-ml/stree/branch/master/graph/badge.svg)](https://codecov.io/gh/doctorado-ml/stree)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/35fa3dfd53a24a339344b33d9f9f2f3d)](https://www.codacy.com/gh/Doctorado-ML/STree?utm_source=github.com&utm_medium=referral&utm_content=Doctorado-ML/STree&utm_campaign=Badge_Grade)
[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/Doctorado-ML/STree.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/Doctorado-ML/STree/context:python)
[![PyPI version](https://badge.fury.io/py/STree.svg)](https://badge.fury.io/py/STree)
![https://img.shields.io/badge/python-3.8%2B-blue](https://img.shields.io/badge/python-3.8%2B-brightgreen)
[![DOI](https://zenodo.org/badge/262658230.svg)](https://zenodo.org/badge/latestdoi/262658230)
@@ -15,7 +15,7 @@ Oblique Tree classifier based on SVM nodes. The nodes are built and splitted wit
## Installation
```bash
pip install git+https://github.com/doctorado-ml/stree
pip install Stree
```
## Documentation

View File

@@ -178,7 +178,7 @@
"outputs": [],
"source": [
"# Stree\n",
"stree = Stree(random_state=random_state, C=.01, max_iter=1e3, kernel=\"liblinear\", multiclass_strategy=\"ovr\")"
"stree = Stree(random_state=random_state, C=.01, max_iter=1000, kernel=\"liblinear\", multiclass_strategy=\"ovr\")"
]
},
{
@@ -198,7 +198,7 @@
"outputs": [],
"source": [
"# SVC (linear)\n",
"svc = LinearSVC(random_state=random_state, C=.01, max_iter=1e3)"
"svc = LinearSVC(random_state=random_state, C=.01, max_iter=1000)"
]
},
{

View File

@@ -267,7 +267,6 @@ class Splitter:
random_state=None,
normalize=False,
):
self._clf = clf
self._random_state = random_state
if random_state is not None:

View File

@@ -153,7 +153,6 @@ class Stree(BaseEstimator, ClassifierMixin):
multiclass_strategy: str = "ovo",
normalize: bool = False,
):
self.max_iter = max_iter
self.C = C
self.kernel = kernel
@@ -485,6 +484,43 @@ class Stree(BaseEstimator, ClassifierMixin):
X = self.check_predict(X)
return self.classes_[np.argmax(self.__predict_class(X), axis=1)]
def get_nodes(self) -> int:
"""Return the number of nodes in the tree
Returns
-------
int
number of nodes
"""
nodes = 0
for _ in self:
nodes += 1
return nodes
def get_leaves(self) -> int:
"""Return the number of leaves in the tree
Returns
-------
int
number of leaves
"""
leaves = 0
for node in self:
if node.is_leaf():
leaves += 1
return leaves
def get_depth(self) -> int:
"""Return the depth of the tree
Returns
-------
int
depth of the tree
"""
return self.depth_
def nodes_leaves(self) -> tuple:
"""Compute the number of nodes and leaves in the built tree

View File

@@ -1 +1 @@
__version__ = "1.3.1"
__version__ = "1.3.2"

View File

@@ -239,6 +239,7 @@ class Stree_test(unittest.TestCase):
)
tcl.fit(*load_dataset(self._random_state))
self.assertEqual(depth, tcl.depth_)
self.assertEqual(depth, tcl.get_depth())
def test_unfitted_tree_is_iterable(self):
tcl = Stree()
@@ -307,9 +308,9 @@ class Stree_test(unittest.TestCase):
for kernel in self._kernels:
clf = Stree(
max_iter=int(1e4),
multiclass_strategy="ovr"
if kernel == "liblinear"
else "ovo",
multiclass_strategy=(
"ovr" if kernel == "liblinear" else "ovo"
),
kernel=kernel,
random_state=self._random_state,
)
@@ -640,10 +641,12 @@ class Stree_test(unittest.TestCase):
clf = Stree(random_state=self._random_state)
clf.fit(X, y)
self.assertEqual(6, clf.depth_)
self.assertEqual(6, clf.get_depth())
X, y = load_wine(return_X_y=True)
clf = Stree(random_state=self._random_state)
clf.fit(X, y)
self.assertEqual(4, clf.depth_)
self.assertEqual(4, clf.get_depth())
def test_nodes_leaves(self):
"""Check number of nodes and leaves."""
@@ -657,13 +660,17 @@ class Stree_test(unittest.TestCase):
clf.fit(X, y)
nodes, leaves = clf.nodes_leaves()
self.assertEqual(31, nodes)
self.assertEqual(31, clf.get_nodes())
self.assertEqual(16, leaves)
self.assertEqual(16, clf.get_leaves())
X, y = load_wine(return_X_y=True)
clf = Stree(random_state=self._random_state)
clf.fit(X, y)
nodes, leaves = clf.nodes_leaves()
self.assertEqual(11, nodes)
self.assertEqual(11, clf.get_nodes())
self.assertEqual(6, leaves)
self.assertEqual(6, clf.get_leaves())
def test_nodes_leaves_artificial(self):
"""Check leaves of artificial dataset."""
@@ -682,7 +689,9 @@ class Stree_test(unittest.TestCase):
clf.tree_ = n1
nodes, leaves = clf.nodes_leaves()
self.assertEqual(6, nodes)
self.assertEqual(6, clf.get_nodes())
self.assertEqual(2, leaves)
self.assertEqual(2, clf.get_leaves())
def test_bogus_multiclass_strategy(self):
"""Check invalid multiclass strategy."""