
The Loudest Stories Were Missing from the Map: Learning Topics on Hacker News
The Loudest Stories Were Missing from the Map: Learning Topics on Hacker News
以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。
Hacker News
Machine Learning
AI
The Loudest Stories Were Missing from the Map: Learning Topics on Hacker News
Yastrebov Kirill
9 min read·
Just now
--
The five highest-scoring submissions in the six-day comparison all received the same topic: Unknown.
That is an awkward opening for a topic-modeling article. It is also the most useful result. Among 5,997 Hacker News submissions dated October 24–29, 2026, a small model assigned 4,432 to no learned topic. Those unknown titles carried 81.55% of the observed points. A chart showing only the named groups would have hidden most of the conversation — and most of its measured attention.
The question was straightforward: which subjects appear on HN, which attract attention, and how does the picture differ across sources and periods? Answering it required more than finding words such as “AI.” It required keeping the model’s vocabulary, the source population and the popularity calculation separate.
This case uses real submissions, a small trained model, and independently callable steps. The examples below run through Splime Public Hub and produce an HTML report with topic summaries, tags, collection details and a linked reading list.
The collector retrieved 13,282 unique stories created from October 17 at 00:00 UTC to October 30 at 00:00 UTC, with the end excluded. Collection ran on October 31 from 11:01:59 to 11:03:03 UTC. Training uses the earlier seven days; the later six days supply the descriptive comparisons and temporal evaluation.
For historical dates, the implementation queries HN Search, splitting busy time intervals until each query fits within one returned page. This run needed 83 requests and exhausted the requested intervals without reaching the item limit. That establishes retrieval coverage of the search index, not a guarantee that every HN submission is indexed. The returned snapshot records its bounds, limits and collection timestamps.
Current Firebase feeds answer a different question. The official API supplies bounded lists of current top, new, Ask and Show stories; filtering those lists by date does not recreate a past front page. The collector exposes both routes and describes their coverage explicitly. Network failures raise errors; they never produce substitute records. Official HN API documentation, HN Search API.
“Direction” is therefore not a field in the model. A topic is a learned word group. A source is a feed or index membership. In the historical data, story includes ask_hn and show_hn; these sources overlap. Each HN ID counts once overall, while its memberships remain available for comparisons.
An earlier baseline, analyze_titles@1, applied supplied phrase rules. It was explainable, but it had no training step. The new model starts with titles and learns its own word groups.
First, fixed text cleanup removes common function words and source prefixes such as “Show HN.” TF-IDF represents each title using words and adjacent word pairs. A term gets more weight when it is informative within the training collection. The vocabulary and document-frequency weights are fitted only on the earlier partition.
Next, nonnegative matrix factorization, or NMF, approximates those title vectors with eight reusable word groups. Think of each title as a mixture of a few word lists, with a different weight on each list. This is a standard, inspectable topic-extraction approach; the scikit-learn example illustrates the same TF-IDF/NMF pairing.
The baseline caps the vocabulary at 600 terms. Eight topics and that small vocabulary are demonstration choices, not a tuned optimum. From 7,285 earlier submissions, training removed 122 titles with too little usable text and 255 repeated normalized titles. The remaining 6,908 titles supplied the learned state; 6,175 had a nonzero vector in the selected vocabulary. NMF converged after 37 iterations.
The topic names are the four highest-weight learned terms, printed without editorial polishing. This matters: open / source / open source / alternative is a useful clue, while video / php / world / context is a diffuse group. Singular agent and plural agents became separate components. The model has learned associations in this corpus, not a comprehensive taxonomy of technology.
For a new title, the vocabulary, IDF and components stay fixed. A nonnegative least-squares fit estimates the title’s mixture of those components. The strongest component supplies a primary topic when the rejection rules allow it. Very short titles, too few known words, weak matches or ambiguous mixtures become Unknown. Those thresholds are heuristics, not calibrated confidence scores.
Tags are even more literal: they are high-weight terms from the assigned topic that occur in the cleaned title; word pairs are adjacent after stop-word removal. A title may receive agent and skills; it does not inherit every word in its topic's name. Nothing in training or inference uses points, comment counts, source membership or future activity as a feature.
The map covers a recognizable corner of HN.
Here is the later six-day population under that single frozen model:
Automatic topic nameStoriesShare of all storiesObserved pointsUnknown4,43273.90%95,396ai / ai agents / ai agent / slop5589.30%9,423agents / ai agents / coding / coding agents1853.08%1,437code / claude / claude code / codex1702.83%3,085open / source / open source / alternative1552.58%1,782agent / ai agent / coding / coding agent1492.48%832video / php / world / context1462.43%1,541browser / data / game / pdf1332.22%1,721model / language / world / first691.15%1,758
The named groups make the corpus look dominated by AI and developer tools. Yet their combined coverage is only 26.10%. For example, the HN submission titled “Anthropic S-1” had 1,708 observed points and remained unknown. So did “We’re releasing the weights of Mistral Large 4”, with 1,694 points. The topic map misses even some conspicuous AI-related titles.
The five highest-point records were checked against the official Firebase API: their IDs, titles, creation times and observed scores matched. This verifies the submissions and metadata, not the truth of claims made in their headlines. Counts, shares and engagement totals were also independently recomputed from the collected records.
A rise in submissions is a different result from a rise in attention.
The comparison uses two equal 72-hour windows: October 24–26, with 2,532 stories, and October 27–29, with 3,465. The broad ai / ai agents / ai agent / slop group moved from 223 to 335 stories, or 8.81% to 9.67% of each population: +0.86 percentage points. The singular-agent group rose by 0.68 points. Unknown stayed near three quarters of both windows.
These are changes in the composition of observed submissions. They are not evidence that a topic is gaining users, that sentiment improved, or that its next post will become popular. Both periods use the same model fingerprint. Comparing “topic 3” from two independently trained models would make the numbers look comparable while changing their meaning.
Points and comments provide another view. The broad AI group accumulated 9,423 points and 6,835 comments. Its highly discussed examples include “AI promised less work. I’ve never worked more”, with 684 points and 662 comments, and “No signs of AI payoff outside the tech sector”, with 653 points and 678 comments. These titles suggest debate about AI’s practical consequences; comment counts alone cannot establish approval or sentiment.
Every topic’s median story score was just two. Totals are sensitive to a few exceptional posts. Counts measure publishing volume; shares account for different submission totals; points summarize observed net scoring; comments measure discussion. Missing engagement remains missing and the report shows how many values were observed.
Age is another constraint. At collection, the median story was 136.5 hours old in the earlier window and 67.6 hours old in the later one. The older group had more time to accumulate activity. These points and comments were collected after the posting periods, so they are not historical “as of midnight” totals. The case describes accumulated attention and does not claim an age-adjusted trend or a popularity forecast.
Among the later stories, 179 carried ask_hn and 858 carried show_hn. Unknown accounted for 70.39% of Ask HN, 59.32% of Show HN and 73.90% overall. The open/source group represented 7.11% of Show HN, compared with 2.58% overall; the plural-agents group also represented 7.11% of Show HN.
This is a useful source contrast, although it partly reflects vocabulary coverage: Show HN titles more often match these learned groups. It is not proof that the unassigned stories lack themes. The overall column already includes Ask and Show, so adding their counts to it would count some submissions twice.
Inspect errors before celebrating coverage.
The temporal evaluation held out submissions created on or after October 24. It conservatively removed 263 later titles whose normalized text or canonical external URL appeared in training, leaving 5,734 evaluation records. That purge applies to evaluation; descriptive counts retain distinct later HN submissions, even when they discuss the same external article.
On that purged holdout, the model assigned 25.99% and rejected 74.01%. Mean known-token coverage was 37.38%. These figures describe the model’s reach, not its semantic accuracy. No independent human topic labels were available, and no rule-generated labels were used to manufacture an accuracy score.
A qualitative review examines deliberately difficult examples, selected by large reconstruction residuals. It is an assistant inspection of titles, not human ground truth or a representative accuracy study. Several errors are easy to understand:
These are specific reasons to improve the representation. A larger vocabulary, phrase handling, longer text or a better tokenizer may help. The next evaluation should use independent human review of future titles. Raising the assignment rate by weakening rejection would not, on its own, demonstrate improvement.
Repeat the computation one step at a time.
Use Python 3.13 and install these tested package versions in the environment used by your notebook:
python -m pip install splime==0.4.13 httpx==0.28.1 numpy==2.3.5
scipy==1.18.0 scikit-learn==1.8.0 ipython==9.18.0
An SPH consumer needs no registration or API key. In embedded mode the published code is downloaded and runs locally; trust=True explicitly permits its execution.
The following version table is generated only from confirmed publication receipts:
Public objectConfirmed immutable versionfetch_snapshotfetch_snapshot@2normalize_storiesnormalize_stories@2train_topic_modeltrain_topic_model@1predict_topicspredict_topics@1evaluate_topics_temporallyevaluate_topics_temporally@2summarize_topicssummarize_topics@2hn_topic_modelhn_topic_model@1tag_titlestag_titles@1render_digestrender_digest@3hn_topic_digesthn_topic_digest@4
In a notebook, set up the client and exact references:
from spl import SPLClient from IPython.display import HTML, display
client = SPLClient.embedded(registry_url="https://splime.io", run_receipts=False) base = "splime://@splime.project/case4-hn"
Fetch and normalize independently. Collection limits are visible rather than hidden in a utility:
snapshot = client.call( f"{base}/fetch_snapshot@2", kwargs=dict(source="algolia", feeds=["story"], start_utc="2026-10-17T00:00:00Z", end_utc="2026-10-30T00:00:00Z", max_items=20000, page_size=500, max_requests=200, timeout=15, attempts=3, budget_seconds=300), trust=True, ).value assert not snapshot["source_info"]["truncated"], "Increase limits or narrow the period" snapshot = client.call( f"{base}/normalize_stories@2", kwargs=dict(records=snapshot["records"], source_info=snapshot["source_info"]), trust=True, ).value
Training remains an explicit operation. Its result is a JSON-compatible model containi
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。