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

如何在Python/R中获取多n值(1-6)n-gram及高频短语与单词

嗨,我来帮你搞定这个问题!不管是用Python还是R,都能轻松提取从1到6的n-gram,找出最常见的单词/短语,甚至能识别出最长的合理短语。下面我给你一步步演示具体实现:

Python实现

我们可以用nltk库生成n-gram,结合collections.Counter统计频率,再通过**点互信息(PMI)**判断短语的合理性(值越高说明越可能是一个连贯的短语)。

步骤1:安装并导入依赖库

from nltk.util import ngrams
from collections import Counter
import string
from nltk.tokenize import word_tokenize
import nltk
from math import log2

# 下载分词所需的资源
nltk.download('punkt')

步骤2:预处理文本

先把文本转小写、分词,去掉标点符号:

# 示例文本
text = "fri evening commute can be long. some people avoid fri evening commute by choosing off-peak hours. there are much less traffic during off-peak."

# 预处理流程
tokens = word_tokenize(text.lower())
tokens = [token for token in tokens if token not in string.punctuation]

步骤3:提取1-6的n-gram并统计频率

# 定义n的范围(1到6)
n_range = range(1, 7)
all_ngrams = {}

for n in n_range:
    # 生成n-gram并转为字符串格式
    n_grams = ngrams(tokens, n)
    n_grams_str = [' '.join(gram) for gram in n_grams]
    # 统计频率,取前5个最常见的
    counter = Counter(n_grams_str)
    all_ngrams[f"{n}-gram"] = counter.most_common(5)

# 打印结果
print("各n-gram最常见的内容:")
for n_type, counts in all_ngrams.items():
    print(f"\n*{n_type}*")
    for phrase, count in counts:
        print(f"- `{phrase}`: 出现{count}次")

步骤4:提取最长合理短语

用PMI判断短语的连贯性,筛选出最长的高PMI短语:

# 先统计单个单词的频率
unigram_counts = Counter(tokens)
total_tokens = len(tokens)

# 计算PMI的函数
def calculate_pmi(gram, n, counter):
    p_gram = counter[gram] / total_tokens
    words = gram.split()
    # 计算每个单词概率的乘积
    p_words_product = 1.0
    for word in words:
        p_words_product *= unigram_counts[word] / total_tokens
    # 避免除以0的情况
    return log2(p_gram / p_words_product) if p_words_product != 0 else 0

# 收集所有高PMI的短语
max_pmi_phrases = []
for n in range(2, 7):  # 从2-gram开始,因为1-gram是单个单词
    n_grams_str = [' '.join(gram) for gram in ngrams(tokens, n)]
    counter = Counter(n_grams_str)
    # 取前10个高频短语计算PMI
    for phrase, count in counter.most_common(10):
        pmi = calculate_pmi(phrase, n, counter)
        # 设定PMI阈值(比如>1,说明比随机组合更连贯)
        if pmi > 1:
            max_pmi_phrases.append((phrase, n, count, pmi))

# 按短语长度从长到短、PMI从高到低排序
max_pmi_phrases.sort(key=lambda x: (-x[1], -x[3]))

print("\n*最长合理短语(基于PMI)*:")
for phrase, n, count, pmi in max_pmi_phrases[:3]:
    print(f"- `{phrase}`({n}-gram): 出现{count}次,PMI={pmi:.2f}")

Python示例输出片段

各n-gram最常见的内容:

*1-gram*
- `fri`: 出现2次
- `evening`: 出现2次
- `commute`: 出现2次
- `off-peak`: 出现2次
- `be`: 出现1次

*3-gram*
- `fri evening commute`: 出现2次
- `off-peak hours`: 出现1次
- `much less traffic`: 出现1次
...

最长合理短语(基于PMI):
- `fri evening commute`(3-gram): 出现2次,PMI=2.58

R语言实现

R中可以用tidytext包快速生成n-gram,结合dplyr做数据处理,同样用PMI识别合理短语。

步骤1:安装并导入依赖库

install.packages(c("tidytext", "dplyr", "stringr", "tidyr"))
library(tidytext)
library(dplyr)
library(stringr)
library(tidyr)

步骤2:预处理文本

# 示例文本
text <- "fri evening commute can be long. some people avoid fri evening commute by choosing off-peak hours. there are much less traffic during off-peak."

# 预处理:分词、小写、去标点
text_df <- tibble(text = text) %>%
  unnest_tokens(word, text, token = "words", to_lower = TRUE) %>%
  filter(!str_detect(word, paste0("[", str_escape(paste(punctuation, collapse = "")), "]")))

步骤3:提取1-6的n-gram并统计频率

# 定义n的范围
n_range <- 1:6
all_ngrams <- list()

for(n in n_range) {
  ngram_df <- text_df %>%
    unnest_tokens(ngram, word, token = "ngrams", n = n) %>%
    count(ngram, sort = TRUE) %>%
    head(5) # 取前5个最常见的
  all_ngrams[[paste0(n, "-gram")]] <- ngram_df
}

# 打印结果
cat("各n-gram最常见的内容:\n")
for(n_type in names(all_ngrams)) {
  cat("\n*", n_type, "*\n")
  print(all_ngrams[[n_type]], row.names = FALSE)
}

步骤4:提取最长合理短语

# 统计单个单词的频率和概率
unigram_counts <- text_df %>%
  count(word, sort = TRUE) %>%
  mutate(p = n / sum(n))

# 计算PMI的函数
calculate_pmi <- function(ngram_df, n) {
  # 拆分n-gram为单个单词
  split_df <- ngram_df %>%
    separate(ngram, into = paste0("word", 1:n), sep = " ")
  
  # 关联每个单词的概率
  pmi_df <- split_df
  for(i in 1:n) {
    pmi_df <- pmi_df %>%
      left_join(unigram_counts, by = setNames("word", paste0("word", i))) %>%
      rename(!!paste0("p", i) := p)
  }
  
  # 计算PMI
  pmi_df %>%
    mutate(p_gram = n / nrow(text_df),
           # 计算单词概率的乘积
           p_product = Reduce(`*`, select(., starts_with("p"))),
           pmi = log2(p_gram / p_product)) %>%
    # 合并回n-gram字符串
    unite(ngram, starts_with("word"), sep = " ") %>%
    select(ngram, count = n, pmi) %>%
    filter(!is.infinite(pmi)) # 过滤无效值
}

# 收集所有高PMI短语
max_pmi_phrases <- list()
for(n in 2:6) {
  ngram_df <- text_df %>%
    unnest_tokens(ngram, word, token = "ngrams", n = n) %>%
    count(ngram, sort = TRUE) %>%
    head(10)
  max_pmi_phrases[[n]] <- calculate_pmi(ngram_df, n) %>% filter(pmi > 1)
}

# 合并并排序
max_pmi_phrases <- bind_rows(max_pmi_phrases) %>%
  mutate(n = str_count(ngram, " ") + 1) %>% # 计算短语长度
  arrange(desc(n), desc(pmi))

cat("\n*最长合理短语(基于PMI)*:\n")
print(max_pmi_phrases %>% head(3), row.names = FALSE)

R示例输出片段

各n-gram最常见的内容:

* 1-gram *
    n
fri  2
evening  2
commute  2
off-peak  2
be  1

* 3-gram *
                 n
fri evening commute  2
off-peak hours  1
much less traffic  1
...

最长合理短语(基于PMI):
                 count      pmi n
fri evening commute     2 2.58496 3

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:39:54