def train(self, messageList):
        """
        messageList is a list of message in dictionary. Major keys are 'title', 'description', and 'categories', and so on.
        """
        binaryClassifierDic = self._binaryClassifierDic
        doCV = self._doCV
        verbose = self._verbose

        #--- set up logger.
        logger = logging.getLogger(__name__)
        ch = logging.StreamHandler()
        logger.setLevel(logging.INFO if verbose else logging.WARNING)
        logger.info(
            '  len(binaryClassifierDic) = %d',
            len(binaryClassifierDic))

        #--- Empty variables
        classifierDic = {}

        #--- extract category list in dataset
        categorySet = set()
        for msg in messageList:
            categorySet.update(msg['categories'])
        #- there might be extra categories in binaryClassifierDic
        categorySet.update(binaryClassifierDic.keys())
        categoryList = sorted(list(categorySet))

        #--- for each category, train a binary classifier
        trainStats = {}
        totNTP = 0
        totNFP = 0
        totNTN = 0
        totNFN = 0
        for cat in categoryList:
            logger.info('Category: %s', cat)
            if (len(binaryClassifierDic) != 0):
                binaryClassifier = binaryClassifierDic[cat]
            else:
                binaryClassifier = copy.deepcopy(self._binaryClassifier)

            #- turn into a binary labeled data
            dset = []
            for msg in messageList:
                binaryLabel = 'pos' if cat in msg['categories'] else 'neg'
                dset.append((msg, binaryLabel))

            #- save stat
            nPos = countTruth(lambda x: x[1] == 'pos', dset)
            nNeg = countTruth(lambda x: x[1] == 'neg', dset)
            assert(len(dset) == nPos + nNeg)

            v = (nPos + nNeg) / float(nPos)
            mvAcc = max([v, 1 - v])
            logger.info(
                '  nPos,nNeg = (%d / %d), majority vote acc = %.3f',
                nPos,
                nNeg,
                mvAcc)

            statDic = {'nPos': nPos, 'nNeg': nNeg, 'majority vote acc': mvAcc}

            #--- run cross validation to estimate performance
            cvResDic = {}
            bContinue = False
            didCV = False
            if (doCV):
                try:
                    cvResDic = dssgRunCV(self._binaryClassifier, dset)
                    strList = (
                        'nFolds',
                        'mean of accuracy',
                        '95% confidence interval',
                        'precision',
                        'recall',
                        'f1')
                    msg = '%2d-CV: %s = %.3f, %s = [%.3f, %.3f]\n' % \
                        (cvResDic[strList[0]], strList[1], cvResDic[strList[1]], strList[
                         2], cvResDic[strList[2]][0], cvResDic[strList[2]][1])
                    for i in [1, 3, 4, 5]:
                        msg += '       %s = %.3f' % (
                            strList[i],
                            cvResDic[strList[i]])
                        if (i != 5):
                            msg += '\n'
                    didCV = True
                except TooSkewedLabelsException:
                    msg = 'CV accuracy estimate is not available due to skewed labels. Skipping'

                logger.info('  ' + msg)

            statDic['CV stat'] = cvResDic
            trainStats[cat] = statDic

            #--- build a classifier using all data.
            if (isinstance(binaryClassifier, DssgBinaryClassifierAdaptiveInterpolation) or
                    isinstance(binaryClassifier, DssgBinaryClassifierAdaptiveSVC)):
                binaryClassifier.train(dset)
            else:
                if (nPos == 0 or nNeg == 0):
                    #- when only one label presents, create a majority vote classifier
                    mvClassifier = DssgBinaryClassifierMajorityVote()
                    mvClassifier.train(dset)
                    binaryClassifier = mvClassifier
                else:
                    binaryClassifier.train(dset)

            #- report vocabulary
            if (isinstance(binaryClassifier, DssgBinaryClassifierAdaptiveInterpolation) or isinstance(binaryClassifier, DssgBinaryClassifierAdaptiveSVC) or isinstance(binaryClassifier, DssgBinaryClassifierMajorityVote)):
                logger.info(
                    '  Can\'t get nVoca since the classifier is: %s',
                    repr(binaryClassifier))
            else:
                nVoca = len(binaryClassifier._vectorizer.getFeatureNameList())
                logger.info('  nVoca = %d', nVoca)
                if (isinstance(binaryClassifier._vectorizer, DssgMultiVectorizer)):
                    logger.info(
                        '  Vectorizer: %s',
                        repr(binaryClassifier._vectorizer))

            #- add classifier to classifier dictionary.
            classifierDic[cat] = binaryClassifier

            logger.info('  type = %s', str(type(binaryClassifier)))
            if (didCV):
                totNTP += statDic['CV stat']['nTP']
                totNFP += statDic['CV stat']['nFP']
                totNTN += statDic['CV stat']['nTN']
                totNFN += statDic['CV stat']['nFN']

        if (doCV):
            didCVCategoryList = []
            for cat, v in trainStats.iteritems():
                if (len(v['CV stat']) != 0):
                    didCVCategoryList.append(cat)
            logger.info('DID CV for categories: %s', str(didCVCategoryList))

            meanF1 = np.mean(
                np.array(map(lambda cat: trainStats[cat]['CV stat']['f1'], didCVCategoryList)))
            logger.info('Overall mean F1 = %.3f', meanF1)

            totPrecision = float(totNTP) / (totNTP + totNFP)
            totRecall = float(totNTP) / (totNTP + totNFN)
            logger.info(
                'Overall aggregate prec = %.3f, recall = %.3f, F1 = %.3f',
                totPrecision, totRecall, sp.stats.hmean([totPrecision, totRecall]))

        self._classifierDic = classifierDic
        self._categoryList = categoryList
        self._trainStats = trainStats
        pass
dataset/ETHPy150Open dssg/ushine-learning/dssg/classifier.py/DssgCategoryClassifier.train/swapped operands of `/`