Python数据挖掘算法入门与实践
一、数据挖掘简介
数据挖掘是一个通过对大量数据进行清理和处理,以发现其中隐藏的信息和模式的过程。简单来说,它是从大量数据中提取或“挖掘”知识的过程,也称为知识发现。
随着互联网和移动工具的发展,我们每天产生的数据量非常庞大,这些数据通常被收集并存储在大型数据库中。数据挖掘技术提供了一种有效的方法,可以从这些海量数据中提取有价值的信息,从而为决策提供重要依据。这个过程在许多领域都有广泛的应用,如新闻分类、推荐系统等。
数据挖掘一般的流程如下:
- 首先,进行数据挖掘的第一步是数据选择。在明确了业务需求后,我们需要从各种来源中选择与需求相关的数据。这些数据可能来自业务原始数据、公开的数据集,或者通过爬虫从网站上抓取的结构化数据。选择合适的数据是进行数据挖掘的基础。
- 接下来是数据预处理阶段。在这个阶段,我们需要对选定的数据进行清洗和处理,以消除其中的噪音和不完整信息。
- 完成数据预处理后,我们进入特征工程或数据转换阶段。这个阶段的目标是根据所选择的算法,从预处理好的数据中提取出有意义的特征,并将其转换为适合特定数据挖掘算法的分析模型。
- 然后是数据挖掘阶段。在这个阶段,我们将使用选定的数据挖掘算法对处理过的数据进行深入分析,以发现其中的模式和关联。
- 最后是解释与评价阶段。在这个阶段,我们将对数据挖掘的结果进行解释和评价,以便将其应用于实际的工作领域。
二、数据挖掘算法简介
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),直至满足条件。
文章转自微信公众号@算法进阶