所有文章 > AI驱动 > Python数据挖掘算法入门与实践

Python数据挖掘算法入门与实践

一、数据挖掘简介

数据挖掘是一个通过对大量数据进行清理和处理,以发现其中隐藏的信息和模式的过程。简单来说,它是从大量数据中提取或“挖掘”知识的过程,也称为知识发现。

随着互联网和移动工具的发展,我们每天产生的数据量非常庞大,这些数据通常被收集并存储在大型数据库中。数据挖掘技术提供了一种有效的方法,可以从这些海量数据中提取有价值的信息,从而为决策提供重要依据。这个过程在许多领域都有广泛的应用,如新闻分类、推荐系统等。

数据挖掘一般的流程如下:

  1. 首先,进行数据挖掘的第一步是数据选择。在明确了业务需求后,我们需要从各种来源中选择与需求相关的数据。这些数据可能来自业务原始数据、公开的数据集,或者通过爬虫从网站上抓取的结构化数据。选择合适的数据是进行数据挖掘的基础。
  2. 接下来是数据预处理阶段。在这个阶段,我们需要对选定的数据进行清洗和处理,以消除其中的噪音和不完整信息。
  3. 完成数据预处理后,我们进入特征工程或数据转换阶段。这个阶段的目标是根据所选择的算法,从预处理好的数据中提取出有意义的特征,并将其转换为适合特定数据挖掘算法的分析模型。
  4. 然后是数据挖掘阶段。在这个阶段,我们将使用选定的数据挖掘算法对处理过的数据进行深入分析,以发现其中的模式和关联。
  5. 最后是解释与评价阶段。在这个阶段,我们将对数据挖掘的结果进行解释和评价,以便将其应用于实际的工作领域。

二、数据挖掘算法简介

2.1 关联分析


关联规则分析的目标是发现数据集中不同属性之间的关联。为了达到这个目标,关联规则算法设置了最小支持度阈值和最小置信度阈值。这些算法致力于在尽可能高效的方式下完成这个任务。

常见的关联规则算法包括Apriori算法、AprioriTid算法和FP-growth算法。

2.2 分类算法


分类算法的目标是将数据集中的对象分配到预定义的类别中。以下是几种经典的分类算法:

  • 决策树算法:使用树形结构表示分类或决策集合,从而产生规则或发现规律。主要的算法包括ID3、C4.5、SLIQ、SPRING和RainForest。
  • 朴素贝叶斯分类算法:基于贝叶斯定理,通过计算每个类别的概率来选择概率最大的类别进行分类。
  • KNN分类算法:基于最近邻原理,将距离相近的归为同一类。
  • CBA(基于关联规则的分类算法):利用关联规则进行分类。
  • MIND(在数据库中挖掘)算法:使用用户定义的函数(UDF)在数据库中实现分类的算法。
  • 神经网络分类算法:利用训练集对多层的神经网络进行训练,然后用训练好的模型对样本进行分类。
  • 粗集理论:一种不需要预先给出特征或属性数量描述的分类方法,直接从问题出发,通过不可分辨关系和不可分辨类确定近似域,找出问题的内在规律。
  • 遗传算法:模拟生物进化过程的优化求解技术,利用选择、交叉和变异三个基本方法进行优化。

2.3 回归分析

回归分析主要研究因变量(目标)和自变量(预测器)之间的关系。在大数据分析中,回归分析是一种预测性的建模技术,它通过研究因变量和影响它的自变量之间的回归模型,来预测因变量的发展趋势。当有多个自变量时,可以研究每个自变量对因变量的影响强度。

回归分析的分类如下:

  • 按自变量的多少分为:一元回归分析和多元回归分析。
  • 按因变量的多少分为:简单回归分析和多重回归分析。
  • 按自变量和因变量之间的相关关系不同分为:线性回归分析和非线性回归分析

2.4 聚类算法


