Python非监督学习
非监督学习是机器学习的重要分支,主要用于挖掘数据本身的结构和规律。下面我将从算法类型、应用场景、评估指标、实战代码等多个维度,对Python中的非监督学习进行详细介绍。
Python非监督学习
在机器学习的世界里,非监督学习是一个重要的分支,它致力于从无标签的数据中发现隐藏的模式和结构。Python提供了丰富的库和工具,使得实现各种非监督学习算法变得轻而易举。本文将深入探讨Python中非监督学习的各个方面,包括算法类型、应用场景、评估指标以及实战代码。
一、非监督学习概述
非监督学习与监督学习最大的区别在于,非监督学习处理的数据没有标签,它的目标是通过对数据的分析,发现数据内部的结构、模式或关系。非监督学习主要包括以下几类算法:
- 聚类算法:将数据点划分为多个组(簇),使得同一簇内的数据点相似度较高,不同簇的数据点相似度较低。
- 降维算法:通过减少数据的维度,同时保留数据的主要信息,从而简化数据结构,提高算法效率。
- 密度估计:估计数据在特征空间中的分布密度。
- 异常检测:识别数据中与正常模式明显不同的异常点。
非监督学习在现实生活中有广泛的应用,如客户细分、图像压缩、基因分析、推荐系统等。
二、Python中非监督学习常用库
Python提供了多个强大的库来支持非监督学习,其中最常用的包括:
- scikit-learn:提供了丰富的非监督学习算法实现,包括聚类、降维、异常检测等。
- NumPy:用于高效的数值计算和数组操作。
- pandas:提供了数据结构和数据分析工具,方便数据的处理和探索。
- Matplotlib和seaborn:用于数据可视化,帮助理解数据的分布和聚类结果。
- TensorFlow和PyTorch:用于深度学习中的非监督学习方法,如自编码器和生成对抗网络。
三、聚类算法
聚类是最常见的非监督学习任务之一,下面介绍几种常用的聚类算法及其Python实现。
1. K-Means聚类
K-Means是一种基于质心的聚类算法,它试图将数据分为K个簇,使得簇内数据点到其质心的距离平方和最小。
Python实现示例:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs# 生成样本数据
X, y = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)# 创建K-Means模型并拟合数据
kmeans = KMeans(n_clusters=4, random_state=0)
kmeans.fit(X)# 获取聚类标签和质心
labels = kmeans.labels_
centers = kmeans.cluster_centers_# 可视化聚类结果
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', s=50, alpha=0.7)
plt.scatter(centers[:, 0], centers[:, 1], c='red', s=200, alpha=0.8, marker='*')
plt.title('K-Means Clustering')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()# 评估聚类效果
from sklearn.metrics import silhouette_score
silhouette_avg = silhouette_score(X, labels)
print(f"Silhouette Score: {silhouette_avg:.3f}")
2. 层次聚类
层次聚类通过构建层次化的簇结构来对数据进行聚类,可以分为凝聚式(自底向上)和分裂式(自顶向下)两种方法。
Python实现示例:
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster.hierarchy import dendrogram
from sklearn.datasets import make_blobs
import numpy as np
import matplotlib.pyplot as plt# 生成样本数据
X, y = make_blobs(n_samples=100, centers=4, random_state=42)# 创建凝聚式层次聚类模型
model = AgglomerativeClustering(n_clusters=4, affinity='euclidean', linkage='ward')
labels = model.fit_predict(X)# 绘制聚类结果
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', s=50)
plt.title('Agglomerative Clustering')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()# 绘制树状图(需要自定义函数)
def plot_dendrogram(model, **kwargs):# 创建连接矩阵并绘制树状图counts = np.zeros(model.children_.shape[0])n_samples = len(model.labels_)for i, merge in enumerate(model.children_):current_count = 0for child_idx in merge:if child_idx < n_samples:current_count += 1 # 叶子节点else:current_count += counts[child_idx - n_samples]counts[i] = current_countlinkage_matrix = np.column_stack([model.children_, model.distances_, counts]).astype(float)# 绘制树状图dendrogram(linkage_matrix, **kwargs)# 重新创建模型以获取距离信息
model = AgglomerativeClustering(distance_threshold=0, n_clusters=None)
model = model.fit(X)plt.figure(figsize=(10, 6))
plt.title('Hierarchical Clustering Dendrogram')
plot_dendrogram(model, truncate_mode='level', p=3)
plt.xlabel("Number of points in node (or index of point if no parenthesis).")
plt.show()
3. DBSCAN聚类
DBSCAN(基于密度的空间聚类应用)是一种基于密度的聚类算法,它将具有足够密度的区域划分为簇,并将低密度区域中的点视为噪声。
Python实现示例:
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_moons
import matplotlib.pyplot as plt
import numpy as np# 生成月牙形数据
X, y = make_moons(n_samples=200, noise=0.05, random_state=42)# 创建DBSCAN模型
dbscan = DBSCAN(eps=0.3, min_samples=5)
labels = dbscan.fit_predict(X)# 可视化聚类结果
plt.figure(figsize=(10, 6))
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', s=50)
plt.title('DBSCAN Clustering')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.show()# 统计核心点、边界点和噪声点的数量
core_samples_mask = np.zeros_like(dbscan.labels_, dtype=bool)
core_samples_mask[dbscan.core_sample_indices_] = True
n_clusters_ = len(set(labels)) - (1 if -1 in labels else 0)
n_noise_ = list(labels).count(-1)print(f'估计的簇数量: {n_clusters_}')
print(f'估计的噪声点数量: {n_noise_}')
四、降维算法
降维是另一个重要的非监督学习任务,主要用于数据压缩和可视化。
1. 主成分分析(PCA)
PCA是一种最常用的线性降维方法,它通过找到数据的主成分来实现降维,主成分是数据中方差最大的方向。
Python实现示例:
from sklearn.decomposition import PCA
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt# 加载鸢尾花数据集
iris = load_iris()
X = iris.data
y = iris.target# 创建PCA模型并降维到2维
pca = PCA(n_components=2)
X_reduced = pca.fit_transform(X)# 可视化降维结果
plt.figure(figsize=(10, 6))
plt.scatter(X_reduced[:, 0], X_reduced[:, 1], c=y, cmap='viridis', s=50)
plt.title('PCA of Iris Dataset')
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.show()# 查看解释方差比
print(f'解释方差比: {pca.explained_variance_ratio_}')
print(f'累计解释方差比: {sum(pca.explained_variance_ratio_):.3f}')
2. t-SNE降维
t-SNE(t分布随机邻域嵌入)是一种非线性降维方法,特别适合用于高维数据的可视化。
Python实现示例:
from sklearn.manifold import TSNE
from sklearn.datasets import load_digits
import matplotlib.pyplot as plt
import numpy as np# 加载手写数字数据集
digits = load_digits()
X = digits.data
y = digits.target# 创建t-SNE模型
tsne = TSNE(n_components=2, random_state=42)
X_reduced = tsne.fit_transform(X)# 可视化降维结果
plt.figure(figsize=(10, 8))
plt.scatter(X_reduced[:, 0], X_reduced[:, 1], c=y, cmap=plt.cm.get_cmap('viridis', 10))
plt.colorbar(ticks=range(10))
plt.title('t-SNE Visualization of Handwritten Digits')
plt.xlabel('t-SNE Feature 1')
plt.ylabel('t-SNE Feature 2')
plt.show()
五、异常检测
异常检测是识别数据中不符合预期模式的罕见事件或数据点。
1. 基于统计的异常检测
Python实现示例:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.covariance import EllipticEnvelope# 生成包含异常点的样本数据
X, y = make_blobs(n_samples=100, centers=1, random_state=42)
# 手动添加一些异常点
X_outliers = np.random.uniform(low=-10, high=10, size=(10, 2))
X = np.vstack([X, X_outliers])# 创建异常检测模型
ee = EllipticEnvelope(contamination=0.1, random_state=42)
ee.fit(X)
y_pred = ee.predict(X)# 可视化结果
plt.figure(figsize=(10, 6))
plt.scatter(X[y_pred == 1, 0], X[y_pred == 1, 1], c='blue', label='正常数据')
plt.scatter(X[y_pred == -1, 0], X[y_pred == -1, 1], c='red', label='异常数据')
plt.title('基于统计的异常检测')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend()
plt.show()
2. 基于隔离森林的异常检测
Python实现示例:
from sklearn.ensemble import IsolationForest
import numpy as np
import matplotlib.pyplot as plt# 生成数据
rng = np.random.RandomState(42)
X = 0.3 * rng.randn(100, 2)
X_train = np.r_[X + 2, X - 2]
X_outliers = rng.uniform(low=-4, high=4, size=(20, 2))# 训练隔离森林模型
clf = IsolationForest(contamination=0.1, random_state=rng)
clf.fit(X_train)
y_pred_train = clf.predict(X_train)
y_pred_outliers = clf.predict(X_outliers)# 可视化结果
xx, yy = np.meshgrid(np.linspace(-5, 5, 50), np.linspace(-5, 5, 50))
Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)plt.figure(figsize=(10, 6))
plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), 0, 7), cmap=plt.cm.PuBu)
a = plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors='darkred')
plt.contourf(xx, yy, Z, levels=[0, Z.max()], colors='palevioletred')b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c='white', s=20, edgecolor='k')
b2 = plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c='black', s=20, edgecolor='k')
plt.legend([a.collections[0], b1, b2],["分离超平面", "训练样本", "异常点"],loc="upper left")
plt.title("隔离森林异常检测")
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.show()
六、非监督学习评估指标
评估非监督学习模型的性能比监督学习更具挑战性,因为没有明确的标签作为参考。以下是一些常用的评估指标:
1. 聚类评估指标
- 轮廓系数(Silhouette Coefficient):衡量每个样本与其所在簇的紧密程度以及与其他簇的分离程度,取值范围为[-1, 1],值越大表示聚类效果越好。
- Calinski-Harabasz指数:也称为方差比准则,值越大表示聚类效果越好。
- Davies-Bouldin指数:值越小表示聚类效果越好。
2. 降维评估指标
- 解释方差比(Explained Variance Ratio):衡量每个主成分解释数据方差的比例,用于PCA等降维方法。
- 重构误差(Reconstruction Error):衡量降维后的数据重构回原始空间的误差,用于自编码器等方法。
3. 异常检测评估指标
- 精确度(Precision)、召回率(Recall)和F1分数(F1-Score):适用于有标记异常点的情况。
- ROC曲线和AUC值:用于评估异常检测模型的性能。
七、实战项目:客户细分
下面通过一个客户细分的实战项目,演示如何在实际应用中使用非监督学习。
项目背景:
某电商公司希望对客户进行细分,以便更好地了解客户需求,提供个性化的营销方案。
项目步骤:
- 数据收集与预处理
- 特征选择与工程
- 应用聚类算法进行客户细分
- 分析和解释聚类结果
- 制定营销策略
Python实现代码:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score# 1. 数据收集与预处理
# 假设我们有一个包含客户信息的CSV文件
data = pd.read_csv('customer_data.csv')# 查看数据基本信息
print('数据基本信息:')
data.info()# 查看数据集行数和列数
rows, columns = data.shapeif rows < 300:# 小数据集(行数少于300)查看全量数据信息print('数据全部内容信息:')print(data.to_csv(sep='\t', na_rep='nan'))
else:# 大数据集查看数据前几行信息print('数据前几行内容信息:')print(data.head().to_csv(sep='\t', na_rep='nan'))# 检查缺失值
missing_values = data.isnull().sum()
print('\n缺失值统计:')
print(missing_values[missing_values > 0])# 处理缺失值(这里简单地用均值填充)
data = data.fillna(data.mean())# 2. 特征选择与工程
# 假设我们选择以下特征进行聚类:年龄、收入、消费频率、平均订单金额
X = data[['age', 'income', 'frequency', 'avg_order_value']]# 数据标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)# 3. 应用聚类算法
# 使用肘部法则确定最佳簇数
wcss = []
for i in range(1, 11):kmeans = KMeans(n_clusters=i, init='k-means++', random_state=42)kmeans.fit(X_scaled)wcss.append(kmeans.inertia_)# 绘制肘部曲线
plt.figure(figsize=(10, 6))
plt.plot(range(1, 11), wcss, marker='o')
plt.title('Elbow Method')
plt.xlabel('Number of clusters')
plt.ylabel('WCSS')
plt.show()# 根据肘部曲线选择最佳簇数(例如,k=4)
kmeans = KMeans(n_clusters=4, init='k-means++', random_state=42)
y_kmeans = kmeans.fit_predict(X_scaled)# 计算轮廓系数
silhouette_avg = silhouette_score(X_scaled, y_kmeans)
print(f"轮廓系数: {silhouette_avg}")# 4. 分析和解释聚类结果
# 将聚类结果添加到原始数据
data['cluster'] = y_kmeans# 计算每个簇的统计特征
cluster_stats = data.groupby('cluster').mean()
print('\n各簇的统计特征:')
print(cluster_stats)# 可视化聚类结果
plt.figure(figsize=(12, 8))plt.subplot(2, 2, 1)
sns.boxplot(x='cluster', y='age', data=data)
plt.title('Age by Cluster')plt.subplot(2, 2, 2)
sns.boxplot(x='cluster', y='income', data=data)
plt.title('Income by Cluster')plt.subplot(2, 2, 3)
sns.boxplot(x='cluster', y='frequency', data=data)
plt.title('Frequency by Cluster')plt.subplot(2, 2, 4)
sns.boxplot(x='cluster', y='avg_order_value', data=data)
plt.title('Average Order Value by Cluster')plt.tight_layout()
plt.show()# 5. 制定营销策略
# 根据聚类结果,可以为不同的客户群体制定不同的营销策略
# 例如:
# 簇0:高收入、高消费的客户,可以提供高端产品和专属服务
# 簇1:中等收入、中等消费的客户,可以提供优惠券和会员制度
# 簇2:低收入、低消费的客户,可以提供折扣商品和基础服务
# 簇3:高收入但消费频率低的客户,可以提供个性化推荐和促销活动# 输出各簇的客户数量和特征描述
cluster_counts = data['cluster'].value_counts()
print('\n各簇的客户数量:')
print(cluster_counts)print('\n客户细分总结:')
for i in range(len(cluster_stats)):print(f"\n簇 {i} ({cluster_counts[i]} 客户):")print(f" - 平均年龄: {cluster_stats.iloc[i]['age']:.1f}")print(f" - 平均收入: {cluster_stats.iloc[i]['income']:.1f}")print(f" - 平均消费频率: {cluster_stats.iloc[i]['frequency']:.1f}")print(f" - 平均订单金额: {cluster_stats.iloc[i]['avg_order_value']:.1f}")print(" - 营销策略建议: 根据该簇客户的特点制定个性化的营销方案")
八、总结
非监督学习是机器学习中一个非常重要的领域,它在数据探索、特征工程、异常检测等多个方面都有广泛的应用。通过本文的介绍,我们了解了Python中常用的非监督学习算法,包括聚类、降维和异常检测,并通过实战项目演示了如何应用这些算法解决实际问题。
在实际应用中,需要根据数据的特点和具体的业务需求选择合适的算法,并使用适当的评估指标来评估模型的性能。非监督学习往往是数据分析的第一步,它可以帮助我们发现数据中的隐藏模式,为后续的监督学习或业务决策提供有价值的信息。
希望本文能为你提供一个全面的Python非监督学习入门指南,帮助你更好地理解和应用非监督学习技术。