使用PySpark统计所有可能单词对出现次数的技术问询
你原来的代码是统计连续相邻的单词对,要改成每行中每个单词与其他所有单词配对,我们需要调整flatMap阶段的逻辑,生成每行内所有可能的单词对,再进行全局计数。下面分几种场景给出实现方案:
场景1:统计无序单词对((a,b)和(b,a)视为同一对,不含自身配对)
如果希望(My, name)和(name, My)算同一个单词对,且不统计单词与自身的配对(比如(My, My)),可以用itertools.combinations生成所有无序的2元组合:
from itertools import combinations # 处理逻辑 wordPairCount = rddData.map(lambda line: line.split()) \ .flatMap(lambda words: [tuple(sorted(pair)) for pair in combinations(words, 2)]) \ .map(lambda pair: (pair, 1)) \ .reduceByKey(lambda a, b: a + b)
代码解释:
map(lambda line: line.split()):将每行文本分割成单词列表;flatMap(...):用combinations(words, 2)生成该行所有长度为2的无序单词组合,再通过sorted确保(a,b)和(b,a)被处理为同一个键(比如(name, My)会被转为(My, name));- 后续的
map和reduceByKey完成计数逻辑,和你原来的代码一致。
场景2:统计有序单词对((a,b)和(b,a)视为不同对,不含自身配对)
如果需要区分单词对的顺序(比如(My, name)和(name, My)算两个不同的对),可以用itertools.permutations生成所有有序的2元排列:
from itertools import permutations wordPairCount = rddData.map(lambda line: line.split()) \ .flatMap(lambda words: permutations(words, 2)) \ .map(lambda pair: (pair, 1)) \ .reduceByKey(lambda a, b: a + b)
代码解释:
permutations(words, 2)会生成该行所有有序的2元组,比如对于单词列表[My, name],会生成(My, name)和(name, My)两个独立的对,后续直接统计即可。
场景3:允许单词与自身配对(比如统计(My, My)的出现次数)
如果需要统计同一行内单词与自身的配对(比如一行中多次出现My,要计算(My, My)的次数),可以用双重循环生成所有i≠j的单词对:
wordPairCount = rddData.map(lambda line: line.split()) \ .flatMap(lambda words: [(words[i], words[j]) for i in range(len(words)) for j in range(len(words)) if i != j]) \ .map(lambda pair: (pair, 1)) \ .reduceByKey(lambda a, b: a + b)
代码解释:
通过嵌套循环遍历所有单词索引对(i,j),并过滤掉i==j的情况(避免单词和自身的同一位置配对),生成所有可能的有序单词对,包括同一单词的不同出现位置的配对。
测试你的示例文档
以你给出的示例文档为例:
My name is Sam My name is Sam My name is Sam; My name is Sam; I am working on pairwords count
按分号分割后得到3行文本,用场景1的代码会统计出(My, name)、(My, is)等无序对的总出现次数,结果符合你需要的全局单词对计数需求。
内容的提问来源于stack exchange,提问作者sudeep

