NLP 预处理必备的 Python 内置函数(二):分词辅助与过滤筛选
写在前面 :上一篇我们把「文本清洗」和「文本规范化」讲透了(
strip()、replace()、re.sub()、lower()、unicodedata.normalize()等)。本篇进入流水线的中间环节------分词辅助 与 过滤筛选。文本洗白之后,就要把它切成一个个 token(词),再把噪声 token(停用词、空串、纯数字)过滤掉。这中间用到的方法,全部是 Python 内置,零第三方依赖。
目录
一、分词与切分辅助
1. str.split() ------ 分词的主力工具
语法
python
str.split(sep=None, maxsplit=-1)
参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
sep |
str,可选 | 分隔符。不传时 按任意空白(空格、\t、\n)切分,且自动过滤空串;传入时严格按该字符串切分,空串会保留 |
maxsplit |
int,可选 | 最大切分次数,-1 表示不限次数 |
返回值:返回字符串列表。
示例代码
python
# 不传 sep:按任意空白切分,自动处理多个空格
s = " hello world python "
print(s.split()) # ['hello', 'world', 'python']
# 传 sep:严格按分隔符切分,空串会保留
s2 = "a,,b,c"
print(s2.split(",")) # ['a', '', 'b', 'c'] ← 注意中间的空串
# maxsplit 限制次数
s3 = "a,b,c,d"
print(s3.split(",", 2)) # ['a', 'b', 'c,d'] ← 只切前 2 次
# 中文按标点切分
s4 = "自然语言处理,人工智能,机器学习"
print(s4.split(",")) # ['自然语言处理', '人工智能', '机器学习']
NLP 场景应用
python
# 英文按空白分词(最常用)
sentence = "I love natural language processing"
tokens = sentence.split()
print(tokens) # ['I', 'love', 'natural', 'language', 'processing']
# 解析 CSV 行
row = "张三,25,北京,工程师"
fields = row.split(",")
print(fields) # ['张三', '25', '北京', '工程师']
注意事项(高频易错点)
"a b".split()和"a b".split(" ")结果不一样:前者自动合并连续空白并去空串,后者遇到连续空格会产生空串;- 中文分词不要 直接用
split()(中文词之间没有空格),交给jieba这类分词库;split()只负责按标点/空白粗切。
2. str.join() ------ 分词的逆操作
语法
python
str.join(iterable)
参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
iterable |
可迭代对象 | 列表、元组、生成器等,元素必须是字符串 |
返回值:用调用者字符串作为分隔符,拼接各元素后返回新字符串。
示例代码
python
print(" ".join(["I", "love", "Python"])) # "I love Python"
print(",".join(["a", "b", "c"])) # "a,b,c"
print("".join(["a", "b", "c"])) # "abc"
print("-".join("abc")) # "a-b-c"(字符串本身可迭代)
# 生成器也可以
print("|".join(str(i) for i in range(3))) # "0|1|2"
NLP 场景应用
python
# 分词 → 处理 → 重组句子(比如去掉停用词后再拼回去)
tokens = ["我", "喜欢", "的", "Python"]
filtered = [t for t in tokens if t != "的"]
print(" ".join(filtered)) # "我 喜欢 Python"
# 生成 CSV 行
row = ["张三", "25", "北京"]
print(",".join(row)) # "张三,25,北京"
注意事项(高频易错点)
- 元素必须是字符串 :
",".join([1, 2, 3])会抛TypeError,需要先map(str, ...)转换; - 大量字符串拼接时,
join()效率远高于+(+是 O(n²),join()是 O(n)),批量拼接永远优先join()。
3. str.splitlines() ------ 按行切分
语法
python
str.splitlines([keepends])
参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
keepends |
bool,可选 | 是否在结果中保留换行符,默认 False 去掉 |
返回值 :按换行符(\n、\r\n、\r 等)切分后的字符串列表。
示例代码
python
text = "第一行\r\n第二行\n第三行\r第四行"
print(text.splitlines())
# ['第一行', '第二行', '第三行', '第四行']
# 保留换行符
print("a\nb".splitlines(True)) # ['a\n', 'b']
# 对比:split("\n") 处理不了 \r\n
print("a\r\nb".split("\n")) # ['a\r', 'b'] ← 残留 \r,需再 strip
NLP 场景应用
python
# 按行读取并清洗语料(比 split("\n") 更健壮)
with open("corpus.txt", encoding="utf-8") as f:
lines = [line.strip() for line in f.read().splitlines()]
注意事项
splitlines() 能识别全部 Unicode 换行符,跨平台处理文本(Windows \r\n、Unix \n、Mac \r)时比 split("\n") 可靠得多。
4. str.find() 与 str.index() ------ 定位子串
语法
python
str.find(sub[, start[, end]]) # 找不到返回 -1
str.index(sub[, start[, end]]) # 找不到抛 ValueError
str.rfind(sub) # 从右侧开始找
str.rindex(sub)
返回值:子串首次出现的索引(int)。
示例代码
python
s = "自然语言处理是人工智能的一个分支"
print(s.find("人工智能")) # 7(0 起始索引)
print(s.find("不存在")) # -1
print(s.index("人工智能")) # 7
# print(s.index("不存在")) # 会抛 ValueError: substring not found
print(s.rfind("的")) # 从右往左找
# 指定搜索范围
print("hello world".find("o", 5)) # 7,从索引 5 开始找
NLP 场景应用
- 定位敏感词位置做脱敏:
python
def mask_sensitive(text, keyword):
idx = text.find(keyword)
if idx == -1:
return text
return text[:idx] + "*" * len(keyword) + text[idx + len(keyword):]
print(mask_sensitive("我的手机号是13812345678", "13812345678"))
# "我的手机号是***********"
注意事项
find() 返回 -1 表示找不到、不会抛异常,适合"判断在不在";index() 找不到直接报错,适合"确定存在再取位置"的场景。不确定存在性时优先 find()。
5. str.startswith() 与 str.endswith() ------ 首尾判断
语法
python
str.startswith(prefix[, start[, end]]) # prefix 可以是字符串或元组
str.endswith(suffix[, start[, end]])
返回值:布尔值。
示例代码
python
s = "人工智能在自然语言处理中的应用"
print(s.startswith("人工")) # True
print(s.startswith("自然")) # False
print(s.endswith("应用")) # True
# 元组参数:满足其中一个即可
url = "https://example.com"
print(url.startswith(("http://", "https://"))) # True
# 指定范围判断
print("hello world".endswith("world")) # True
NLP 场景应用
- 过滤掉以特殊字符开头/结尾的噪声行:
python
lines = ["# 标题", "正文内容", "【广告】xxx", "------分割线------"]
clean = [l for l in lines
if not l.startswith(("#", "【"))
and not l.endswith("------")]
print(clean) # ['正文内容']
二、过滤与筛选
6. filter() ------ 函数式过滤
语法
python
filter(function, iterable)
参数说明
| 参数 | 类型 | 说明 |
|---|---|---|
function |
函数 / None | 返回 True 的元素被保留;传 None 时过滤掉所有"假值"(空串、0、None 等) |
iterable |
可迭代对象 | 待过滤的数据 |
返回值 :Python 3 中返回迭代器 (惰性求值),需要用 list() 等转成列表。
示例代码
python
nums = [1, 0, 5, -3, 8]
print(list(filter(lambda x: x > 0, nums))) # [1, 5, 8]
# function 为 None:过滤假值
data = ["hello", "", "world", None, 0]
print(list(filter(None, data))) # ['hello', 'world']
NLP 场景应用
python
# 去空串 + 去停用词,一条 filter 搞定
stopwords = {"的", "了", "和", "是"}
tokens = ["我", "爱", "的", "Python", "", "是"]
clean = list(filter(
lambda w: w and w not in stopwords,
tokens
))
print(clean) # ['我', '爱', 'Python']
注意事项
filter() 是惰性的,直接 print(filter(...)) 看到的是迭代器对象;务必包一层 list()。想同时做转换(比如 str()),可以 map() + filter() 连用,或直接上列表推导式。
7. len() ------ 长度过滤与统计
语法
python
len(obj)
返回值 :对象长度。字符串返回字符数,列表/字典返回元素个数。
示例代码
python
print(len("自然语言处理")) # 6,中文字符按 1 个字符计
print(len(["a", "b", "c"])) # 3
print(len({})) # 0
NLP 场景应用
- 过滤过短的噪声 token(单字、空白串):
python
tokens = ["我", "爱", "自然语言处理", "Python", "的"]
meaningful = [t for t in tokens if len(t) >= 2]
print(meaningful) # ['自然语言处理', 'Python']("我""爱""的"长度1被过滤)
- 截断超长文本(限制模型输入长度):
python
def truncate(text, max_len=200):
return text[:max_len] if len(text) > max_len else text
注意事项
对中文分词结果用 len() 时注意:中文按字符计数,英文 token 按字母计数,两者的"长度"语义不同,过滤阈值要分别设定。
8. str.isalpha() / isdigit() / isalnum() ------ 字符类型判断
语法
python
str.isalpha() # 是否全是字母(中文也返回 True)
str.isdigit() # 是否全是数字
str.isalnum() # 是否全是字母或数字
str.isdecimal() # 是否全是十进制数字(比 isdigit 更严格)
str.isnumeric() # 是否全是数字字符(比 isdigit 更宽松)
返回值:布尔值。
示例代码
python
print("abc".isalpha()) # True
print("自然语言".isalpha()) # True ← 中文也算字母!
print("abc123".isalpha()) # False
print("123".isdigit()) # True
print("abc".isdigit()) # False
print("abc123".isalnum()) # True
print("abc 123".isalnum()) # False(空格不是字母数字)
三类数字判断的区别(易混淆,重点记)
| 方法 | 识别内容 | 示例 |
|---|---|---|
isdigit() |
0-9 及部分 Unicode 数字 | "²".isdigit() → True |
isdecimal() |
仅十进制数字(最严格) | "²".isdecimal() → False |
isnumeric() |
数字字符(含中文数字、罗马数字) | "三".isnumeric() → True |
NLP 场景应用
python
# 过滤纯数字 token(对情感分析等任务通常是噪声)
tokens = ["房价", "30000", "元", "2024年"]
clean = [t for t in tokens if not t.isdigit()]
print(clean) # ['房价', '元', '2024年']
# 识别中文(利用 isalpha 对中文返回 True 的特性)
def is_chinese_text(s):
return all('\u4e00' <= ch <= '\u9fff' for ch in s)
注意事项
isalpha()对中文返回 True ,想只判断英文字母需配合正则[a-zA-Z];- 处理文本中的年份"2024年"这类混合串时,
isdigit()返回 False,需要re.search(r'\d+', t)判断是否含数字。
9. set() ------ 去重与建词表
语法
python
set(iterable)
返回值:去重后的集合(无序)。
示例代码
python
words = ["我", "爱", "Python", "我", "爱", "编程"]
print(set(words)) # {'编程', '我', '爱', 'Python'}(顺序不固定)
NLP 场景应用
python
# 快速统计唯一词数量(词表大小)
vocab = set(tokens)
print(f"词表大小:{len(vocab)}")
# 词表转索引字典(需要稳定顺序时先排序)
vocab = sorted(set(tokens))
word2idx = {w: i for i, w in enumerate(vocab)}
注意事项
-
set()是无序的,每次运行顺序可能不同; -
需要固定顺序建词表时,用
sorted(set(...))或dict.fromkeys(tokens)(Python 3.7+ 字典保序):python# 按首次出现顺序去重 ordered_unique = list(dict.fromkeys(words)) # ['我', '爱', 'Python', '编程']
10. map() ------ 批量转换
语法
python
map(function, iterable, ...)
返回值 :迭代器(惰性),需 list() 转换。
示例代码
python
nums = ["1", "2", "3"]
print(list(map(int, nums))) # [1, 2, 3]
# 多参数:zip 风格并行传入
a = [1, 2, 3]
b = [10, 20, 30]
print(list(map(lambda x, y: x + y, a, b))) # [11, 22, 33]
NLP 场景应用
python
# 分词结果统一转小写 / 去空格
tokens = [" Hello ", "WORLD", "Python "]
clean = list(map(lambda t: t.strip().lower(), tokens))
print(clean) # ['hello', 'world', 'python']
# join 前批量转字符串
nums = [1, 2, 3]
print(",".join(map(str, nums))) # "1,2,3"
注意事项
map() 惰性求值,且参数是函数在前、可迭代对象在后 ,和 filter() 的传参顺序一致,别写反。
三、综合实战:完整的过滤清洗流水线
把第 2 篇的方法组合成一段可复用的过滤函数:
python
import re
STOPWORDS = {"的", "了", "和", "是", "在", "有", "我", "你"}
def filter_tokens(tokens, min_len=1, stopwords=None):
"""分词结果过滤:去空串、去停用词、去纯数字、去过短 token"""
stopwords = stopwords or STOPWORDS
return [
t for t in tokens
if t # 非空
and t not in stopwords # 非停用词
and not t.isdigit() # 非纯数字
and len(t) >= min_len # 长度达标
and t.isalnum() # 只保留字母/中文/数字组合(去掉标点 token)
]
def tokenize_and_filter(text):
# 清洗 → 分词 → 过滤
text = re.sub(r'[^\w\s\u4e00-\u9fff]', ' ', text)
tokens = text.split()
return filter_tokens(tokens)
text = "我 爱 Python!的 自然语言处理 是 2024 最热门的 方向 !!!"
print(tokenize_and_filter(text))
# ['爱', 'Python', '自然语言处理', '最热门的', '方向']
可以看到:
我/的/是(停用词)、2024(纯数字)、!!!(标点)都被过滤掉了,剩下的是有实际语义的 token。
四、小结
本篇覆盖了流水线的中间两个阶段:
- 分词辅助 :
split()(按空白/分隔符切分)、join()(重组)、splitlines()(按行)、find()/index()(定位)、startswith()/endswith()(首尾判断); - 过滤筛选 :
filter()(函数式过滤)、len()(长度过滤)、isalpha()/isdigit()家族(类型判断)、set()(去重建词表)、map()(批量转换)。
下一篇(系列完结篇)将讲解 统计、建词表与完整实战 :collections.Counter、sorted()、enumerate()、zip()、ord() / chr()、isinstance(),并给出一段从原始文本到词表索引的全流程可运行代码。敬请关注。