Machine Learning Mastery 数据科学教程(四)
理解 LangChain LLM 输出解析器
原文:
machinelearningmastery.com/understanding-langchain-llm-output-parser/
图片来自 Freepik 的 nikitabuida
大型语言模型(LLM)彻底改变了人们的工作方式。通过帮助用户从文本提示中生成答案,LLM 可以完成许多任务,例如回答问题、总结、计划事件等。
然而,有时 LLM 的输出可能达不到我们的标准。例如,生成的文本可能完全错误,需要进一步的指导。这时 LLM 输出解析器可以提供帮助。
通过使用 LangChain 输出解析器标准化输出结果,我们可以对输出进行一些控制。那么它是如何工作的呢?让我们深入了解一下。
准备工作
在本文中,我们将依赖于 LangChain 包,因此需要在环境中安装这些包。为此,你可以使用以下code。
pip install langchain langchain_core langchain_community langchain_openai python-dotenv
此外,我们将使用 OpenAI GPT 模型进行文本生成,因此确保你拥有对它们的 API 访问权限。你可以从 OpenAI 平台获取 API 密钥。
我会在 Visual Studio Code IDE 中工作,但你可以在任何你喜欢的 IDE 中工作。在项目文件夹中创建一个名为.env的文件,并将 OpenAI API 密钥放入其中。它应该如下所示。
OPENAI_API_KEY = sk-XXXXXXXXXX
一切准备就绪后,我们将进入文章的核心部分。
输出解析器
我们可以使用 LangChain 的多种输出解析器来标准化我们的 LLM 输出。我们将尝试其中几种,以更好地理解输出解析器。
首先,我们会尝试 Pydantic Parser。这是一个输出解析器,我们可以用来控制和验证生成文本的输出。让我们通过一个例子更好地使用它们。在你的 IDE 中创建一个 Python 脚本,然后将下面的代码复制到你的脚本中。
from typing import List
from dotenv import load_dotenv
from langchain.output_parsers import PydanticOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field, validator
from langchain_openai import ChatOpenAI
load_dotenv()
class MovieReview(BaseModel):
title: str = Field(description="The movie title")
year: int = Field(description="The year of the movie was released")
genre: List[str] = Field(description="The main genres of the movie")
rating: float = Field(description="Rating out of 10")
summary: str = Field(description="Brief summary of the movie plot")
review: str = Field(description="Critical review of the movie")
@validator("year")
def valid_year(cls, val):
if val 2025:
raise ValueError("Must a valid movie year")
return val
@validator("rating")
def valid_rating(cls, val):
if val 10:
raise ValueError("Rating must be between 0 and 10")
return val
parser = PydanticOutputParser(pydantic_object=MovieReview)
prompt = PromptTemplate(
template="Generate a movie review for the following movie:\n{movie_title}\n\n{format_instructions}",
input_variables=["movie_title"],
partial_variables={"format_instructions": parser.get_format_instructions()}
)
model = ChatOpenAI(temperature=0)
chain = prompt | model | parser
movie_title = "The Matrix"
review = chain.invoke({"movie_title": movie_title})
print(review)
我们最初在上面的代码中导入了这些包,并使用 load_dotenv 加载了 OpenAI 密钥。之后,我们创建了一个名为 MovieReview 的类,该类包含我们想要的所有信息输出。输出将包括标题、年份、类型、评分、摘要和评论。对于每个输出,我们定义了所需输出的描述。
从输出中,我们创建一个用于验证年份和评分的验证器,以确保结果符合我们的期望。你也可以根据需要添加更多验证机制。
然后我们创建了一个提示模板,该模板接受我们的查询输入以及其应有的格式。
我们最后做的事情是创建模型链并传递查询以获取结果。值得注意的是,上面的 chain 变量使用 “|” 接受结构,这是 LangChain 中的一种独特方法。
总的来说,结果类似于下面的内容。
输出:
title='The Matrix' year=1999 genre=['Action', 'Sci-Fi'] rating=9.0 summary='A computer hacker learns about the true nature of reality and his role in the war against its controllers.' review="The Matrix is a groundbreaking film that revolutionized the action genre with its innovative special effects and thought-provoking storyline. Keanu Reeves delivers a memorable performance as Neo, the chosen one who must navigate the simulated reality of the Matrix to save humanity. The film's blend of martial arts, philosophy, and dystopian themes make it a must-watch for any movie enthusiast."
正如你所见,输出符合我们想要的格式,并且结果通过了我们的验证方法。
Pedantic Parser 是我们可以使用的标准输出解析器。如果我们已经有特定的格式需求,可以使用其他输出解析器。例如,如果我们希望结果以逗号分隔的项呈现,可以使用 CSV Parser。
from dotenv import load_dotenv
from langchain.output_parsers import CommaSeparatedListOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
load_dotenv()
output_parser = CommaSeparatedListOutputParser()
format_instructions = output_parser.get_format_instructions()
prompt = PromptTemplate(
template="List six {subject}.\n{format_instructions}",
input_variables=["subject"],
partial_variables={"format_instructions": format_instructions},
)
model = ChatOpenAI(temperature=0)
chain = prompt | model | output_parser
print(chain.invoke({"subject": "Programming Language"}))
输出:
['Java', 'Python', 'C++', 'JavaScript', 'Ruby', 'Swift']
结果是一个以逗号分隔的值的列表。如果结果是逗号分隔的,你可以按任何方式扩展模板。
也可以将输出格式更改为日期时间格式。通过修改代码和提示,我们可以期望得到我们想要的结果。
from dotenv import load_dotenv
from langchain.output_parsers import DatetimeOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
load_dotenv()
output_parser = DatetimeOutputParser()
format_instructions = output_parser.get_format_instructions()
prompt = PromptTemplate(
template="""Answer the users question:
{question}
{format_instructions}""",
input_variables=["question"],
partial_variables={"format_instructions": format_instructions},
)
model = ChatOpenAI(temperature=0)
chain = prompt | model | output_parser
print(chain.invoke({"question": "When is the Python Programming Language invented?"}))
输出:
1991-02-20 00:00:00
你可以看到结果是日期时间格式。
以上就是关于 LangChain LLM 输出解析器的内容。你可以访问它们的文档来找到你需要的输出解析器,或者使用 Pydantic 自行结构化输出。
结论
在这篇文章中,我们了解了 LangChain 输出解析器,它可以将 LLM 生成的文本标准化。我们可以使用 Pydantic Parser 来结构化 LLM 输出并提供所需结果。LangChain 还提供了许多其他可能适合你情况的输出解析器,如 CSV 解析器和日期时间解析器。
展开数据故事:从初步观察到深入分析
原文:
machinelearningmastery.com/unfolding-data-stories-from-first-glance-to-in-depth-analysis/
揭示有意义的洞察通常从一个简单的步骤开始:在提问之前查看数据。这段通过艾姆斯住房数据集的旅程不仅是探索,更是关于隐藏在数字中的故事等待被讲述的叙述。通过“数据优先方法”,我们邀请您深入数据驱动的讲故事过程,每一个可视化、每一个统计检验和每一个假设都是更大叙事的一部分。本文旨在指导您通过逐步的过程理解和呈现数据,从数据集的初步广泛视角到假设检验的聚焦视角,解开艾姆斯住房市场中错综复杂的故事。
展开数据故事:从初步观察到深入分析
图片来源:Emily Morter。保留部分权利。
概述
本文分为三个部分,它们是:
-
数据优先方法
-
数据为基础,通过视觉展现
-
从模式到证据:在艾姆斯住房市场中的假设检验
数据优先方法
先有问题还是先有数据?
开始我们的数据科学旅程通常涉及一个逆向直觉的第一步:先从数据本身开始,然后再提出具体的问题。这种观点是“数据优先方法”的核心,这一理念通过让数据引领方向来倡导发现的力量。倡导开放思维的探索,这种方法将手头的数据集——如详细而丰富的艾姆斯住房数据集——变成了指引之光,揭示故事、秘密和有见地的分析潜力。这一理念促使我们抛开先入之见,使数据固有的趋势、模式和洞察自然浮现。
简洁的三步指南以拥抱这种方法包括:
-
数据规模评估:初步步骤,强调我们的“数据优先方法”,涉及理解数据的规模和形状,如揭示隐形中所述。这一阶段对把握数据集的范围和解决缺失值至关重要,为全面分析奠定基础。
-
理解数据类型的范围:深入挖掘我们的数据集,探索其包含的数据类型的多样性,这是决定视觉展示方式和框定分析问题的重要步骤。这种探索类似于探索字典,对根据数据的固有特征定制我们的分析和可视化策略至关重要,确保我们的方法既相关又有效。
-
描述性统计:在解码数据中概述了这一步骤,提供了定量总结和理解数据集的工具,为更深入的分析和解释做好准备。
将这些步骤整合到我们的初步探索中,强调了“数据优先方法”,系统地揭示了 Ames Housing 数据集中蕴含的故事。每一步都是揭示更完整叙事的基石。通过让数据先发言,我们解锁了隐藏在数字中的最吸引人的故事。
启动你的项目,请参阅我的书籍数据科学入门指南。它提供了自学教程和可运行代码。
以数据为基础,通过视觉呈现
继我们的“数据优先方法”之后,在我们对数据集及其变量有了透彻理解后,自然会进展到下一个关键步骤:可视化。这一阶段是根据我们对数据的初步接触,选择最合适的视觉工具来揭示我们发现的见解。可视化不仅仅是让数据看起来更具吸引力;它是讲述故事过程中的一个重要组成部分,使我们能够“展示,而非陈述”隐藏在数据中的故事。关键在于选择与数据叙事相契合的可视化类型,这一决策深深植根于我们的初步探索中。以下是几种关键的可视化类型及其最佳应用场景:
-
直方图:理想用于展示单一数值变量的分布。直方图有助于识别数据的偏斜、峰值和分布,非常适合分析诸如收入水平或人群中的年龄等变量。
-
条形图:适用于比较不同类别的数量。使用条形图来突出不同组之间的差异,例如不同地区的销售数据或按产品类别统计的客户数量。
-
折线图:最适合展示数据随时间的变化趋势。折线图是可视化股票价格变化、全年温度波动或季度销售增长的首选工具。
-
散点图:非常适合探索两个数值变量之间的关系。散点图可以帮助识别相关性,例如广告支出与销售收入之间的关系,或身高与体重的相关性。
-
箱形图(箱线图):用于总结数据集的分布情况和比较组间分布。箱形图提供有关数据的中位数、四分位数和潜在异常值的见解,使其在统计分析中非常有价值,比如比较不同课堂的考试成绩。
-
热图:适合可视化复杂的数据矩阵,展示相似性或变化模式。热图在显示不同时间段的网页流量来源或理解地理数据分布等方面效果显著。
-
地理空间地图:适合展示具有地理组成的数据,允许对不同区域的模式和趋势进行可视化。地理空间地图非常适合可视化人口密度,按位置分布的销售情况,或任何具有空间元素的数据。它们有助于识别区域趋势,因此在需要地理背景的分析中非常宝贵,例如不同城市的市场渗透或全球各地的气候变化影响。
-
堆积条形图:非常适合显示部分与整体的关系和分类比较,每个条形段代表一个子类别的值。使用堆积条形图来展示按产品类型划分的销售数据。
-
面积图:类似于折线图,但填充在折线下方,面积图对于强调随时间变化的幅度非常有用。它们非常适合可视化累计总量,如网站流量来源或人口增长。
-
对角线图:理想用于同时探索多个变量之间的相关性和分布。对角线图或散点图矩阵提供了数据集中每个变量彼此关系的全面视图,突出潜在的关系和趋势,值得进一步调查。它们在分析的早期阶段特别有用,可以快速评估潜在的兴趣变量。
可视化是一个迭代过程。初步的可视化通常会引发新问题,从而促使进一步分析和改进的可视化。这一循环提升了我们的理解,逐步揭示了数据中更完整的叙述。为了更深入地探索使用 Ames Housing 数据集的迭代可视化过程,我们将探讨潜在问题以及可能帮助解答这些问题的可视化类型。以下是一些问题及建议的可视化类型:
-
在不同的月份和季节中,售价有哪些模式可以观察到?
- 视觉:折线图或柱状图用于分析售价的季节性趋势。
-
地块面积在不同区域分类中的售价比较如何?
- 视觉:不同颜色的散点图用于探索地块面积与售价之间的关系。
-
泳池对房产售价的影响是什么?
- 视觉:箱线图比较有泳池和没有泳池的房屋售价。
-
建造年份和翻修年份如何影响房产的整体状况和售价?
- 视觉:对比图同时探索建造年份、翻修年份、整体状况和售价之间的关系。
-
各种设施(如公园、学校等)与售价之间是否存在相关性?
- 视觉:地理空间地图叠加设施距离,并用散点图将这些距离与售价相关联。
这些问题鼓励从不同角度探索数据集,通过迭代可视化实现更丰富的理解。每个可视化不仅回答了初步的问题,还可能激发进一步的探究,展示了数据探索和讲故事的动态过程。
从模式到证据:Ames 房地产市场中的假设检验
在深入了解“数据优先方法”并利用视觉工具揭示 Ames Housing 数据集中隐藏的模式和关系后,我们的旅程进入了关键阶段,即假设形成和测试。这种循环的提问、探索和推理过程代表了数据驱动讲故事的本质,将观察转化为可操作的洞察。
我们现在准备提出更深层次的问题,受我们可视化揭示的模式和异常的启发。以下是一些可能的方向,这些方向在我们之前的帖子中尚未展示:
-
售价是否依赖于所在社区?
- 统计测试:单因素方差分析(ANOVA)用于比较多个社区的售价,假设方差相等;否则使用 Kruskal-Wallis 测试。
-
不同类型住宅(例如 1 层与 2 层房屋)之间的售价是否存在显著差异?
- 统计测试:ANOVA 多组测试,或 t 检验比较两种特定住宅类型。
-
不同外部材料的房屋销售价格是否存在显著差异?
- 统计测试:在将销售价格分类为(低、中、高)并与外部材料类型进行比较后,进行卡方独立性检验。
-
房屋的销售价格是否受到出售季节的影响?
- 统计测试:Kruskal-Wallis 检验或 ANOVA,取决于分布情况,用于比较不同季节的中位销售价格,识别是否某些时间的销售价格较高。
-
完成的地下室与未完成的地下室是否显著影响销售价格?
- 统计测试:T 检验或 Mann-Whitney U 检验(基于数据分布)来比较有完成地下室与无完成地下室的房屋销售价格。
从可视化到假设检验的过渡不仅仅是分析性的;这是一个创造性的过程,涉及将数据洞察合成引人注目的叙事。每一个检验过的假设都揭示了住房市场中的动态,为 Ames 数据集的更大故事贡献了章节。当我们验证或反驳我们的假设时,我们不仅是在收集证据;我们是在构建一个以数据为基础的故事。这个叙事可能揭示了 Ames 房市如何随季节的节奏而脉动,或现代性如何要求溢价,反映了当代买家的偏好。
想开始学习数据科学初学者指南吗?
现在就报名参加我的免费邮件速成课程(包含示例代码)。
点击注册并免费获得课程的 PDF 电子书版本。
进一步阅读
资源
总结
通过将“数据优先方法”与视觉的迭代探索和假设检验的严谨结合,我们解锁了对数据的更深刻理解。这种方法不仅增强了我们的理解,还为我们提供了有力的工具,将我们的发现生动而有说服力地呈现出来,使数据探索成为与观众产生共鸣的引人入胜的叙事。通过拥抱这一三重路径——以数据为基础,通过视觉展现,通过假设叙述——我们创作出不仅传达信息而且激发灵感的故事,展示了数据驱动叙事的变革力量。
具体来说,你学到了:
-
数据优先思维的重要性。
-
迭代发现过程在构建视觉效果中的作用。
-
涉及假设检验的创造性过程。
你有任何问题吗?请在下面的评论中提问,我会尽力回答。
使用机器学习进行客户细分
原文:
machinelearningmastery.com/using-machine-learning-in-customer-segmentation/
编辑 | Midjourney 提供的图片
过去,企业根据年龄或性别等简单标准对客户进行分组。现在,机器学习改变了这一过程。机器学习算法可以分析大量数据。在这篇文章中,我们将探讨机器学习如何改进客户细分。
客户细分简介
客户细分将客户划分为不同的组。这些组基于相似的特征或行为。主要目标是更好地理解每个组。这有助于企业制定适合每个组特定需求的营销策略和产品。
客户可以根据多个标准划分为不同的组:
-
人口统计学细分:基于年龄、性别和职业等因素。
-
心理图像细分:关注客户的生活方式和兴趣。
-
行为细分:分析客户的行为,如品牌忠诚度和使用频率。
-
地理细分:根据客户的地理位置进行划分。
客户细分为企业带来了几个优势:
-
个性化营销:企业可以向每个客户组发送特定的信息。
-
改善客户留存:组织可以识别客户的偏好并使其成为忠实客户。
-
增强产品开发:细分帮助了解客户希望得到哪些产品。
机器学习算法在客户细分中的应用
机器学习使用多种算法根据客户的特征进行分类。一些常用的算法包括:
-
K-means 聚类:根据相似特征将客户划分为不同的簇。
-
层次聚类:将客户组织成树状的簇层次结构。
-
DBSCAN:根据数据空间中点的密度识别簇。
-
主成分分析(PCA):减少数据的维度并保留重要信息。
-
决策树:根据一系列层次决策将客户划分。
-
神经网络:通过互连的节点层学习数据中的复杂模式。
我们将使用 K-means 算法将客户细分为不同的组。
实施 K-means 聚类算法
K-means 聚类是一种无监督算法。它在没有任何预定义标签或训练示例的情况下运行。该算法用于将数据集中相似的数据点分组。目标是将数据分成若干个簇。每个簇包含相似的数据点。让我们看看这个算法如何工作。
-
初始化:选择簇的数量(k)。随机初始化 k 个点作为质心。
-
任务:将每个数据点分配到最近的质心,并形成簇。
-
更新质心:计算分配给每个质心的所有数据点的均值。将质心移动到这个均值位置。
重复步骤 2 和 3 直到收敛。
在接下来的部分中,我们将实现 K 均值聚类算法,根据不同的特征将客户分组。
数据准备
让我们来探索客户数据集。我们的数据集大约有 500,000 个数据点。
客户数据集
删除了缺失值和重复项,并选择了三个特征(‘Quantity’,‘UnitPrice’,‘CustomerID’)用于聚类。
import pandas as pd
from sklearn.preprocessing import StandardScaler
# Load the dataset (replace 'data.csv' with your actual file path)
df = pd.read_csv('userdata.csv')
# Data cleaning: remove duplicates and handle missing values
df = df.drop_duplicates()
df = df.dropna()
# Feature selection: selecting relevant features for clustering
selected_features = ['Quantity', 'UnitPrice', 'CustomerID']
X = df[selected_features]
# Normalization (standardization)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
预处理数据集
超参数调整
K 均值聚类中的一个挑战是找出最佳的簇数量。肘部法则可以帮助我们做到这一点。它绘制了每个点到其分配的簇质心的平方距离之和(惯性)与 K 的关系图。寻找惯性随着 K 的增加不再显著减少的点。这个点被称为聚类模型的肘部。它建议了一个合适的 K 值。
# Determine the optimal number of clusters using the Elbow Method
def determine_optimal_clusters(X_scaled, max_clusters=10):
distances = []
for n in range(2, max_clusters+1):
kmeans = KMeans(n_clusters=n, random_state=42)
kmeans.fit(X_scaled)
distances.append(kmeans.inertia_)
plt.figure(figsize=(7, 5))
plt.plot(range(2, max_clusters+1), distances, marker='o')
plt.title('Elbow Method')
plt.xlabel('Number of clusters')
plt.ylabel('Sum of squared distances')
plt.xticks(range(2, max_clusters+1))
plt.grid(True)
plt.show()
return distances
distances = determine_optimal_clusters(X_scaled)
我们可以使用上述代码生成惯性与簇数量的图。
肘部法则
在 K=1 时,惯性达到最高。从 K=1 到 K=5,惯性急剧下降。K=5 到 K=7 之间,曲线逐渐下降。最后,在 K=7 时,它变得稳定,因此 K 的最佳值是 7\。
可视化细分结果
让我们实现 K 均值聚类算法并可视化结果。
# Apply K-means clustering with the chosen number of clusters
chosen_clusters = 7
kmeans = KMeans(n_clusters=chosen_clusters, random_state=42)
kmeans.fit(X_scaled)
# Get cluster labels
cluster_labels = kmeans.labels_
# Add the cluster labels to the original dataframe
df['Cluster'] = cluster_labels
# Visualize the clusters in 3D
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')
# Scatter plot for each cluster
for cluster in range(chosen_clusters):
cluster_data = df[df['Cluster'] == cluster]
ax.scatter(cluster_data['Quantity'], cluster_data['UnitPrice'], cluster_data['CustomerID'],
label=f'Cluster {cluster}', s=50)
ax.set_xlabel('Quantity')
ax.set_ylabel('UnitPrice')
ax.set_zlabel('CustomerID')
# Add a legend
ax.legend()
plt.show()
散点图
3D 散点图根据‘Quantity’,‘UnitPrice’和‘CustomerID’可视化了簇。每个簇通过颜色区分,并相应地标记。
结论
我们讨论了使用机器学习进行客户细分及其好处。此外,我们展示了如何实现 K 均值算法将客户细分为不同的组。首先,我们使用肘部法则找到了适合的簇数量。然后,我们实现了 K 均值算法,并使用散点图可视化结果。通过这些步骤,公司可以高效地将客户分组。