Skip to content

自然语言处理(NLP)应用开发:从文本处理到智能对话

概述

自然语言处理(Natural Language Processing,NLP)是人工智能的重要分支,它研究如何让计算机理解、处理和生成人类语言。从智能助手到机器翻译,从情感分析到智能客服,NLP 技术已经深入我们生活的方方面面。

本教程将带你系统学习 NLP 的核心技术,并通过 4 个完整的实战案例,掌握使用 Python 进行 NLP 应用开发的能力。无论你是 NLP 初学者还是有一定经验的开发者,本教程都将帮助你建立扎实的 NLP 基础。

学完本教程,你将能够:

  • 理解 NLP 基础概念和处理流程
  • 使用主流 NLP 库进行文本处理
  • 构建文本分类和命名实体识别系统
  • 开发情感分析和对话系统应用
  • 运用预训练模型解决实际问题

第一章:NLP 基础概念

1.1 什么是自然语言处理?

自然语言处理是计算机科学和人工智能的交叉领域,它关注计算机与人类语言之间的交互。NLP 的目标是让计算机能够:

  • 理解人类语言的含义
  • 生成自然流畅的文本
  • 分析语言结构和情感

NLP 应用场景:

应用领域具体场景
文本处理分词、词性标注、句法分析
信息抽取命名实体识别、关系抽取
文本分类垃圾邮件检测、新闻分类
情感分析产品评论分析、舆情监控
机器翻译多语言互译
问答系统智能客服、知识问答
对话系统聊天机器人、语音助手
文本生成文章写作、代码生成

1.2 NLP 处理流程

典型的 NLP 任务处理流程:

原始文本 → 文本清洗 → 分词 → 词性标注 → 特征提取 → 模型处理 → 输出结果

各步骤说明:

  1. 文本清洗:去除噪声、标准化格式
  2. 分词(Tokenization):将文本切分为单词或子词
  3. 词性标注(POS Tagging):标注每个词的词性
  4. 命名实体识别(NER):识别人名、地名、机构名等
  5. 特征提取:将文本转换为数值特征
  6. 模型处理:使用机器学习/深度学习模型
  7. 输出结果:生成预测或响应

1.3 文本表示方法

1.3.1 词袋模型(Bag of Words)

python
from sklearn.feature_extraction.text import CountVectorizer

# 示例文档
documents = [
    "我喜欢机器学习",
    "深度学习是机器学习的子领域",
    "自然语言处理很有趣"
]

# 创建词袋模型
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(documents)

print("词汇表:", vectorizer.get_feature_names_out())
print("词频矩阵:")
print(X.toarray())

优点: 简单、高效 缺点: 忽略词序、语义信息

1.3.2 TF-IDF

python
from sklearn.feature_extraction.text import TfidfVectorizer

# TF-IDF 向量化
tfidf_vectorizer = TfidfVectorizer(max_features=1000)
X_tfidf = tfidf_vectorizer.fit_transform(documents)

print("TF-IDF 矩阵形状:", X_tfidf.shape)
print("TF-IDF 矩阵:")
print(X_tfidf.toarray())

TF(词频): 词在文档中出现的频率 IDF(逆文档频率): 衡量词的重要性

1.3.3 词嵌入(Word Embedding)

python
# 使用预训练词向量(示例)
import numpy as np

# 模拟词向量
word_embeddings = {
    '机器学习': np.random.randn(300),
    '深度学习': np.random.randn(300),
    '自然语言处理': np.random.randn(300),
    '人工智能': np.random.randn(300)
}

# 词向量可以捕捉语义相似性
# 相似词在向量空间中距离较近

常见预训练词向量:

  • Word2Vec(Google)
  • GloVe(Stanford)
  • FastText(Facebook)
  • BERT Embeddings

1.4 中文 NLP 特殊处理

中文与英文的主要差异:

特性英文中文
分词天然空格分隔需要专门分词
词形变化有时态、复数等无词形变化
字符集26 个字母数千汉字

中文分词工具:

  • jieba(最常用)
  • HanLP
  • THULAC
  • LTP

第二章:NLP 环境搭建

2.1 安装必要库

bash
# 核心 NLP 库
pip install nltk spacy jieba

# 深度学习 NLP
pip install transformers torch tensorflow

# 实用工具
pip install scikit-learn pandas numpy matplotlib

2.2 下载 NLTK 数据

python
import nltk

