'Construct and return new feature encoding, based on a given
training corpus ``train_toks``.  See the class description
``TypedMaxentFeatureEncoding`` for a description of the
joint-features that will be included in this encoding.
Note: recognized feature values types are (int, float), over
types are interpreted as regular binary features.
:type train_toks: list(tuple(dict, str))
:param train_toks: Training data, represented as a list of
pairs, the first member of which is a feature dictionary,
and the second of which is a classification label.
:type count_cutoff: int
:param count_cutoff: A cutoff value that is used to discard
rare joint-features.  If a joint-feature\'s value is 1
fewer than ``count_cutoff`` times in the training corpus,
then that joint-feature is not included in the generated
encoding.
:type labels: list
:param labels: A list of labels that should be used by the
classifier.  If not specified, then the set of labels
attested in ``train_toks`` will be used.
:param options: Extra parameters for the constructor, such as
``unseen_features`` and ``alwayson_features``.'

@classmethod
def train(cls, train_toks, count_cutoff=0, labels=None, **options):

    mapping = {}
    seen_labels = set()
    count = defaultdict(int)
    for (tok, label) in train_toks:
        if (labels and (label not in labels)):
            raise ValueError((u'Unexpected    label    %s' % label))
        seen_labels.add(label)
        for (fname, fval) in tok.items():
            if (type(fval) in (int, float)):
                fval = type(fval)
            count[(fname, fval)] += 1
            if (count[(fname, fval)] >= count_cutoff):
                if ((fname, fval, label) not in mapping):
                    mapping[(fname, fval, label)] = len(mapping)
    if (labels is None):
        labels = seen_labels
    return cls(labels, mapping, **options)
