diff --git a/Orange/data/table.py b/Orange/data/table.py index ef2ca7dd228..66bac3297c2 100644 --- a/Orange/data/table.py +++ b/Orange/data/table.py @@ -912,15 +912,20 @@ def is_copy(self): def ensure_copy(self): """ - Ensure that the table owns its data; copy arrays when necessary + Ensure that the table owns its data; copy arrays when necessary. """ - if self.X.base is not None: + def is_view(x): + # Sparse matrices don't have views like numpy arrays. Since indexing on + # them creates copies in constructor we can skip this check here. + return not sp.issparse(x) and x.base is not None + + if is_view(self.X): self.X = self.X.copy() - if self._Y.base is not None: + if is_view(self._Y): self._Y = self._Y.copy() - if self.metas.base is not None: + if is_view(self.metas): self.metas = self.metas.copy() - if self.W.base is not None: + if is_view(self.W): self.W = self.W.copy() def copy(self): diff --git a/Orange/tests/test_table.py b/Orange/tests/test_table.py index 7fc43ee276f..f7e9cc814f1 100644 --- a/Orange/tests/test_table.py +++ b/Orange/tests/test_table.py @@ -649,6 +649,19 @@ def test_copy(self): self.assertFalse(np.all(t.Y == copy.Y)) self.assertFalse(np.all(t.metas == copy.metas)) + def test_copy_sparse(self): + t = data.Table('iris') + t.X = csr_matrix(t.X) + copy = t.copy() + + self.assertEqual((t.X != copy.X).nnz, 0) # sparse matrices match by content + np.testing.assert_equal(t.Y, copy.Y) + np.testing.assert_equal(t.metas, copy.metas) + + self.assertNotEqual(id(t.X), id(copy.X)) + self.assertNotEqual(id(t._Y), id(copy._Y)) + self.assertNotEqual(id(t.metas), id(copy.metas)) + def test_concatenate(self): d1 = data.Domain([data.ContinuousVariable('a1')]) t1 = data.Table.from_numpy(d1, [[1],