【梗直哥】机器学习必修课:经典算法与Python实战

2 阅读6分钟

经典AI算法与编程实战:从原理到代码实现

不堆砌公式,不迷恋调参,用最直接的方式理解经典算法,并亲手写几行关键代码。

前言

人工智能(AI)在过去十年取得了惊人进展,但无论深度学习如何火热,经典机器学习算法依然是数据科学家的“基本功”。它们可解释性强、训练成本低,在中小规模数据集上往往表现优异,更是理解现代复杂模型的基石。

本文将带你快速重温 六大经典算法 的核心思想,并用 极简 Python 代码 展示其关键实现步骤。全文不追求工业级封装,只求让你“一眼看透”算法本质。


1. 线性回归(Linear Regression)—— 最朴素的预测器

原理

线性回归假设目标值 yy 与特征 XX 之间存在线性关系:
y=Xw+by=Xw+b。
通过最小化 均方误差(MSE)  来求解最优权重 ww。解析解为 w=(XTX)−1XTyw=(XTX)−1XTy,实际中常用梯度下降迭代。

代码片段(手写梯度下降)

import numpy as np

class LinearRegressionGD:
    def __init__(self, lr=0.01, epochs=1000):
        self.lr = lr
        self.epochs = epochs
        self.w = None
        self.b = None

    def fit(self, X, y):
        n_samples, n_features = X.shape
        self.w = np.zeros(n_features)
        self.b = 0
        for _ in range(self.epochs):
            y_pred = X @ self.w + self.b
            dw = (1/n_samples) * X.T @ (y_pred - y)
            db = (1/n_samples) * np.sum(y_pred - y)
            self.w -= self.lr * dw
            self.b -= self.lr * db

    def predict(self, X):
        return X @ self.w + self.b

实战建议:使用 sklearn.linear_model.LinearRegression 时注意特征缩放,且数据需满足多重共线性较低的条件。


2. 逻辑回归(Logistic Regression)—— 二分类的看门人

原理

逻辑回归并非回归,而是分类。它将线性输出通过 Sigmoid函数 映射到 (0,1) 区间,视为正类概率。损失函数采用 交叉熵,梯度下降求解。

代码片段(核心梯度更新)

def sigmoid(z):
    return 1 / (1 + np.exp(-z))

class LogisticRegressionGD:
    def __init__(self, lr=0.1, epochs=1000):
        self.lr = lr
        self.epochs = epochs
        self.w = None
        self.b = None

    def fit(self, X, y):
        n_samples, n_features = X.shape
        self.w = np.zeros(n_features)
        self.b = 0
        for _ in range(self.epochs):
            linear = X @ self.w + self.b
            predictions = sigmoid(linear)
            dw = (1/n_samples) * X.T @ (predictions - y)
            db = (1/n_samples) * np.sum(predictions - y)
            self.w -= self.lr * dw
            self.b -= self.lr * db

    def predict_proba(self, X):
        return sigmoid(X @ self.w + self.b)

实战提醒:逻辑回归对类别不平衡敏感,可设置 class_weight 或采用过采样/欠采样。


3. 决策树(Decision Tree)—— 人类决策的数字化

原理

决策树通过递归划分特征空间,每次选择 信息增益(或基尼不纯度)最大的特征进行分裂。它天然支持多分类和可解释性,但易过拟合。

代码片段(计算基尼不纯度)

python

def gini(y):
    classes = np.unique(y)
    p = [np.sum(y == c) / len(y) for c in classes]
    return 1 - sum(p_i**2 for p_i in p)

def best_split(X, y):
    best_gain = 0
    best_thresh = None
    best_feature = None
    for feature in range(X.shape[1]):
        thresholds = np.unique(X[:, feature])
        for thresh in thresholds:
            left_mask = X[:, feature] <= thresh
            right_mask = ~left_mask
            if sum(left_mask)==0 or sum(right_mask)==0:
                continue
            gain = gini(y) - (sum(left_mask)/len(y))*gini(y[left_mask]) - (sum(right_mask)/len(y))*gini(y[right_mask])
            if gain > best_gain:
                best_gain = gain
                best_thresh = thresh
                best_feature = feature
    return best_feature, best_thresh

实战中直接使用 sklearn.tree.DecisionTreeClassifier,通过 max_depth 和 min_samples_split 控制过拟合。


4. K 近邻(KNN)—— 物以类聚,人以群分

原理

KNN 是一种“懒惰学习”算法,它不显式训练模型,而是存储全部训练样本。预测时计算新样本与所有训练点的距离,选取最近的 K 个点,投票决定类别(或均值回归)。

代码片段(距离计算与预测)

python

from collections import Counter

