Skip to content

docs: show the two commands working together - #172

Merged
cardmagic merged 2 commits into
masterfrom
docs/cli-workflow
Aug 15, 2026
Merged

docs: show the two commands working together#172
cardmagic merged 2 commits into
masterfrom
docs/cli-workflow

Conversation

@cardmagic

Copy link
Copy Markdown
Owner

Neither README.md nor docs/cli.md said how classifier and keywords relate. Each was documented alone, so a reader met two commands and no reason to run them together.

Adds three workflows to docs/cli.md, plus a short pointer in the README. Every console block was run against the installed 2.7.0 binaries and the output pasted from the real run.

1. Read the label and the reason side by side

$ classifier -f reviews-model.json -p "Broken on arrival, awful quality and useless customer service"
positive:0.07 negative:0.93

$ keywords -m reviews.json -n 5 "Broken on arrival, awful quality and useless customer service"
useless:0.4 awful:0.4 arrival:0.4 broken:0.4 service:0.34

The verdict, then the terms that carried it. This is what the explainability literature calls showing top terms alongside the predicted label, and it is the thing you want when a classification surprises you.

2. Find corpus-specific stopwords

A term in nearly every document tells a classifier nothing, and every corpus grows its own. No general stopword list knows that a review corpus repeats delivery.

$ keywords info -m default.json
Vocabulary: 42

$ keywords fit -m pruned.json --max-df 0.5 good.txt bad.txt
$ keywords info -m pruned.json
Vocabulary: 41

One term went. Scoring under each model names it:

$ keywords -m default.json -n 3 "delivery was awful and broken"
broken:0.69 awful:0.69 delivery:0.24

$ keywords -m pruned.json -n 3 "delivery was awful and broken"
broken:0.71 awful:0.71

delivery sat in all 12 documents and still drew weight. Dropping it sharpens every term that carries real signal. The section also warns that these bounds cut fast: --min-df 2 took the same vocabulary from 42 terms to 7.

3. Keep the models straight

The commands write different formats and reject each other, which is worth stating because the flags differ too (-f vs -m):

$ classifier -f reviews.json "broken awful"
Error: Unknown classifier type in model: tfidf

$ keywords -m reviews-model.json "broken awful"
Error: Invalid vectorizer type: bayes

What I deliberately did not recommend

Piping keywords into classifier. It looks clever and it makes results worse:

$ classifier -f reviews-model.json -p "$LONG_REVIEW"
positive:0.08 negative:0.92        # whole review

$ keywords -m reviews.json -n 4 "$LONG_REVIEW"
arrived:0.6 refund:0.3 useless:0.3 build:0.3

$ classifier -f reviews-model.json -p "arrived refund useless build"
positive:0.21 negative:0.79        # top terms alone

Confidence drops from 0.92 to 0.79. TF-IDF ranks a term by how well it separates one document from the corpus, not by how well it signals a category, so it puts arrived first, a neutral delivery word. The docs now say to classify the full text and use keywords to explain it.

The literature does back TF-IDF feature selection feeding Naive Bayes, but as an in-pipeline weighting step, not as two CLIs piped together. The --min-df / --max-df workflow above is the part of that idea these commands actually expose.

Verified

  • 761 runs, 0 failures, 1 skip
  • static doc checks pass
  • no em or en dashes

Neither README.md nor docs/cli.md said how classifier and keywords relate.
Each was documented alone, so a reader met two tools and no reason to run
them together.

Add three workflows, each verified against the installed 2.7.0 binaries:

Read the label and the reason side by side. classifier -p gives the verdict
and keywords -n gives the terms that carried it, which is what you want when
a classification surprises you. This is the pattern the explainability
literature calls showing top terms alongside the predicted label.

Find corpus-specific stopwords. A review corpus repeats "delivery" and no
general stopword list knows it. --max-df drops a term above a document ratio,
so comparing keywords info before and after names the term, and dropping it
sharpens every term that carries signal.

Keep the models straight. The two commands write different formats and reject
each other, classifier takes -f, and keywords takes -m.

Also warn against piping keywords into classifier. TF-IDF ranks a term by how
well it separates one document from the corpus, not by how well it signals a
category, so the top terms are not the strongest evidence. Measured on a long
review, the full text classifies at 0.92 and its top four terms at 0.79.
@greptile-apps

greptile-apps Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR documents how to use classifier and keywords side by side while clearly distinguishing classification from TF-IDF document context.

  • Adds an end-to-end two-command workflow and corpus-vocabulary tuning examples.
  • Clarifies that the commands use separate model formats and that keyword scores do not explain classifier predictions.
  • Warns against feeding keyword output back into the classifier.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
README.md Adds a concise cross-command example and correctly warns that TF-IDF terms are context rather than prediction attribution.
docs/cli.md Adds detailed joint workflows and resolves the prior misleading attribution claim with an explicit explanation of the models’ independence.

Reviews (2): Last reviewed commit: "docs: stop calling TF-IDF terms an expla..." | Re-trigger Greptile

Comment thread docs/cli.md Outdated
Comment on lines +172 to +173
The first line is the verdict. The second says which terms drove it, which is
what you need when a classification surprises you.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 TF-IDF terms do not explain predictions

When users follow this workflow, it presents corpus-wide TF-IDF terms from an independent model as the terms that drove the classifier verdict, causing users to attribute predictions to features that do not determine the category and make incorrect model-tuning decisions.

Prompt To Fix With AI
This is a comment left during a code review.
Path: docs/cli.md
Line: 172-173

Comment:
**TF-IDF terms do not explain predictions**

When users follow this workflow, it presents corpus-wide TF-IDF terms from an independent model as the terms that drove the classifier verdict, causing users to attribute predictions to features that do not determine the category and make incorrect model-tuning decisions.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid, and fixed in a585814. You are right that this was the core claim of the section and it was wrong.

The two commands hold separate models. keywords reports TF-IDF weight, which measures how well a term separates one document from the rest of its corpus. It never sees the classifier and does not know which category a term favors, so a term can top that list and carry no weight in the decision. Calling it "which terms drove it" invites exactly the mis-tuning you describe.

Corrected in four places, in docs/cli.md and README.md. The section now says the terms are the document in shorthand, useful for checking that it says what you assumed, and adds an explicit warning:

The second line is not an explanation of the first. The two commands hold separate models. keywords reports TF-IDF weight, which measures how well a term separates this document from the rest of the corpus. It never sees the classifier, and it does not know which category a term favors. A term can top the list and carry no weight in the decision.

It now points at Classifier::LogisticRegression#weights for the weights a model actually holds, and notes that no CLI flag reports per-term weights for a Bayes model, which I confirmed against the source.

Worth noting the PR already made the same argument in its "Do not pipe one into the other" section, with measurements showing confidence dropping from 0.92 to 0.79. I made the opposite claim two sections earlier without noticing the contradiction. Good catch.

The side-by-side section said the keywords output showed "which terms drove"
the classifier verdict. It does not. The two commands hold separate models.
keywords reports TF-IDF weight, which measures how well a term separates one
document from its corpus, and it never sees the classifier or learns which
category a term favors. A term can top that list and carry no weight in the
decision.

Presenting it as attribution invites the reader to tune the wrong thing.

Say what the terms are: the document in shorthand, useful for checking that
it says what you assumed. Point at
Classifier::LogisticRegression#weights for the weights a model actually
holds, and note that no command line flag reports per-term weights for a
Bayes model.

Found by Greptile on #172.
@cardmagic
cardmagic merged commit 4f8384e into master Aug 15, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant