File size: 2,633 Bytes
1b19efc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3f21703
 
 
 
 
 
 
 
1b19efc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import numpy as np
import pytest

from sgd_classifier import SUPPORTED_LOSSES, SGDClassifier


def dataset(seed=4, samples=61, features=8):
    rng = np.random.default_rng(seed)
    X = rng.normal(size=(samples, features))
    y = np.where(X[:, 0] - 0.5 * X[:, 1] > 0, "positive", "negative")
    return X, y


@pytest.mark.parametrize("loss", SUPPORTED_LOSSES)
@pytest.mark.parametrize("selection", ["random", "permutation"])
def test_every_loss_and_selection_mode_trains(loss, selection):
    X, y = dataset()
    model = SGDClassifier(
        loss=loss, batch_size=13, batch_selection=selection, max_epochs=2,
        random_state=7,
    ).fit(X, y)
    assert model.predict(X).shape == (61,)
    assert model.n_updates_ == 10


def test_train_step_updates_and_returns_model():
    X, y = dataset(samples=20)
    model = SGDClassifier(loss="log_loss", learning_rate=0.1)
    returned = model.train_step(X, y)
    assert returned is model
    assert model.n_updates_ == 1
    assert np.any(model.coef_ != 0)


def test_get_update_previews_without_applying_it():
    X, y = dataset(samples=20)
    model = SGDClassifier(loss="log_loss", learning_rate=0.1)
    coef_update, intercept_update = model.get_update(X, y)
    np.testing.assert_array_equal(model.coef_, np.zeros_like(model.coef_))
    np.testing.assert_array_equal(model.intercept_, np.zeros_like(model.intercept_))
    assert model.n_updates_ == 0
    model.train_step(X, y)
    np.testing.assert_allclose(model.coef_, coef_update)
    np.testing.assert_allclose(model.intercept_, intercept_update)


def test_evaluate_returns_dataset_loss_and_accuracy():
    X, y = dataset(samples=30)
    model = SGDClassifier(loss="log_loss").fit(X, y)
    metrics = model.evaluate(X, y)
    assert metrics["loss"] >= 0
    assert 0 <= metrics["accuracy"] <= 1


def test_train_step_can_declare_classes_missing_from_batch():
    model = SGDClassifier()
    model.train_step([[1.0, 2.0]], ["a"], classes=["a", "b"])
    assert model.classes_.tolist() == ["a", "b"]


def test_permutation_batches_cover_each_example_once():
    model = SGDClassifier(batch_size=4, batch_selection="permutation")
    batches = list(model._batches(11, np.random.default_rng(1)))
    assert sorted(np.concatenate(batches).tolist()) == list(range(11))
    assert [len(batch) for batch in batches] == [4, 4, 3]


def test_seed_is_reproducible():
    X, y = dataset(samples=50)
    options = dict(batch_selection="random", max_epochs=3, random_state=9)
    first = SGDClassifier(**options).fit(X, y)
    second = SGDClassifier(**options).fit(X, y)
    np.testing.assert_array_equal(first.coef_, second.coef_)