From 13d1ae916724eeb867cfe221446fad6a6a07ea0a Mon Sep 17 00:00:00 2001 From: oooo26 <1160141009@qq.com> Date: Fri, 11 Mar 2022 12:42:18 +0800 Subject: [PATCH 1/6] Improve Python codecov --- python/abess/functions.py | 47 ++++++++++++++++++++------------------- python/pytest/test_alg.py | 6 +++++ 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/python/abess/functions.py b/python/abess/functions.py index 21d690db..2f5fe6c5 100644 --- a/python/abess/functions.py +++ b/python/abess/functions.py @@ -72,9 +72,9 @@ def __call__(self, x): return value[0] return value - def __repr__(self): - return "StepFunction(x=%r, y=%r, a=%r, b=%r)" % ( - self.x, self.y, self.a, self.b) + # def __repr__(self): + # return "StepFunction(x=%r, y=%r, a=%r, b=%r)" % ( + # self.x, self.y, self.a, self.b) class BreslowEstimator: @@ -125,25 +125,25 @@ def fit(self, linear_predictor, event, time): np.exp(- self.cum_baseline_hazard_.y)) return self - def get_cumulative_hazard_function(self, linear_predictor): - r"""Predict cumulative hazard function. - Parameters - ---------- - linear_predictor : array-like, shape = (n_samples,) - Linear predictor of risk: `X @ coef`. - Returns - ------- - cum_hazard : ndarray, shape = (n_samples,) - Predicted cumulative hazard functions. - """ - risk_score = np.exp(linear_predictor) - n_samples = risk_score.shape[0] - funcs = np.empty(n_samples, dtype=object) - for i in range(n_samples): - funcs[i] = StepFunction(x=self.cum_baseline_hazard_.x, - y=self.cum_baseline_hazard_.y, - a=risk_score[i]) - return funcs + # def get_cumulative_hazard_function(self, linear_predictor): + # r"""Predict cumulative hazard function. + # Parameters + # ---------- + # linear_predictor : array-like, shape = (n_samples,) + # Linear predictor of risk: `X @ coef`. + # Returns + # ------- + # cum_hazard : ndarray, shape = (n_samples,) + # Predicted cumulative hazard functions. + # """ + # risk_score = np.exp(linear_predictor) + # n_samples = risk_score.shape[0] + # funcs = np.empty(n_samples, dtype=object) + # for i in range(n_samples): + # funcs[i] = StepFunction(x=self.cum_baseline_hazard_.x, + # y=self.cum_baseline_hazard_.y, + # a=risk_score[i]) + # return funcs def get_survival_function(self, linear_predictor): r"""Predict survival function. @@ -164,7 +164,8 @@ def get_survival_function(self, linear_predictor): y=np.power(self.baseline_survival_.y, risk_score[i])) return funcs - def _compute_counts(self ,event, time, order=None): + @staticmethod + def _compute_counts(event, time, order=None): """Count right censored and uncensored samples at each unique time point. Parameters diff --git a/python/pytest/test_alg.py b/python/pytest/test_alg.py index 1623df59..f0db4999 100644 --- a/python/pytest/test_alg.py +++ b/python/pytest/test_alg.py @@ -176,6 +176,12 @@ def assert_reg(coef): # assert_fit(model1.coef_, model2.coef_) # TODO assert_reg(model2.coef_) + # survival function + surv = model1.predict_survival_function(data.x) + time_points = np.quantile(data.y[:, 0], np.linspace(0, 0.6, 100)) + surv[0](time_points) + + @staticmethod def test_poisson(): np.random.seed(9) From 08a066a73d250ba45773cc44b64dc809e8e22eec Mon Sep 17 00:00:00 2001 From: oooo26 <1160141009@qq.com> Date: Fri, 11 Mar 2022 13:23:19 +0800 Subject: [PATCH 2/6] Test SDist --- .github/workflows/pypi.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 338b32f8..2ebfceba 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -31,10 +31,11 @@ jobs: - name: Check metadata run: | pipx run twine check dist/* + realpath dist/* - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: - path: dist/*.tar.gz + path: dist/* build_wheels: name: Wheels on ${{ matrix.os }} From e94f243776a73608e75d66343008a27c0b6fa452 Mon Sep 17 00:00:00 2001 From: oooo26 <1160141009@qq.com> Date: Fri, 11 Mar 2022 13:27:31 +0800 Subject: [PATCH 3/6] Update SDist path --- .github/workflows/pypi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 2ebfceba..5b91a07c 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -35,7 +35,7 @@ jobs: - uses: actions/upload-artifact@v3 with: - path: dist/* + path: python/dist/* build_wheels: name: Wheels on ${{ matrix.os }} From 304c1af10e87b0b9780190b5465ec960da436926 Mon Sep 17 00:00:00 2001 From: oooo26 <1160141009@qq.com> Date: Fri, 11 Mar 2022 13:30:08 +0800 Subject: [PATCH 4/6] Test PyPI upload --- .github/workflows/pypi.yml | 34 +++++++++++++++++----------------- python/abess/__init__.py | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 5b91a07c..92dc2f90 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -73,23 +73,23 @@ jobs: with: path: wheelhouse/*.whl -# upload_TestPyPI: -# name: Upload alpha version to TestPyPI -# needs: [build_wheels, build_sdist] -# runs-on: ubuntu-latest - -# steps: -# - uses: actions/download-artifact@v3 -# with: -# name: artifact -# path: dist - -# - uses: pypa/gh-action-pypi-publish@release/v1 -# with: -# user: __token__ -# password: ${{ secrets.TEST_PYPI_API_TOKEN }} -# repository_url: https://test.pypi.org/legacy/ -# verbose: true + upload_TestPyPI: + name: Upload alpha version to TestPyPI + needs: [build_wheels, build_sdist] + runs-on: ubuntu-latest + + steps: + - uses: actions/download-artifact@v3 + with: + name: artifact + path: dist + + - uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.TEST_PYPI_API_TOKEN }} + repository_url: https://test.pypi.org/legacy/ + verbose: true upload_PyPI: name: Upload to PyPI if release diff --git a/python/abess/__init__.py b/python/abess/__init__.py index fcf18699..0ba23a25 100644 --- a/python/abess/__init__.py +++ b/python/abess/__init__.py @@ -5,7 +5,7 @@ # @Site : # @File : __init__.py -__version__ = "0.4.2" +__version__ = "0.4.3" __author__ = ("Jin Zhu, Kangkang Jiang, " "Junhao Huang, Yanhang Zhang, " "Yanhang Zhang, Shiyun Lin, " From 5def1b3e5b1c0c6c96104c9b7f81832317854c5f Mon Sep 17 00:00:00 2001 From: Jason Huang <68503286+oooo26@users.noreply.github.com> Date: Fri, 11 Mar 2022 15:38:59 +0800 Subject: [PATCH 5/6] Disable TestPyPI --- .github/workflows/pypi.yml | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 92dc2f90..5b91a07c 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -73,23 +73,23 @@ jobs: with: path: wheelhouse/*.whl - upload_TestPyPI: - name: Upload alpha version to TestPyPI - needs: [build_wheels, build_sdist] - runs-on: ubuntu-latest - - steps: - - uses: actions/download-artifact@v3 - with: - name: artifact - path: dist - - - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.TEST_PYPI_API_TOKEN }} - repository_url: https://test.pypi.org/legacy/ - verbose: true +# upload_TestPyPI: +# name: Upload alpha version to TestPyPI +# needs: [build_wheels, build_sdist] +# runs-on: ubuntu-latest + +# steps: +# - uses: actions/download-artifact@v3 +# with: +# name: artifact +# path: dist + +# - uses: pypa/gh-action-pypi-publish@release/v1 +# with: +# user: __token__ +# password: ${{ secrets.TEST_PYPI_API_TOKEN }} +# repository_url: https://test.pypi.org/legacy/ +# verbose: true upload_PyPI: name: Upload to PyPI if release From 516111d2f57ae2ac1c3b02032235bd79dbf5c3eb Mon Sep 17 00:00:00 2001 From: oooo26 <1160141009@qq.com> Date: Fri, 11 Mar 2022 16:45:34 +0800 Subject: [PATCH 6/6] Improve codecov --- python/abess/decomposition.py | 38 ++++++------- python/abess/utilities.py | 10 ++-- python/pytest/test_alg.py | 13 ++++- python/pytest/test_check.py | 100 ++++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 27 deletions(-) diff --git a/python/abess/decomposition.py b/python/abess/decomposition.py index cfab4ff8..5c438c7b 100644 --- a/python/abess/decomposition.py +++ b/python/abess/decomposition.py @@ -110,14 +110,14 @@ def ratio(self, X): """ X = new_data_check(self, X) s = np.cov(X.T) - if len(self.coef_.shape) == 1: - explain = self.coef_.T.dot(s).dot(self.coef_) - else: - explain = np.sum(np.diag(self.coef_.T.dot(s).dot(self.coef_))) - if isinstance(s, (int, float)): - full = s - else: - full = np.sum(np.diag(s)) + # if len(self.coef_.shape) == 1: + # explain = self.coef_.T.dot(s).dot(self.coef_) + # else: + explain = np.sum(np.diag(self.coef_.T.dot(s).dot(self.coef_))) + # if isinstance(s, (int, float)): + # full = s + # else: + full = np.sum(np.diag(s)) return explain / full def fit(self, X=None, is_normal=False, @@ -261,7 +261,7 @@ def fit(self, X=None, is_normal=False, elif self.screening_size > p: raise ValueError( "screening size should be smaller than X.shape[1].") - elif self.screening_size < max(support_sizes): + elif self.screening_size < np.nonzero(support_sizes)[0].max() + 1: raise ValueError( "screening size should be more than max(support_size).") @@ -290,11 +290,11 @@ def fit(self, X=None, is_normal=False, "number should be an positive integer and" " not bigger than X.shape[1].") - # Important_search - if (not isinstance(self.important_search, int) - or self.important_search < 0): - raise ValueError( - "important_search should be a non-negative number.") + # # Important_search + # if (not isinstance(self.important_search, int) + # or self.important_search < 0): + # raise ValueError( + # "important_search should be a non-negative number.") # A_init if A_init is None: @@ -547,11 +547,11 @@ def fit(self, X, r, group=None, A_init=None): if self.splicing_type not in (0, 1): raise ValueError("splicing type should be 0 or 1.") - # Important_search - if (not isinstance(self.important_search, int) - or self.important_search < 0): - raise ValueError( - "important_search should be a non-negative number.") + # # Important_search + # if (not isinstance(self.important_search, int) + # or self.important_search < 0): + # raise ValueError( + # "important_search should be a non-negative number.") # A_init if A_init is None: diff --git a/python/abess/utilities.py b/python/abess/utilities.py index 7e00683e..fb45aeec 100644 --- a/python/abess/utilities.py +++ b/python/abess/utilities.py @@ -69,9 +69,9 @@ def categorical_to_dummy(x, classes=None): for i, x_i in enumerate(x): if x_i in classes: dummy_x[i, index[x_i]] = 1 - else: - print( - "Data {} (index {}) is not in classes.".format( - x_i, - i)) + # else: + # print( + # "Data {} (index {}) is not in classes.".format( + # x_i, + # i)) return dummy_x diff --git a/python/pytest/test_alg.py b/python/pytest/test_alg.py index f0db4999..ae758dda 100644 --- a/python/pytest/test_alg.py +++ b/python/pytest/test_alg.py @@ -181,7 +181,6 @@ def assert_reg(coef): time_points = np.quantile(data.y[:, 0], np.linspace(0, 0.6, 100)) surv[0](time_points) - @staticmethod def test_poisson(): np.random.seed(9) @@ -385,8 +384,12 @@ def test_PCA(): # ic for ic in ['aic', 'bic', 'ebic', 'gic']: - model4 = abess.SparsePCA(support_size=support_size, ic_type=ic) - model4.fit(X, is_normal=False) + model = abess.SparsePCA(support_size=support_size, ic_type=ic) + model.fit(X, is_normal=False) + + # A_init + model = abess.SparsePCA(support_size=support_size) + model.fit(X, A_init=[0, 1, 2]) @staticmethod def test_gamma(): @@ -446,6 +449,10 @@ def test_RPCA(): model4 = abess.RobustPCA(support_size=s, ic_type=ic) model4.fit(X, r=r) + # always select + model5 = abess.RobustPCA(support_size=s, always_select=[1]) + model5.fit(X, r=r) + @staticmethod def test_ordinal(): np.random.seed(0) diff --git a/python/pytest/test_check.py b/python/pytest/test_check.py index 87df4723..fb7740f5 100644 --- a/python/pytest/test_check.py +++ b/python/pytest/test_check.py @@ -272,8 +272,19 @@ def test_base(): else: assert False + try: + data = abess.make_glm_data(n=100, p=10, k=3, family='gaussian') + model = abess.LinearRegression() + model.fit(data.x, data.y) + model.score(data.x[:, 1:], data.y) + except ValueError as e: + print(e) + else: + assert False + # lack of necessary parameter try: + model = abess.LinearRegression() model.fit(X=[[1]]) except ValueError as e: print(e) @@ -281,6 +292,7 @@ def test_base(): assert False try: + model = abess.LinearRegression() model.fit(y=[1]) except ValueError as e: print(e) @@ -361,6 +373,14 @@ def test_pca(): else: assert False + try: + model = abess.SparsePCA(screening_size=np.ones((100, 1))) + model.fit(data) + except ValueError as e: + print(e) + else: + assert False + # screening_size model = abess.SparsePCA(screening_size=0) model.fit(data) @@ -373,6 +393,14 @@ def test_pca(): else: assert False + try: + model = abess.SparsePCA(screening_size=1, support_size=2) + model.fit(data) + except ValueError as e: + print(e) + else: + assert False + # lack of necessary parameter try: model.fit() @@ -444,6 +472,38 @@ def test_pca(): else: assert False + try: + model1 = abess.SparsePCA(exchange_num=-1) + model1.fit([[1]]) + except ValueError as e: + print(e) + else: + assert False + + try: + model1 = abess.SparsePCA(thread=-1) + model1.fit([[1]]) + except ValueError as e: + print(e) + else: + assert False + + try: + model1 = abess.SparsePCA() + model.fit([[1]], A_init=[[0, 1, 2]]) + except ValueError as e: + print(e) + else: + assert False + + try: + model1 = abess.SparsePCA() + model.fit([[1]], A_init=[-1]) + except ValueError as e: + print(e) + else: + assert False + @staticmethod def test_rpca(): model = abess.RobustPCA() @@ -507,3 +567,43 @@ def test_rpca(): print(e) else: assert False + + try: + model1 = abess.RobustPCA(support_size=[100]) + model1.fit([[1]], r=1) + except ValueError as e: + print(e) + else: + assert False + + try: + model1 = abess.RobustPCA() + model1.fit([[1]], r=0.1) + except ValueError as e: + print(e) + else: + assert False + + try: + model1 = abess.RobustPCA(exchange_num=-1) + model1.fit([[1]], r=1) + except ValueError as e: + print(e) + else: + assert False + + try: + model1 = abess.RobustPCA(splicing_type=-1) + model1.fit([[1]], r=1) + except ValueError as e: + print(e) + else: + assert False + + try: + model1 = abess.RobustPCA(thread=-1) + model1.fit([[1]], r=1) + except ValueError as e: + print(e) + else: + assert False