source: orange/Orange/testing/unit/tests/test_svm.py @ 11651:f6d8c39c686e

Revision 11651:f6d8c39c686e, 9.8 KB checked in by Ales Erjavec <ales.erjavec@…>, 9 months ago (diff)

Added a test for SVMLearner and SVMLearnerSparse equivalence.

Line 
1try:
2    import unittest2 as unittest
3except:
4    import unittest
5   
6import Orange
7from Orange.classification.svm import SVMLearner, SVMLearnerSparse, \
8                            ScoreSVMWeights, LinearSVMLearner, \
9                            MultiClassSVMLearner, RFE, \
10                            get_linear_svm_weights, \
11                            example_weighted_sum
12from Orange.classification import svm                           
13from Orange.classification.svm.kernels import BagOfWords, RBFKernelWrapper
14from Orange.testing import testing
15from Orange.testing.testing import datasets_driven, test_on_datasets, test_on_data
16import orange
17
18import copy
19
20import pickle
21import numpy as np
22
23def multiclass_from1vs1(dec_values, class_var):
24    n_class = len(class_var.values)
25    votes = [0] * n_class
26    p = 0
27    for i in range(n_class - 1):
28        for j in range(i + 1, n_class):
29            val = dec_values[p]
30            if val > 0:
31                votes[i] += 1
32            else:
33                votes[j] += 1
34            p += 1
35    max_i = np.argmax(votes)
36    return class_var(int(max_i))
37   
38   
39def svm_test_binary_classifier(self, data):
40    if isinstance(data.domain.class_var, Orange.feature.Discrete):
41        # Test binary classifiers equivalence. 
42        classes = data.domain.class_var.values
43        bin_cls = []
44        # Collect all binary classifiers
45        for i in range(len(classes) - 1):
46            for j in range(i + 1, len(classes)):
47                bin_cls.append(self.classifier.get_binary_classifier(i, j))
48               
49        pickled_bin_cls = pickle.loads(pickle.dumps(bin_cls))
50       
51        indices = Orange.data.sample.SubsetIndices2(p0=0.2)
52        sample = data.select(indices(data), 0)
53       
54        learner = copy.copy(self.learner)
55        learner.probability = False 
56        classifier_no_prob = learner(data)
57       
58        for inst in sample:
59            d_val = list(self.classifier.get_decision_values(inst))
60            d_val_b = [bc.get_decision_values(inst)[0] for bc in bin_cls]
61            d_val_b1 = [bc.get_decision_values(inst)[0] for bc in pickled_bin_cls]
62            for v1, v2, v3 in zip(d_val, d_val_b, d_val_b1):
63                self.assertAlmostEqual(v1, v2, places=3)
64                self.assertAlmostEqual(v1, v3, places=3)
65           
66            prediction_1 = classifier_no_prob(inst)
67            d_val = classifier_no_prob.get_decision_values(inst)
68            prediciton_2 = multiclass_from1vs1(d_val, classifier_no_prob.class_var)
69            self.assertEqual(prediction_1, prediciton_2)
70           
71datasets = testing.CLASSIFICATION_DATASETS + testing.REGRESSION_DATASETS
72@datasets_driven(datasets=datasets)
73class LinearSVMTestCase(testing.LearnerTestCase):
74    LEARNER = SVMLearner(name="svm-lin", kernel_type=SVMLearner.Linear)
75
76    @test_on_data
77    def test_learner_on(self, dataset):
78        testing.LearnerTestCase.test_learner_on(self, dataset)
79        svm_test_binary_classifier(self, dataset)
80       
81   
82    # Don't test on "monks" the coefs are really large and
83    @test_on_datasets(datasets=["iris", "brown-selected", "lenses", "zoo"])
84    def test_linear_classifier_weights_on(self, dataset):
85        # Test get_linear_svm_weights
86        classifier = self.LEARNER(dataset)
87        weights = get_linear_svm_weights(classifier, sum=True)
88       
89        weights = get_linear_svm_weights(classifier, sum=False)
90       
91        n_class = len(classifier.class_var.values)
92       
93        def class_pairs(n_class):
94            for i in range(n_class - 1):
95                for j in range(i + 1, n_class):
96                    yield i, j
97                   
98        l_map = classifier._get_libsvm_labels_map()
99   
100        for inst in dataset[:20]:
101            dec_values = classifier.get_decision_values(inst)
102           
103            for dec_v, weight, rho, pair in zip(dec_values, weights,
104                                    classifier.rho, class_pairs(n_class)):
105                t_inst = Orange.data.Instance(classifier.domain, inst)                   
106                dec_v1 = example_weighted_sum(t_inst, weight) - rho
107                self.assertAlmostEqual(dec_v, dec_v1, 4)
108                   
109    @test_on_datasets(datasets=testing.REGRESSION_DATASETS)
110    def test_linear_regression_weights_on(self, dataset):
111        predictor = self.LEARNER(dataset)
112        weights = get_linear_svm_weights(predictor)
113       
114        for inst in dataset[:20]:
115            t_inst = Orange.data.Instance(predictor.domain, inst)
116            prediction = predictor(inst)
117            w_sum = example_weighted_sum(t_inst, weights)
118            self.assertAlmostEqual(float(prediction), 
119                                   w_sum - predictor.rho[0],
120                                   places=4)
121       
122
123@datasets_driven(datasets=datasets)
124class PolySVMTestCase(testing.LearnerTestCase):
125    LEARNER = SVMLearner(name="svm-poly", kernel_type=SVMLearner.Polynomial)
126   
127    @test_on_data
128    def test_learner_on(self, dataset):
129        testing.LearnerTestCase.test_learner_on(self, dataset)
130        svm_test_binary_classifier(self, dataset)
131       
132
133@datasets_driven(datasets=datasets)
134class RBFSVMTestCase(testing.LearnerTestCase):
135    LEARNER = SVMLearner(name="svm-RBF", kernel_type=SVMLearner.RBF)
136   
137    @test_on_data
138    def test_learner_on(self, dataset):
139        testing.LearnerTestCase.test_learner_on(self, dataset)
140        svm_test_binary_classifier(self, dataset)
141
142@datasets_driven(datasets=datasets)
143class SigmoidSVMTestCase(testing.LearnerTestCase):
144    LEARNER = SVMLearner(name="svm-sig", kernel_type=SVMLearner.Sigmoid)
145   
146    @test_on_data
147    def test_learner_on(self, dataset):
148        testing.LearnerTestCase.test_learner_on(self, dataset)
149        svm_test_binary_classifier(self, dataset)
150
151
152def to_sparse(data):
153    domain = Orange.data.Domain([], data.domain.class_var)
154    domain.add_metas(dict([(Orange.core.newmetaid(), v)
155                           for v in data.domain.attributes]))
156    return Orange.data.Table(domain, data)
157
158
159def sparse_data_iter():
160    for name, (data, ) in testing.datasets_iter(datasets):
161        yield name, (to_sparse(data), )
162
163
164@testing.data_driven(data_iter=sparse_data_iter())
165class SparseSVMTestCase(testing.LearnerTestCase):
166    LEARNER = SVMLearnerSparse(name="svm-sparse")
167
168    @test_on_data
169    def test_learner_on(self, dataset):
170        testing.LearnerTestCase.test_learner_on(self, dataset)
171        svm_test_binary_classifier(self, dataset)
172
173
174@datasets_driven(datasets=testing.CLASSIFICATION_DATASETS +
175                 testing.REGRESSION_DATASETS)
176class SparseLearnerEquivalence(unittest.TestCase):
177    @test_on_data
178    def test_sparse_learner_equivalence(self, dataset):
179        sparse_dataset = to_sparse(dataset)
180        if isinstance(dataset.domain.class_var, Orange.feature.Discrete):
181            svm_type = SVMLearner.C_SVC
182        else:
183            svm_type = SVMLearner.Epsilon_SVR
184
185        sparse_learner = Orange.core.SVMLearnerSparse(
186            probability=False,
187            svm_type=svm_type,
188            shrinking=False,
189            eps=1e-10
190        )
191        dense_learner = Orange.core.SVMLearner(
192            probability=False,
193            svm_type=svm_type,
194            shrinking=False,
195            eps=1e-10
196        )
197        sparse_cls = sparse_learner(sparse_dataset)
198        dense_cls = dense_learner(dataset)
199
200        for sparse, dense in zip(sparse_dataset, dataset):
201            val1, dist1 = sparse_cls(sparse, Orange.core.GetBoth)
202            val2, dist2 = dense_cls(dense, Orange.core.GetBoth)
203
204            if isinstance(dataset.domain.class_var, Orange.feature.Discrete):
205                for p1, p2 in zip(dist1, dist2):
206                    self.assertAlmostEqual(float(p1), float(p2), places=3)
207            else:
208                self.assertAlmostEqual(float(val1), float(val2), places=3)
209
210
211@datasets_driven(datasets=datasets)
212class CustomWrapperSVMTestCase(testing.LearnerTestCase):
213    LEARNER = SVMLearner
214
215    @test_on_data
216    def test_learner_on(self, data):
217        """ Test custom kernel wrapper
218        """
219        if data.domain.has_continuous_attributes():
220            dist = orange.ExamplesDistanceConstructor_Euclidean(data)
221        else:
222            dist = orange.ExamplesDistanceConstructor_Hamming(data)
223        self.learner = self.LEARNER(kernel_type=SVMLearner.Custom,
224                                    kernel_func=RBFKernelWrapper(dist, gamma=0.5))
225
226        testing.LearnerTestCase.test_learner_on(self, data)
227        svm_test_binary_classifier(self, data)
228
229@datasets_driven(datasets=testing.CLASSIFICATION_DATASETS)
230class TestLinLearner(testing.LearnerTestCase):
231    LEARNER = LinearSVMLearner
232   
233   
234@datasets_driven(datasets=testing.CLASSIFICATION_DATASETS)
235class TestMCSVMLearner(testing.LearnerTestCase):
236    LEARNER = MultiClassSVMLearner
237
238
239@datasets_driven(datasets=datasets)
240class TestScoreSVMWeights(testing.MeasureAttributeTestCase):
241    MEASURE = ScoreSVMWeights()
242   
243@datasets_driven(datasets=testing.CLASSIFICATION_DATASETS)
244class TestScoreSVMWeightsWithMCSVM(testing.MeasureAttributeTestCase):
245    MEASURE = ScoreSVMWeights(learner=MultiClassSVMLearner())
246   
247@datasets_driven(datasets=["iris"])
248class TestRFE(testing.DataTestCase):
249    @test_on_data
250    def test_rfe_on(self, data):
251        rfe = RFE()
252        num_selected = min(5, len(data.domain.attributes))
253        reduced = rfe(data, num_selected)
254        self.assertEqual(len(reduced.domain.attributes), num_selected)
255        scores = rfe.get_attr_scores(data, stop_at=num_selected)
256        self.assertEqual(len(data.domain.attributes) - num_selected, len(scores))
257        self.assertTrue(set(reduced.domain.attributes).isdisjoint(scores.keys()))
258
259    def test_pickle(self):
260        import cPickle
261        rfe = RFE()
262        copy = cPickle.loads(cPickle.dumps(rfe))
263
264def load_tests(loader, tests, ignore):
265    import doctest
266    tests.addTests(doctest.DocTestSuite(svm, optionflags=doctest.ELLIPSIS))
267    return tests
268
269if __name__ == "__main__":
270    unittest.main()
Note: See TracBrowser for help on using the repository browser.