# 下载必要数据
nltk.download('punkt')
nltk.download('averaged_perceptron_tagger')
nltk.download('stopwords')
nltk.download('wordnet')

2.3 加载 spaCy 模型

python
import spacy

# 加载英文模型
nlp_en = spacy.load('en_core_web_sm')

# 加载中文模型(需要单独安装)
# python -m spacy download zh_core_web_sm
# nlp_zh = spacy.load('zh_core_web_sm')

第三章:实战案例

案例 1:新闻文本分类

构建一个新闻分类系统,将新闻文章自动分类到不同类别。

3.1.1 数据加载与探索

python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import fetch_20newsgroups
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
import seaborn as sns

# 加载 20 新闻组数据集
print("加载 20 新闻组数据集...")
categories = ['comp.graphics', 'rec.sport.baseball', 'sci.med', 'talk.politics.misc']
newsgroups = fetch_20newsgroups(
    subset='all',
    categories=categories,
    remove=('headers', 'footers', 'quotes')
)

texts = newsgroups.data
labels = newsgroups.target
target_names = newsgroups.target_names

print(f"总样本数:{len(texts)}")
print(f"类别:{target_names}")

# 数据可视化
plt.figure(figsize=(10, 6))
label_counts = pd.Series(labels).value_counts().sort_index()
plt.bar(range(len(target_names)), label_counts.values)
plt.xticks(range(len(target_names)), [name.split('.')[-1] for name in target_names], rotation=45)
plt.xlabel('类别')
plt.ylabel('样本数')
plt.title('各类别样本分布')
plt.tight_layout()
plt.savefig('news_classification_distribution.png', dpi=150)
plt.show()

# 查看样本
print("\n样本文章:")
print(texts[0][:300] + "...")
print(f"类别:{target_names[labels[0]]}")

# 文本长度分析
text_lengths = [len(text.split()) for text in texts]

plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
plt.hist(text_lengths, bins=50, edgecolor='black')
plt.xlabel('词数')
plt.ylabel('频数')
plt.title('文本长度分布')
plt.grid(True, alpha=0.3)

plt.subplot(1, 2, 2)
plt.boxplot(text_lengths)
plt.ylabel('词数')
plt.title('文本长度箱线图')
plt.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('news_text_length.png', dpi=150)
plt.show()

print(f"\n文本长度统计:")
print(f"  最短:{min(text_lengths)} 词")
print(f"  最长:{max(text_lengths)} 词")
print(f"  平均:{np.mean(text_lengths):.1f} 词")
print(f"  中位数:{np.median(text_lengths):.1f} 词")

3.1.2 文本预处理

python
import re
from sklearn.feature_extraction.text import TfidfVectorizer
import nltk
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer

# 下载 NLTK 数据
nltk.download('stopwords', quiet=True)
nltk.download('wordnet', quiet=True)
nltk.download('omw-1.4', quiet=True)

# 文本预处理函数
def preprocess_text(text):
    # 转小写
    text = text.lower()
    
    # 移除特殊字符和数字
    text = re.sub(r'[^a-zA-Z\s]', '', text)
    
    # 分词
    words = text.split()
    
    # 移除停用词
    stop_words = set(stopwords.words('english'))
    words = [w for w in words if w not in stop_words]
    
    # 词形还原
    lemmatizer = WordNetLemmatizer()
    words = [lemmatizer.lemmatize(w) for w in words]
    
    # 重新组合
    return ' '.join(words)

# 应用预处理
print("正在预处理文本...")
texts_processed = [preprocess_text(text) for text in texts]

print(f"预处理完成!")
print(f"\n原始文本:{texts[0][:100]}...")
print(f"处理后:{texts_processed[0][:100]}...")

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
    texts_processed, labels, test_size=0.2, random_state=42, stratify=labels
)

print(f"\n训练集:{len(X_train)} 样本")
print(f"测试集:{len(X_test)} 样本")

3.1.3 特征提取与模型训练

python
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import LogisticRegression
from sklearn.svm import LinearSVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix, accuracy_score

# TF-IDF 特征提取
print("提取 TF-IDF 特征...")
tfidf_vectorizer = TfidfVectorizer(
    max_features=5000,
    min_df=2,
    max_df=0.8,
    ngram_range=(1, 2)
)

X_train_tfidf = tfidf_vectorizer.fit_transform(X_train)
X_test_tfidf = tfidf_vectorizer.transform(X_test)

print(f"特征维度:{X_train_tfidf.shape}")