聚类分析处理的对象集合中,对象的类是未知的。它的目标是将对象集合分组为多个由类似对象组成的簇。聚类分析的方法可以分为以下三类:

  • 分区方法:给定一个包含N个对象或元组的数据库,分区方法构建数据的K个划分,每个划分表示一个聚簇,且K < N。经典算法是K-MEAN(K平均值)算法。
  • 层次方法:对给定的数据对象集合进行层次的分解。经典算法是BIRCH(平衡迭代减少和聚类使用层次结构)算法。
  • 基于网格的方法:采用多分辨率的网格数据结构,将空间量化为有限数目的单元,形成网格结构,所有的聚类分析都在网格上进行。常用的算法有STING(统计信息网格)、CLIQUE(基于网格的聚类)和SKWAVECLUSTER(声波聚类)等。

三、相关预备知识

3.1 距离(相似度)度量

距离度量可用于在数据挖掘中明确样本数据相似度,通常可以计算样本间的距离,如下为常用距离度量的介绍。

样本数据以如下三个人的身高体重示例:

展示到坐标图中是这样的:

曼哈顿距离: 也称曼哈顿街区距离,就如从街区的一个十字路口点到另一个十字路口点的距离, 二维空间(多维空间按同理扩展)用公式表示为

欧氏距离:表示为点到点的距离。二维空间(多维空间按同理扩展)的公式表示为

闵可夫斯基距离:其实就是距离方法的通用概括,当 p=1 既是曼哈顿距离,当 p=2 既是欧氏距离。当p越大,单一维度的差值对整体的影响就越大。

余弦相关系数

样本数据视为向量,通过两向量间的夹角余弦值确认相关性,数值范围[-1,1]。-1表示负相关,0表示无关,1表示正相关。

余弦相关系数的优缺点:

优点:余弦相似度与向量的幅值无关,只与向量的方向相关,在文档相似度(TF-IDF)和图片相似性(histogram)计算上都有它的身影;而且在样本数值稀疏的时候仍可以使用。

缺点:余弦相似度受到向量的平移影响,上式如果将 x 平移到 x+1, 余弦值就会改变。(可以理解为受样本的起始标准的影响,接下来介绍的皮尔逊相关系数可以消除这个影响)

皮尔逊相关系数

计算出了样本向量间的相关性,数值范围[-1,1]。

考虑计算的遍历的次数,有一个替代公式可以近似计算皮尔逊相关系数:

皮尔逊相关系数优点:可消除每个分量标准不同(分数膨胀)的影响,具有平移不变性和尺度不变性

3.2 数据标准化

数据中如果各分量的单位尺度差异很大,可以使用数据标准化消除不同分量间单位尺度的影响,,加速模型收敛的效率,常用的方法有三种:

min-max 标准化:将数值范围缩放到(0,1),但没有改变数据分布。max为样本最大值,min为样本最小值。

z-score 标准化:将数值范围缩放到0附近, 经过处理的数据符合标准正态分布。u是平均值,σ是标准差。

修正的标准z-score:修正后可以减少样本数据异常值的影响。将z-score标准化公式中的均值改为中位数,将标准差改为绝对偏差。

其中asd绝对偏差:u为中位数,card(x)为样本个数

3.3 算法的效果评估方法

  • 十折交叉验证:将数据集随机分成十份,每次使用九份进行训练,剩余一份进行测试,这个过程重复十次,确保每份数据都至少被使用过一次作为测试集。关键在于保证数据集被均匀地分成十份。
  • N折交叉验证:又称为留一法,它利用几乎所有的数据来进行训练,然后留出一份数据进行测试。这个过程会迭代进行,确保每一份数据都被用作过测试集。
  • 训练-测试划分验证:随机将数据集划分为训练集和验证集,用于评估模型的性能。

四、数据挖掘算法原理及实践

4.1 Apriori关联分析算法

模型原理:Apriori算法是一种用于频繁项集挖掘和关联规则学习的算法。其主要思想是通过候选生成和剪枝策略发现频繁项集。它利用了数据集中的项集(items)的先验知识,通过减少不必要的搜索来提高效率。

使用场景:常用于市场篮子分析,如超市购物篮分析,以发现商品之间的关联关系。

Python示例代码:

