
文本预处理是nlp任务中至关重要的一步,它旨在将原始文本转换为机器学习模型可以理解和处理的格式。常见的预处理步骤包括:
在Pandas DataFrame中处理这些步骤时,一个常见的问题是,不同的预处理函数可能期望不同类型的数据(例如,字符串或字符串列表),而如果未能正确管理这些类型转换,就会导致运行时错误,如AttributeError: 'list' object has no attribute 'split'。
原始问题中出现的AttributeError: 'list' object has no attribute 'split'是一个典型的例子。这通常发生在对DataFrame列应用apply函数时,如果某一列的单元格内容在之前的步骤中被转换为列表(例如,通过分词),而后续的函数(如contractions.fix或re.sub)期望接收一个字符串作为输入,就会引发此错误。
关键在于: 当对DataFrame的某一列进行操作时,df[column].apply(func)会将该列中的每一个单元格内容作为参数传递给func。如果func内部需要对字符串进行操作(如x.split()),但它接收到的是一个列表,那么就会报错。因此,我们需要确保:
解决这类问题的核心是确保在整个预处理管道中,每个操作都接收到其期望的数据类型。通常,这意味着在分词后,后续的许多操作都需要在列表中的每个单词(字符串)上进行。
以下是一个修正后的、结构清晰的文本预处理管道实现。
import pandas as pd import nltk from nltk.corpus import stopwords, wordnet from nltk.stem import WordNetLemmatizer from nltk.tokenize import word_tokenize, sent_tokenize import re import string from unidecode import unidecode import contractions # from textblob import TextBlob # TextBlob可能导致性能问题,此处可选
词形还原(Lemmatization)通常需要词性标签(Part-of-Speech Tag)来更准确地还原词形。
def lemmatize_pos_tagged_text(text, lemmatizer, pos_tag_dict):
"""
对给定的文本进行词形还原,结合词性标签。
text: 单个字符串(单词)。
lemmatizer: WordNetLemmatizer实例。
pos_tag_dict: NLTK词性标签到WordNet词性标签的映射字典。
"""
# 注意:这个函数期望一个单词(字符串),而不是一个句子或段落。
# 如果传入的是句子,它会尝试分句和分词,但在这里的管道中,它将接收单个词。
# 原始函数设计是处理句子,但我们将其用于处理列表中的单个词,
# 因此需要确保传入的是单个词,或者调整其内部逻辑以适应单个词的输入。
# 为了与外部管道的“每个词”处理保持一致,我们假设它接收一个单词。
# 优化:当传入的是单个词时,直接进行词形还原
word = text.lower() # 确保单词是小写
pos_tuples = nltk.pos_tag([word]) # 对单个词进行词性标注
nltk_word_pos = pos_tuples[0][1] # 获取词性标签
wordnet_word_pos = pos_tag_dict.get(nltk_word_pos[0].upper(), None)
if wordnet_word_pos is not None:
new_word = lemmatizer.lemmatize(word, wordnet_word_pos)
else:
new_word = lemmatizer.lemmatize(word)
return new_word注意: 原始的lemmatize_pos_tagged_text函数设计用于处理句子,内部包含分句和分词逻辑。但在修正后的processing_steps函数中,它被应用于列表中的单个单词。为了保持逻辑一致性,上述代码对lemmatize_pos_tagged_text进行了微调,使其更适用于处理单个单词,而不是重新分词。如果需要处理整个句子并进行词形还原,原始函数是合适的,但此处为了适应管道的“逐词处理”模式,我们将其调整为接受单个词。
以下是核心的processing_steps函数,它展示了如何通过列表推导式和apply函数来正确处理数据类型。
def processing_steps(df: pd.DataFrame) -> pd.DataFrame:
"""
对Pandas DataFrame中的文本列进行NLP预处理。
参数:
df (pd.DataFrame): 包含文本数据的DataFrame。
返回:
pd.DataFrame: 经过预处理的DataFrame。
"""
# 初始化NLP工具和资源
lemmatizer = WordNetLemmatizer()
pos_tag_dict = {"J": wordnet.ADJ, "N": wordnet.NOUN, "V": wordnet.VERB, "R": wordnet.ADV}
local_stopwords = set(stopwords.words('english'))
additional_stopwords = ["http", "u", "get", "like", "let", "nan"]
words_to_keep = ["i'", " i ", "me", "my", "we", "our", "us"] # 注意:i'可能需要特殊处理,通常是"i'm"的一部分
local_stopwords.update(additional_stopwords)
# 确保要保留的词不在停用词列表中
local_stopwords = {word for word in local_stopwords if word not in words_to_keep}
new_data = {}
for column in df.columns:
# 确保处理的列是字符串类型,如果不是,先转换为字符串
temp_series = df[column].astype(str)
# 1. 分词 (Tokenization)
# 将每个字符串单元格转换为单词列表
results = temp_series.apply(word_tokenize)
# 此时 results 中的每个元素是一个列表,例如 ['hello', 'world']
# 2. 小写转换 (Lowercasing)
# 对列表中每个单词进行小写转换
results = results.apply(lambda x: [word.lower() for word in x])
# 此时 results 仍是列表的列表,例如 ['hello', 'world']
# 3. 移除停用词、非字母字符 (Removing stopwords and non-alpha)
# 遍历列表中的每个单词,移除停用词和非字母词
results = results.apply(lambda tokens: [word for word in tokens if word.isalpha() and word not in local_stopwords])
# 4. 处理变音符号 (Replace diacritics)
# 对列表中每个单词进行变音符号替换
results = results.apply(lambda x: [unidecode(word, errors="preserve") for word in x])
# 5. 扩展缩写词 (Expand contractions)
# contractions.fix期望字符串,因此需要对列表中的每个单词进行处理
# 注意:contractions.fix通常处理整个短语,如果只给单个词,效果可能不明显
# 这里的处理方式是先将列表中的词连接成一个字符串,再进行缩写词扩展,然后再分词。
# 但更常见且更符合后续逐词处理的方式是:如果contractions.fix能处理单个词,就直接处理。
# 如果不能,此步骤可能需要在分词前进行。
# 鉴于原始问题中的解决方案,它尝试在每个词上应用,但contractions.fix通常用于完整的句子或短语。
# 这里我们假设它能处理单个词或词组,并将其作为一个整体处理。
# 修正:contractions.fix通常处理完整的字符串,而不是单个单词。
# 如果列表中的每个元素都是一个单词,且该单词本身可能包含缩写,则可以这样处理。
# 例如,"i'm"作为一个单词,contractions.fix("i'm") -> "i am"。
# 如果是"don't", "can't"等,则直接处理。
results = results.apply(lambda x: [contractions.fix(word) for word in x])
# 6. 移除数字 (Remove numbers)
# 对列表中每个单词移除数字
results = results.apply(lambda x: [re.sub(r'\d+', '', word) for word in x])
# 7. 拼写校正 (Typos correction) - 可选,可能影响性能且需TextBlob库
# TextBlob.correct()期望字符串。此处如果使用,也需对列表中的每个单词进行
# results = results.apply(lambda x: [str(TextBlob(word).correct()) for word in x])
# 考虑到TextBlob的性能开销和潜在的错误校正,通常在生产环境中谨慎使用或使用更专业的校正模型。
# 示例中将其注释掉,以避免不必要的复杂性或性能瓶颈。
# 8. 移除标点符号 (Remove punctuation except period)
# 对列表中每个单词移除标点符号
# re.escape用于转义特殊字符,string.punctuation是所有标点符号
# replace('.', '')表示保留句号
punctuation_to_remove = re.escape(string.punctuation.replace('.', ''))
results = results.apply(lambda x: [re.sub(f'[{punctuation_to_remove}]', '', word) for word in x])
# 9. 移除多余空格 (Remove double space)
# 对列表中每个单词移除多余空格
results = results.apply(lambda x: [re.sub(r' +', ' ', word).strip() for word in x]) # .strip()去除首尾空格
# 10. 词形还原 (Lemmatization)
# 对列表中每个单词进行词形还原
results = results.apply(lambda x: [lemmatize_pos_tagged_text(word, lemmatizer, pos_tag_dict) for word in x])
# 最后,将列表中的单词重新连接成一个字符串,或者保留为列表,取决于后续任务
# 如果后续任务需要字符串,则连接
results = results.apply(lambda x: " ".join(x))
# 如果后续任务需要词列表,则跳过上面一行
new_data[column] = results
# 创建新的DataFrame
new_df = pd.DataFrame(new_data)
return new_df# 创建一个示例DataFrame
data = {
'title': [
"I'm trying to preprocess a data frame.",
"NLP is gr8! Don't you think so? http://example.com",
"The quick brown fox jumps over the lazy dog."
],
'body': [
"Each cell contains a string, called 'title' and 'body'. It's complicated.",
"Based on this article, I tried to reproduce the preprocessing. U get errors.",
"Here's what I've done: type list has no attribute str. 123 test."
]
}
df = pd.DataFrame(data)
print("原始DataFrame:")
print(df)
# 运行预处理
processed_df = processing_steps(df.copy()) # 使用.copy()避免修改原始DataFrame
print("\n预处理后的DataFrame:")
print(processed_df)输出示例:
原始DataFrame:
title body
0 I'm trying to preprocess a data frame. Each cell contains a string, called 'title' and 'body'. It's complicated.
1 NLP is gr8! Don't you think so? http://example.com Based on this article, I tried to reproduce the preprocessing. U get errors.
2 The quick brown fox jumps over the lazy dog. Here's what I've done: type list has no attribute str. 123 test.
预处理后的DataFrame:
title body
0 try preprocess data frame cell contains string call title body complicate
1 nlp great think examplecom get error base article try reproduce preprocess error
2 quick brown fox jump lazy dog type list attribute str test预处理步骤的顺序并非一成不变,但通常遵循以下逻辑:
注意事项:
在Pandas DataFrame中进行NLP文本预处理时,理解并管理数据类型在不同操作之间的转换是至关重要的。通过在分词后采用元素级处理(即对列表中的每个单词应用函数),并使用列表推导式来确保每个操作都接收到其期望的输入类型,可以有效避免AttributeError并构建健壮的预处理管道。正确的处理顺序和对性能的考量也将进一步提升预处理流程的效率和质量。
以上就是高效管理Pandas DataFrame中的NLP文本预处理流程与类型一致性的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号