# 训练多个模型对比
models = {
    '朴素贝叶斯': MultinomialNB(),
    '逻辑回归': LogisticRegression(max_iter=1000, random_state=42),
    '线性 SVM': LinearSVC(random_state=42),
    '随机森林': RandomForestClassifier(n_estimators=100, random_state=42)
}

results = []

for name, model in models.items():
    print(f"\n训练 {name}...")
    model.fit(X_train_tfidf, y_train)
    
    # 预测
    y_pred = model.predict(X_test_tfidf)
    
    # 评估
    acc = accuracy_score(y_test, y_pred)
    results.append({'模型': name, '准确率': acc})
    
    print(f"  准确率:{acc:.4f}")

# 结果对比
results_df = pd.DataFrame(results)
print("\n=== 模型对比 ===")
print(results_df.sort_values('准确率', ascending=False))

# 可视化
plt.figure(figsize=(10, 6))
plt.bar(results_df['模型'], results_df['准确率'])
plt.xlabel('模型')
plt.ylabel('准确率')
plt.title('不同模型准确率对比')
plt.xticks(rotation=45)
for i, v in enumerate(results_df['准确率']):
    plt.text(i, v + 0.01, f'{v:.3f}', ha='center')
plt.tight_layout()
plt.savefig('news_model_comparison.png', dpi=150)
plt.show()

3.1.4 最佳模型评估

python
# 使用最佳模型(通常是 SVM 或逻辑回归)
best_model = LinearSVC(random_state=42)
best_model.fit(X_train_tfidf, y_train)

# 测试集评估
y_pred = best_model.predict(X_test_tfidf)

print(f"\n=== 最佳模型评估(LinearSVC)===")
print(f"准确率:{accuracy_score(y_test, y_pred):.4f}")
print("\n分类报告:")
print(classification_report(y_test, y_pred, target_names=[name.split('.')[-1] for name in target_names]))

# 混淆矩阵
cm = confusion_matrix(y_test, y_pred)

plt.figure(figsize=(10, 8))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
           xticklabels=[name.split('.')[-1] for name in target_names],
           yticklabels=[name.split('.')[-1] for name in target_names])
plt.xlabel('预测类别')
plt.ylabel('真实类别')
plt.title('混淆矩阵')
plt.tight_layout()
plt.savefig('news_confusion_matrix.png', dpi=150)
plt.show()

# 预测示例
test_indices = np.random.choice(len(X_test), 5, replace=False)

print("\n=== 预测示例 ===")
for idx in test_indices:
    text = X_test[idx][:100] + "..."
    true_label = target_names[y_test[idx]].split('.')[-1]
    pred_label = target_names[y_pred[idx]].split('.')[-1]
    print(f"\n文本:{text}")
    print(f"真实:{true_label}, 预测:{pred_label}")

案例要点总结:

  • TF-IDF 是文本分类的有效特征表示
  • 线性模型在文本分类上表现良好
  • 停用词移除和词形还原提升效果
  • 多模型对比帮助选择最佳方案

案例 2:命名实体识别(NER)

构建命名实体识别系统,从文本中提取人名、地名、机构名等实体。

3.2.1 使用 spaCy 进行 NER

python
import spacy
import matplotlib.pyplot as plt
from collections import Counter

# 加载英文模型
print("加载 spaCy 模型...")
nlp = spacy.load('en_core_web_sm')

# 示例文本
texts = [
    "Apple is looking at buying U.K. startup for $1 billion",
    "Google's CEO Sundar Pichai visited Paris last week",
    "Microsoft was founded by Bill Gates and Paul Allen in Albuquerque",
    "Amazon's Jeff Bezos announced new headquarters in New York",
    "Tesla CEO Elon Musk tweeted about SpaceX launch from California"
]

# 处理文本
print("\n命名实体识别结果:")
for text in texts:
    doc = nlp(text)
    print(f"\n文本:{text}")
    for ent in doc.ents:
        print(f"  {ent.text}: {ent.label_} ({spacy.explain(ent.label_)})")

# 可视化第一个文本的实体
doc = nlp(texts[0])

# 使用 spaCy 的 displacy 可视化(保存为 HTML)
from spacy import displacy
svg = displacy.render(doc, style='ent')
with open('ner_visualization.html', 'w', encoding='utf-8') as f:
    f.write(svg)
print("\n实体可视化已保存为 ner_visualization.html")