from mlxtend.frequent_patterns import apriori  
from mlxtend.frequent_patterns import association_rules

# 假设df是包含交易数据的DataFrame,'item'是商品列
frequent_itemsets = apriori(df, min_support=0.05, use_colnames=True)
rules = association_rules(frequent_itemsets, metric="confidence",min_threshold=0.7)

4.2 协同过滤推荐算法

基于用户的协同过滤是通过计算用户之间的距离找出最相似的用户(需要将所有的评价数据在读取在内存中处理进行推荐),并将相似用户评价过的物品推荐给目标用户。

而基于物品的协同过滤则是找出最相似的物品(通过构建一个物品的相似度模型来做推荐),再结合用户的评价来给出推荐结果。算法常用有 修正余弦相似度算法:以物品的评分作为物品的属性值,通过对比物品i,j的共有的用户相对评分的计算相关性s(i,j)。

import numpy as np  

# 用户-物品评分矩阵
ratings = np.array([[5, 3, 0, 1],
[4, 0, 0, 0],
[0, 5, 3, 0],
[0, 4, 5, 5]])

# 计算用户之间的相似度
def similarity(ratings):
n = ratings.shape[0]
sim = np.zeros((n, n))
for i in range(n):
for j in range(n):
if i != j:
sim[i][j] = np.corrcoef(ratings[i], ratings[j])[0, 1]
return sim

# 基于用户的协同过滤推荐算法
def user_based_collaborative_filtering(ratings, threshold=0.6):
n = ratings.shape[0]
sim = similarity(ratings)
rec_list = {}
for i in range(n):
for j in range(n):
if i != j and sim[i][j] > threshold:
for k in range(len(ratings[j])):
if ratings[j][k] == 0 and ratings[i][k] != 0:
rec_list[k] = ratings[i][k]
return rec_list

# 获取推荐结果
rec_list = user_based_collaborative_filtering(ratings)
print(rec_list)

4.3 分类算法

(1)基于物品特征值的KNN分类算法

代码实现:iris鸢尾花KNN分类算法

...

# KNN核心逻辑手写
def knn(self, oj_list):
weight_dict = {"Iris-setosa":0.0, "Iris-versicolor":0.0, "Iris-virginica":0.0}
for atuple in oj_list:
weight_dict[atuple[1]] += (1.0 / atuple[0])
rel_class = [(key, value) for key, value in weight_dict.items()]
#print(sorted(rel_class, key=lambda x:x[1], reverse=True))
rel_class = sorted(rel_class, key=lambda x:x[1], reverse=True)[0][0]
return rel_class

...
# 调用sklearn直接实现
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import classification_report, confusion_matrix

# 加载鸢尾花数据集
iris = load_iris()
X = iris.data
y = iris.target

# 划分数据集为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建KNN分类器,并设置邻居数量为3
knn = KNeighborsClassifier(n_neighbors=3)

# 使用训练数据训练KNN分类器
knn.fit(X_train, y_train)

# 使用测试数据进行预测
y_pred = knn.predict(X_test)

# 输出分类器的评估结果
print("Classification Report:\n", classification_report(y_test, y_pred))
print("Confusion Matrix:\n", confusion_matrix(y_test, y_pred))

前面我们讨论的协同推荐算法,需要在用户生成的各种数据上进行深入分析,因此也被称为社会化过滤算法。然而,这种算法存在一些明显的问题,如数据的稀疏性、算法的可扩展性,以及过度依赖用户数据。为了解决这些问题,我们可以采用基于物品特征值分类的算法。这个算法主要分为两个步骤:第一步是特征值的选取。这一步是至关重要的,因为它决定了算法的准确性和效率。我们需要挑选出具有代表性且能提供区分度的特征值。以Iris花为例,我们可以选取花萼长度、花萼宽度、花瓣长度和花瓣宽度作为特征值。

第二步是计算距离。在这一步中,我们将测试集与训练集的特征值进行比较,计算它们之间的曼哈顿距离。通过这种方式,我们可以找到与测试集最相似的k个训练样本。然后,我们使用加权后的结果来预测分类。
然而,KNN分类算法也存在一些缺点。首先,它无法对分类结果的置信度进行量化,这意味着我们无法确定分类的准确性。其次,它是一种被动学习的算法,这意味着每次进行测试时都需要遍历所有的训练集,这可能导致算法的效率较低。

