NLTK,一个高级的 Python 库!
一、库的简介:让计算机理解人类语言的桥梁
在人工智能飞速发展的今天,让计算机理解和处理人类语言已经成为众多应用的核心需求。从智能客服自动回复用户咨询,到社交媒体舆情监控分析品牌口碑,再到邮件客户端自动分类垃圾邮件,这些看似智能的行为背后,都离不开自然语言处理(NLP)技术的支撑。而NLTK,正是Python生态中最经典、最全面的自然语言处理工具包。
NLTK(Natural Language Toolkit)诞生于2001年,由宾夕法尼亚大学计算机与信息科学系的Steven Bird和Edward Loper主导开发,经过二十余年的持续演进,已成为NLP教学和科研领域的标杆性工具。它不仅仅是一个库,更是一个完整的自然语言处理平台,提供了超过50种语料库和词汇资源(如WordNet)、全面的文本处理工具(分词、词干提取、词形还原、词性标注)、以及多种机器学习模型的封装(分类器、分块器、句法解析器)。
在实际生活中,NLTK的应用场景极为广泛:
-
智能客服系统:通过文本分类理解用户意图,自动匹配常见问题解答
-
舆情监控平台:对社交媒体评论进行情感分析,实时掌握品牌口碑变化
-
内容审核系统:识别文本中的敏感词汇、垃圾信息或不当言论
-
法律文书处理:自动提取合同中的关键条款、当事人信息
-
教育辅助工具:分析学生作文的词汇丰富度、语法正确性
-
搜索引擎优化:理解用户查询意图,提升搜索结果相关性
-
医疗文本挖掘:从病历、医学文献中提取关键临床信息
NLTK的核心价值在于,它将学术界最前沿的语言处理技术封装成简单易用的API,让开发者无需深入理解复杂的语言学理论,就能构建出功能强大的文本处理应用。同时,它内置的丰富语料库也为模型训练和算法验证提供了宝贵的数据资源。
二、安装NLTK
NLTK的安装分为两个步骤:库本身的安装和数据资源的下载。
bash
# 使用pip安装NLTK核心库 pip install nltk # 如果需要最新开发版本 pip install https://github.com/nltk/nltk/archive/develop.tar.gz
安装完成后,需要下载NLTK的数据资源包:
python
import nltk
# 下载常用资源包(推荐)
nltk.download('popular')
# 或者下载所有资源(包括语料库、模型等)
nltk.download('all')
# 按需下载特定资源
nltk.download('punkt') # 分词器
nltk.download('averaged_perceptron_tagger') # 词性标注模型
nltk.download('stopwords') # 停用词列表
nltk.download('wordnet') # 词汇数据库
nltk.download('vader_lexicon') # 情感分析词典
验证安装是否成功:
python
from nltk import word_tokenize
print(word_tokenize("Hello, NLTK!"))
如果遇到下载速度慢的问题,可以手动下载数据包并指定路径,具体方法可参考NLTK官方文档。
三、基本用法:四步掌握NLTK
1. 分词(Tokenization)
分词是将连续的文本切分成独立的词语或句子的过程,是NLP任务的基础。
python
from nltk.tokenize import word_tokenize, sent_tokenize
text = "Dr. Smith visited New York City. He bought a car for $20,000!"
# 句子分词
sentences = sent_tokenize(text)
print("句子分词结果:", sentences)
# 输出: ['Dr. Smith visited New York City.', 'He bought a car for $20,000!']
# 词语分词
words = word_tokenize(text)
print("词语分词结果:", words)
# 输出: ['Dr.', 'Smith', 'visited', 'New', 'York', 'City', '.', 'He', 'bought', 'a', 'car', 'for', '$', '20,000', '!']
# 处理中文文本(需额外资源)
chinese_text = "我爱自然语言处理。"
# 对于中文,NLTK的分词器效果有限,建议使用结巴分词
2. 停用词移除
停用词是指在文本中频繁出现但对语义贡献不大的词语(如"the"、"is"、"and"等),移除它们可以减少噪声。
python
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
# 获取英文停用词
stop_words = set(stopwords.words('english'))
text = "This is a simple example to demonstrate stop word removal."
words = word_tokenize(text)
# 过滤停用词
filtered_words = [word for word in words if word.lower() not in stop_words]
print("原始词语:", words)
print("过滤后:", filtered_words)
# 支持多种语言
french_stops = set(stopwords.words('french'))
german_stops = set(stopwords.words('german'))
3. 词干提取与词形还原
这两种技术都将词语转换为基本形式,但策略不同:
-
词干提取:粗暴地切除词缀,得到可能不是真实单词的词干
-
词形还原:基于词典将单词还原为原型(如"better" → "good")
python
from nltk.stem import PorterStemmer, SnowballStemmer, WordNetLemmatizer
from nltk.tokenize import word_tokenize
words = ["running", "better", "studies", "crying", "mice", "was"]
# 词干提取
porter = PorterStemmer()
snowball = SnowballStemmer('english')
print("词干提取结果:")
for word in words:
print(f"{word:10} -> Porter: {porter.stem(word):10} | Snowball: {snowball.stem(word)}")
# 词形还原
lemmatizer = WordNetLemmatizer()
print("\n词形还原结果:")
for word in words:
print(f"{word:10} -> {lemmatizer.lemmatize(word, pos='v'):10}") # pos指定词性
4. 词性标注
词性标注是为每个单词标注语法类别(名词、动词、形容词等)的过程。
python
from nltk import pos_tag
from nltk.tokenize import word_tokenize
text = "The quick brown fox jumps over the lazy dog."
words = word_tokenize(text)
tagged = pos_tag(words)
print("词性标注结果:")
for word, tag in tagged:
print(f"{word:10} -> {tag}")
# 解释词性标签的含义
from nltk.help import upenn_tagset
print("\n名词标签说明:")
upenn_tagset('NN') # 显示NN标签的含义
输出示例:'The'是限定词(DT),'quick'是形容词(JJ),'fox'是名词(NN),'jumps'是动词(VBZ)等。
四、高级用法
1. 命名实体识别
命名实体识别(NER)是识别文本中具有特定意义的实体,如人名、地名、组织名等。
python
from nltk import ne_chunk, pos_tag, word_tokenize
from nltk.tree import Tree
def extract_entities(text):
"""提取文本中的命名实体"""
words = word_tokenize(text)
tagged = pos_tag(words)
tree = ne_chunk(tagged)
entities = []
for subtree in tree:
if isinstance(subtree, Tree):
entity_type = subtree.label()
entity_text = " ".join([word for word, tag in subtree.leaves()])
entities.append((entity_text, entity_type))
return entities
# 示例
text = "Barack Obama was born in Hawaii. He worked at Google in California."
entities = extract_entities(text)
print("命名实体识别结果:")
for entity_text, entity_type in entities:
print(f"{entity_text}: {entity_type}")
# 可视化句法树
import nltk
nltk.tree.Tree.fromstring(str(ne_chunk(pos_tag(word_tokenize(text))))).draw()
2. 情感分析
NLTK提供了两种情感分析方案:基于规则的VADER和基于机器学习的分类器。
python
from nltk.sentiment import SentimentIntensityAnalyzer
from nltk.sentiment.vader import SentimentIntensityAnalyzer
from nltk.classify import NaiveBayesClassifier
from nltk.corpus import movie_reviews
import random
# 2.1 VADER情感分析(适合社交媒体)
def vader_sentiment_demo():
sid = SentimentIntensityAnalyzer()
texts = [
"I love this product! It's absolutely amazing!",
"This movie was terrible and boring.",
"The weather is okay, nothing special."
]
print("VADER情感分析结果:")
for text in texts:
scores = sid.polarity_scores(text)
sentiment = "positive" if scores['compound'] > 0.05 else "negative" if scores['compound'] < -0.05 else "neutral"
print(f"\n文本: {text}")
print(f"分数: {scores}")
print(f"情感: {sentiment}")
# 2.2 基于电影评论的情感分类
def movie_review_classifier_demo():
# 加载电影评论语料库
documents = [(list(movie_reviews.words(fileid)), category)
for category in movie_reviews.categories()
for fileid in movie_reviews.fileids(category)]
random.shuffle(documents)
# 特征提取函数
all_words = nltk.FreqDist(w.lower() for w in movie_reviews.words())
word_features = list(all_words.keys())[:2000]
def document_features(document):
document_words = set(document)
features = {}
for word in word_features:
features[f'contains({word})'] = (word in document_words)
return features
# 训练分类器
featuresets = [(document_features(doc), category) for (doc, category) in documents]
train_set, test_set = featuresets[100:], featuresets[:100]
classifier = NaiveBayesClassifier.train(train_set)
# 评估
accuracy = nltk.classify.accuracy(classifier, test_set)
print(f"分类器准确率: {accuracy:.2f}")
classifier.show_most_informative_features(10)
3. 文本分类
NLTK提供了多种机器学习分类器,可用于垃圾邮件过滤、新闻分类等任务。
python
from nltk.classify import NaiveBayesClassifier
from nltk.classify.util import accuracy
from nltk.corpus import names
import random
def gender_classifier_demo():
"""基于姓名的性别分类"""
# 准备数据
labeled_names = ([(name, 'male') for name in names.words('male.txt')] +
[(name, 'female') for name in names.words('female.txt')])
random.shuffle(labeled_names)
# 特征提取:名字的最后n个字母
def gender_features(word, num_letters=2):
return {'last_letters': word[-num_letters:].lower()}
# 测试不同特征长度
for num_letters in range(1, 5):
featuresets = [(gender_features(name, num_letters), gender)
for (name, gender) in labeled_names]
train_set, test_set = featuresets[500:], featuresets[:500]
classifier = NaiveBayesClassifier.train(train_set)
acc = accuracy(classifier, test_set)
print(f"使用{num_letters}个字母的准确率: {acc:.3f}")
# 预测新名字
test_names = ['Leonardo', 'Amy', 'Sam']
print("\n预测结果:")
for name in test_names:
features = gender_features(name, 2)
prediction = classifier.classify(features)
print(f"{name}: {prediction}")
4. 词云生成
虽然NLTK本身不提供词云功能,但可以与其他库结合使用。
python
from nltk.corpus import gutenberg
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
from collections import Counter
import matplotlib.pyplot as plt
from wordcloud import WordCloud
def create_wordcloud_from_text(text, title="Word Cloud"):
"""从文本生成词云"""
# 分词并过滤停用词
words = word_tokenize(text.lower())
stop_words = set(stopwords.words('english'))
words = [word for word in words if word.isalpha() and word not in stop_words]
# 统计词频
word_freq = Counter(words)
# 生成词云
wordcloud = WordCloud(width=800, height=400,
background_color='white',
max_words=100).generate_from_frequencies(word_freq)
plt.figure(figsize=(10, 5))
plt.imshow(wordcloud, interpolation='bilinear')
plt.title(title)
plt.axis('off')
plt.show()
# 使用古腾堡语料库
text = gutenberg.raw('shakespeare-hamlet.txt')
create_wordcloud_from_text(text, "Hamlet Word Cloud")
五、实际应用场景
场景一:智能客服意图识别系统
python
import nltk
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
from nltk.classify import NaiveBayesClassifier
import json
class IntentClassifier:
"""智能客服意图分类器"""
def __init__(self):
self.classifier = None
self.intents = ['greeting', 'farewell', 'product_inquiry', 'complaint', 'shipping', 'payment']
self.stop_words = set(stopwords.words('english'))
def extract_features(self, text):
"""从文本中提取特征"""
# 分词
words = word_tokenize(text.lower())
# 移除停用词和非字母字符
words = [word for word in words if word.isalpha() and word not in self.stop_words]
# 提取特征:词干化后计算词频
from nltk.stem import PorterStemmer
stemmer = PorterStemmer()
words = [stemmer.stem(word) for word in words]
# 构建特征字典
features = {}
for word in words:
features[f'word_{word}'] = True
return features
def train(self, training_data):
"""训练分类器"""
featuresets = [(self.extract_features(text), intent)
for text, intent in training_data]
self.classifier = NaiveBayesClassifier.train(featuresets)
print(f"训练完成,准确率: {nltk.classify.util.accuracy(self.classifier, featuresets):.2f}")
def predict(self, text):
"""预测意图"""
if not self.classifier:
raise ValueError("分类器尚未训练")
features = self.extract_features(text)
intent = self.classifier.classify(features)
confidence = max(self.classifier.prob_classify(features).prob(intent)
for intent in self.intents)
return intent, confidence
def save_model(self, path):
"""保存模型"""
with open(path, 'w') as f:
json.dump(self.classifier, f)
def load_model(self, path):
"""加载模型"""
with open(path, 'r') as f:
self.classifier = json.load(f)
# 使用示例
def intent_classifier_demo():
# 准备训练数据
training_data = [
("Hello, how are you?", "greeting"),
("Hi there!", "greeting"),
("Good morning", "greeting"),
("Goodbye, thanks", "farewell"),
("See you later", "farewell"),
("I need to return this product", "complaint"),
("This item is defective", "complaint"),
("How much does this cost?", "product_inquiry"),
("Tell me about the features", "product_inquiry"),
("When will my order arrive?", "shipping"),
("Where is my package?", "shipping"),
("Can I pay with credit card?", "payment"),
("Do you accept PayPal?", "payment")
]
# 训练分类器
classifier = IntentClassifier()
classifier.train(training_data)
# 测试新消息
test_messages = [
"Hey, what's up?",
"I want to buy this laptop",
"My package hasn't arrived",
"This is broken, I want a refund",
"Can I use Apple Pay?",
"Talk to you later"
]
print("\n意图识别结果:")
for msg in test_messages:
intent, confidence = classifier.predict(msg)
print(f"消息: {msg[:30]:30} -> 意图: {intent:15} (置信度: {confidence:.2f})")
# 显示最有信息量的特征
classifier.classifier.show_most_informative_features(10)
# 集成到简单的客服响应系统
class SimpleChatbot:
def __init__(self, intent_classifier):
self.classifier = intent_classifier
self.responses = {
'greeting': ["Hello! How can I help you today?", "Hi there!", "Welcome!"],
'farewell': ["Thank you for contacting us!", "Have a great day!", "Goodbye!"],
'product_inquiry': ["I'd be happy to tell you about our products. What would you like to know?"],
'complaint': ["I'm sorry to hear that. Could you provide more details so I can help?"],
'shipping': ["I'll check your order status. Could you provide your order number?"],
'payment': ["We accept credit cards, PayPal, and Apple Pay."]
}
def respond(self, user_input):
intent, confidence = self.classifier.predict(user_input)
if confidence > 0.5:
import random
return random.choice(self.responses[intent])
else:
return "I'm not sure I understand. Could you rephrase that?"
if __name__ == "__main__":
intent_classifier_demo()
# 启动简单对话
print("\n" + "="*50)
print("智能客服模拟")
print("="*50)
classifier = IntentClassifier()
classifier.train(training_data) # 需要定义training_data
bot = SimpleChatbot(classifier)
# 模拟对话
test_inputs = [
"Hi there",
"What's the price of your laptop?",
"I haven't received my package yet",
"This product is defective",
"Do you accept credit cards?",
"Bye"
]
for user_input in test_inputs:
print(f"\n用户: {user_input}")
response = bot.respond(user_input)
print(f"客服: {response}")
场景二:社交媒体舆情监控系统
python
from nltk.sentiment import SentimentIntensityAnalyzer
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
from collections import Counter, defaultdict
import datetime
import json
import matplotlib.pyplot as plt
class SentimentMonitor:
"""舆情情感监控系统"""
def __init__(self):
self.sid = SentimentIntensityAnalyzer()
self.stop_words = set(stopwords.words('english'))
self.data = defaultdict(list) # 按日期存储
self.keywords = set()
def analyze_post(self, text, timestamp=None, platform="unknown"):
"""分析单条社交媒体帖子"""
if timestamp is None:
timestamp = datetime.datetime.now()
# 情感分析
scores = self.sid.polarity_scores(text)
# 提取关键词
words = word_tokenize(text.lower())
words = [word for word in words if word.isalpha() and word not in self.stop_words]
# 记录分析结果
analysis = {
'timestamp': timestamp.isoformat(),
'text': text[:100],
'platform': platform,
'sentiment': {
'compound': scores['compound'],
'positive': scores['pos'],
'negative': scores['neg'],
'neutral': scores['neu']
},
'keywords': words,
'word_count': len(word_tokenize(text))
}
# 根据情感分数分类
if scores['compound'] >= 0.05:
analysis['sentiment_label'] = 'positive'
elif scores['compound'] <= -0.05:
analysis['sentiment_label'] = 'negative'
else:
analysis['sentiment_label'] = 'neutral'
# 更新关键词
self.keywords.update(words)
# 按日期存储
date_key = timestamp.strftime('%Y-%m-%d')
self.data[date_key].append(analysis)
return analysis
def batch_analyze(self, posts):
"""批量分析"""
results = []
for post in posts:
result = self.analyze_post(post['text'], post.get('timestamp'), post.get('platform'))
results.append(result)
return results
def generate_report(self, start_date=None, end_date=None):
"""生成舆情报告"""
report = {
'total_posts': 0,
'sentiment_distribution': {'positive': 0, 'negative': 0, 'neutral': 0},
'avg_sentiment': 0,
'top_keywords': Counter(),
'platform_stats': defaultdict(int),
'daily_stats': {}
}
for date_key, posts in self.data.items():
if start_date and date_key < start_date:
continue
if end_date and date_key > end_date:
continue
daily_stats = {
'total': len(posts),
'positive': 0,
'negative': 0,
'neutral': 0,
'avg_compound': 0
}
for post in posts:
report['total_posts'] += 1
report['sentiment_distribution'][post['sentiment_label']] += 1
report['avg_sentiment'] += post['sentiment']['compound']
report['platform_stats'][post['platform']] += 1
report['top_keywords'].update(post['keywords'])
daily_stats[post['sentiment_label']] += 1
daily_stats['avg_compound'] += post['sentiment']['compound']
if daily_stats['total'] > 0:
daily_stats['avg_compound'] /= daily_stats['total']
report['daily_stats'][date_key] = daily_stats
if report['total_posts'] > 0:
report['avg_sentiment'] /= report['total_posts']
return report
def visualize_trends(self):
"""可视化舆情趋势"""
if not self.data:
print("无数据可供可视化")
return
dates = sorted(self.data.keys())
positive_counts = []
negative_counts = []
neutral_counts = []
avg_sentiment = []
for date in dates:
posts = self.data[date]
pos = sum(1 for p in posts if p['sentiment_label'] == 'positive')
neg = sum(1 for p in posts if p['sentiment_label'] == 'negative')
neu = sum(1 for p in posts if p['sentiment_label'] == 'neutral')
positive_counts.append(pos)
negative_counts.append(neg)
neutral_counts.append(neu)
avg = sum(p['sentiment']['compound'] for p in posts) / len(posts)
avg_sentiment.append(avg)
# 创建子图
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))
# 情感分布堆叠图
ax1.stackplot(dates, positive_counts, neutral_counts, negative_counts,
labels=['Positive', 'Neutral', 'Negative'],
colors=['#2ecc71', '#95a5a6', '#e74c3c'], alpha=0.7)
ax1.set_title('情感趋势变化', fontsize=14)
ax1.set_xlabel('日期')
ax1.set_ylabel('帖子数量')
ax1.legend(loc='upper left')
ax1.grid(True, alpha=0.3)
# 平均情感分数折线图
ax2.plot(dates, avg_sentiment, marker='o', color='#3498db', linewidth=2)
ax2.axhline(y=0, color='red', linestyle='--', alpha=0.5)
ax2.set_title('平均情感分数变化', fontsize=14)
ax2.set_xlabel('日期')
ax2.set_ylabel('情感分数')
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
def alert_if_negative(self, threshold=-0.3, window_hours=24):
"""检测负面舆情并报警"""
from datetime import datetime, timedelta
cutoff = datetime.now() - timedelta(hours=window_hours)
recent_posts = []
for date_key, posts in self.data.items():
for post in posts:
post_time = datetime.fromisoformat(post['timestamp'])
if post_time > cutoff:
recent_posts.append(post)
if recent_posts:
avg_sentiment = sum(p['sentiment']['compound'] for p in recent_posts) / len(recent_posts)
negative_count = sum(1 for p in recent_posts if p['sentiment']['compound'] < threshold)
alert = {
'timestamp': datetime.now().isoformat(),
'avg_sentiment': avg_sentiment,
'negative_ratio': negative_count / len(recent_posts),
'total_posts': len(recent_posts),
'needs_attention': avg_sentiment < threshold
}
if alert['needs_attention']:
print(f"⚠️ 舆情警报!近{window_hours}小时内负面情感比例过高")
print(f"平均情感分数: {avg_sentiment:.2f}")
print(f"负面帖子占比: {alert['negative_ratio']:.1%}")
return alert
return None
# 模拟监控过程
def sentiment_monitor_demo():
monitor = SentimentMonitor()
# 模拟社交媒体数据
sample_posts = [
{"text": "I love this new product! It's amazing!", "platform": "twitter",
"timestamp": datetime.datetime.now() - datetime.timedelta(days=5)},
{"text": "Great customer service, very helpful", "platform": "facebook",
"timestamp": datetime.datetime.now() - datetime.timedelta(days=4)},
{"text": "This update is terrible, keeps crashing", "platform": "twitter",
"timestamp": datetime.datetime.now() - datetime.timedelta(days=3)},
{"text": "Average quality, nothing special", "platform": "reddit",
"timestamp": datetime.datetime.now() - datetime.timedelta(days=2)},
{"text": "Worst experience ever! Will not buy again.", "platform": "twitter",
"timestamp": datetime.datetime.now() - datetime.timedelta(days=1)},
{"text": "Finally fixed the bug, works great now", "platform": "facebook",
"timestamp": datetime.datetime.now()},
]
# 批量分析
monitor.batch_analyze(sample_posts)
# 生成报告
report = monitor.generate_report()
print("舆情监控报告")
print("="*50)
print(f"总分析帖子数: {report['total_posts']}")
print(f"情感分布: 正面 {report['sentiment_distribution']['positive']} | "
f"中性 {report['sentiment_distribution']['neutral']} | "
f"负面 {report['sentiment_distribution']['negative']}")
print(f"平均情感分数: {report['avg_sentiment']:.2f}")
print("\n热门关键词:")
for word, count in report['top_keywords'].most_common(10):
print(f" {word}: {count}")
# 检查负面警报
alert = monitor.alert_if_negative(threshold=0)
if alert and alert['needs_attention']:
print("\n⚠️ 建议立即关注负面反馈!")
# 可视化
monitor.visualize_trends()
if __name__ == "__main__":
sentiment_monitor_demo()
场景三:文本摘要生成器
python
from nltk.tokenize import sent_tokenize, word_tokenize
from nltk.corpus import stopwords
from nltk.probability import FreqDist
from nltk.stem import PorterStemmer
from heapq import nlargest
import math
class TextSummarizer:
"""基于频率的文本摘要生成器"""
def __init__(self):
self.stop_words = set(stopwords.words('english'))
self.stemmer = PorterStemmer()
def preprocess(self, text):
"""文本预处理"""
# 分句
sentences = sent_tokenize(text)
# 分词并过滤
words = word_tokenize(text.lower())
words = [self.stemmer.stem(word) for word in words
if word.isalpha() and word not in self.stop_words]
return sentences, words
def compute_word_frequencies(self, words):
"""计算词频"""
freq_dist = FreqDist(words)
# 归一化
max_freq = max(freq_dist.values())
for word in freq_dist.keys():
freq_dist[word] /= max_freq
return freq_dist
def score_sentences(self, sentences, word_freq):
"""计算句子得分"""
sentence_scores = {}
for i, sentence in enumerate(sentences):
words = word_tokenize(sentence.lower())
words = [self.stemmer.stem(word) for word in words
if word.isalpha() and word not in self.stop_words]
# 句子得分 = 词频之和
score = sum(word_freq.get(word, 0) for word in words)
# 考虑句子长度(惩罚过短或过长的句子)
length_penalty = len(words)
if length_penalty > 5 and length_penalty < 30:
score *= 1.2
sentence_scores[i] = score
return sentence_scores
def summarize(self, text, num_sentences=3):
"""生成摘要"""
if not text:
return ""
sentences, words = self.preprocess(text)
if len(sentences) <= num_sentences:
return text
# 计算词频
word_freq = self.compute_word_frequencies(words)
# 计算句子得分
sentence_scores = self.score_sentences(sentences, word_freq)
# 选择得分最高的句子
top_sentences = nlargest(num_sentences, sentence_scores, key=sentence_scores.get)
top_sentences.sort() # 按原始顺序排列
# 生成摘要
summary = ' '.join([sentences[i] for i in top_sentences])
return summary
def extract_keywords(self, text, num_keywords=5):
"""提取关键词"""
_, words = self.preprocess(text)
word_freq = FreqDist(words)
return [word for word, freq in word_freq.most_common(num_keywords)]
# 高级版本:使用TF-IDF加权
class AdvancedSummarizer(TextSummarizer):
"""基于TF-IDF的高级摘要生成器"""
def __init__(self, corpus=None):
super().__init__()
self.corpus = corpus or []
self.doc_count = len(self.corpus)
self.document_freq = {}
if self.corpus:
self.build_inverse_freq()
def build_inverse_freq(self):
"""构建逆文档频率"""
for doc in self.corpus:
words = set(word_tokenize(doc.lower()))
words = [self.stemmer.stem(word) for word in words
if word.isalpha() and word not in self.stop_words]
for word in set(words):
self.document_freq[word] = self.document_freq.get(word, 0) + 1
def compute_tfidf(self, words):
"""计算TF-IDF"""
# 词频
word_counts = FreqDist(words)
total_words = len(words)
tfidf = {}
for word, count in word_counts.items():
tf = count / total_words
if self.doc_count > 0 and word in self.document_freq:
idf = math.log(self.doc_count / self.document_freq[word])
else:
idf = 1
tfidf[word] = tf * idf
return tfidf
def summarize(self, text, num_sentences=3):
sentences, words = self.preprocess(text)
if len(sentences) <= num_sentences:
return text
# 使用TF-IDF而不是简单词频
if self.corpus:
word_weights = self.compute_tfidf(words)
else:
word_freq = self.compute_word_frequencies(words)
word_weights = word_freq
sentence_scores = {}
for i, sentence in enumerate(sentences):
sentence_words = word_tokenize(sentence.lower())
sentence_words = [self.stemmer.stem(word) for word in sentence_words
if word.isalpha() and word not in self.stop_words]
# 考虑句子位置(开头和结尾的句子更重要)
position_weight = 1.0
if i < len(sentences) * 0.2: # 前20%
position_weight = 1.5
elif i > len(sentences) * 0.8: # 后20%
position_weight = 1.3
score = sum(word_weights.get(word, 0) for word in sentence_words)
sentence_scores[i] = score * position_weight
top_sentences = nlargest(num_sentences, sentence_scores, key=sentence_scores.get)
top_sentences.sort()
return ' '.join([sentences[i] for i in top_sentences])
# 使用示例
def summarizer_demo():
# 测试文本
long_text = """
Natural language processing (NLP) is a subfield of linguistics, computer science, and artificial intelligence
concerned with the interactions between computers and human language, in particular how to program computers
to process and analyze large amounts of natural language data. The goal is a computer capable of "understanding"
the contents of documents, including the contextual nuances of the language within them. The technology can
then accurately extract information and insights contained in the documents as well as categorize and organize
the documents themselves.
Challenges in natural language processing frequently involve speech recognition, natural language understanding,
and natural language generation. The history of NLP generally starts in the 1950s, although work can be found
from earlier periods. In 1950, Alan Turing published an article titled "Computing Machinery and Intelligence"
which proposed what is now called the Turing test as a criterion of intelligence.
NLP has significant overlap with the field of computational linguistics, and it is often considered a subfield
of artificial intelligence. Major tasks in NLP include speech recognition, text segmentation, part-of-speech
tagging, parsing, information extraction, and sentiment analysis. Modern NLP algorithms are based on machine
learning, especially statistical machine learning and deep learning.
Recent advances in deep learning have dramatically improved NLP performance. Models like BERT, GPT, and their
variants have achieved state-of-the-art results on many NLP tasks. These models use transformer architectures
and large-scale pre-training on massive text corpora to learn general language representations that can be
fine-tuned for specific tasks with relatively little task-specific data.
"""
# 基本摘要
summarizer = TextSummarizer()
summary = summarizer.summarize(long_text, num_sentences=3)
keywords = summarizer.extract_keywords(long_text, 10)
print("原文长度:", len(long_text.split()), "词")
print("\n生成摘要:")
print(summary)
print("\n关键词:")
print(keywords)
# 高级摘要(使用TF-IDF)
corpus = [
"Natural language processing is a fascinating field of artificial intelligence.",
"Machine learning algorithms have revolutionized how we process text data.",
"Deep learning models like BERT achieve state-of-the-art results in NLP.",
# 更多文档...
]
advanced = AdvancedSummarizer(corpus)
advanced_summary = advanced.summarize(long_text, num_sentences=2)
print("\n高级摘要(TF-IDF加权):")
print(advanced_summary)
场景四:文本可读性分析工具
python
from nltk.tokenize import sent_tokenize, word_tokenize
from nltk.corpus import cmudict
import re
class ReadabilityAnalyzer:
"""文本可读性分析工具"""
def __init__(self):
try:
self.cmu_dict = cmudict.dict()
except LookupError:
nltk.download('cmudict')
self.cmu_dict = cmudict.dict()
def count_syllables(self, word):
"""计算单词的音节数(基于CMU发音词典)"""
word = word.lower()
if word in self.cmu_dict:
# 取第一个发音,统计元音数量
return max([len([y for y in pron if y[-1].isdigit()]) for pron in self.cmu_dict[word]])
else:
# 简单回退算法:统计元音字母组
return self._count_syllables_fallback(word)
def _count_syllables_fallback(self, word):
"""备用音节计数算法"""
word = word.lower()
count = 0
vowels = 'aeiouy'
prev_was_vowel = False
for char in word:
is_vowel = char in vowels
if is_vowel and not prev_was_vowel:
count += 1
prev_was_vowel = is_vowel
if word.endswith('e'):
count -= 1
if count == 0:
count = 1
return count
def analyze(self, text):
"""全面分析文本可读性"""
# 分句分词
sentences = sent_tokenize(text)
words = word_tokenize(text)
# 过滤掉标点符号
words = [word for word in words if any(c.isalpha() for c in word)]
# 基础统计
num_sentences = len(sentences)
num_words = len(words)
num_chars = sum(len(word) for word in words)
# 统计长词(超过6个字母)
long_words = [word for word in words if len(word) > 6]
# 统计音节
total_syllables = sum(self.count_syllables(word) for word in words)
# 计算各种可读性指数
if num_sentences > 0 and num_words > 0:
# 平均句子长度
avg_sentence_length = num_words / num_sentences
# 平均词长(字符数)
avg_word_length = num_chars / num_words
# 平均音节数
avg_syllables_per_word = total_syllables / num_words
# Flesch Reading Ease
flesch_score = 206.835 - 1.015 * avg_sentence_length - 84.6 * avg_syllables_per_word
# Flesch-Kincaid Grade Level
fk_grade = 0.39 * avg_sentence_length + 11.8 * avg_syllables_per_word - 15.59
# Coleman-Liau Index
cl_index = 0.0588 * (num_chars / num_words * 100) - 0.296 * (num_sentences / num_words * 100) - 15.8
# 自动化可读性指数
ari = 4.71 * (num_chars / num_words) + 0.5 * (num_words / num_sentences) - 21.43
# 复杂词比例
complex_word_ratio = len(long_words) / num_words if num_words > 0 else 0
else:
avg_sentence_length = avg_word_length = avg_syllables_per_word = 0
flesch_score = fk_grade = cl_index = ari = complex_word_ratio = 0
# 评估可读性等级
if flesch_score >= 90:
reading_level = "非常容易(小学4年级)"
elif flesch_score >= 80:
reading_level = "容易(小学5年级)"
elif flesch_score >= 70:
reading_level = "较容易(小学6年级)"
elif flesch_score >= 60:
reading_level = "标准(初中生)"
elif flesch_score >= 50:
reading_level = "较难(高中生)"
elif flesch_score >= 30:
reading_level = "难(大学生)"
else:
reading_level = "非常难(研究生)"
return {
'statistics': {
'sentences': num_sentences,
'words': num_words,
'characters': num_chars,
'syllables': total_syllables,
'long_words': len(long_words),
'avg_sentence_length': round(avg_sentence_length, 2),
'avg_word_length': round(avg_word_length, 2),
'avg_syllables_per_word': round(avg_syllables_per_word, 2),
'complex_word_ratio': round(complex_word_ratio * 100, 1)
},
'readability_scores': {
'flesch_reading_ease': round(flesch_score, 1),
'flesch_kincaid_grade': round(fk_grade, 1),
'coleman_liau_index': round(cl_index, 1),
'automated_readability_index': round(ari, 1)
},
'reading_level': reading_level
}
def compare_texts(self, texts):
"""比较多个文本的可读性"""
results = []
for text in texts:
results.append(self.analyze(text))
return results
# 使用示例
def readability_demo():
analyzer = ReadabilityAnalyzer()
# 测试不同难度的文本
texts = [
"The cat sat on the mat. It was a sunny day. The bird sang.", # 简单
"The development of artificial intelligence has revolutionized many industries. However, concerns about job displacement persist.", # 中等
"The epistemological underpinnings of post-structuralist discourse necessitate a critical examination of hegemonic power structures within socio-linguistic frameworks." # 难
]
print("文本可读性分析")
print("="*60)
for i, text in enumerate(texts):
print(f"\n文本 {i+1}:")
print(f"内容: {text[:100]}...")
result = analyzer.analyze(text)
print("\n统计信息:")
for key, value in result['statistics'].items():
print(f" {key}: {value}")
print("\n可读性分数:")
for key, value in result['readability_scores'].items():
print(f" {key}: {value}")
print(f"\n阅读难度等级: {result['reading_level']}")
print("-"*40)
# 生成阅读建议
print("\n阅读建议:")
for result in analyzer.compare_texts(texts):
if result['readability_scores']['flesch_reading_ease'] < 30:
print("⚠️ 文本难度较高,建议简化句子结构,使用更常见的词汇。")
elif result['readability_scores']['flesch_reading_ease'] > 80:
print("✅ 文本易于理解,适合广泛受众。")
六、结尾
NLTK作为自然语言处理领域的经典工具包,以其全面的功能、丰富的语料库和成熟的算法实现,为无数开发者打开了通往NLP世界的大门。从本文的介绍中,我们不仅学习了分词、词性标注、情感分析等基础功能,更深入探索了命名实体识别、文本分类、意图识别等高级应用,并通过舆情监控、智能客服、文本摘要、可读性分析四个完整的实战项目,展示了NLTK在实际场景中的强大能力。
自然语言处理是人工智能皇冠上的明珠,它让机器能够理解、生成和处理人类语言,从而架起了人与计算机沟通的桥梁。NLTK作为这一领域的启蒙者和奠基者,二十多年来持续为学术界和工业界提供着可靠的支持。虽然近年来深度学习框架如BERT、GPT等带来了革命性的进步,但NLTK所奠定的基础概念和处理流程,依然是每个NLP从业者必须掌握的宝贵知识。理解NLTK,就是理解NLP的底层逻辑;掌握NLTK,就是掌握文本处理的核心能力。
现在,轮到你了!你是否在工作中遇到过有趣的文本处理需求?是用NLTK解决的,还是尝试了spaCy、Transformers等新工具?有没有什么独到的技巧或踩过的坑想要分享?欢迎在评论区留言交流。如果你有一个创意,想要用自然语言处理来实现,也欢迎提出来,我们一起探讨实现方案。期待看到你的分享和思考!
更多推荐


所有评论(0)