# 统计实体类型分布
all_entities = []
for text in texts:
    doc = nlp(text)
    for ent in doc.ents:
        all_entities.append(ent.label_)

entity_counts = Counter(all_entities)

plt.figure(figsize=(10, 6))
plt.bar(entity_counts.keys(), entity_counts.values())
plt.xlabel('实体类型')
plt.ylabel('数量')
plt.title('实体类型分布')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('ner_entity_distribution.png', dpi=150)
plt.show()

3.2.2 自定义 NER 模型训练

python
import random
from spacy.training.example import Example

# 准备训练数据(简化示例)
TRAIN_DATA = [
    ("Google was founded by Larry Page and Sergey Brin.", {"entities": [(0, 6, "ORG"), (20, 30, "PERSON"), (35, 47, "PERSON")]}),
    ("Apple is headquartered in Cupertino.", {"entities": [(0, 5, "ORG"), (27, 37, "GPE")]}),
    ("Microsoft CEO Satya Nadella spoke at the conference.", {"entities": [(0, 9, "ORG"), (14, 27, "PERSON")]}),
    ("Amazon was started by Jeff Bezos in Seattle.", {"entities": [(0, 6, "ORG"), (20, 30, "PERSON"), (34, 41, "GPE")]}),
    ("Facebook's Mark Zuckerberg visited London.", {"entities": [(0, 8, "ORG"), (11, 26, "PERSON"), (35, 41, "GPE")]}),
]

# 创建空白模型或加载现有模型
nlp_train = spacy.blank('en')

# 添加 NER 管道
ner = nlp_train.add_pipe('ner')

# 添加标签
for _, annotations in TRAIN_DATA:
    for ent in annotations.get('entities'):
        ner.add_label(ent[2])

# 训练
print("开始训练自定义 NER 模型...")
optimizer = nlp_train.begin_training()

for epoch in range(50):
    random.shuffle(TRAIN_DATA)
    losses = {}
    
    for text, annotations in TRAIN_DATA:
        example = Example.from_dict(nlp_train.make_doc(text), annotations)
        nlp_train.update([example], drop=0.35, losses=losses)
    
    if (epoch + 1) % 10 == 0:
        print(f"Epoch {epoch + 1}, Loss: {losses}")

print("训练完成!")

# 测试
test_text = "Elon Musk works at Tesla in California"
doc = nlp_train(test_text)
print(f"\n测试:{test_text}")
for ent in doc.ents:
    print(f"  {ent.text}: {ent.label_}")

3.2.3 中文 NER 示例

python
# 中文 NER 需要使用中文模型
# python -m spacy download zh_core_web_sm

print("\n=== 中文 NER 示例 ===")

# 模拟中文 NER 结果(实际需要中文模型)
chinese_texts = [
    "马云创立了阿里巴巴集团,总部位于杭州",
    "马化腾是腾讯公司的创始人",
    "李彦宏在北京大学学习计算机科学"
]

# 使用 jieba 分词 + 自定义规则(简化示例)
import jieba

for text in chinese_texts:
    print(f"\n文本:{text}")
    print(f"分词:{'/'.join(jieba.cut(text))}")

案例要点总结:

  • spaCy 提供开箱即用的 NER 功能
  • 可以训练自定义实体识别模型
  • 中文 NER 需要专门的中文模型
  • 实体类型包括人名、地名、机构名等

案例 3:产品评论情感分析

构建情感分析系统,自动判断产品评论的情感倾向。

3.3.1 数据准备

python
import numpy as np
import pandas as pd
from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split

# 使用 Amazon 评论数据集(简化版)
# 实际使用时可以加载真实数据
print("准备情感分析数据...")

# 模拟数据(实际应使用真实数据集)
np.random.seed(42)
n_samples = 2000

# 正面评论模板
positive_templates = [
    "这个产品非常好,我非常喜欢{}",
    "质量超出预期,强烈推荐{}",
    "物超所值,会再次购买{}",
    "完美的产品,没有任何问题{}",
    "这是我买过最好的{},太满意了"
]

# 负面评论模板
negative_templates = [
    "这个产品太差了,非常失望{}",
    "质量很差,不推荐购买{}",
    "完全不值这个价格{}",
    "用了一次就坏了,很生气{}",
    "最差的一次购物体验{}"
]

# 产品词
products = ["手机", "电脑", "耳机", "手表", "相机", "音箱", "键盘", "鼠标"]

# 生成数据
texts = []
labels = []

