From 65e91f715cc7122442c1f57ef2b6090eebff4f3d Mon Sep 17 00:00:00 2001 From: YenChenLin Date: Mon, 16 May 2016 12:01:50 +0800 Subject: [PATCH 1/2] Make csr_row_norms support fused types --- sklearn/utils/sparsefuncs_fast.pyx | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/sklearn/utils/sparsefuncs_fast.pyx b/sklearn/utils/sparsefuncs_fast.pyx index 10c143ed5078a..9335e48321e79 100644 --- a/sklearn/utils/sparsefuncs_fast.pyx +++ b/sklearn/utils/sparsefuncs_fast.pyx @@ -23,24 +23,29 @@ ctypedef np.float64_t DOUBLE def csr_row_norms(X): """L2 norm of each row in CSR matrix X.""" + if X.dtype != np.float32: + X = X.astype(np.float64) + return _csr_row_norms(X.data, X.shape, X.indices, X.indptr) + + +def _csr_row_norms(np.ndarray[floating, ndim=1, mode="c"] X_data, + shape, + np.ndarray[int, ndim=1, mode="c"] X_indices, + np.ndarray[int, ndim=1, mode="c"] X_indptr): cdef: - unsigned int n_samples = X.shape[0] - unsigned int n_features = X.shape[1] + unsigned int n_samples = shape[0] + unsigned int n_features = shape[1] np.ndarray[DOUBLE, ndim=1, mode="c"] norms - np.ndarray[DOUBLE, ndim=1, mode="c"] data - np.ndarray[int, ndim=1, mode="c"] indices = X.indices - np.ndarray[int, ndim=1, mode="c"] indptr = X.indptr np.npy_intp i, j double sum_ norms = np.zeros(n_samples, dtype=np.float64) - data = np.asarray(X.data, dtype=np.float64) # might copy! for i in range(n_samples): sum_ = 0.0 - for j in range(indptr[i], indptr[i + 1]): - sum_ += data[j] * data[j] + for j in range(X_indptr[i], X_indptr[i + 1]): + sum_ += X_data[j] * X_data[j] norms[i] = sum_ return norms From c7d6f9ffc31578dbcc66de221631ab6139fc42db Mon Sep 17 00:00:00 2001 From: YenChenLin Date: Mon, 16 May 2016 14:34:22 +0800 Subject: [PATCH 2/2] Test row_norms for float32 data --- sklearn/utils/tests/test_extmath.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/sklearn/utils/tests/test_extmath.py b/sklearn/utils/tests/test_extmath.py index ea3ee6077005b..5847d0566a9e5 100644 --- a/sklearn/utils/tests/test_extmath.py +++ b/sklearn/utils/tests/test_extmath.py @@ -148,14 +148,23 @@ def test_norm_squared_norm(): def test_row_norms(): X = np.random.RandomState(42).randn(100, 100) - sq_norm = (X ** 2).sum(axis=1) - - assert_array_almost_equal(sq_norm, row_norms(X, squared=True), 5) - assert_array_almost_equal(np.sqrt(sq_norm), row_norms(X)) - - Xcsr = sparse.csr_matrix(X, dtype=np.float32) - assert_array_almost_equal(sq_norm, row_norms(Xcsr, squared=True), 5) - assert_array_almost_equal(np.sqrt(sq_norm), row_norms(Xcsr)) + for dtype in (np.float32, np.float64): + if dtype is np.float32: + precision = 4 + else: + precision = 5 + + X = X.astype(dtype) + sq_norm = (X ** 2).sum(axis=1) + + assert_array_almost_equal(sq_norm, row_norms(X, squared=True), + precision) + assert_array_almost_equal(np.sqrt(sq_norm), row_norms(X), precision) + + Xcsr = sparse.csr_matrix(X, dtype=dtype) + assert_array_almost_equal(sq_norm, row_norms(Xcsr, squared=True), + precision) + assert_array_almost_equal(np.sqrt(sq_norm), row_norms(Xcsr), precision) def test_randomized_svd_low_rank_with_noise():