scikit-learn/examples/svm/plot_svm_scale_c.py

152 lines
5.3 KiB
Python
Raw Normal View History

2012-07-25 18:50:00 +08:00
"""
=========================================================================
Support Vector Classification (SVC): scaling the regularization parameter
=========================================================================
The following example illustrates the effect of scaling the
2012-07-25 22:43:42 +08:00
regularization parameter when using :ref:`svm` for
:ref:`classification <svm_classification>`.
2012-07-25 18:50:00 +08:00
For SVC classification, we are interested in a risk minimization for the
equation:
.. math::
C \sum_{i=1, n} \mathcal{L} (f(x_i), y_i) + \Omega (w)
where
- :math:`C` is used to set the amount of regularization
- :math:`\mathcal{L}` is a `loss` function of our samples
and our model parameters.
- :math:`\Omega` is a `penalty` function of our model parameters
2012-07-25 22:43:42 +08:00
If we consider the loss function to be the individual error per
sample, then the data-fit term, or the sum of the error for each sample, will
increase as we add more samples. The penalization term, however, will not
2012-07-25 18:50:00 +08:00
increase.
When using, for example, :ref:`cross validation <cross_validation>`, to
2012-09-04 20:00:41 +08:00
set the amount of regularization with `C`, there will be a
2012-08-27 23:33:03 +08:00
different amount of samples between the main problem and the smaller problems
withing the folds of the cross validation.
2012-07-25 18:50:00 +08:00
Since our loss function is dependant on the amount of samples, the latter
2012-07-25 22:43:42 +08:00
will influence the selected value of `C`.
2012-07-25 18:50:00 +08:00
The question that arises is `How do we optimally adjust C to
2012-09-04 20:00:41 +08:00
account for the different amount of training samples?`
2012-07-25 18:50:00 +08:00
The figures below are used to illustrate the effect of scaling our
2012-08-09 20:48:17 +08:00
`C` to compensate for the change in the number of samples, in the
2012-07-25 22:43:42 +08:00
case of using an `L1` penalty, as well as the `L2` penalty.
2012-07-25 18:50:00 +08:00
L1-penalty case
-----------------
2012-07-25 22:43:42 +08:00
In the `L1` case, theory says that prediction consistency
2012-07-25 18:50:00 +08:00
(i.e. that under given hypothesis, the estimator
2012-09-04 20:00:41 +08:00
learned predicts as well as a model knowing the true distribution)
2012-08-09 20:48:17 +08:00
is not possible because of the bias of the `L1`. It does say, however,
that model consistency, in terms of finding the right set of non-zero
2012-07-25 22:43:42 +08:00
parameters as well as their signs, can be achieved by scaling
`C1`.
2012-07-25 18:50:00 +08:00
L2-penalty case
-----------------
2012-09-04 20:00:41 +08:00
The theory says that in order to achieve prediction consistency, the
penalty parameter should be kept constant
as the number of samples grow.
2012-07-25 18:50:00 +08:00
Simulations
------------
2012-07-25 22:43:42 +08:00
The two figures below plot the values of `C` on the `x-axis` and the
2012-07-25 18:50:00 +08:00
corresponding cross-validation scores on the `y-axis`, for several different
fractions of a generated data-set.
2012-08-27 23:33:03 +08:00
In the `L1` penalty case, the cross-validation-error correlates best with
the test-error, when scaling our `C` with the number of samples, `n`,
which can be seen in the first figure.
2012-07-25 18:50:00 +08:00
2012-07-25 22:43:42 +08:00
For the `L2` penalty case, the best result comes from the case where `C`
2012-07-25 18:50:00 +08:00
is not scaled.
2012-07-25 22:43:42 +08:00
.. topic:: Note:
2012-07-25 18:50:00 +08:00
2012-07-25 22:43:42 +08:00
Two seperate datasets are used for the two different plots. The reason
behind this is the `L1` case works better on sparse data, while `L2`
is better suited to the non-sparse case.
2012-07-25 18:50:00 +08:00
"""
print __doc__
# Author: Andreas Mueller <amueller@ais.uni-bonn.de>
# Jaques Grobler <jaques.grobler@inria.fr>
# License: BSD
import numpy as np
import pylab as pl
from sklearn.svm import LinearSVC
from sklearn.cross_validation import ShuffleSplit
from sklearn.grid_search import GridSearchCV
from sklearn.utils import check_random_state
from sklearn import datasets
rnd = check_random_state(1)
# set up dataset
n_samples = 100
2012-07-25 21:18:45 +08:00
n_features = 300
2012-07-25 22:43:42 +08:00
2012-09-04 20:00:41 +08:00
# L1 data (only 5 informative features)
2012-09-05 01:39:25 +08:00
X_1, y_1 = datasets.make_classification(n_samples=n_samples,
2012-12-25 20:16:05 +08:00
n_features=n_features, n_informative=5,
random_state=1)
2012-07-25 22:43:42 +08:00
2012-09-04 20:00:41 +08:00
# L2 data: non sparse, but less features
2012-07-25 21:18:45 +08:00
y_2 = np.sign(.5 - rnd.rand(n_samples))
2012-09-05 01:39:25 +08:00
X_2 = rnd.randn(n_samples, n_features / 5) + y_2[:, np.newaxis]
X_2 += 5 * rnd.randn(n_samples, n_features / 5)
2012-07-25 22:43:42 +08:00
clf_sets = [(LinearSVC(penalty='L1', loss='L2', dual=False,
2012-07-25 18:50:00 +08:00
tol=1e-3),
2012-09-04 20:34:42 +08:00
np.logspace(-2.3, -1.3, 10), X_1, y_1),
2012-07-25 22:43:42 +08:00
(LinearSVC(penalty='L2', loss='L2', dual=True,
2012-07-25 21:18:45 +08:00
tol=1e-4),
np.logspace(-4.5, -2, 10), X_2, y_2)]
2012-07-25 22:43:42 +08:00
2012-07-25 18:50:00 +08:00
colors = ['b', 'g', 'r', 'c']
for fignum, (clf, cs, X, y) in enumerate(clf_sets):
# set up the plot for each regressor
pl.figure(fignum, figsize=(9, 10))
2012-07-25 22:43:42 +08:00
2012-07-25 21:18:45 +08:00
for k, train_size in enumerate(np.linspace(0.3, 0.7, 3)[::-1]):
2012-07-25 18:50:00 +08:00
param_grid = dict(C=cs)
2012-07-25 21:18:45 +08:00
# To get nice curve, we need a large number of iterations to
# reduce the variance
2012-07-25 18:50:00 +08:00
grid = GridSearchCV(clf, refit=False, param_grid=param_grid,
2012-12-25 20:16:05 +08:00
cv=ShuffleSplit(n=n_samples, train_size=train_size,
n_iter=250, random_state=1))
2012-07-25 18:50:00 +08:00
grid.fit(X, y)
scores = [x[1] for x in grid.grid_scores_]
2012-07-25 22:43:42 +08:00
scales = [(1, 'No scaling'),
((n_samples * train_size), '1/n_samples'),
2012-07-25 18:50:00 +08:00
]
for subplotnum, (scaler, name) in enumerate(scales):
2012-07-25 21:18:45 +08:00
pl.subplot(2, 1, subplotnum + 1)
2012-07-25 22:43:42 +08:00
pl.xlabel('C')
pl.ylabel('CV Score')
2012-09-05 01:39:25 +08:00
grid_cs = cs * float(scaler) # scale the C's
2012-07-25 18:50:00 +08:00
pl.semilogx(grid_cs, scores, label="fraction %.2f" %
2012-07-25 21:18:45 +08:00
train_size)
2012-09-04 20:00:41 +08:00
pl.title('scaling=%s, penalty=%s, loss=%s' %
(name, clf.penalty, clf.loss))
2012-07-25 18:50:00 +08:00
2012-07-25 21:18:45 +08:00
pl.legend(loc="best")
2012-07-25 18:50:00 +08:00
pl.show()