

# 如何衡量给定 X 帖子样本中的关键词共现

在给定样本中，对每篇文本完整的帖子，目标词和搭配词各只计数 1 次。然后比较：有目标词时，搭配词出现的比例；没有目标词时，搭配词出现的比例。

词项是你在计数前选定的词。目标词是你要跟踪的词。搭配词是你要检验是否与目标词一起出现的另一个词。词对就是这 2 个词。共现是指 2 个词出现在同一篇帖子中。符合条件的帖子，是样本范围内文本完整且不重复的一篇帖子。样本范围由日期范围和确切的 URL 列表共同确定。

共现计数是同时包含这 2 个词的符合条件的帖子数。条件占比等于共现计数除以包含目标词的帖子数。背景占比等于其余帖子中包含搭配词的帖子数，除以其余帖子的总数。分母就是除数。没有分母的占比没有定义。

结果包括一组词项标记、一张词对表、这 2 个占比，以及一份文本缺失记录。文本缺失记录是你保存的、不纳入计数的采集尝试清单。结论仅描述这个给定样本。

## 1. 确定样本范围

采集帖子前，写下目标词和每个搭配词。写下要纳入的发布日期范围。写下构成样本范围的确切已知 URL。

这项计数说明，在这个给定样本中，哪些搭配词与目标词一起出现。它不会建立词项使用情况随时间变化的历史记录。它也不是搜索 X 上所有帖子的服务。

先写下这些选择。如果看到帖子中的词之后才选择搭配词，你可能会偏向自己已经注意到的模式。

## 2. 采集已知的公开帖子

Actor 是用于采集来源数据行的托管程序。Task 是为 Actor 保存的一组输入。一次运行是指执行 Actor 1 次。

