You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效统计人名中双词组合的出现次数?

高效统计人名中单词共现次数的方法

问题背景

我有一个包含单列人名的DataFrame,数据如下:

name
--------------
john doe
john david doe
doe henry john
john henry

需求是统计每对单词在人名中的无序共现次数:即两个单词只要在同一条人名记录中出现就算一次,不考虑顺序。例如john和doe在3条记录中共同出现,共3次。

预期输出

name1 | name2 | count
----------------------
david | doe   | 1
doe   | henry | 1
doe   | john  | 3
henry | john  | 2

注意:name1需为按字母顺序排在前面的单词。

当前采用暴力解法:

  • 生成DataFrame中所有唯一单词的列表
  • 对每个唯一单词W,筛选出包含W的记录
  • 从筛选后的记录中统计其他单词的出现频率,得到W与其他单词的共现次数

但该方法为二次复杂度,数据量大时效率极低;尝试过NLP包的n-gram提取,但会将所有名字拼接成字符串,导致相邻名字的首尾单词被误统计,高估共现次数。

高效解决方案

方法1:词频矩阵+矩阵乘法

核心逻辑是通过词频矩阵的转置乘积直接计算共现次数,适合大数据量场景:

import pandas as pd
import numpy as np

# 构造示例DataFrame
df = pd.DataFrame({
    'name': ['john doe', 'john david doe', 'doe henry john', 'john henry']
})

# 1. 提取所有唯一单词,建立单词-索引映射
all_words = df['name'].str.split(expand=True).stack().unique()
word_idx_map = {word: idx for idx, word in enumerate(all_words)}

# 2. 构建词频矩阵:每行对应一条人名,每列对应一个单词,值为1表示该单词出现在人名中
freq_matrix = np.zeros((len(df), len(all_words)), dtype=int)
for row_idx, name in enumerate(df['name']):
    for word in name.split():
        freq_matrix[row_idx, word_idx_map[word]] = 1

# 3. 计算共现矩阵:矩阵转置相乘,得到单词对的共现次数
cooccur_matrix = freq_matrix.T @ freq_matrix

# 4. 转换为目标格式:提取非重复对、排序
cooccur_df = pd.DataFrame(cooccur_matrix, index=all_words, columns=all_words)
# 提取上三角区域(排除自身共现和重复对)
cooccur_df = cooccur_df.where(np.triu(np.ones(cooccur_df.shape), k=1).astype(bool)).stack().reset_index()
cooccur_df.columns = ['name1', 'name2', 'count']

# 确保name1按字母顺序在前,然后排序输出
cooccur_df[['name1', 'name2']] = np.sort(cooccur_df[['name1', 'name2']], axis=1)
cooccur_df = cooccur_df.sort_values(['name1', 'name2']).reset_index(drop=True)

print(cooccur_df)

方法2:生成合法单词对+分组统计

直接针对每条人名生成所有无序单词对,再全局统计次数,内存占用更低:

import pandas as pd
from itertools import combinations

df = pd.DataFrame({
    'name': ['john doe', 'john david doe', 'doe henry john', 'john henry']
})

# 对每条人名生成排序后的单词对(保证统一顺序,避免重复统计)
df['word_pairs'] = df['name'].apply(
    lambda x: [tuple(sorted(pair)) for pair in combinations(x.split(), 2)]
)

# 展开所有单词对并统计次数
result = df.explode('word_pairs').value_counts('word_pairs').reset_index()
# 拆分单词对为两列
result[['name1', 'name2']] = pd.DataFrame(result['word_pairs'].tolist(), index=result.index)
# 整理格式并排序
result = result.drop('word_pairs', axis=1).rename(columns={0: 'count'})
result = result.sort_values(['name1', 'name2']).reset_index(drop=True)

print(result)

两种方法都能高效得到符合要求的结果,其中方法1适合单词数量较多的场景,方法2适合人名拆分后单词数量较少的场景。

内容的提问来源于stack exchange,提问作者Stacker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 23:25:18