source: orange/Orange/testing/unit/tests/test_projection_linear.py @ 10803:921898cb37bd

Revision 10803:921898cb37bd, 8.2 KB checked in by anze <anze.staric@…>, 2 years ago (diff)

BUG Fixed pickling of pca projector.

Line 
1try:
2    import unittest2 as unittest
3except:
4    import unittest
5
6import numpy as np
7import pickle, random
8
9from Orange import data, feature
10from Orange.projection import linear
11
12np.random.seed(0)
13random.seed(0)
14
15def normalize(a):
16    a = a if isinstance(a, np.ndarray) else np.array(a)
17    return a / np.linalg.norm(a)
18
19datasets = None
20
21def prepare_dataset(components=((),), n=150):
22    components = components if isinstance(components, np.ndarray) else np.array(components)
23
24    ncomponents, m = components.shape
25    coefficients = np.random.normal(0., 1., (n, ncomponents))
26
27    d = np.dot(coefficients, components)
28
29    domain = data.Domain([feature.Continuous("A%d" % i) for i in range(m)], False)
30    return domain, d
31
32def create_base(ncomponents, m):
33    vector = np.random.randint(0,5,m)
34    while not vector.any():
35        vector = np.random.randint(0,5,m)
36    principal_components = np.zeros((ncomponents, m))
37    k = float(m) / ncomponents
38    to = 0
39    for i in range(1,ncomponents):
40        from_, to = int(k*(i-1)), int(k*i)
41        principal_components[i-1,from_:to] = vector[from_:to]
42    principal_components[ncomponents-1,to:m] = normalize(vector[to:m])
43    return principal_components
44
45
46class TestPca(unittest.TestCase):
47    def create_dataset(self, ncomponents=3, m=10):
48        self.principal_components = create_base(ncomponents, m)
49        self.dataset = data.Table(*prepare_dataset(components=self.principal_components))
50
51    def create_empty_dataset(self):
52        self.dataset = data.Table(*prepare_dataset(components=([0, 0, 0, 0, 0],), n=0))
53
54    def create_constant_dataset(self):
55        self.dataset = data.Table(*prepare_dataset(components=([0, 0, 0, 0, 0],)))
56
57    def create_dataset_with_unknowns(self, percentage=0.05):
58        self.principal_component = normalize([random.randint(0, 5) for _ in range(10)])
59        self.dataset = data.Table(*prepare_dataset(components=[self.principal_component]))
60
61        for ex in self.dataset:
62            for i, _ in enumerate(ex):
63                if random.random() < percentage:
64                    ex[i] = "?"
65
66
67    def test_pca(self):
68        for m in (10, 250):
69            self.create_dataset(m=m)
70
71            pca = linear.Pca(standardize=False)(self.dataset)
72
73            self.assertInCorrectSpace(pca.projection[pca.variances > 0.01, :])
74            for v in pca.projection:
75                # projections vectors should be normalized
76                self.assertAlmostEqual(np.linalg.norm(v), 1.)
77
78            # Components should have decreasing variants
79            self.assertListEqual(pca.variances.tolist(), sorted(pca.variances, reverse=True))
80
81    def test_pca_with_standardization(self):
82        self.create_dataset(ncomponents=1)
83
84        pca = linear.Pca(standardize=True)(self.dataset)
85        projection = pca.projection[0]
86        non_zero_elements = projection[projection.nonzero()]
87
88        # since values in all dimensions are normally distributed, dimensions should be treated as equally important
89        self.assertAlmostEqual(non_zero_elements.min(), non_zero_elements.max())
90
91    def test_pca_with_variance_covered(self):
92        ncomponents = 3
93        self.create_dataset(ncomponents=ncomponents)
94
95        pca = linear.Pca(variance_covered=.99)(self.dataset)
96
97        nvectors, vector_dimension = pca.projection.shape
98        self.assertEqual(nvectors, ncomponents)
99
100    def test_pca_with_max_components(self):
101        max_components = 3
102        self.create_dataset(ncomponents = max_components + 3)
103
104        pca = linear.Pca(max_components=max_components)(self.dataset)
105
106        nvectors, vector_dimension = pca.projection.shape
107        self.assertEqual(nvectors, max_components)
108
109    def test_pca_handles_unknowns(self):
110        self.create_dataset_with_unknowns()
111
112        linear.Pca()(self.dataset)
113
114    def test_total_variance_remains_the_same(self):
115        for m in (10, 250):
116            self.create_dataset(m=m)
117
118            pca = linear.Pca()(self.dataset)
119
120            self.assertAlmostEqual(pca.variance_sum, pca.variances.sum())
121            self.assertAlmostEqual(pca.variance_sum, (self.principal_components != 0).sum())
122
123    def test_pca_on_empty_data(self):
124        self.create_empty_dataset()
125
126        with self.assertRaises(ValueError):
127            linear.Pca()(self.dataset)
128
129    def test_pca_on_only_constant_features(self):
130        self.create_constant_dataset()
131
132        with self.assertRaises(ValueError):
133            linear.Pca()(self.dataset)
134
135    def assertInCorrectSpace(self, vectors):
136        vectors = vectors.copy()
137        for component in self.principal_components:
138            i = component.nonzero()[0][0]
139            coef = vectors[:,i] / component[i]
140            vectors -= np.dot(coef.reshape(-1, 1), component.reshape(1, -1))
141
142        for vector in vectors:
143            for value in vector:
144                self.assertAlmostEqual(value, 0.)
145
146
147class TestProjector(unittest.TestCase):
148    def create_normal_dataset(self):
149        self.principal_component = normalize([random.randint(0, 5) for _ in range(10)])
150        self.dataset = data.Table(*prepare_dataset(components=[self.principal_component]))
151
152    def create_dataset_with_classes(self):
153        domain, features = prepare_dataset(components=[[random.randint(0, 5) for _ in range(10)]])
154        domain = data.Domain(domain.features,
155                             feature.Discrete("C", values=["F", "T"]),
156                             class_vars=[feature.Discrete("MC%i" % i, values=["F", "T"]) for i in range(4)])
157
158        self.dataset = data.Table(domain, np.hstack((features, np.random.random((len(features), 5)))))
159
160
161    def test_projected_domain_can_convert_data_with_class(self):
162        self.create_dataset_with_classes()
163        projector = linear.Pca(variance_covered=.99)(self.dataset)
164
165        projected_data = projector(self.dataset)
166        converted_data = data.Table(projected_data.domain, self.dataset)
167
168        self.assertItemsEqual(projected_data, converted_data)
169
170    def test_projected_domain_can_convert_data_without_class(self):
171        self.create_normal_dataset()
172        projector = linear.Pca(variance_covered=.99)(self.dataset)
173
174        projected_data = projector(self.dataset)
175        converted_data = data.Table(projected_data.domain, self.dataset)
176
177        self.assertItemsEqual(projected_data, converted_data)
178
179    def test_projected_domain_contains_class_vars(self):
180        self.create_dataset_with_classes()
181
182        projector = linear.Pca(variance_covered=.99)(self.dataset)
183        projected_data = projector(self.dataset)
184
185        self.assertIn(self.dataset.domain.class_var, projected_data.domain)
186        for class_ in self.dataset.domain.class_vars:
187            self.assertIn(class_, projected_data.domain)
188        for ex1, ex2 in zip(self.dataset, projected_data):
189            self.assertEqual(ex1.get_class(), ex2.get_class())
190            for v1, v2 in zip(ex1.get_classes(), ex2.get_classes()):
191                self.assertEqual(v2, v2)
192
193
194    def test_projects_example(self):
195        self.create_normal_dataset()
196        projector = linear.Pca(variance_covered=.99)(self.dataset)
197
198        projector(self.dataset[0])
199
200    def test_projects_data_table(self):
201        self.create_normal_dataset()
202        projector = linear.Pca(variance_covered=.99)(self.dataset)
203
204        projector(self.dataset)
205
206    def test_converts_input_domain_if_needed(self):
207        self.create_normal_dataset()
208        projector = linear.Pca(variance_covered=.99)(self.dataset)
209
210        new_examples = data.Table(data.Domain(self.dataset.domain.features[:5]), [[1.,2.,3.,4.,5.]])
211
212        projector(new_examples)
213
214    def test_can_pickle_and_unpickle(self):
215        self.create_normal_dataset()
216        projector = linear.PCA(variance_covered=.99)(self.dataset)
217
218        pickled = pickle.dumps(projector)
219        restored = pickle.loads(pickled)
220
221        self.assertFalse((projector.projection - restored.projection).any())
222        self.assertFalse((projector.center - restored.center).any())
223        self.assertFalse((projector.scale - restored.scale).any())
224
225        transformed, new_transformed = projector(self.dataset), restored(self.dataset)
226        print transformed[0][0]
227        for ex1, ex2 in zip(transformed, new_transformed):
228            for v1, v2 in zip(ex1, ex2):
229                self.assertEqual(v1, v2)
230
231
232class TestFda(unittest.TestCase):
233    pass
234
235if __name__ == '__main__':
236    unittest.main()
237
Note: See TracBrowser for help on using the repository browser.