(2)贝叶斯分类算法

代码实现:

...
# bayes 核心逻辑手写
def bayes(self):
#训练组的条件概率
for word in self.vocabulary:
for category,value in self.prob.items():
if word not in self.prob[category]:
count = 0
else :
count = self.prob[category][word]
#优化条件概率公式
self.prob[category][word] = (count + 1) / (self.total[category] + len(self.vocabulary))

...
# 调用sklearn实现
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import pandas as pd

# 假设你有一个文本数据集,存储在CSV文件中,有两列:'text'和'label'
data = pd.read_csv('text_data.csv')

# 提取特征和标签
X = data['text'].values
y = data['label'].values

# 切分数据集为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 使用CountVectorizer将文本转换为向量
vectorizer = CountVectorizer()
X_train_transformed = vectorizer.fit_transform(X_train)
X_test_transformed = vectorizer.transform(X_test)

# 使用朴素贝叶斯分类器进行训练
classifier = MultinomialNB()
classifier.fit(X_train_transformed, y_train)

# 对测试集进行预测
y_pred = classifier.predict(X_test_transformed)

# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy}")

贝叶斯分类算法是基于概率的分类算法。相比于KNN分类算法,它是主动学习的算法,它会根据训练集建立一个模型,并用这个模型对新样本进行分类,速度也会快很多。

贝叶斯分类算法的理论基础是基于条件概率的公式(应用于现实中P(X|Y&Z)不直观得出,而P(Y|X)*P(Z|X)比较直观得出),并假设已存在的子事件(y,z…实际应用中会有多个)间是相互独立的(因此也称为朴素贝叶斯),当y,z事件假设为独立便有:

如下举例推测买牛奶和有机食品,再会买绿茶的概率:

第一步:计算先验概率及条件概率

先验概率:为单独事件发生的概率,如P(买绿茶),P(有机食品)

条件概率(后验概率):y事件已经发生,观察y数据集后得出x发生的概率。如P(买有机食品|买绿茶),通过以下公式计算(nc表示y数据集下x的发生频数,n为y数据集的总数):

上式存在一个缺陷,当一个条件概率 P(y|x)为0时,整体的预测结果P(x) * P(y|x) * P(z|x)只能为0,这样便不能更全面地预测。

修正后的条件概率:(公式摘自Tom Mitchell《机器学习》。m是一个常数,表示等效样本大小。决定常数m的方法有很多,我们这里可以使用预测结果的类别来作为m,比如投票有赞成和否决两种类别,所以m就为2。p则是相应的先验概率,比如说赞成概率是0.5,那p(赞成)就是0.5。):

第二歩:根据贝叶斯公式做出预测

由公式计算比较y&z事件发生下,不同x事件发生的概率差异,如得出P(x=喜欢),P(x=不喜欢) 的概率大小,预测为概率比较大的事件。因为P(y)*p(z)在上式都一样,因此公式可以简化为计算概率最大项而预测分类:


贝叶斯算法的优点:能够给出分类结果的置信度;它是一种主动学习算法,速度更快。

贝叶斯算法的缺点:需要特定格式;数值型数据需要转换为类别计算概率或用高斯分布计算概率;

(3)神经网络(DNN)分类算法

代码实现 :

import tensorflow as tf  
from tensorflow.keras import layers, models
import numpy as np
import matplotlib.pyplot as plt
import cv2

