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

如何让scikit-learn的CountVectorizer以标点分隔分词且不含标点?

解决CountVectorizer跨标点生成n-gram的问题

你遇到的问题是默认CountVectorizer的行为导致的:它会先剥离标点,再将剩余单词视为连续序列,所以"data. format"会被处理成["data", "format"],进而生成二元ngram"data format"。要实现以标点为分隔符、不包含标点,同时阻止跨标点的n-gram,可以用以下两种方法解决:

方法1:拆分分句独立生成ngram

先按标点把文本拆分成独立分句,每个分句单独生成ngram,这样跨标点的词不会被组合:

import re
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.preprocessing import MultiLabelBinarizer

c = ["data. format", "data are format hello world"]

def extract_ngrams(text, ngram_range=(1,2)):
    # 按非单词/空白字符分割分句,过滤空内容
    clauses = re.split(r'[^\w\s]', text)
    clauses = [clause.strip() for clause in clauses if clause.strip()]
    
    ngrams = []
    # 对每个分句单独生成ngram
    vectorizer = CountVectorizer(ngram_range=ngram_range)
    for clause in clauses:
        vec = vectorizer.fit_transform([clause])
        ngrams.extend(vectorizer.get_feature_names_out())
    return ngrams

# 提取每个文本的ngram列表
corpus_ngrams = [extract_ngrams(text) for text in c]

# 统计频率并生成DataFrame
mlb = MultiLabelBinarizer()
ngram_counts = mlb.fit_transform(corpus_ngrams)
df = pd.DataFrame(ngram_counts, columns=mlb.classes_)
print(df)

运行后,第一个文本只会有data和format两个一元ngram,不会出现跨标点的data format二元ngram。

方法2:自定义预处理与分词逻辑

通过预处理把标点替换成特殊分隔符,打断词的连续序列,同时过滤掉分隔符:

import re
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer

c = ["data. format", "data are format hello world"]

def custom_preprocessor(text):
    # 把标点替换成特殊分隔标记
    return re.sub(r'[^\w\s]', ' __DELIM__ ', text)

def custom_tokenizer(text):
    tokens = text.split()
    # 过滤分隔标记,只保留有效单词
    return [token for token in tokens if token != '__DELIM__']

vectorizer = CountVectorizer(
    ngram_range=(1,2),
    preprocessor=custom_preprocessor,
    tokenizer=custom_tokenizer,
    # 禁用默认token_pattern,避免过滤短词
    token_pattern=None
)

X = vectorizer.fit_transform(c)
terms = vectorizer.get_feature_names_out()
df = pd.DataFrame(X.todense(), columns=terms)
print(df)

这种方法通过分隔标记打破词的连续性,既不会把标点纳入分词结果,也不会生成跨标点的ngram。

为什么默认处理没生效?

默认CountVectorizer的token_pattern是r"(?u)\b\w\w+\b",它只会提取由字母/数字/下划线组成的至少2个字符的词,所以会自动剥离data.中的句号,但不会改变词的顺序连续性——剥离标点后,data和format仍被视为同一序列中的连续词,因此会生成二元ngram。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 09:17:04