Fix performance hit during classification

Previously, the `vocabulary` property was computed dynamically when
accessed by returning a new set taken from the union of the vocabulary
of each class label. Unfortunately, this caused a major performance
issue in the `conditional` method, which needs to find the length of the
vocabulary across all class labels during every call. Ultimately, this
leads to very poor performance when classifying documents.

To address this, we *could* convert `vocabulary` from a property to an
attribute by having it be a separate `set` that is updated during
training along with the label-vocabulary. Though doing so would be a
space-time tradeoff that would greatly improve performance, we would
have to keep a duplicate copy of the entire vocabulary. I argue that
this wastes too much space.

An alternative is to add another attribute `_vocab_size`, which is a
simply integer, which uses much less space than storing another `set`
with the entire vocabulary. The issue with this approach is that we have
to update this variable carefully, as we must first check that the new
token hasn't been seen for any label before incrementing the
`_vocab_size`. Checking this results in more time spent during training,
however it is nice compromise of the space-time tradeoff.
This closes gh-12.