使用 [X Post Metrics](https://apify.com/chronometrica/x-post-metrics) Actor，公开构建版本为 1.0.4。当前 Task 是 [X Post Analytics Snapshot](https://apify.com/chronometrica/x-post-metrics/examples/x-post-analytics-snapshot)。该 Task 保存了一组初始输入。它不会替你统计词项。保存了 Task，并不能证明计数会自动完成。

这个构建版本读取 `startUrls`。每个值都必须是已知的公开帖子 URL，且包含 `/status/`。已保存的列表中有 3 个示例 URL：

- https://x.com/OpenAI/status/2074907025537224840
- https://x.com/OpenAI/status/2074907027378511884
- https://x.com/OpenAI/status/2074907031862190406

用你已经知道的 1 个公开 `/status/` URL 替换整个列表。首次运行只使用这个 URL。不要添加搜索。不要要求获取帖子历史。不要设置 `maxItems`。这个 Actor 不会返回完整存档。检查首行数据后，再添加更多已知 URL。

每行保存的数据可以包含以下字段：

| 字段 | 保存的内容 |
| --- | --- |
| `inputUrl` | 你提交的 URL |
| `postUrl` | 该行记录中的帖子 URL |
| `postId` | 帖子 ID |
| `postType` | 帖子类型 |
| `publishedAt` | 发布时间 |
| `text` | 帖子当前的文本 |
| `profileUrl` | 个人资料页 URL |
| `profileId` | 个人资料 ID |
| `profileUsername` | 个人资料的用户名 |
| `profileName` | 个人资料的显示名称 |
| `status` | 该行记录的状态 |
| `statusReason` | 该状态的原因 |
| `observedAt` | 观测到该行记录的时间 |

`text` 可以为 null。该行中的其他信息也可以为 null。null 表示值缺失，不表示计数为 0。

`postMetricStatus` 与 `text` 相互独立。它为 6 项指标各提供 1 个条目。这些指标是浏览量、点赞数、回复数、转发数、引用数和书签数。每个条目都有各自的状态和精度。精度表示该指标值有多精确。不要把这 6 个条目理解成同一个量表的 6 个等级。它们不能证明文本完整。

OUTPUT 提供有关本次运行的证据。它不是词项表。它列出 `inputCount`、`datasetRows`、`usefulRows`、`billableRows`、`failedRows`、`statusCounts` 和 `stopReason`。`inputCount` 是本次运行收到的 URL 数。`datasetRows` 是保存的数据行数。`usefulRows` 是本次运行的有效行总数。`billableRows` 是本次运行的计费行总数。`failedRows` 是本次运行的失败行总数。`statusCounts` 按状态汇总数据行。`stopReason` 说明本次运行停止的原因。这些汇总信息不是每行记录中的字段。

一次经过核对的读取针对 1 篇已知的 OpenAI 公开帖子，返回了正确的帖子 ID 和个人资料 ID。它还返回了发布时间和当前计数值。文本存在，且不为空。文本长度为 200 个字符。本文不复制这段文本。该次检查的 OUTPUT 为：`inputCount` 1、`datasetRows` 1、`usefulRows` 1、`billableRows` 1、`failedRows` 0。`statusCounts` 为 ok 1。`stopReason` 为 `inputs_exhausted`。

这个结果表明，程序支持读取这 1 篇已知公开帖子的文本。它不能证明每个 URL 都会得到相同结果。它不能证明读取了图片中的文字。它不能证明读取了被引用帖子的正文、链接页面或视频中的语音。隐藏或受限部分需要另行检查。状态为 ok，并不能证明文本足以用于你的计数。文本长度为 200 个字符，也不能证明该行记录包含整篇帖子。

用 `postId` 匹配数据行，确保每篇帖子只作为 1 个统计单位。保留 `publishedAt` 和 `observedAt`。如果帖子 ID 缺失，为该次采集尝试单独记录状态。如果来源读取失败，也为该次采集尝试单独记录状态。如果样本范围有日期限制，未知的 `publishedAt` 不能算作已确认处于该时间范围内的日期。在确认日期前，不要将该次采集尝试纳入有日期限制的计数。不要将信息缺失转化为词项计数为 0。

## 3. 判断文本是否完整

本项分析只使用帖子文本。对每行记录，写明文本是否完整到足以用于计数。保存这条说明。

不要把状态为 ok 当作文本完整的证明。也不要把 `postMetricStatus` 当作这项证明。如果 `text` 缺失或不完整，将该帖子排除在完整文本的分母之外。只有亲自核对过其他文本副本后，才能将其补入。

不要从图片中提取词项。不要从链接页面中提取词项。不要从视频中提取词项。即使数据行状态为成功，文本是否足够完整的问题仍可能没有答案。

`text` 字段保存的是在 `observedAt` 时刻观测到的文字。如果帖子经过编辑，这些文字可能与旧版本不同。它也可能缺少一部分。如果这种差异会改变计数，将当前文本与任何旧副本分开保存。没有书面决定，不要合并它们。

## 4. 计数前写明词项匹配规则

使用一套按字面匹配的规则，并在设置第 1 个标记前写下来。本文的英语示例使用固定规则。

忽略字母大小写。只匹配完整单词。完整单词的两侧都有边界，或者位于文本开头或结尾。边界就是单词的分界位置。空格是边界。句点、逗号或引号也是边界。标点符号不属于单词。按这套规则，字符 timer. 可以匹配词项 timer。

不要进行词干提取。词干是缩短后的词根。不要将同义词计为同一个词项。保持原始文本不变。由 2 个或更多单词组成的短语，需要另行写明规则。其他书写系统也需要自己的规则。链接或别名同样需要自己的规则。使用规则前，先在原始文本上测试。

匹配到完整单词，不表示作者支持该词表达的内容。它也不能证明[这个词指的是哪个真实事物](/zh-Hans/articles/%E5%AE%A1%E6%A0%B8-x-%E5%B8%96%E5%AD%90%E6%98%AF%E5%90%A6%E6%8F%90%E5%8F%8A%E4%BD%A0%E7%9A%84%E4%BA%A7%E5%93%81/)。

## 5. 为每篇符合条件的帖子设置标记

二元标记的值为 1 或 0。如果符合条件的文本按你的规则包含该词项，标记为 1。如果完整文本不包含该词项，标记为 0。对每篇不重复且符合条件的帖子，每个词项设置 1 个标记。

统计单位是帖子。如果词项在同一篇帖子中出现 5 次，标记仍为 1。这些重复反映的是帖子内部的用词情况，不会增加帖子数。同一份导出数据的完全重复副本也不会增加帖子数。

如果同一篇帖子的 2 个版本不一致，在计数前选定来源。记录这项选择。记录任何因此改变的分母。不要把 2 个版本当作 2 篇帖子保留。

## 6. 建立 2×2 列联表

选择 1 个搭配词，将每篇符合条件的帖子归入 4 个单元格之一。每个单元格对应 1 项计数。这 4 类分别是：同时包含 2 个词、仅包含目标词、仅包含搭配词，以及 2 个词都不包含。

报告 n、包含目标词的帖子数、包含搭配词的帖子数，以及共现计数。n 是符合条件的帖子总数。

使用以下简单公式：

条件占比 = 共现计数 / 包含目标词的帖子数

背景占比 = 包含搭配词但不含目标词的帖子数 / 不含目标词的帖子数

条件占比是包含目标词的帖子中，包含搭配词的比例。背景占比是不含目标词的帖子中，包含搭配词的比例。

如果包含目标词的帖子数为 0，条件占比没有定义。如果不含目标词的帖子数为 0，背景占比没有定义。将该占比留空。不要用 0 填充。写成 0，就等于声称对一个空组进行了测量。

## 7. 结合分母比较占比

同时展示这 2 个分数。条件占比很高的词，也可能只是一个常用词。背景占比可以帮助判断这种可能性。共现次数多，不能证明存在特定关联。

这个样本很小，而且 URL 是你选择的。它不能代表整个 X。它不能说明因果关系。它不能说明 X 上有多少帖子使用该词项。它不能说明某种模式变化得有多快。它不能说明统计显著性。统计显著性需要通过正式检验，判断结果是否可能由偶然因素造成。这张表不是这样的检验。

作者可能只是引用某个词，并不支持其表达的内容。含义审查是另一项工作。仅用这些占比描述这些符合条件的帖子。

## 8. 保存计数并说明局限

保存词项标记、词对表、书面规则和排除记录。只有保存这些内容，读者才能重新计算每个分母。

如果你需要一段时间内所有匹配的帖子，应说明这个样本无法满足哪些要求。已知 URL 列表不是完整的帖子集合。用这个样本检验一个已明确提出的想法，然后完善书面样本范围。不要将这张表呈现为整个 X 的趋势。

## 将同一套规则用于原创虚构示例

以下为原创虚构内容。下面的帖子、ID 和计数仅用于教学。它们不是 Actor 的运行结果。它们不是 OUTPUT。它们不能估计 X 上的语言使用情况。它们不能说明因果关系。

每篇帖子都有不同的虚构 ID，并具有按上述规则可用于计数的完整文本。这些 ID 不是真实的 X 帖子 ID。不区分大小写，因此 Job 可以匹配 job。句末的句点是边界。Job 位于开头，因此文本开头也是边界。这里没有哪个词只是把 retry、timer 或 job 作为较长单词的一部分包含在内。

| ID | 当前的虚构文本 | retry | timer | job |
| --- | --- | --- | --- | --- |
| F1 | Job retry uses a timer.（任务重试使用计时器。） | 1 | 1 | 1 |
| F2 | Job retry checks the timer.（任务重试检查计时器。） | 1 | 1 | 1 |
| F3 | Job retry waits for a timer.（任务重试等待计时器。） | 1 | 1 | 1 |
| F4 | Job retry cancels the timer.（任务重试取消计时器。） | 1 | 1 | 1 |
| F5 | Job retry adds a log.（任务重试添加一条日志。） | 1 | 0 | 1 |
| F6 | Job retry follows the rule.（任务重试遵循规则。） | 1 | 0 | 1 |
| F7 | Job timer logs a message.（任务计时器将一条消息写入日志。） | 0 | 1 | 1 |
| F8 | Job log records a message.（任务日志记录一条消息。） | 0 | 0 | 1 |
| F9 | Job rule records a message.（任务规则记录一条消息。） | 0 | 0 | 1 |
| F10 | Job workers send a message.（任务工作进程发送一条消息。） | 0 | 0 | 1 |

前四篇帖子包含 retry、timer 和 job。接下来的两篇包含 retry 和 job，但不含 timer。第七篇包含 timer 和 job，但不含 retry。最后三篇只包含 job。

将标记相加。retry 的合计为 6。timer 的合计为 5。job 的合计为 10。在 F1、F2、F3 和 F4 中，retry 和 timer 的标记都为 1。共现计数为 4。

retry 与 timer 的列联表如下：

| 目标词 | timer 1 | timer 0 | 行合计 |
| --- | --- | --- | --- |
| retry 1 | 4 | 2 | 6 |
| retry 0 | 1 | 3 | 4 |
| 列合计 | 5 | 5 | 10 |

n 为 10。包含目标词的帖子数为 6。包含搭配词的帖子数为 5。共现计数为 4。4 个单元格的计数分别是 4、2、1 和 3。

条件占比为 4/6。这个分数四舍五入后为 66.7%。分母是 retry 1 这一行中的 6 篇帖子。不要用 4 除以全部 10 篇帖子。

背景占比为 1/4，即 25%。分母是 retry 0 这一行中的 4 篇帖子。该行中只有 F7 包含 timer。timer 0 这一列的合计为 5。那是另一个总数。不要将 5 用作这里的分母。

retry 与 job 的列联表使用同样的 10 篇帖子：

| 目标词 | job 1 | job 0 | 行合计 |
| --- | --- | --- | --- |
| retry 1 | 6 | 0 | 6 |
| retry 0 | 4 | 0 | 4 |
| 列合计 | 10 | 0 | 10 |

retry 与 job 的共现计数为 6。条件占比为 6/6，即 100%。背景占比为 4/4，即 100%。job 的共现次数比 timer 多。timer 为 4 次。job 为 6 次。job 的 2 个占比相等，因此在这个示例中，job 在两组之间没有差异。值为 0 的单元格表示在完整文本中确实没有相应词项，并不表示文本缺失。

另外 2 次来源采集尝试没有文本。将它们保留在供读者查看的记录中。不要将它们命名为 F11 和 F12。不要把它们放入 2 个词都不包含的单元格。不要将这份记录复制到 OUTPUT 中。不要将其视为 `failedRows`。文本缺失表示情况未知，不表示标记为假。也不能仅因未见某个词，就推断来源原本返回了失败状态。

| 采集尝试 | 文本 | retry | timer | job | 是否符合条件 | 原因 |
| --- | --- | --- | --- | --- | --- | --- |
| S1 | 无法获取 | 未知 | 未知 | 未知 | 否 | 文本缺失，因此每个标记都未知。不能将这次采集尝试视为不含这些词项的帖子。 |
| S2 | 无法获取 | 未知 | 未知 | 未知 | 否 | 文本缺失，因此每个标记都未知。不能将这次采集尝试视为不含这些词项的帖子。 |

这组采集共包含 12 次来源采集尝试。其中 10 篇是不重复、符合条件且文本完整的帖子。另有 2 次尝试无法获取文本。完整文本的分母仍为 10。

如果目标组中符合条件的帖子数为 0，其条件占比就没有定义。如果背景组的帖子数为 0，该组的占比也没有定义。写明“未定义”。不要凭空写成 0%。

仅就这个示例，将 4/6 与 1/4 放在一起比较。两者的差距描述的是这 10 个句子，不是整个 X。它不能说明因果关系、统计显著性或趋势。job 说明了为什么第 2 个占比很重要。它的共现计数更大，但 2 个占比都是 100%。

## 下一步

对经过核对的文本应用事先声明的词项匹配规则。保存二元标记、词对表和排除记录。比较条件占比与背景占比。展示 2 个分母。使用 [X Post Metrics](https://apify.com/chronometrica/x-post-metrics) Actor 和 [X Post Analytics Snapshot](https://apify.com/chronometrica/x-post-metrics/examples/x-post-analytics-snapshot) Task。计数前，用 1 个已知的公开 `/status/` URL 替换已保存的 `startUrls` 列表。

## 来源和延伸阅读

- [X Post Metrics Actor](https://apify.com/chronometrica/x-post-metrics)
- [X Post Analytics Snapshot Task](https://apify.com/chronometrica/x-post-metrics/examples/x-post-analytics-snapshot)