for i in range(n_samples):
    if i < n_samples // 2:
        # 正面评论
        text = random.choice(positive_templates).format(random.choice(products))
        label = 1  # 正面
    else:
        # 负面评论
        text = random.choice(negative_templates).format(random.choice(products))
        label = 0  # 负面
    
    # 添加一些变化
    if random.random() > 0.5:
        text += " " + random.choice(["!", "!!", "!!!", "。", ""])
    
    texts.append(text)
    labels.append(label)

# 创建 DataFrame
df = pd.DataFrame({'text': texts, 'label': labels})

print(f"数据集大小:{len(df)}")
print(f"标签分布:{df['label'].value_counts().to_dict()}")

# 查看样本
print("\n样本数据:")
print(df.head(10))

# 标签分布可视化
plt.figure(figsize=(8, 6))
df['label'].value_counts().plot(kind='bar')
plt.xlabel('情感')
plt.ylabel('样本数')
plt.title('情感标签分布')
plt.xticks(range(2), ['负面', '正面'], rotation=0)
for i, v in enumerate(df['label'].value_counts().values):
    plt.text(i, v + 20, str(v), ha='center')
plt.tight_layout()
plt.savefig('sentiment_distribution.png', dpi=150)
plt.show()

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(
    df['text'].values, df['label'].values, 
    test_size=0.2, random_state=42, stratify=df['label']
)

print(f"\n训练集:{len(X_train)} 样本")
print(f"测试集:{len(X_test)} 样本")

3.3.2 使用预训练模型进行情感分析

python
from transformers import pipeline, AutoTokenizer, AutoModelForSequenceClassification
import torch

# 使用 Hugging Face 预训练情感分析模型
print("加载预训练情感分析模型...")

# 加载情感分析 pipeline
sentiment_pipeline = pipeline(
    "sentiment-analysis",
    model="distilbert-base-uncased-finetuned-sst-2-english"
)

# 测试
test_texts = [
    "I love this product, it's amazing!",
    "This is the worst thing I've ever bought.",
    "It's okay, nothing special.",
    "Absolutely fantastic, highly recommend!",
    "Very disappointed with the quality."
]

print("\n预训练模型测试结果:")
for text in test_texts:
    result = sentiment_pipeline(text)[0]
    sentiment = "正面" if result['label'] == 'POSITIVE' else "负面"
    confidence = result['score']
    print(f"\n文本:{text}")
    print(f"情感:{sentiment}, 置信度:{confidence:.2%}")

# 批量预测
print("\n批量预测测试集...")
batch_size = 32
predictions = []

for i in range(0, len(X_test), batch_size):
    batch = list(X_test[i:i+batch_size])
    batch_results = sentiment_pipeline(batch)
    batch_preds = [1 if r['label'] == 'POSITIVE' else 0 for r in batch_results]
    predictions.extend(batch_preds)

# 评估
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix

y_pred = predictions
accuracy = accuracy_score(y_test, y_pred)

print(f"\n=== 预训练模型评估 ===")
print(f"准确率:{accuracy:.4f}")
print("\n分类报告:")
print(classification_report(y_test, y_pred, target_names=['负面', '正面']))

# 混淆矩阵
cm = confusion_matrix(y_test, y_pred)

plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.xlabel('预测')
plt.ylabel('真实')
plt.title('预训练模型混淆矩阵')
plt.xticks(range(2), ['负面', '正面'])
plt.yticks(range(2), ['负面', '正面'])
plt.tight_layout()
plt.savefig('sentiment_confusion_matrix.png', dpi=150)
plt.show()

3.3.3 自定义情感分析模型

python
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression

# TF-IDF 特征提取
print("\n训练自定义情感分析模型...")
tfidf = TfidfVectorizer(max_features=1000, ngram_range=(1, 2))
X_train_tfidf = tfidf.fit_transform(X_train)
X_test_tfidf = tfidf.transform(X_test)

# 训练逻辑回归模型
lr_model = LogisticRegression(max_iter=1000, random_state=42)
lr_model.fit(X_train_tfidf, y_train)

# 预测
y_pred_custom = lr_model.predict(X_test_tfidf)

# 评估
accuracy_custom = accuracy_score(y_test, y_pred_custom)

print(f"\n=== 自定义模型评估 ===")
print(f"准确率:{accuracy_custom:.4f}")
print("\n分类报告:")
print(classification_report(y_test, y_pred_custom, target_names=['负面', '正面']))

