CountVectorizer
sklearn
Python
text analysis
NLP

How do I use sklearn CountVectorizer with both 'word' and 'char' analyzer? - python

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

One CountVectorizer instance can use only one analyzer at a time. If you want both word-level and character-level features from the same text, the normal solution is to build two vectorizers and combine their outputs.

Why One Vectorizer Is Not Enough

CountVectorizer has an analyzer parameter, but it accepts one mode per instance:

  • 'word'
  • 'char'
  • 'char_wb'

That means this is not possible in one object:

python
CountVectorizer(analyzer=["word", "char"])

Instead, create one vectorizer for words and another for character n-grams.

Combine Two Vectorizers with FeatureUnion

Scikit-learn's FeatureUnion is the standard tool for combining multiple feature extractors that operate on the same input.

python
1from sklearn.feature_extraction.text import CountVectorizer
2from sklearn.pipeline import FeatureUnion
3
4texts = [
5    "The cat sat on the mat",
6    "The dog chased the cat",
7    "Cats and dogs are pets",
8]
9
10features = FeatureUnion([
11    ("word", CountVectorizer(analyzer="word", ngram_range=(1, 2))),
12    ("char", CountVectorizer(analyzer="char", ngram_range=(3, 5))),
13])
14
15X = features.fit_transform(texts)
16print(X.shape)

The result is one sparse matrix whose columns include both word n-grams and character n-grams.

Why This Is Useful

Word features capture meaning at the token level, while character features capture spelling patterns, prefixes, suffixes, and resilience to small typos.

That combination is often helpful when:

  • text contains misspellings or noisy user input
  • morphology matters
  • you want both semantic and subword information

It is a common pattern in text classification tasks.

Add the Combined Features to a Classifier Pipeline

You can feed the union directly into a classifier:

python
1from sklearn.feature_extraction.text import CountVectorizer
2from sklearn.linear_model import LogisticRegression
3from sklearn.pipeline import FeatureUnion, Pipeline
4
5pipeline = Pipeline([
6    ("features", FeatureUnion([
7        ("word", CountVectorizer(analyzer="word", ngram_range=(1, 2))),
8        ("char", CountVectorizer(analyzer="char", ngram_range=(3, 5))),
9    ])),
10    ("clf", LogisticRegression(max_iter=1000)),
11])
12
13labels = [0, 1, 1]
14pipeline.fit(texts, labels)
15print(pipeline.predict(["dog on mat"]))

This keeps the preprocessing and model together in one reusable object.

Consider char_wb as a Variation

If plain character n-grams feel too noisy, char_wb can be a good compromise. It creates character n-grams inside word boundaries, which often reduces cross-word artifacts.

You can swap the character branch easily:

python
CountVectorizer(analyzer="char_wb", ngram_range=(3, 5))

That small change can matter in short-text classification or language-identification tasks.

It is especially useful when you want character features that stay inside individual words instead of creating n-grams that cross whitespace boundaries.

That often produces a cleaner feature space for short texts, product names, and typo-prone user input.

Watch the Feature Space Size

Combining word and character analyzers increases dimensionality quickly. That is not automatically bad, but it does mean:

  • more memory usage
  • larger sparse matrices
  • potentially slower model training

Practical controls include min_df, max_features, and narrower n-gram ranges.

Common Pitfalls

The biggest pitfall is trying to force both analyzers into one CountVectorizer. The API is not designed that way.

Another issue is converting the combined sparse matrix to dense form with .toarray() on large datasets. That can explode memory usage immediately.

People also underestimate how large character n-gram vocabularies become. Start with a narrow range and tune from there instead of enabling everything at once.

Summary

  • One CountVectorizer can use only one analyzer setting at a time.
  • To use both word and character features, build two vectorizers and combine them with FeatureUnion.
  • The combined output is a single sparse matrix suitable for normal scikit-learn pipelines.
  • 'char_wb is worth considering when raw character n-grams are too noisy.'
  • Control vocabulary growth with sensible n-gram ranges and feature limits.

Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Basis Lab
No course covers this one yet

Basis Lab writes one for you from a sentence about what you want to be able to do, then teaches it and checks you understood. Your first course is free.

Build my course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design