# 加载数据集,这里我们使用的是MNIST数据集,你可以替换成自己的数据集
(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()

# 对数据进行归一化处理
train_images = train_images / 255.0
test_images = test_images / 255.0

# 构建DNN模型
model = models.Sequential()
model.add(layers.Dense(512, activation='sigmoid', input_shape=(28, 28))) # 输入层,28x28是MNIST图片的大小
model.add(layers.Dense(512, activation='sigmoid')) # 隐藏层
model.add(layers.Dense(10, activation='softmax')) # 输出层,10个类别,使用softmax激活函数进行多分类

# 编译模型,设置损失函数、优化器和评估指标
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

# 训练模型
model.fit(train_images, train_labels, epochs=5)

# 在测试集上评估模型性能
test_loss, test_acc = model.evaluate(test_images, test_labels)
print('\nTest accuracy:', test_acc)

# 使用模型进行预测并可视化结果
predictions = model.predict(test_images)
predicted_class = np.argmax(predictions, axis=1) # 获取预测类别
true_class = np.argmax(test_labels, axis=1) # 获取真实类别
plt.figure(figsize=(10, 5))
for i in range(len(test_images)):
plt.subplot(1, 2, i+1)
plt.imshow(test_images[i].reshape(28, 28), cmap='gray')
plt.title('Predicted: ' + str(predicted_class[i]) + ', True: ' + str(true_class[i]))
plt.show()

DNN分类算法实现了输入图片特征向量X,输出Y(范围0~1)预测X的分类。

第一步,得到关于X线性回归函数

可以通过线性回归得到WX + b,其中W是权重,b是偏差值。但不能用本式表述预测的值,因为输出Y的值需要在(0~1)区间;

第二歩,通过激活函数转换

激活函数的特点是可以将线性函数转换为非线性函数,并且有输出值有限,可微分,单调性的特点。本例使用sigmoid,使输出为预测值Y=sigmoid(WX+b);

多个神经网络层,也就是重复第一、二步,类似sigmoid(sigmoid(WX+b))..的复合函数。

第三歩,构建Cost函数

训练W,b更好的预测真实的类别需要构建Cost代价函数,y^为sigmoid(WX+b)的预测分类值,y为实际分类值(0或者1):

其中L(y^,y)称为损失函数

训练的目的就是为了让L(y^,y)足够小,也就是当y实际分类值为1时,y^要尽量偏向1。y实际分类值为0时,y^尽量小接近0。

第四步,梯度下降得到Cost函数的极小值

通过对W,b两个参数求偏导,不断迭代往下坡的的位置移动(对w,b值往极小值方向做优化,其中α为学习率控制下降的幅度),全局最优解也就是代价函数(成本函数)J (w,b)这个凸函数的极小值点。

第五步、通过训练好的W,b预测分类。

4.4 聚类算法

(1)层次聚类

层次聚类将每条数据都当作是一个分类,每次迭代的时候合并距离最近的两个分类,直到剩下一个分类为止。

代码实现:

from sklearn.cluster import AgglomerativeClustering  
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt

# 生成样本数据
X, y = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)

# 实例化层次聚类模型,n_clusters为聚类数
cluster = AgglomerativeClustering(n_clusters=4)

# 拟合数据
cluster.fit(X)

# 获取聚类标签
labels = cluster.labels_

# 绘制结果
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
plt.show()


(2)K-means++聚类

注:Kmean算法与Kmean++区别在于初始的中心点是直接随机选取k各点。

代码实现:

from sklearn.cluster import KMeans  
from sklearn import datasets
import matplotlib.pyplot as plt

# 加载Iris数据集
iris = datasets.load_iris()
X = iris.data
y = iris.target

# 创建KMeans实例并拟合数据
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)

# 获取聚类标签和聚类中心点
labels = kmeans.labels_
centroids = kmeans.cluster_centers_

# 绘制聚类结果
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis')
plt.scatter(centroids[:, 0], centroids[:, 1], c='red', s=300) # 绘制聚类中心点
plt.show()

k-means++算法可概括为:

(1)基于各点到中心点得距离分量,依次随机选取到k个元素作为中心点:先随机选择一个点。重复以下步骤,直到选完k个点。

计算每个数据点dp(n)到各个中心点的距离(D),选取最小的值D(dp);

根据D(dp)距离所占的份量来随机选取下一个点作为中心点。

(2)根据各点到中心点的距离分类;

(3)计算各个分类新的中心点。重复(2、3),直至满足条件。

文章转自微信公众号@算法进阶