NLP 预处理必备的 Python 内置函数(二):分词辅助与过滤筛选
写在前面:上一篇我们把「文本清洗」和「文本规范化」讲透了(strip()、replace()、re.sub()、lower()、unicodedata.normalize() 等)。本篇进入流水线的中间环节——分词辅助 与 过滤筛选。
文本洗白之后,就要把它切成一个个 token(词),再把噪声 token(停用词、空串、纯数字)过滤掉。这中间用到的方法,全部是 Python 内置,零第三方依赖。
目录
一、分词与切分辅助
1. str.split() —— 分词的主力工具
语法
str.split(sep=None, maxsplit=–1)
参数说明
| sep | str,可选 | 分隔符。不传时按任意空白(空格、\\t、\\n)切分,且自动过滤空串;传入时严格按该字符串切分,空串会保留 |
| maxsplit | int,可选 | 最大切分次数,-1 表示不限次数 |
返回值:返回字符串列表。
示例代码
# 不传 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 场景应用
# 英文按空白分词(最常用)
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', '北京', '工程师']
注意事项(高频易错点)
2. str.join() —— 分词的逆操作
语法
str.join(iterable)
参数说明
| iterable | 可迭代对象 | 列表、元组、生成器等,元素必须是字符串 |
返回值:用调用者字符串作为分隔符,拼接各元素后返回新字符串。
示例代码
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 场景应用
# 分词 → 处理 → 重组句子(比如去掉停用词后再拼回去)
tokens = ["我", "喜欢", "的", "Python"]
filtered = [t for t in tokens if t != "的"]
print(" ".join(filtered)) # "我 喜欢 Python"
# 生成 CSV 行
row = ["张三", "25", "北京"]
print(",".join(row)) # "张三,25,北京"
注意事项(高频易错点)
3. str.splitlines() —— 按行切分
语法
str.splitlines([keepends])
参数说明
| keepends | bool,可选 | 是否在结果中保留换行符,默认 False 去掉 |
返回值:按换行符(\\n、\\r\\n、\\r 等)切分后的字符串列表。
示例代码
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 场景应用
# 按行读取并清洗语料(比 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() —— 定位子串
语法
str.find(sub[, start[, end]]) # 找不到返回 -1
str.index(sub[, start[, end]]) # 找不到抛 ValueError
str.rfind(sub) # 从右侧开始找
str.rindex(sub)
返回值:子串首次出现的索引(int)。
示例代码
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 场景应用
- 定位敏感词位置做脱敏:
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() —— 首尾判断
语法
str.startswith(prefix[, start[, end]]) # prefix 可以是字符串或元组
str.endswith(suffix[, start[, end]])
返回值:布尔值。
示例代码
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 场景应用
- 过滤掉以特殊字符开头/结尾的噪声行:
lines = ["# 标题", "正文内容", "【广告】xxx", "——分割线——"]
clean = [l for l in lines
if not l.startswith(("#", "【"))
and not l.endswith("——")]
print(clean) # ['正文内容']
二、过滤与筛选
6. filter() —— 函数式过滤
语法
filter(function, iterable)
参数说明
| function | 函数 / None | 返回 True 的元素被保留;传 None 时过滤掉所有"假值"(空串、0、None 等) |
| iterable | 可迭代对象 | 待过滤的数据 |
返回值:Python 3 中返回迭代器(惰性求值),需要用 list() 等转成列表。
示例代码
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 场景应用
# 去空串 + 去停用词,一条 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() —— 长度过滤与统计
语法
len(obj)
返回值:对象长度。字符串返回字符数,列表/字典返回元素个数。
示例代码
print(len("自然语言处理")) # 6,中文字符按 1 个字符计
print(len(["a", "b", "c"])) # 3
print(len({})) # 0
NLP 场景应用
- 过滤过短的噪声 token(单字、空白串):
tokens = ["我", "爱", "自然语言处理", "Python", "的"]
meaningful = [t for t in tokens if len(t) >= 2]
print(meaningful) # ['自然语言处理', 'Python']("我""爱""的"长度1被过滤)
- 截断超长文本(限制模型输入长度):
def truncate(text, max_len=200):
return text[:max_len] if len(text) > max_len else text
注意事项
对中文分词结果用 len() 时注意:中文按字符计数,英文 token 按字母计数,两者的"长度"语义不同,过滤阈值要分别设定。
8. str.isalpha() / isdigit() / isalnum() —— 字符类型判断
语法
str.isalpha() # 是否全是字母(中文也返回 True)
str.isdigit() # 是否全是数字
str.isalnum() # 是否全是字母或数字
str.isdecimal() # 是否全是十进制数字(比 isdigit 更严格)
str.isnumeric() # 是否全是数字字符(比 isdigit 更宽松)
返回值:布尔值。
示例代码
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 场景应用
# 过滤纯数字 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)
注意事项
9. set() —— 去重与建词表
语法
set(iterable)
返回值:去重后的集合(无序)。
示例代码
words = ["我", "爱", "Python", "我", "爱", "编程"]
print(set(words)) # {'编程', '我', '爱', 'Python'}(顺序不固定)
NLP 场景应用
# 快速统计唯一词数量(词表大小)
vocab = set(tokens)
print(f"词表大小:{len(vocab)}")
# 词表转索引字典(需要稳定顺序时先排序)
vocab = sorted(set(tokens))
word2idx = {w: i for i, w in enumerate(vocab)}
注意事项
ordered_unique = list(dict.fromkeys(words))
# ['我', '爱', 'Python', '编程']
10. map() —— 批量转换
语法
map(function, iterable, ...)
返回值:迭代器(惰性),需 list() 转换。
示例代码
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 场景应用
# 分词结果统一转小写 / 去空格
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 篇的方法组合成一段可复用的过滤函数:
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(),并给出一段从原始文本到词表索引的全流程可运行代码。敬请关注。
网硕互联帮助中心





评论前必须登录!
注册