# 特征重要性
feature_names = tfidf.get_feature_names_out()
coef = lr_model.coef_[0]

# Top 10 正面词
top_positive_indices = np.argsort(coef)[-10:][::-1]
top_positive_words = [(feature_names[i], coef[i]) for i in top_positive_indices]

# Top 10 负面词
top_negative_indices = np.argsort(coef)[:10]
top_negative_words = [(feature_names[i], coef[i]) for i in top_negative_indices]

print("\nTop 10 正面特征词:")
for word, score in top_positive_words:
    print(f"  {word}: {score:.4f}")

print("\nTop 10 负面特征词:")
for word, score in top_negative_words:
    print(f"  {word}: {score:.4f}")

# 可视化
fig, axes = plt.subplots(1, 2, figsize=(14, 6))

# 正面词
axes[0].barh(range(len(top_positive_words)), [score for _, score in top_positive_words])
axes[0].set_yticks(range(len(top_positive_words)))
axes[0].set_yticklabels([word for word, _ in top_positive_words])
axes[0].set_xlabel('权重')
axes[0].set_title('正面特征词')
axes[0].invert_yaxis()

# 负面词
axes[1].barh(range(len(top_negative_words)), [score for _, score in top_negative_words])
axes[1].set_yticks(range(len(top_negative_words)))
axes[1].set_yticklabels([word for word, _ in top_negative_words])
axes[1].set_xlabel('权重')
axes[1].set_title('负面特征词')
axes[1].invert_yaxis()

plt.tight_layout()
plt.savefig('sentiment_features.png', dpi=150)
plt.show()

案例要点总结:

  • 预训练模型提供强大的零样本能力
  • 自定义模型可以针对特定领域优化
  • 特征词分析帮助理解模型决策
  • 情感分析广泛应用于产品评论、舆情监控

案例 4:智能对话系统(聊天机器人)

构建一个简单的任务型对话系统。

3.4.1 对话系统设计

python
import random
import re
from datetime import datetime

# 定义对话意图和响应
INTENTS = {
    'greeting': {
        'patterns': [r'你好', r'hello', r'hi', r'早上好', r'下午好', r'晚上好'],
        'responses': ['您好!有什么可以帮助您的?', '你好!我是智能助手。', '很高兴见到您!']
    },
    'weather': {
        'patterns': [r'天气.*', r'.*气温.*', r'.*下雨.*', r'.*晴天.*'],
        'responses': ['我可以帮您查询天气,请告诉我城市名称。', '您想查询哪个城市的天气呢?']
    },
    'time': {
        'patterns': [r'现在.*时间', r'几点了', r'what time'],
        'responses': [f'现在是 {datetime.now().strftime("%H:%M:%S")}。', f'当前时间是 {datetime.now().strftime("%Y年%m月%d日 %H:%M")}。']
    },
    'thanks': {
        'patterns': [r'谢谢', r'感谢', r'thank', r'太感谢了'],
        'responses': ['不客气!', '很高兴能帮助您!', '随时为您效劳!']
    },
    'goodbye': {
        'patterns': [r'再见', r'bye', r'拜拜', r'下次见'],
        'responses': ['再见!祝您有美好的一天!', '期待下次与您交流!', '保重!']
    },
    'name': {
        'patterns': [r'你叫什么', r'你是谁', r'your name'],
        'responses': ['我是智能对话助手泡泡龙。', '您可以叫我泡泡龙!']
    },
    'help': {
        'patterns': [r'帮助', r'help', r'你能做什么', r'功能'],
        'responses': ['我可以帮您查询天气、时间,陪您聊天。有什么需要帮助的吗?']
    }
}

# 默认响应
DEFAULT_RESPONSES = [
    '抱歉,我没有理解您的意思。您可以换个方式问我。',
    '这个问题我还不太懂,能再说详细一点吗?',
    '我还在努力学习中,这个问题暂时回答不了。'
]

class Chatbot:
    def __init__(self):
        self.intents = INTENTS
        self.context = {}
        self.conversation_history = []
    
    def detect_intent(self, text):
        """检测用户意图"""
        text = text.lower()
        
        for intent, data in self.intents.items():
            for pattern in data['patterns']:
                if re.search(pattern, text, re.IGNORECASE):
                    return intent
        
        return 'unknown'
    
    def get_response(self, text):
        """获取响应"""
        # 检测意图
        intent = self.detect_intent(text)
        
        # 记录对话历史
        self.conversation_history.append({
            'user': text,
            'intent': intent,
            'timestamp': datetime.now().isoformat()
        })
        
        # 生成响应
        if intent != 'unknown':
            response = random.choice(self.intents[intent]['responses'])
        else:
            response = random.choice(DEFAULT_RESPONSES)
        
        return response, intent
    
    def chat(self, text):
        """对话接口"""
        response, intent = self.get_response(text)
        return response

