本篇存在大量的公式,数学不好的孩子们要开始恶补数学了,尤其是统计学和回归方程类的内容。
小伙伴们量力而行~~~~~
游戏呢,其实最早就是数学家、元祖程序员编写的数学游戏,一脉相承传承至今,囊括了更多的设计师、美术家、音乐家、作家、导演、演员等等,发展形成了今天大家看到的繁花般的多彩游戏世界。作为游戏工作者特别是游戏算法程序员,我们应当不停的学习数学知识,满足应用需求哦
大家共勉!
(后面算法先给出些简单示例和伪代码,可能有些来不及写完,后续逐步补充)
目录
[4. 最常见的机器学习算法](#4. 最常见的机器学习算法)
[4.1. 线性回归(Linear Regression)](#4.1. 线性回归(Linear Regression))
[4.2. 逻辑回归(Logistic Regression)](#4.2. 逻辑回归(Logistic Regression))
[4.2.1. 逻辑回归模型](#4.2.1. 逻辑回归模型)
[4.2.2. 损失函数](#4.2.2. 损失函数)
[4.2.3. 优化方法](#4.2.3. 优化方法)
[4.2.4. 算法示例](#4.2.4. 算法示例)
[4.3. 决策树(Decision Tree)](#4.3. 决策树(Decision Tree))
[4.3.1. 特征选择](#4.3.1. 特征选择)
[4.3.2. 决策树生成](#4.3.2. 决策树生成)
[4.3.3. 决策树剪枝](#4.3.3. 决策树剪枝)
[4.3.4. 算法示例](#4.3.4. 算法示例)
[4.4. 支持向量机(Support Vector Machine, SVM)](#4.4. 支持向量机(Support Vector Machine, SVM))
[4.4.1. SVM 的主要概念](#4.4.1. SVM 的主要概念)
[4.4.2. SVM 的优点](#4.4.2. SVM 的优点)
[4.4.3. 算法示例](#4.4.3. 算法示例)
[C++ 算法示例](#C++ 算法示例)
[4.5. 朴素贝叶斯(Naive Bayes)](#4.5. 朴素贝叶斯(Naive Bayes))
[4.5.1. 算法介绍](#4.5.1. 算法介绍)
[4.5.2. 算法示例](#4.5.2. 算法示例)
[4.6. k-近邻算法(K-Nearest Neighbors, KNN)](#4.6. k-近邻算法(K-Nearest Neighbors, KNN))
[4.6.1. k-近邻算法介绍](#4.6.1. k-近邻算法介绍)
[4.6.2. k-近邻算法步骤](#4.6.2. k-近邻算法步骤)
[4.6.3. 算法示例](#4.6.3. 算法示例)
[4.7. k-平均算法(K-Means)](#4.7. k-平均算法(K-Means))
[4.7.1. k-平均算法介绍](#4.7.1. k-平均算法介绍)
[4.7.2. k-平均算法步骤](#4.7.2. k-平均算法步骤)
[4.7.3. 算法示例](#4.7.3. 算法示例)
[4.8. 庆祝下](#4.8. 庆祝下)
4. 最常见的机器学习算法
最常见的机器学习算法包括线性回归、逻辑回归、支持向量机、决策树、随机森林、神经网络(包括卷积神经网络)等。机器学习的基础算法及其示例可以归纳为以下几点:
4.1. 线性回归(Linear Regression)
- 基础概念:线性回归是一种用于预测数值类型的机器学习算法,通过建立自变量和因变量之间的线性关系模型来进行预测。
- 算法示例:北京房价预测。通过收集房屋的各种特征(如面积、房间数等),使用线性回归模型来预测房价。
线性回归(Linear Regression)是一种统计学上的预测分析,用于估计两个或多个变量之间的关系。在线性回归中,目标变量(因变量)被预测为自变量的线性组合。简单来说,线性回归试图找到一条最佳拟合直线,使得预测值与实际值之间的残差平方和最小。
线性回归模型可以表示为:
其中是因变量,是自变量,是回归系数,是误差项。
Python 算法示例
在 Python 中,我们通常使用 sklearn 库来进行线性回归。以下是一个简单的示例:
python
from sklearn.linear_model import LinearRegression
import numpy as np
# 创建一些样本数据
X = np.array([[1], [2], [3], [4], [5]]) # 自变量
y = np.array([2, 4, 6, 8, 10]) # 因变量
# 创建一个线性回归模型对象
model = LinearRegression()
# 使用样本数据训练模型
model.fit(X, y)
# 使用模型进行预测
X_test = np.array([[6], [7]])
y_pred = model.predict(X_test)
print("预测值:", y_pred)
C++ 算法示例
在 C++ 中,你可能需要手动实现线性回归算法。以下是一个简单的示例,使用最小二乘法求解回归系数:
cpp
#include <iostream>
#include <vector>
#include <Eigen/Dense>
int main() {
// 样本数据
Eigen::MatrixXd X(5, 2); // 5个样本,每个样本有1个自变量和1个截距项(全为1)
X << 1, 1,
1, 2,
1, 3,
1, 4,
1, 5;
Eigen::VectorXd y(5); // 5个因变量值
y << 2, 4, 6, 8, 10;
// 使用最小二乘法求解回归系数 (beta = (X'X)^(-1)X'y)
Eigen::VectorXd beta = X.transpose() * X).inverse() * X.transpose() * y;
// 输出回归系数
std::cout << "回归系数: " << beta.transpose() << std::endl;
// 使用模型进行预测
Eigen::MatrixXd X_test(2, 2); // 2个测试样本,每个样本有1个自变量和1个截距项(全为1)
X_test << 1, 6,
1, 7;
Eigen::VectorXd y_pred = X_test * beta; // 进行预测
// 输出预测值
std::cout << "预测值: " << y_pred.transpose() << std::endl;
return 0;
}
注意:C++ 示例中使用了 Eigen 库来进行矩阵运算。你需要先安装 Eigen 库才能编译和运行此代码。你可以从 Eigen 官网下载和安装 Eigen。
这两个示例都展示了如何使用线性回归模型进行简单的预测。Python 示例使用了 scikit-learn: machine learning in Python --- scikit-learn 1.5.0 documentation 库,而 C++ 示例则使用了 Eigen 库来进行矩阵运算。
4.2. 逻辑回归(Logistic Regression)
- 基础概念:逻辑回归是一种用于分类问题的机器学习算法,特别适用于二分类问题。它通过将数据映射到概率空间来进行建模。
- 算法示例:信用卡欺诈检测。通过分析信用卡交易数据,使用逻辑回归模型来预测某笔交易是否为欺诈行为。
逻辑回归(Logistic Regression)是一种广义的线性模型,用于解决二分类问题。它使用逻辑函数(也称为Sigmoid函数)将线性回归的输出映射到0和1之间,从而表示概率。逻辑回归的名字中虽然有"回归",但它实际上是一种分类算法。
4.2.1. 逻辑回归模型
逻辑回归的模型可以表示为:
其中,是权重向量, 是特征向量,是偏置项。这个函数将线性回归的输出 通过Sigmoid函数映射到0和1之间,表示给定特征 下,的概率。
4.2.2. 损失函数
逻辑回归通常使用交叉熵损失函数(Cross-Entropy Loss):
其中,是样本数量,是第个样本的真实标签(0或1),是模型预测的第 个样本为正类的概率。
4.2.3. 优化方法
逻辑回归通常使用梯度下降法(Gradient Descent)或其变种(如随机梯度下降SGD、小批量梯度下降Mini-Batch GD等)来优化损失函数。
4.2.4. 算法示例
Python算法示例
在Python中,我们可以使用scikit-learn
库中的LogisticRegression
类来实现逻辑回归:
python
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 加载数据集
iris = load_iris()
X = iris.data
y = iris.target
# 将多分类问题简化为二分类问题
y = (y != 0) * 1
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建逻辑回归模型并训练
model = LogisticRegression(max_iter=1000)
model.fit(X_train, y_train)
# 预测测试集并计算准确率
y_pred = model.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy}")
C++算法示例
在C++中,我们可以使用mlpack
库可以从mlpack - Home官网获取哦(一个C++机器学习库)来实现逻辑回归。以下是一个简化的示例:
cpp
#include <mlpack/core.hpp>
#include <mlpack/methods/logistic_regression/logistic_regression.hpp>
#include <mlpack/methods/logistic_regression/logistic_regression_function.hpp>
using namespace mlpack;
using namespace mlpack::regression;
using namespace mlpack::optimization;
int main() {
// 假设你已经有了一些训练数据X_train和y_train
arma::mat X_train; // 特征数据,大小为N x D(N个样本,D个特征)
arma::Row<size_t> y_train; // 标签数据,大小为1 x N
// 创建并训练逻辑回归模型
LogisticRegressionFunction<> lrf(X_train, y_train, 0.01); // 0.01是正则化参数
LBFGS<LogisticRegressionFunction<> > optimizer;
arma::vec parameters; // 模型参数将被存储在这里
optimizer.Optimize(lrf, parameters); // 训练模型
// 使用训练好的模型进行预测
LogisticRegression<> model(parameters);
arma::Row<size_t> predictions;
model.Predict(X_train, predictions); // 对训练集进行预测,仅作为示例
// 计算准确率等性能指标...
// ...
return 0;
}
注意:上述C++示例代码是一个简化的模板,用于说明如何在C++中使用逻辑回归。在实际应用中,你可能需要处理数据加载、预处理、模型评估等多个方面。此外,mlpack
库可能需要单独安装和配置。
4.3. 决策树(Decision Tree)
- 基础概念:决策树是一种基于树状结构的分类和回归算法,通过对数据集进行递归分割来形成决策规则。
- 算法示例:风险评估。游戏中可以用来评估玩家继续游戏的欲望程度,采取降低难度、给与奖励或激励,或提升难度,给与更大奖励刺激,以及及时给出充值付费买道具等等措施。
决策树(Decision Tree)是一种基本的分类与回归方法,它可以被认为是一个树形结构,每个内部节点表示一个属性上的判断条件,每个分支代表一个判断结果的输出,每个叶子节点代表一种分类结果。决策树学习通常包括三个步骤:特征选择、决策树生成和决策树剪枝。
4.3.1. 特征选择
特征选择在于选取对训练数据具有分类能力的特征,常用的准则有信息增益(如ID3算法)、信息增益比(如C4.5算法)和基尼指数(如CART算法)。
4.3.2. 决策树生成
根据选择的特征评估准则,从上至下递归地生成子节点,直到数据集不可分则停止。
4.3.3. 决策树剪枝
决策树容易过拟合,一般通过剪枝来简化决策树,防止过拟合。剪枝有预剪枝和后剪枝两种方法。
4.3.4. 算法示例
Python算法示例
在Python中,我们可以使用scikit-learn
库中的DecisionTreeClassifier
来实现决策树分类:
python
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score
# 加载数据集
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)
# 创建决策树模型并训练
clf = DecisionTreeClassifier(random_state=42)
clf.fit(X_train, y_train)
# 预测测试集并计算准确率
y_pred = clf.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy}")
C++算法示例
在C++中,实现决策树算法通常比较复杂,因为需要手动处理数据的加载、预处理、特征选择、树的构建和剪枝等步骤。不过,有一些库如mlpack
也提供了决策树的实现。以下是一个使用mlpack
的简化示例:
cpp
#include <mlpack/methods/decision_tree/decision_tree.hpp>
#include <mlpack/core/data/load.hpp>
using namespace mlpack;
using namespace mlpack::tree;
using namespace mlpack::data;
int main()
{
// 加载数据集(假设数据集是CSV格式,且最后一列是标签)
arma::mat data;
arma::Row<size_t> labels;
Load("dataset.csv", data, true); // 假设数据集文件名为dataset.csv
labels = data.row(data.n_rows - 1);
data.shed_row(data.n_rows - 1);
// 划分训练集和测试集(这里简化为只使用前80%作为训练集)
size_t trainSize = data.n_cols * 0.8;
arma::mat trainData = data(:, arma::span(0, trainSize - 1));
arma::Row<size_t> trainLabels = labels(arma::span(0, trainSize - 1));
// 创建并训练决策树模型
const size_t numClasses = 3; // 假设是3分类问题
const size_t minimumLeafSize = 10;
DecisionTree<> dt(trainData, trainLabels, numClasses, minimumLeafSize);
// 使用训练好的模型进行预测(这里简化为对训练集自身进行预测)
arma::Row<size_t> predictions;
dt.Classify(trainData, predictions);
// 计算准确率等性能指标...
// ...
return 0;
}
请注意,C++示例代码是一个高度简化的模板,用于说明如何在C++中使用决策树。在实际应用中,数据集的加载、预处理、模型评估和性能度量等步骤可能更加复杂。另外,mlpack
库可能需要单独安装和配置。如果你打算在生产环境中使用C++实现决策树,可能需要考虑更多细节和异常处理。
如果你希望完全从底层实现决策树算法,那么你需要手动编写代码来处理决策树的构建、特征选择、树的遍历以及剪枝等操作,这通常需要对算法和数据结构有深入的理解。
4.4. 支持向量机(Support Vector Machine, SVM)
- 基础概念:支持向量机是一种二分类和多分类的监督学习算法,通过构建超平面或超曲面来实现分类。
- 算法示例:图像识别。在图像处理领域,SVM 可以用于识别手写数字、人脸识别等任务。
支持向量机(Support Vector Machine, SVM)是一种非常流行的监督学习算法,主要用于分类和回归分析。SVM 的主要思想是在高维空间中寻找一个最优超平面,这个超平面能够将不同类别的数据点分隔开,并且使得两侧距离超平面最近的点(即支持向量)到超平面的间隔最大化。
4.4.1. SVM 的主要概念
-
支持向量:是数据集中距离决策边界(超平面)最近的点,这些点对确定决策边界起到了关键作用。
-
间隔(Margin):是指支持向量到决策边界的距离,SVM 的目标是最大化这个间隔。
-
核函数:当数据不是线性可分的时候,可以通过核函数将数据映射到更高维的空间,使其在新的空间中线性可分。
-
软间隔与硬间隔:硬间隔是指所有数据点都必须严格分类正确,不允许有错误分类;而软间隔则允许一些数据点被错误分类,通过引入惩罚项来控制错误分类的程度。
4.4.2. SVM 的优点
- 在高维空间中表现良好。
- 只使用部分训练数据(支持向量)来做决策,使得模型更加高效。
- 可以使用不同的核函数来处理非线性问题。
4.4.3. 算法示例
Python 算法示例
在 Python 中,通常使用 scikit-learn
库来应用 SVM 算法。
python
from sklearn import svm
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 加载数据集
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)
# 创建 SVM 分类器
clf = svm.SVC(kernel='linear', C=1.0, random_state=42)
# 训练模型
clf.fit(X_train, y_train)
# 预测测试集
y_pred = clf.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy}")
C++ 算法示例
在 C++ 中,可以使用一些机器学习库,如 mlpack
或 OpenCV
,来实现 SVM。以下是一个使用 OpenCV
OpenCV - Open Computer Vision Library 的 SVM 示例:
cpp
#include <opencv2/opencv.hpp>
#include <opencv2/ml/ml.hpp>
#include <iostream>
int main() {
// 加载数据(这里只是一个示例,实际数据需要自行准备)
cv::Mat_<float> trainingData(4, 2); // 4个样本,每个样本2个特征
cv::Mat_<int> labels(4, 1); // 4个标签
// 填充数据和标签(仅为示例)
trainingData << 501, 10, 255, 10, 501, 255, 10, 501;
labels << 1, -1, -1, 1;
// 创建 SVM 对象
cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::create();
svm->setType(cv::ml::SVM::C_SVC);
svm->setC(0.1);
svm->setKernel(cv::ml::SVM::LINEAR);
svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER, 100, 1e-6));
// 训练 SVM
svm->train(trainingData, cv::ml::ROW_SAMPLE, labels);
// 预测
cv::Mat_<float> sample(1, 2);
sample << 400, 150; // 测试样本
float response = svm->predict(sample)[0];
std::cout << "Prediction for sample [" << sample << "] is: " << response << std::endl;
return 0;
}
在这个 C++ 示例中,我们使用了 OpenCV 库来创建和训练一个 SVM 模型。需要注意的是,OpenCV 中的 SVM 实现与 scikit-learn 略有不同,特别是在参数设置和接口方面。你需要根据你的具体数据和任务来调整这些参数。
在使用这些代码之前,请确保你已经正确安装了所需的库(如 scikit-learn
或 OpenCV
),并根据你的环境和数据集调整代码。
4.5. 朴素贝叶斯(Naive Bayes)
- 基础概念:朴素贝叶斯算法是基于贝叶斯定理和特征条件独立性假设的分类算法。
- 算法示例:垃圾邮件过滤。通过分析邮件内容中的关键词,使用朴素贝叶斯模型来判断一封邮件是否为垃圾邮件。
4.5.1. 算法介绍
朴素贝叶斯算法基于以下两个核心思想:
贝叶斯定理:用于计算后验概率,即在已知某些特征的情况下,样本属于某个类别的概率。
特征条件独立假设:朴素贝叶斯假设各个特征之间相互独立,这是算法"朴素"之名的由来。尽管这个假设在实际应用中往往不成立,但朴素贝叶斯算法在很多情况下仍然表现良好。
算法步骤如下:
数据准备:准备训练数据集,包括特征和对应的类别标签。
计算先验概率:计算每个类别在训练数据中出现的概率。
计算条件概率:对于每个特征,计算它在每个类别中出现的概率。
应用贝叶斯定理:对于新的数据样本,使用贝叶斯定理和前面计算得到的先验概率及条件概率,计算该样本属于每个类别的后验概率。
分类决策:将样本分类到后验概率最大的类别中。
4.5.2. 算法示例
Python算法示例
在Python中,可以使用scikit-learn
库中的GaussianNB
(适用于连续特征)或MultinomialNB
(适用于离散特征)等实现朴素贝叶斯分类器。以下是一个使用GaussianNB
的示例:
python
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import accuracy_score
# 加载数据集
iris = load_iris()
X, y = iris.data, iris.target
# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建并训练朴素贝叶斯分类器
gnb = GaussianNB()
gnb.fit(X_train, y_train)
# 预测测试集并计算准确率
y_pred = gnb.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy}")
C++算法示例
在C++中实现朴素贝叶斯算法通常需要手动编写更多的代码,因为C++标准库没有直接提供机器学习算法。以下是一个简化的朴素贝叶斯分类器的C++示例,仅用于说明基本概念:
cpp
#include <iostream>
#include <vector>
#include <map>
// 假设特征只有一维,且为离散值
struct DataPoint {
int feature;
int label;
};
class NaiveBayesClassifier {
private:
std::map<int, int> classCounts; // 类别计数
std::map<int, std::map<int, int>> featureCounts; // 特征在每个类别的计数
std::map<int, int> totalFeatureCounts; // 每个类别的总特征计数
public:
void train(const std::vector<DataPoint>& data) {
for (const auto& point : data) {
// 更新类别计数
classCounts[point.label]++;
// 更新特征计数
featureCounts[point.label][point.feature]++;
// 更新每个类别的总特征计数
totalFeatureCounts[point.label]++;
}
}
int predict(int feature) {
int bestClass = -1;
double maxProbability = 0.0;
for (const auto& classCount : classCounts) {
int classLabel = classCount.first;
int classTotalCount = classCount.second;
int featureCountInClass = featureCounts[classLabel][feature];
double probability = static_cast<double>(featureCountInClass + 1) / (totalFeatureCounts[classLabel] + 2); // 使用拉普拉斯平滑
if (probability > maxProbability) {
maxProbability = probability;
bestClass = classLabel;
}
}
return bestClass;
}
};
int main() {
NaiveBayesClassifier classifier;
std::vector<DataPoint> trainingData = {
{1, 0}, {2, 0}, {1, 1}, {2, 1}, {3, 1}, {2, 0}
};
classifier.train(trainingData);
int prediction = classifier.predict(2);
std::cout << "Predicted class for feature 2: " << prediction << std::endl;
return 0;
}
请注意,这个C++示例非常简化,仅用于教学目的。在实际应用中,朴素贝叶斯分类器可能需要处理多维特征和连续特征,这会增加实现的复杂性。此外,为了提高性能和准确性,可能还需要进行特征选择、特征转换和模型评估等步骤。
4.6. k-近邻算法(K-Nearest Neighbors, KNN)
- 基础概念:KNN 是一种基于实例的学习算法,通过计算新数据与训练数据集中数据点之间的距离来找到最近的 k 个邻居,并根据这些邻居的类别来确定新数据的类别。
- 算法示例:手写数字识别。可以使用 KNN 算法来识别手写数字图像。
4.6.1. k-近邻算法介绍
k-近邻算法(k-Nearest Neighbors,简称k-NN)是一种基于实例的学习算法,它的基本思想是通过测量不同数据点之间的距离进行分类。在k-NN中,一个对象的分类是由其邻居的"多数表决"确定的,k个最近邻居(k为正整数,通常较小)中最常见的分类决定了赋予该对象的类别。若k=1,则该对象的类别直接由最近的一个节点赋予。
4.6.2. k-近邻算法步骤
- 计算距离:对于未知分类的数据,计算它到每个已知分类数据之间的距离。
- 寻找邻居:按照距离的递增关系进行排序,然后选择距离最小的k个点。
- 确定类别:确定前k个点所在类别的出现频率,返回前k个点出现频率最高的类别作为预测分类。
4.6.3. 算法示例
Python算法示例
在Python中,我们可以使用scikit-learn
库中的KNeighborsClassifier
来实现k-NN算法。以下是一个简单的示例:
python
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
# 加载iris数据集
iris = datasets.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)
# 数据标准化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
# 创建k-NN分类器,并设置邻居数为3
knn = KNeighborsClassifier(n_neighbors=3)
# 训练模型
knn.fit(X_train, y_train)
# 预测测试集
y_pred = knn.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Accuracy: {accuracy}")
C++算法示例
在C++中实现k-NN算法需要手动编写距离计算、排序和分类的逻辑。以下是一个简化的k-NN分类器的C++示例:
cpp
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <limits>
struct Point {
std::vector<double> features;
int label;
};
double euclideanDistance(const std::vector<double>& a, const std::vector<double>& b) {
double sum = 0.0;
for (size_t i = 0; i < a.size(); ++i) {
sum += pow(a[i] - b[i], 2);
}
return sqrt(sum);
}
int kNearestNeighbors(const std::vector<Point>& dataset, const std::vector<double>& point, int k) {
std::vector<std::pair<double, int>> distances; // 存储距离和对应的标签索引
for (size_t i = 0; i < dataset.size(); ++i) {
double dist = euclideanDistance(dataset[i].features, point);
distances.push_back(std::make_pair(dist, i));
}
// 按距离排序
std::sort(distances.begin(), distances.end());
// 统计k个最近邻居的标签
std::map<int, int> labelCounts;
for (int i = 0; i < k; ++i) {
int label = dataset[distances[i].second].label;
labelCounts[label]++;
}
// 找到出现次数最多的标签
int maxCount = 0;
int majorityLabel = -1;
for (const auto& entry : labelCounts) {
if (entry.second > maxCount) {
maxCount = entry.second;
majorityLabel = entry.first;
}
}
return majorityLabel;
}
int main() {
std::vector<Point> dataset = {
{{1, 2}, 1}, {{1, 4}, 1}, {{3, 4}, 2}, {{4, 2}, 2}, {{2, 3}, 1}
};
std::vector<double> queryPoint = {2, 2};
int k = 3; // 设置k值
int predictedLabel = kNearestNeighbors(dataset, queryPoint, k);
std::cout << "Predicted label for point (" << queryPoint[0] << ", " << queryPoint[1] << "): " << predictedLabel << std::endl;
return 0;
}
这个C++示例中,我们定义了一个Point
结构体来存储数据点的特征和标签。euclideanDistance
函数用于计算两个点之间的欧几里得距离。kNearestNeighbors
函数实现了k-NN算法的核心逻辑,包括计算距离、排序、统计标签和确定多数类别。在main
函数中,我们创建了一个简单的数据集,并设置了一个查询点和k值来演示算法的使用。
4.7. k-平均算法(K-Means)
- 基础概念:K-Means 是一种无监督学习算法,用于将数据集中的样本划分为 k 个类别或簇。
- 算法示例:市场细分。通过分析消费者的购买行为等数据,使用 K-Means 算法将消费者划分为不同的群体,以便制定更精准的营销策略。算法可以运用于游戏中游戏世界内商城控制、交易类金额控制,但真的不建议做在真银子换游戏币中,会有被惩罚的可能性哦
4.7.1. k-平均算法介绍
k-平均算法(k-means clustering)是一种非常流行的无监督学习算法,用于将数据点划分为K个集群。该算法的目标是使得每个数据点与其所属集群的中心点之间的距离之和最小。
4.7.2. k-平均算法步骤
- 初始化:选择K个点作为初始集群中心(这些点可以是数据集中的随机点)。
- 分配数据点到最近的集群中心:对于数据集中的每个点,计算它到每个集群中心的距离,并将其分配给最近的集群。
- 重新计算集群中心:对于每个集群,计算所有数据点的平均值,并将这个平均值设为新的集群中心。
- 迭代:重复步骤2和3,直到集群中心不再发生显著变化,或者达到预定的迭代次数。
4.7.3. 算法示例
Python算法示例
在Python中,我们可以使用scikit-learn
库中的KMeans
类来实现k-means算法。以下是一个简单的示例:
python
from sklearn.cluster import KMeans
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)
# 创建KMeans实例,并设置集群数量为4
kmeans = KMeans(n_clusters=4)
# 训练模型
kmeans.fit(X)
# 预测集群标签
labels = kmeans.predict(X)
# 绘制结果
plt.scatter(X[:, 0], X[:, 1], c=labels, s=50, cmap='viridis')
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s=300, c='red', marker='x')
plt.show()
C++算法示例
在C++中实现k-means算法需要手动编写距离计算、集群中心更新和数据点分配的逻辑。以下是一个简化的k-means算法的C++示例:
cpp
#include <iostream>
#include <vector>
#include <cmath>
#include <limits>
#include <ctime>
#include <cstdlib>
struct Point {
double x, y;
int cluster;
};
double distance(const Point& a, const Point& b) {
return std::sqrt(std::pow(a.x - b.x, 2) + std::pow(a.y - b.y, 2));
}
void kMeansClustering(std::vector<Point>& data, int K, int maxIterations) {
srand(time(0)); // 使用当前时间作为随机数生成器的种子
// 初始化集群中心
std::vector<Point> centers(K);
for (int i = 0; i < K; ++i) {
centers[i] = data[rand() % data.size()]; // 随机选择数据点作为初始中心
centers[i].cluster = i; // 设置集群标签
}
bool changed;
int iteration = 0;
do {
changed = false;
// 分配数据点到最近的集群中心
for (auto& point : data) {
double minDist = std::numeric_limits<double>::max();
int closestCenter = -1;
for (int i = 0; i < K; ++i) {
double dist = distance(point, centers[i]);
if (dist < minDist) {
minDist = dist;
closestCenter = i;
}
}
if (point.cluster != closestCenter) {
point.cluster = closestCenter;
changed = true;
}
}
// 重新计算集群中心
if (changed || iteration == 0) {
for (int i = 0; i < K; ++i) {
double sumX = 0, sumY = 0;
int count = 0;
for (const auto& point : data) {
if (point.cluster == i) {
sumX += point.x;
sumY += point.y;
count++;
}
}
if (count > 0) {
centers[i].x = sumX / count;
centers[i].y = sumY / count;
}
}
}
iteration++;
} while (changed && iteration < maxIterations);
}
int main() {
// 示例数据点(在实际应用中,这些数据通常是从文件或数据库中读取的)
std::vector<Point> data = { /* 填充数据点 */ };
const int K = 3; // 集群数量
const int maxIterations = 100; // 最大迭代次数
kMeansClustering(data, K, maxIterations);
// 输出集群结果或进行其他后续处理...
return 0;
}
注意:上述C++示例代码是一个框架性的实现,你需要填充实际的数据点以及可能的其他逻辑来完成k-means算法的实现。在实际应用中,通常还需要添加更多的错误处理和优化。
4.8. 庆祝下
看到这里的小伙伴是壮士,写这些我自己也头秃,下一步加油,这只是刚开始哦~~~~