Solved – Simple text classifier: classification taking forever

classificationmachine learningpythonscikit learntext mining

I work for a small tech startup, and I want to classify our users into demographics based on the domain of their email address. When users sign up to our site, they can enter a job category or pick "other". The goal is to classify as many of the "other" type as possible using a bag-of-words approach.

To do this, I have written some code in Python. For each user, I look at the domain name of their email address and scrape the text from their homepage (using Beautiful Soup). I also look for an "About Us" page, which I also scrape. What I'm left with is a map of domains to text. Some domains are classified (i.e., users whose email address comes from this domain have self-classified their job types), and some aren't (those users who have self-classified as "other"). The total data set for classified users is about 2000 (neglecting domains like gmail and hotmail and [I can't believe I'm about to type this] aol). I'm using a train/test split of 75/25.

Using scikit-learn, I'm trying to implement a simple classifier, but there seems to be an issue with either convergence or performance. The data set doesn't seem particularly big, but the two classifiers I've tried (Perceptron and RidgeClassifier) seem to be having some issues finding a fit. I haven't really tried to change the parameters for the classifiers, and it's not clear to me which nobs I should be turning.

I lack intuition into this problem, and it's difficult for me to tell whether the issues I'm having are due to not enough data, or what. I'd like to know

  • Am I barking up the wrong tree? Has anyone tried something like this and made it work?
  • Do other ML packages for Python do a better job of text classification? (I'm looking at you, nltk.)
  • Is my data set large enough? Are there any "rules-of-thumb" for how much data you'd need for something like this (~5-10 categories)?
  • What's a reasonable amount of time for the learning to take? Are there any hints that will tell me the difference between "this is really hard" and "this isn't going to work"?
  • I've tried to follow the examples here and here. These examples are pretty speedy, so it makes me worry that I don't have enough data to make things work nicely. Is the "20 newsgroups" classification problem typical, or does it show up because it's easily solvable?

Any guidance here would be appreciated!


As an update: the huge performance hit seems to come from the "vectorizer": that is, the thing that maps a vector of words to the reals. For some reason, Tfidf was taking a long time to do its thing—I switched to a different vectorizer, and now things run quite quickly.

In regards to the actual learning, I've found that the Naive Bayes routines work pretty well out of the box (f-score around 70-75%, which is good enough for now). The model that I found works the best, however, is one based on a linear SVM (scikits.svm.LinearSVC), which gets me somewhere in the 80-85% range with a bit of tinkering.

Best Answer

I think the issue here may be the use of term vectors. Your instances (bags of words) are translated to a vector of probably 150 to 10000 dimensions. Each word that occurs in your corpus (the websites) is one dimension and the value for each instance is the frequency (it the tf/idf score) of that word in the given website.

In a space with that many dimensions, most machine learning algorithms will suffer. You've chosen fairly lightweight algorithms, but they may still take a while to converge, depending on how they're implemented.

The most common classifier in this scenario is naive Bayes, which doesn't see the instance space as a high dimensional space, but just as a collection of frequencies (from which it estimates, using Bayes theorem, the probability of each class). Training this classifier should take as long as it takes to read the data once, and classification should take as long as it takes to read the instance. Since it shouldn't have any parameters, it will at least give you a good baseline. Nltk almost certainly has this algorithm (it's the mother of spam detection).

Another option, if you want to use more traditional ML algorithms, is to reduce the dimensionality of the dataset to something manageable (anything below 50), using PCA. This will take more time, and make it more difficult to update your classifier, but it can lead to good performance.

Related Question