# 测试聊天机器人
bot = Chatbot()

print("=== 智能对话系统测试 ===\n")

test_inputs = [
    "你好",
    "现在几点了",
    "今天天气怎么样",
    "你叫什么名字",
    "谢谢",
    "再见",
    "你能做什么",
    "这是一个测试消息"
]

for input_text in test_inputs:
    response = bot.chat(input_text)
    print(f"用户:{input_text}")
    print(f"助手:{response}\n")

3.4.2 基于规则的对话流程

python
class TaskBot:
    """任务型对话机器人"""
    
    def __init__(self):
        self.state = 'INIT'
        self.slots = {}
        self.task_flows = {
            'weather_query': {
                'required_slots': ['city', 'date'],
                'prompts': {
                    'city': '请问您想查询哪个城市的天气?',
                    'date': '请问您想查询哪天的天气?(今天/明天/后天)'
                }
            }
        }
        self.current_task = None
    
    def process(self, user_input):
        """处理用户输入"""
        user_input = user_input.lower()
        
        # 状态机处理
        if self.state == 'INIT':
            if '天气' in user_input:
                self.current_task = 'weather_query'
                self.state = 'COLLECT_CITY'
                return self.task_flows['weather_query']['prompts']['city']
            elif '时间' in user_input or '点' in user_input:
                return f"现在是 {datetime.now().strftime('%H:%M:%S')}"
            else:
                return "您好!我可以帮您查询天气或时间。需要什么帮助?"
        
        elif self.state == 'COLLECT_CITY':
            # 简单提取城市名(实际应使用 NER)
            self.slots['city'] = user_input
            self.state = 'COLLECT_DATE'
            return self.task_flows['weather_query']['prompts']['date']
        
        elif self.state == 'COLLECT_DATE':
            self.slots['date'] = user_input
            # 完成槽位收集,执行任务
            result = self.execute_task()
            self.reset()
            return result
        
        return "抱歉,我没有理解。"
    
    def execute_task(self):
        """执行任务"""
        if self.current_task == 'weather_query':
            city = self.slots.get('city', '未知城市')
            date = self.slots.get('date', '今天')
            # 模拟天气查询
            weathers = ['晴', '多云', '阴', '小雨', '大雨']
            temps = [f"{random.randint(15, 30)}°C"]
            return f"{city}{date}的天气:{random.choice(weathers)},气温:{temps[0]}"
        return "任务执行完成。"
    
    def reset(self):
        """重置状态"""
        self.state = 'INIT'
        self.slots = {}
        self.current_task = None

# 测试任务型机器人
task_bot = TaskBot()

print("=== 任务型对话测试 ===\n")

# 模拟对话
conversation = [
    "我想查天气",
    "北京",
    "明天"
]

for user_input in conversation:
    response = task_bot.process(user_input)
    print(f"用户:{user_input}")
    print(f"助手:{response}\n")

3.4.3 使用 Transformers 构建高级对话系统

python
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

print("=== 高级对话系统(使用 DialoGPT)===")

# 加载 DialoGPT 模型(需要网络连接)
try:
    tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-medium")
    model = AutoModelForCausalLM.from_pretrained("microsoft/DialoGPT-medium")
    
    print("模型加载成功!")
    
    # 对话函数
    def chat_with_model(user_input, chat_history_ids=None):
        # 编码用户输入
        new_input_ids = tokenizer.encode(
            user_input + tokenizer.eos_token, 
            return_tensors='pt'
        )
        
        # 拼接到对话历史
        if chat_history_ids is not None:
            bot_input_ids = torch.cat([chat_history_ids, new_input_ids], dim=1)
        else:
            bot_input_ids = new_input_ids
        
        # 生成响应
        chat_history_ids = model.generate(
            bot_input_ids,
            max_length=1000,
            pad_token_id=tokenizer.eos_token_id,
            no_repeat_ngram_size=3,
            do_sample=True,
            top_k=50,
            top_p=0.95,
            temperature=0.7
        )
        
        # 解码响应
        response = tokenizer.decode(
            chat_history_ids[:, bot_input_ids.shape[-1]:][0],
            skip_special_tokens=True
        )
        
        return response, chat_history_ids
    
    # 测试对话
    print("\n开始对话测试(输入'quit'退出):\n")
    chat_history_ids = None
    
    test_inputs = ["你好", "你今天怎么样", "你喜欢做什么"]
    
    for user_input in test_inputs:
        response, chat_history_ids = chat_with_model(user_input, chat_history_ids)
        print(f"用户:{user_input}")
        print(f"助手:{response}\n")
        
