常见机器学习算法原理:线性回归、决策树、SVM 与聚类
四种常见的机器学习算法:线性回归、决策树、支持向量机(SVM)和聚类算法。详细阐述了各算法的基本原理、核心公式、Python 代码实现及应用场景。线性回归通过梯度下降优化参数;决策树基于信息熵或基尼系数构建;SVM 寻找最大间隔超平面;K-Means 等聚类算法用于无监督学习。文末提供算法选择指南,帮助根据数据特征选择合适的模型。

四种常见的机器学习算法:线性回归、决策树、支持向量机(SVM)和聚类算法。详细阐述了各算法的基本原理、核心公式、Python 代码实现及应用场景。线性回归通过梯度下降优化参数;决策树基于信息熵或基尼系数构建;SVM 寻找最大间隔超平面;K-Means 等聚类算法用于无监督学习。文末提供算法选择指南,帮助根据数据特征选择合适的模型。

机器学习算法是人工智能领域的核心工具,不同的算法适用于不同的问题场景。本文将深入讲解几种最常用的机器学习算法,包括线性回归、决策树、支持向量机和聚类算法,帮助读者理解它们的原理、应用场景以及实现方式。
线性回归是机器学习中最基础也是最重要的算法之一。虽然它看起来很简单,但在实际应用中却非常有效,很多复杂的算法都是在线性回归的基础上发展而来的。
线性回归的核心思想是找到一条直线(或者高维空间中的超平面),使得这条线能够最好地拟合数据点。用数学语言来说,就是找到一个函数关系,使得预测值和真实值之间的误差最小。
对于最简单的一元线性回归,我们要找的是这样一个函数:
y = wx + b
其中,x 是输入特征,y 是预测值,w 是权重(斜率),b 是偏置(截距)。我们的目标是找到最优的 w 和 b,使得所有样本点到这条直线的距离之和最小。
这个距离通常用均方误差来衡量:
MSE = (1/n) * Σ(y_i - ŷ_i)²
其中,y_i 是真实值,ŷ_i 是预测值,n 是样本数量。
要找到最优的参数,最常用的方法就是梯度下降法。梯度下降的思想很直观:想象你站在山顶,想要下到山谷,最快的方法就是沿着最陡的方向往下走。在数学上,这个最陡的方向就是梯度的反方向。
具体的更新规则是:
w = w - α * ∂L/∂w
b = b - α * ∂L/∂b
其中,α是学习率,控制每次更新的步长。学习率太大可能导致震荡,太小则收敛速度慢。
下面用代码来实现一个简单的线性回归:
import numpy as np
import matplotlib.pyplot as plt
class LinearRegression:
def __init__(self, learning_rate=0.01, iterations=1000):
self.lr = learning_rate
self.iterations = iterations
self.w = None
self.b = None
self.losses = []
def fit(self, X, y):
# 初始化参数
n_samples, n_features = X.shape
self.w = np.zeros(n_features)
self.b = 0
# 梯度下降
for i in range(self.iterations):
# 前向传播:计算预测值
y_pred = np.dot(X, self.w) + self.b
# 计算损失
loss = np.mean((y - y_pred)**2)
self.losses.append(loss)
# 计算梯度
dw = -(2/n_samples) * np.dot(X.T, (y - y_pred))
db = -(2/n_samples) * np.sum(y - y_pred)
# 更新参数
self.w -= self.lr * dw
self.b -= self.lr * db
if i % 100 == 0:
print(f"Iteration {i}: Loss = {loss:.4f}")
def predict(self, X):
return np.dot(X, self.w) + self.b
# 生成示例数据
np.random.seed(42)
X = 2 * np.random.rand(100, 1)
y = 4 + 3 * X + np.random.randn(100, 1)
# 训练模型
model = LinearRegression(learning_rate=0.1, iterations=1000)
model.fit(X, y.ravel())
# 预测
X_test = np.array([[0], [2]])
predictions = model.predict(X_test)
print(f"预测结果:{predictions}")
# 可视化
plt.scatter(X, y, color='blue', label='真实数据')
plt.plot(X_test, predictions, color='red', linewidth=2, label='拟合直线')
plt.xlabel('X')
plt.ylabel('y')
plt.legend()
plt.title('线性回归拟合结果')
plt.show()
在实际应用中,我们通常需要处理多个特征的情况。多元线性回归的形式是:
y = w₁x₁ + w₂x₂ + … + wₙxₙ + b
用向量形式表示就是:
y = w^T · x + b
求解方法和一元线性回归类似,只是梯度计算变成了向量形式。上面的代码实现实际上已经支持多元线性回归了。
线性回归适用于以下场景:
需要注意的是,线性回归假设特征和目标之间存在线性关系,如果关系是非线性的,需要进行特征工程或使用其他算法。
决策树是一种非常直观的算法,它的决策过程就像人类的思维方式一样,通过一系列的判断来得出结论。
决策树通过树形结构来表示决策过程。每个内部节点表示一个特征的判断,每个分支表示判断的结果,每个叶子节点表示最终的决策结果。
晴天 阴天 雨天 高 正常 天气如何? 湿度如何? 去打球 不去打球 不去打球 去打球
构建决策树的关键问题是:如何选择最优的特征进行分裂?这就需要用到信息增益或基尼系数等指标。
信息熵是衡量数据不确定性的指标。熵越大,数据越混乱;熵越小,数据越纯净。
信息熵的计算公式:
H(D) = -Σ p_i * log₂(p_i)
其中,p_i 是第 i 类样本在数据集中的比例。
信息增益表示使用某个特征进行分裂后,信息熵的减少量:
Gain(D, A) = H(D) - Σ (|D_v|/|D|) * H(D_v)
其中,D_v 是特征 A 取值为 v 的样本子集。
我们选择信息增益最大的特征进行分裂,这样可以使得分裂后的子节点尽可能纯净。
除了信息增益,还可以使用基尼系数来选择分裂特征。基尼系数表示从数据集中随机抽取两个样本,其类别不一致的概率:
Gini(D) = 1 - Σ p_i²
基尼系数越小,数据集的纯度越高。
下面用代码实现一个简单的决策树分类器:
import numpy as np
from collections import Counter
class DecisionTreeNode:
def __init__(self, feature=None, threshold=None, left=None, right=None, value=None):
self.feature = feature # 分裂特征的索引
self.threshold = threshold # 分裂阈值
self.left = left # 左子树
self.right = right # 右子树
self.value = value # 叶子节点的类别
class DecisionTree:
def __init__(self, max_depth=10, min_samples_split=2):
self.max_depth = max_depth
self.min_samples_split = min_samples_split
self.root = None
def _entropy(self, y):
"""计算信息熵"""
counter = Counter(y)
probs = np.array(list(counter.values())) / len(y)
return -np.sum(probs * np.log2(probs + 1e-10))
def _information_gain(self, X, y, feature, threshold):
"""计算信息增益"""
# 父节点熵
parent_entropy = ._entropy(y)
left_mask = X[:, feature] <= threshold
right_mask = ~left_mask
np.(left_mask) == np.(right_mask) == :
n = (y)
n_left, n_right = np.(left_mask), np.(right_mask)
e_left = ._entropy(y[left_mask])
e_right = ._entropy(y[right_mask])
child_entropy = (n_left / n) * e_left + (n_right / n) * e_right
parent_entropy - child_entropy
():
best_gain = -
best_feature =
best_threshold =
n_features = X.shape[]
feature (n_features):
thresholds = np.unique(X[:, feature])
threshold thresholds:
gain = ._information_gain(X, y, feature, threshold)
gain > best_gain:
best_gain = gain
best_feature = feature
best_threshold = threshold
best_feature, best_threshold
():
n_samples, n_features = X.shape
n_classes = (np.unique(y))
depth >= .max_depth n_samples < .min_samples_split n_classes == :
leaf_value = Counter(y).most_common()[][]
DecisionTreeNode(value=leaf_value)
best_feature, best_threshold = ._best_split(X, y)
best_feature :
leaf_value = Counter(y).most_common()[][]
DecisionTreeNode(value=leaf_value)
left_mask = X[:, best_feature] <= best_threshold
right_mask = ~left_mask
left_subtree = ._build_tree(X[left_mask], y[left_mask], depth + )
right_subtree = ._build_tree(X[right_mask], y[right_mask], depth + )
DecisionTreeNode(best_feature, best_threshold, left_subtree, right_subtree)
():
.root = ._build_tree(X, y)
():
node.value :
node.value
x[node.feature] <= node.threshold:
._predict_sample(x, node.left)
:
._predict_sample(x, node.right)
():
np.array([._predict_sample(x, .root) x X])
sklearn.datasets load_iris
sklearn.model_selection train_test_split
iris = load_iris()
X, y = iris.data, iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=, random_state=)
tree = DecisionTree(max_depth=)
tree.fit(X_train, y_train)
y_pred = tree.predict(X_test)
accuracy = np.mean(y_pred == y_test)
()
优点:
缺点:
为了克服决策树容易过拟合的问题,可以使用集成学习方法,其中最著名的就是随机森林。随机森林通过构建多棵决策树,然后对它们的预测结果进行投票或平均,从而提高模型的泛化能力。
训练数据 决策树 1 决策树 2 决策树 3 ... 决策树 N 投票/平均 最终预测
支持向量机是一种非常强大的分类算法,它的核心思想是找到一个最优的超平面,使得不同类别的样本被正确分开,并且分类间隔最大。
对于线性可分的数据,SVM 要找的是这样一个超平面:
w^T · x + b = 0
使得所有样本点到这个超平面的距离之和最大。这个距离称为间隔(margin)。
SVM 核心思想 找到最优超平面 最大化分类间隔 支持向量 距离超平面最近的点 决定超平面位置
数学上,这个问题可以表示为:
最小化:(1/2) ||w||² 约束条件:y_i(w^T · x_i + b) ≥ 1
其中,y_i 是样本的类别标签(+1 或 -1),x_i 是样本特征。
在实际应用中,数据往往不是完全线性可分的,可能存在一些噪声点。为了处理这种情况,引入了软间隔的概念,允许一些样本点违反间隔约束。
引入松弛变量ξ_i,优化目标变为:
最小化:(1/2) ||w||² + C * Σξ_i 约束条件:y_i(w^T · x_i + b) ≥ 1 - ξ_i,ξ_i ≥ 0
其中,C 是惩罚参数,控制对误分类的惩罚程度。C 越大,对误分类的惩罚越大,模型越复杂;C 越小,模型越简单,但可能欠拟合。
当数据不是线性可分时,可以通过核函数将数据映射到高维空间,使其在高维空间中线性可分。
常用的核函数有:
其中,RBF 核是最常用的核函数,它可以将数据映射到无限维空间。
下面用代码演示如何使用 SVM:
import numpy as np
from sklearn import svm
from sklearn.datasets import make_classification, make_circles
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
# 生成线性可分数据
X_linear, y_linear = make_classification(n_samples=100, n_features=2, n_redundant=0, n_informative=2, n_clusters_per_class=1, random_state=42)
# 生成非线性数据
X_nonlinear, y_nonlinear = make_circles(n_samples=100, noise=0.1, factor=0.5, random_state=42)
def plot_svm_decision_boundary(X, y, model, title):
"""绘制 SVM 决策边界"""
plt.figure(figsize=(10, 6))
# 创建网格
h = 0.02
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
# 预测网格点
Z = model.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# 绘制决策边界
plt.contourf(xx, yy, Z, alpha=0.3, cmap=plt.cm.RdYlBu)
plt.scatter(X[:, 0], X[:, ], c=y, cmap=plt.cm.RdYlBu, edgecolors=)
plt.scatter(model.support_vectors_[:, ], model.support_vectors_[:, ], s=, linewidth=, facecolors=, edgecolors=, label=)
plt.xlabel()
plt.ylabel()
plt.title(title)
plt.legend()
plt.show()
()
svm_linear = svm.SVC(kernel=, C=)
svm_linear.fit(X_linear, y_linear)
()
plot_svm_decision_boundary(X_linear, y_linear, svm_linear, )
()
svm_rbf = svm.SVC(kernel=, C=, gamma=)
svm_rbf.fit(X_nonlinear, y_nonlinear)
()
plot_svm_decision_boundary(X_nonlinear, y_nonlinear, svm_rbf, )
()
C [, , , ]:
model = svm.SVC(kernel=, C=C)
model.fit(X_linear, y_linear)
(
)
SVM 适用于以下场景:
SVM 的优点是在高维空间中表现良好,对于小样本数据也能取得不错的效果。但缺点是训练时间较长,对大规模数据不太适用。
聚类是无监督学习的典型代表,它的目标是将相似的样本归为一类,不同的样本分到不同的类。聚类不需要标签数据,完全依靠数据本身的特征进行分组。
K-Means 是最常用的聚类算法,它的思想很简单:将数据分成 K 个簇,使得每个簇内的样本尽可能相似,不同簇之间的样本尽可能不同。
是 否 开始 随机初始化 K 个中心点 分配样本到最近的中心点 更新中心点位置 中心点是否变化? 结束
K-Means 算法的步骤:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
class KMeans:
def __init__(self, n_clusters=3, max_iters=100):
self.n_clusters = n_clusters
self.max_iters = max_iters
self.centroids = None
self.labels = None
def fit(self, X):
# 随机初始化聚类中心
n_samples = X.shape[0]
random_indices = np.random.choice(n_samples, self.n_clusters, replace=False)
self.centroids = X[random_indices]
for i in range(self.max_iters):
# 分配样本到最近的聚类中心
distances = np.sqrt(((X - self.centroids[:, np.newaxis])**2).sum(axis=2))
self.labels = np.argmin(distances, axis=0)
# 更新聚类中心
new_centroids = np.array([X[self.labels == k].mean(axis=0) for k in range(self.n_clusters)])
# 检查是否收敛
if np.allclose(self.centroids, new_centroids):
()
.centroids = new_centroids
():
distances = np.sqrt(((X - .centroids[:, np.newaxis])**).(axis=))
np.argmin(distances, axis=)
X, y_true = make_blobs(n_samples=, centers=, cluster_std=, random_state=)
kmeans = KMeans(n_clusters=, max_iters=)
kmeans.fit(X)
plt.figure(figsize=(, ))
plt.subplot(, , )
plt.scatter(X[:, ], X[:, ], c=y_true, cmap=, alpha=)
plt.title()
plt.xlabel()
plt.ylabel()
plt.subplot(, , )
plt.scatter(X[:, ], X[:, ], c=kmeans.labels, cmap=, alpha=)
plt.scatter(kmeans.centroids[:, ], kmeans.centroids[:, ], c=, marker=, s=, edgecolors=, label=)
plt.title()
plt.xlabel()
plt.ylabel()
plt.legend()
plt.tight_layout()
plt.show()
选择合适的 K 值是 K-Means 算法的关键问题。常用的方法有:
def elbow_method(X, max_k=10):
"""肘部法则选择 K 值"""
sse = []
for k in range(1, max_k + 1):
kmeans = KMeans(n_clusters=k)
kmeans.fit(X)
# 计算簇内误差平方和
sse_k = sum([np.sum((X[kmeans.labels == i] - kmeans.centroids[i])**2) for i in range(k)])
sse.append(sse_k)
plt.figure(figsize=(8, 5))
plt.plot(range(1, max_k + 1), sse, marker='o')
plt.xlabel('聚类数量 K')
plt.ylabel('簇内误差平方和 SSE')
plt.title('肘部法则选择 K 值')
plt.grid(True)
plt.show()
elbow_method(X, max_k=10)
除了 K-Means,层次聚类也是一种常用的聚类方法。层次聚类不需要预先指定簇的数量,它通过构建一个树状结构来表示样本之间的层次关系。
层次聚类分为两种:
from scipy.cluster.hierarchy import dendrogram, linkage
import matplotlib.pyplot as plt
# 生成数据
X, _ = make_blobs(n_samples=50, centers=3, random_state=42)
# 层次聚类
linkage_matrix = linkage(X, method='ward')
# 绘制树状图
plt.figure(figsize=(12, 6))
dendrogram(linkage_matrix)
plt.title('层次聚类树状图')
plt.xlabel('样本索引')
plt.ylabel('距离')
plt.show()
DBSCAN 是一种基于密度的聚类算法,它可以发现任意形状的簇,并且能够识别噪声点。
DBSCAN 的核心概念:
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_moons
# 生成月牙形数据
X, _ = 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', alpha=0.6)
plt.title('DBSCAN 聚类结果')
plt.xlabel('特征 1')
plt.ylabel('特征 2')
plt.colorbar(label='簇标签')
plt.show()
print(f"发现{len(set(labels))-(1if-1in labels else0)}个簇")
print(f"噪声点数量:{list(labels).count(-1)}")
聚类算法在实际中有广泛的应用:
面对不同的问题,如何选择合适的算法呢?下面给出一些建议:
是 否 是 否 是 否 机器学习问题 有标签数据? 预测连续值? 聚类算法 回归算法 分类算法 线性回归 岭回归 Lasso 回归 数据线性可分? 逻辑回归 线性 SVM 决策树 随机森林 核 SVM 神经网络 K-Means 层次聚类 DBSCAN
选择算法时需要考虑的因素:
本文详细介绍了机器学习中最常用的几种算法:线性回归、决策树、支持向量机和聚类算法。每种算法都有其适用的场景和特点:
线性回归简单高效,适合处理线性关系的问题,是入门机器学习的最佳选择。通过梯度下降法,我们可以找到最优的参数,使得预测误差最小。
决策树直观易懂,可以处理非线性问题,通过信息增益或基尼系数选择最优分裂特征。虽然单棵决策树容易过拟合,但通过随机森林等集成方法可以大大提高性能。
支持向量机通过最大化分类间隔来找到最优分界线,对于高维数据表现优异。通过核函数,SVM 可以处理非线性问题,是一种非常强大的分类算法。
聚类算法不需要标签数据,可以自动发现数据的内在结构。K-Means 简单高效,层次聚类可以展示数据的层次关系,DBSCAN 可以发现任意形状的簇并识别噪声点。
在实际应用中,没有一种算法是万能的,需要根据具体问题选择合适的算法。通常的做法是尝试多种算法,通过交叉验证等方法比较它们的性能,最终选择效果最好的模型。同时,特征工程、参数调优等技巧也对模型性能有重要影响。
掌握这些基础算法的原理和实现,是深入学习机器学习的重要基础。在此基础上,可以进一步学习深度学习、强化学习等更高级的技术。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online