def euclidean_distance(a, b):
    return np.sqrt(np.sum((a - b)**2))

class KNN:
    def __init__(self, k=3):
        self.k = k
        self.X_train = None
        self.y_train = None

    def fit(self, X, y):
        self.X_train = X
        self.y_train = y

    def predict(self, X):
        preds = []
        for sample in X:
            distances = [euclidean_distance(sample, x_train) for x_train in self.X_train]
            k_indices = np.argsort(distances)[:self.k]
            k_labels = [self.y_train[i] for i in k_indices]
            preds.append(Counter(k_labels).most_common(1)[0][0])
        return np.array(preds)

注意事项:KNN 对特征尺度敏感,务必进行标准化;K 值过小易过拟合,过大易欠拟合。


5. 支持向量机(SVM)—— 寻找最大间隔的防线

原理

SVM 寻找一个超平面,使得两类样本到该平面的 最小距离(间隔)最大化。对于线性不可分数据,通过 核函数 映射到高维空间。经典核有 RBF、多项式等。

代码片段(线性 SVM 的软间隔——使用 SGD)

实际中很少手动实现 SVM 优化(涉及二次规划),但可以用梯度下降近似解决线性 SVM 的合页损失。

def hinge_loss(w, b, X, y, C=1.0):
    n_samples = X.shape[0]
    margins = y * (X @ w + b)
    loss = 0.5 * np.dot(w, w) + C * np.sum(np.maximum(0, 1 - margins))
    return loss / n_samples

# 梯度下降更新(省略完整类,仅示意)
# dw = w - C * X[y * (X@w+b) < 1].T @ y[y*(X@w+b)<1]   (简化版)

实战中请直接用 sklearn.svm.SVC,选择合适核函数并调节 C 和 gamma。注意数据标准化是 SVM 的“生死线”。


6. K-Means 聚类 —— 无监督的分组艺术

原理

K-Means 将数据划分为 K 个簇,每个簇由簇中心(质心)代表。迭代过程:分配样本到最近质心 → 更新质心为簇均值,直至收敛。

代码片段(完整实现)

class KMeans:
    def __init__(self, k=3, max_iters=100):
        self.k = k
        self.max_iters = max_iters
        self.centroids = None

    def fit(self, X):
        # 随机初始化质心
        indices = np.random.choice(len(X), self.k, replace=False)
        self.centroids = X[indices]
        for _ in range(self.max_iters):
            # 分配簇
            distances = np.linalg.norm(X[:, np.newaxis] - self.centroids, axis=2)
            labels = np.argmin(distances, axis=1)
            # 更新质心
            new_centroids = np.array([X[labels == i].mean(axis=0) for i in range(self.k)])
            if np.allclose(self.centroids, new_centroids):
                break
            self.centroids = new_centroids
        return labels

实战要点:K 值选择常用“肘部法则”;初始质心影响较大,可多次运行取最优(sklearn 默认 n_init=10)。


综合实战指南

1. 数据预处理(比算法更重要)

  • 缺失值处理:删除或中位数/众数填充。
  • 标准化(Z-score)或 归一化(Min-Max)—— 对 KNN、SVM、逻辑回归尤为关键。
  • 类别编码:One-Hot 或 LabelEncoder。
  • 训练/测试拆分:保持分层(分类问题用 stratify)。

2. 模型选择与调参

  • 小数据集(<10万样本):优先尝试逻辑回归、线性 SVM 或决策树。
  • 中等规模:随机森林(Bagging)或 XGBoost(Boosting)通常更强。
  • 文本/图像高维数据:线性 SVM 或朴素贝叶斯可作为基线。
  • 调参使用 GridSearchCV 或 RandomizedSearchCV,注意交叉验证。

3. 评估指标

  • 分类:准确率、精确率/召回率、F1、AUC-ROC。
  • 回归:MSE、MAE、R²。
  • 聚类:轮廓系数、Calinski-Harabasz 指数。

4. 完整流水线示例(使用 sklearn)

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('clf', LogisticRegression(max_iter=1000))
])
pipeline.fit(X_train, y_train)
print("Test accuracy:", pipeline.score(X_test, y_test))
print("CV score:", cross_val_score(pipeline, X_train, y_train, cv=5).mean())

最后的话

经典算法并非“过时之物”,而是 AI 大厦的基石。掌握它们,你才能真正理解偏差-方差权衡、正则化、核技巧、维度灾难等核心概念。这些思想在深度学习中同样适用。

编程实战的真正意义在于:手写一次代码,胜过阅读十遍公式。本文提供的代码片段均为“教育版”,生产环境请直接使用 sklearnXGBoost 等成熟库,但请务必理解其背后的优化细节。

祝你编程愉快,学有所成!