except Exception as e:
    print(f"模型加载失败(可能需要网络):{e}")
    print("可以使用规则-based 对话系统作为替代。")

案例要点总结:

  • 规则-based 系统适合简单场景
  • 槽位填充是任务型对话的核心
  • 预训练对话模型提供更自然的交互
  • 对话历史管理很重要

第四章:NLP 最佳实践

4.1 文本预处理技巧

python
def advanced_preprocessing(text):
    """高级文本预处理"""
    # 1. 统一大小写
    text = text.lower()
    
    # 2. 移除 URL
    text = re.sub(r'http\S+|www\S+', '', text)
    
    # 3. 移除@提及
    text = re.sub(r'@\w+', '', text)
    
    # 4. 移除特殊字符
    text = re.sub(r'[^a-zA-Z\s]', '', text)
    
    # 5. 移除多余空格
    text = ' '.join(text.split())
    
    return text

4.2 处理类别不平衡

python
from imblearn.over_sampling import SMOTE

# SMOTE 过采样
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X_train, y_train)

4.3 模型部署

python
import joblib

# 保存模型和向量化器
joblib.dump(model, 'nlp_model.pkl')
joblib.dump(vectorizer, 'vectorizer.pkl')

# 加载
model = joblib.load('nlp_model.pkl')
vectorizer = joblib.load('vectorizer.pkl')

第五章:常见问题解答(FAQ)

Q1: 中文 NLP 和英文 NLP 有什么区别?

答: 主要区别:

  • 中文需要分词,英文天然分词
  • 中文无词形变化
  • 中文需要使用专门的模型和工具

Q2: 如何选择预训练模型?

答: 根据任务选择:

  • 文本分类:BERT、RoBERTa
  • NER:BERT-CRF、spaCy
  • 对话:DialoGPT、BlenderBot
  • 翻译:MarianMT、mBART

Q3: 数据量不够怎么办?

答: 解决方法:

  • 使用预训练模型(迁移学习)
  • 数据增强(同义词替换、回译)
  • 少样本学习技术

Q4: 如何处理长文本?

答: 方法:

  • 文本分段处理
  • 使用 Longformer、BigBird 等长文本模型
  • 提取关键句/段

Q5: NLP 模型评估指标有哪些?

答: 常用指标:

  • 分类:准确率、精确率、召回率、F1
  • NER:实体级 F1
  • 生成:BLEU、ROUGE、Perplexity

第六章:总结与下一步

6.1 本教程要点回顾

  1. 基础概念:理解了 NLP 处理流程和文本表示方法
  2. 文本分类:掌握了新闻分类的完整流程
  3. 命名实体识别:学会了使用 spaCy 进行实体提取
  4. 情感分析:构建了产品评论情感分析系统
  5. 对话系统:开发了规则-based 和深度学习对话机器人

6.2 学习路线建议

初级(已完成):

  • ✅ 掌握 NLP 基础概念
  • ✅ 熟悉主流 NLP 库
  • ✅ 完成基础实战项目

中级(下一步):

  • 学习 Transformer 架构
  • 掌握 BERT 等预训练模型
  • 学习文本生成技术

高级:

  • 研究大语言模型(LLM)
  • 学习 RAG、Fine-tuning
  • 掌握模型部署和优化

6.3 推荐资源

课程:

  • CS224n: NLP with Deep Learning (Stanford)
  • NLP Specialization (Coursera)

书籍:

  • 《Speech and Language Processing》
  • 《Natural Language Processing in Action》

工具:

  • Hugging Face Transformers
  • spaCy
  • NLTK
  • Gensim

作者注: NLP 领域正在快速发展,大语言模型带来了新的机遇。保持学习,紧跟前沿!

更新日期: 2026-03-21
字数统计: 约 8800 字

Released under the MIT License.