GoBuy 評論歷史的形態:以軌跡分析評估信任評分
The Shape of a Review History: Trajectory Analysis for Trust Scoring
GoBuy 以評論歷史軌跡分析補充商品信任評分,識別單看平均評分難以發現的操縱模式。系統以評論突發密度、評分熵、均值變點和評論者重疊四項統計特徵評估,無需模型或 GPU。軌跡分析先標記需審查的商品,再選擇性使用語言特徵判斷評論文本是否合成,評分則作為 Smart Score 的其中一項輸入。
When we started scoring products at GoBuy, the obvious first move was treating the review history as a pile: aggregate the ratings, compute a Wilson confidence interval, ship a score. That works fine for a book with 400 reviews accumulated over six years at a steady 4.2 stars. It fails catastrophically for the products fraudsters care about — the ones whose histories look fine in aggregate but wrong in shape.
This post is about the second layer of our pipeline: trajectory analysis. We stopped asking "what is the average rating?" and started asking "how did this product get here?" Because in 2026, with agents writing synthetic reviews at scale, the shape of a review history is more informative than its content.
The intuition
A real product's rating history is noisy but boring. New products get a small burst of early reviews (friends, enthusiasts, people who buy on launch day), then a long tail. The average drifts slightly as the product finds its audience. Sometimes there's a dip after a bad batch, and a recovery. Human purchasing is lumpy and seasonal.
A manipulated history has a different signature. The most common one looks like this: months of near-silence, then a short window of intense 5-star activity, then back to silence. The aggregate numbers can look great. The trajectory looks like a heart attack on an ECG.
Here's a toy example we use internally for testing:
import numpy as np
rng = np.random.default_rng(42)
# Organic: steady, noisy
organic = np.concatenate([
rng.normal(4.3, 0.8, 30), # launch bump
rng.normal(4.1, 0.9, 90), # long tail
rng.normal(3.9, 1.0, 30), # slight decay
])
# Manipulated: silence, burst, silence
manipulated = np.concatenate([
rng.normal(3.5, 1.0, 40), # early genuine reviews, mediocre
np.full(50, 5.0), # the burst
rng.normal(3.6, 0.9, 20), # back to reality
])
Same count of reviews. Both average around 4.0. One of them you'd buy. The other you'd report.
Decomposing the signal
We compute four features over the full timestamped history. All of them are cheap — no models, no GPU, just statistics you can run in a few milliseconds per product.
1. Burst density. For each sliding window of width w (we use 48 hours for marketplace data), compute the share of lifetime reviews that fall inside it. For an organic product, the maximum window share is bounded — you'd need a viral moment to concentrate 40% of a year's reviews into two days, and viral moments leave traces elsewhere (sales rank, cart-adds, external mentions). For an inflated product, the max window share is often the single most predictive feature we track.
2. Rating entropy. Real reviewers disagree. Even beloved products collect 3s and the occasional 1. A history where 95% of reviews are exactly 5 stars has near-zero entropy, and zero-entropy histories with n > 30 reviews are, in our data, almost never organic. We use Shannon entropy over the discrete rating distribution:
from scipy.stats import entropy
def rating_entropy(ratings: np.ndarray) -> float:
counts = np.bincount(ratings.astype(int), minlength=6)[1:]
p = counts / counts.sum()
return entropy(p, base=2)
A fully concentrated history scores 0.0 bits; a uniform spread over the five star levels scores ~2.32 bits. Organic products cluster between 1.1 and 1.8 bits.
3. Regime change points. We run a simple change-point detection (CUSUM on the mean rating) and look for sharp upward jumps that coincide with volume jumps. A product going from 3.4 → 4.9 average while its review velocity triples is not "improving." Real quality improvements show up in the text and in return-rate signals long before the star average moves a full point.
4. Reviewer overlap. This one crosses products. If 30% of a product's reviewers also reviewed three other products from the same seller — all in the same week — that's a ring, not a fandom. (Cross-product analysis deserves its own post; the short version is that we build a bipartite graph of reviewers × sellers and look for dense subgraphs.)
Why not just use an LLM?
We get this question constantly, including from our own team. Why bother with CUSUM and entropy when a language model can read the reviews and tell you which ones feel fake?
Three reasons. First, cost: we score hundreds of thousands of products; LLM passes per product per refresh would be orders of magnitude more expensive than computing four statistics over a vector. Trajectory features are computed in Postgres with window functions, roughly for free.
Second, determinism: the score a user sees must be reproducible. If someone disputes a trust score, we can show exactly which features fired, what the burst density was, when the change point occurred. "The model said so" is not an audit trail.
Third, trajectory features catch what text analysis can't. The fake reviews of 2026 are fluent, specific, and stylistically indistinguishable from real ones — they're written by models that have read a million genuine reviews. But the timing of a paid campaign is set by a contract and a deadline, not by human enthusiasm. Language can be synthesized. Logistics can't.
The two layers compose nicely: trajectory analysis flags which products deserve scrutiny, and language features (which we do run, selectively) determine whether the flagged text itself is synthetic. Cheap first, expensive second.
The composite signal
Each feature is normalized against a per-category baseline — because a niche hobby product with 60 reviews behaves differently from a phone case with 8,000, and "burst" means different things at those scales. The normalized features feed a logistic scorer whose weights we re-fit quarterly against a labeled set (products removed by marketplaces for review manipulation — the best ground truth available, even if it's conservative).
The output isn't a verdict. It's one input into the composite Smart Score, weighted so that a single suspicious feature can't tank an honest product, but a converging pattern — burst + low entropy + change point + reviewer overlap — pushes the score down hard and fast.
That design decision matters. False positives on legitimate small sellers are the worst failure mode a trust system can have: the seller loses their livelihood, and we lose the credibility that makes the score worth computing. Trajectory analysis earns its keep precisely because it constrains the accusations to products whose histories are, statistically, almost impossible.
What's next
The current frontier for us is reviewer-side trajectories instead of product-side: modeling each reviewer's own history — their entropy, their timing, their category spread — so that a suspicious product's score can be decomposed into "bad product" versus "bad reviewers." Early results are promising and the math is pretty. That'll be the next post in this series.
If you want to see the scoring standard we anchor all of this to, it's public at docs.gobuy.ai/standard — critique welcome, especially the parts about category baselines, which are the hardest thing we've published.
來源:DEV Community · dev.to