云计算百科
云计算领域专业知识百科平台

SerpBase 的 PAA 题库怎么清洗:去重、聚类、意图标注(附代码)

用「相关问题」(people_also_ask)做选题库,是个很顺手的办法:用户真实在问什么,谷歌直接摆在你面前。但真跑几十个关键词就会发现一个问题——同一批问题反复出现,而且措辞还不一样:「怎么学 Python」「如何学 Python」「学 Python 的方法」,三条其实是一条。

直接堆起来,几百条里一半是重复。这篇把题库清洗成可用的样子:去重、聚类、标意图。

取数:一次搜索带出问题

网页搜索(1 credit/次)的响应里,people_also_ask 是可选模块,每条通常带 question、answer 和来源链接:

import os
import requests

def fetch_questions(q: str) –> list[dict]:
data = requests.post(
"https://api.serpbase.dev/google/search",
headers={"Content-Type": "application/json",
"X-API-Key": os.environ["SERP_BASE_API_KEY"]},
json={"q": q, "hl": "zh-cn", "gl": "cn"},
timeout=(5, 30),
).json()
if data.get("status") != 0:
return []
return data.get("people_also_ask") or []

rows = []
for kw in keywords:
for item in fetch_questions(kw):
rows.append({"keyword": kw, "question": item.get("question", "")})

第一步:规范化,先统一「说法」

去重之前先归一,否则「怎么」和「如何」永远对不上:

import re

SYNONYMS = [
("如何", "怎么"), ("怎样", "怎么"), ("方法", "怎么"),
("哪些", "什么"), ("为什么", "原因"),
]

def normalize(q: str) –> str:
q = q.strip().lower()
q = re.sub(r"[\\s,。!?、,.!?::;;\\"'()()【】\\[\\]]", "", q)
for a, b in SYNONYMS:
q = q.replace(a, b)
return q

这一步会损失一点语义,换来的是去重准确率的大幅提升。中文题库不清洗,去重就是自欺欺人。

第二步:模糊去重

归一之后仍有语序差异,用相似度兜底。rapidfuzz 比标准库快得多:

from rapidfuzz import fuzz

def dedupe(items: list[dict], threshold: int = 90) –> list[dict]:
kept = []
for it in items:
norm = normalize(it["question"])
dup = False
for k in kept:
if fuzz.token_set_ratio(norm, k["norm"]) >= threshold:
k["sources"].add(it["keyword"])
dup = True
break
if not dup:
kept.append({**it, "norm": norm, "sources": {it["keyword"]}})
return kept

阈值 90 是个起点:低了会误删(「怎么学 Python」和「怎么学 Java」可能被合并),高了漏删。先抽样看二十对,再定阈值。

第三步:聚类,把问题分成主题

去重完还有几百条,需要按主题归堆。最简单的做法是 TF-IDF 加层次聚类:

from sklearn.cluster import AgglomerativeClustering
from sklearn.feature_extraction.text import TfidfVectorizer

texts = [k["norm"] for k in kept]
vec = TfidfVectorizer(analyzer="char", ngram_range=(2, 3), min_df=2)
X = vec.fit_transform(texts)

clusters = AgglomerativeClustering(
n_clusters=12, metric="cosine", linkage="average"
).fit_predict(X)

for k, c in zip(kept, clusters):
k["cluster"] = int(c)

字符 n-gram 对中文短句比词级切分更稳,不用额外装分词器。簇数先按「词量 ÷ 30」估,再人工调整。

第四步:标意图

规则足够用,不必上模型:

RULES = {
"原因": ["为什么", "原因"],
"方法": ["怎么", "步骤", "教程"],
"对比": ["哪个", "对比", "区别", "vs"],
"交易": ["价格", "多少钱", "费用", "购买"],
}

def tag_intent(q: str) –> str:
for label, words in RULES.items():
if any(w in q for w in words):
return label
return "其他"

输出成表:

question | cluster | intent | sources | count

sources 是这条问题出现过的关键词——它比问题本身更有用,能告诉你「哪些词背后是同一个疑问」。

五个坑

坑 1:不做归一直接去重。 「如何」和「怎么」被当成两条,题库虚胖。

坑 2:阈值拍脑袋。 太低误删、太高漏删。先人工抽样,再定阈值。

坑 3:把 PAA 当搜索量。 文档明确:这些问题和联想词不是搜索量测量。它代表「有人问」,不代表「很多人问」。

坑 4:不记来源关键词。 丢掉上下文,后面做内容规划时不知道这个问题该挂在哪篇文章下。

坑 5:一次采集当永久。 PAA 会随时间变,一季度重采一次,才能看到关注点的迁移。

小结

PAA 题库的清洗链:取数(1 credit/次)→ 规范化(同义词 + 去标点)→ 模糊去重(rapidfuzz)→ 聚类(TF-IDF + 层次)→ 意图标注(规则)。清洗完的题库,才配叫「选题库」;没清洗的,只是一堆重复的字符串。

people_also_ask 的字段结构见 SerpBase 文档。你清洗过 PAA 题库吗?评论区聊聊。

赞(0)
未经允许不得转载:网硕互联帮助中心 » SerpBase 的 PAA 题库怎么清洗:去重、聚类、意图标注(附代码)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!