游戏AI的创造思路-技术基础-机器学习(2)

本篇存在大量的公式,数学不好的孩子们要开始恶补数学了,尤其是统计学和回归方程类的内容。

小伙伴们量力而行~~~~~

游戏呢,其实最早就是数学家、元祖程序员编写的数学游戏,一脉相承传承至今,囊括了更多的设计师、美术家、音乐家、作家、导演、演员等等,发展形成了今天大家看到的繁花般的多彩游戏世界。作为游戏工作者特别是游戏算法程序员,我们应当不停的学习数学知识,满足应用需求哦

大家共勉!

(后面算法先给出些简单示例和伪代码,可能有些来不及写完,后续逐步补充)

目录

4. 最常见的机器学习算法

4.1. 线性回归(Linear Regression)

4.2. 逻辑回归(Logistic Regression)

4.2.1. 逻辑回归模型

4.2.2. 损失函数

4.2.3. 优化方法

4.2.4. 算法示例

4.3. 决策树(Decision Tree)

4.3.1. 特征选择

4.3.2. 决策树生成

4.3.3. 决策树剪枝

4.3.4. 算法示例

4.4. 支持向量机(Support Vector Machine, SVM)

4.4.1. SVM 的主要概念

4.4.2. SVM 的优点

4.4.3. 算法示例

C++ 算法示例

4.5. 朴素贝叶斯(Naive Bayes)

4.5.1. 算法介绍

4.5.2. 算法示例

4.6. k-近邻算法(K-Nearest Neighbors, KNN)

4.6.1. k-近邻算法介绍

4.6.2. k-近邻算法步骤

4.6.3. 算法示例

4.7. k-平均算法(K-Means)

4.7.1. k-平均算法介绍

4.7.2. k-平均算法步骤

4.7.3. 算法示例

4.8. 庆祝下


4. 最常见的机器学习算法

最常见的机器学习算法包括线性回归、逻辑回归、支持向量机、决策树、随机森林、神经网络(包括卷积神经网络)等。机器学习的基础算法及其示例可以归纳为以下几点:

4.1. 线性回归(Linear Regression)

  • 基础概念:线性回归是一种用于预测数值类型的机器学习算法,通过建立自变量和因变量之间的线性关系模型来进行预测。
  • 算法示例:北京房价预测。通过收集房屋的各种特征(如面积、房间数等),使用线性回归模型来预测房价。

线性回归(Linear Regression)是一种统计学上的预测分析,用于估计两个或多个变量之间的关系。在线性回归中,目标变量(因变量)被预测为自变量的线性组合。简单来说,线性回归试图找到一条最佳拟合直线,使得预测值与实际值之间的残差平方和最小。

线性回归模型可以表示为:

(y = \beta_0 + \beta_1x_1 + \beta_2x_2 + ... + \beta_nx_n + \epsilon)

其中(y)是因变量,(x_1, x_2, ..., x_n)是自变量,(\beta_0, \beta_1, ..., \beta_n)是回归系数,(\epsilon)是误差项。

Python 算法示例
在 Python 中,我们通常使用 sklearn 库来进行线性回归。以下是一个简单的示例:

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++ 中,你可能需要手动实现线性回归算法。以下是一个简单的示例,使用最小二乘法求解回归系数:

#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. 逻辑回归模型

逻辑回归的模型可以表示为:

[ P(Y=1|x) = \frac{1}{1 + e^{-(w \cdot x + b)}} ]

其中,( w )是权重向量,( x ) 是特征向量,( b )是偏置项。这个函数将线性回归的输出 ( w \cdot x + b )通过Sigmoid函数映射到0和1之间,表示给定特征 ( x ) 下,( Y=1 )的概率。

4.2.2. 损失函数

逻辑回归通常使用交叉熵损失函数(Cross-Entropy Loss):

[ L(w, b) = -\frac{1}{m} \sum_{i=1}^{m} [y_i \log(p_i) + (1-y_i) \log(1-p_i)] ]

其中,( m )是样本数量,( y_i )是第( i )个样本的真实标签(0或1),( p_i )是模型预测的第 ( i )个样本为正类的概率。

4.2.3. 优化方法

逻辑回归通常使用梯度下降法(Gradient Descent)或其变种(如随机梯度下降SGD、小批量梯度下降Mini-Batch GD等)来优化损失函数。

4.2.4. 算法示例

Python算法示例

在Python中,我们可以使用scikit-learn库中的LogisticRegression类来实现逻辑回归:

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++机器学习库)来实现逻辑回归。以下是一个简化的示例:

#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来实现决策树分类:

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的简化示例:

#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 的主要概念
  1. 支持向量:是数据集中距离决策边界(超平面)最近的点,这些点对确定决策边界起到了关键作用。

  2. 间隔(Margin):是指支持向量到决策边界的距离,SVM 的目标是最大化这个间隔。

  3. 核函数:当数据不是线性可分的时候,可以通过核函数将数据映射到更高维的空间,使其在新的空间中线性可分。

  4. 软间隔与硬间隔:硬间隔是指所有数据点都必须严格分类正确,不允许有错误分类;而软间隔则允许一些数据点被错误分类,通过引入惩罚项来控制错误分类的程度。

4.4.2. SVM 的优点
  • 在高维空间中表现良好。
  • 只使用部分训练数据(支持向量)来做决策,使得模型更加高效。
  • 可以使用不同的核函数来处理非线性问题。
4.4.3. 算法示例

Python 算法示例

在 Python 中,通常使用 scikit-learn 库来应用 SVM 算法。

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。以下是一个使用 OpenCVOpenCV - Open Computer Vision Library 的 SVM 示例:

#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. 算法介绍

朴素贝叶斯算法基于以下两个核心思想:

  1. 贝叶斯定理:用于计算后验概率,即在已知某些特征的情况下,样本属于某个类别的概率。

  2. 特征条件独立假设:朴素贝叶斯假设各个特征之间相互独立,这是算法“朴素”之名的由来。尽管这个假设在实际应用中往往不成立,但朴素贝叶斯算法在很多情况下仍然表现良好。

算法步骤如下:

  1. 数据准备:准备训练数据集,包括特征和对应的类别标签。

  2. 计算先验概率:计算每个类别在训练数据中出现的概率。

  3. 计算条件概率:对于每个特征,计算它在每个类别中出现的概率。

  4. 应用贝叶斯定理:对于新的数据样本,使用贝叶斯定理和前面计算得到的先验概率及条件概率,计算该样本属于每个类别的后验概率。

  5. 分类决策:将样本分类到后验概率最大的类别中。

4.5.2. 算法示例

Python算法示例

在Python中,可以使用scikit-learn库中的GaussianNB(适用于连续特征)或MultinomialNB(适用于离散特征)等实现朴素贝叶斯分类器。以下是一个使用GaussianNB的示例:

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++示例,仅用于说明基本概念:

#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-近邻算法步骤
  1. 计算距离:对于未知分类的数据,计算它到每个已知分类数据之间的距离。
  2. 寻找邻居:按照距离的递增关系进行排序,然后选择距离最小的k个点。
  3. 确定类别:确定前k个点所在类别的出现频率,返回前k个点出现频率最高的类别作为预测分类。
4.6.3. 算法示例

Python算法示例

在Python中,我们可以使用scikit-learn库中的KNeighborsClassifier来实现k-NN算法。以下是一个简单的示例:

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++示例:

#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-平均算法步骤
  1. 初始化:选择K个点作为初始集群中心(这些点可以是数据集中的随机点)。
  2. 分配数据点到最近的集群中心:对于数据集中的每个点,计算它到每个集群中心的距离,并将其分配给最近的集群。
  3. 重新计算集群中心:对于每个集群,计算所有数据点的平均值,并将这个平均值设为新的集群中心。
  4. 迭代:重复步骤2和3,直到集群中心不再发生显著变化,或者达到预定的迭代次数。
4.7.3. 算法示例

Python算法示例

在Python中,我们可以使用scikit-learn库中的KMeans类来实现k-means算法。以下是一个简单的示例:

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++示例:

#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. 庆祝下

看到这里的小伙伴是壮士,写这些我自己也头秃,下一步加油,这只是刚开始哦~~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/860114.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT拖放事件之五:自定义拖放操作-拖动中的修饰符操作

1、效果 2、代码 #include "SelfButton.h" #include <QApplication>SelfButton::SelfButton(QString str ,QWidget* parent):Q

JAVA系列---HttpServletRequest

Servlet 处理 HTTP 请求的流程 一般情况下&#xff0c;浏览器&#xff08;客户端&#xff09;通过 HTTP 协议来访问服务器的资源&#xff0c;Servlet 主要用来处理 HTTP 请求。核心对象有三个 Servlet&#xff1a;提供service()方法处理请求ServletRequest&#xff1a;请求信…

linux中的调试工具gdb

目录 1.背景知识补充 2.使用 知识补充 1.背景知识补充 1.gcc下编译默认是release方式发布的&#xff0c;无法直接进行调试 如果要以debug方式发布&#xff0c;需要携带-g 可以使用grep查询 因为携带debug信息&#xff0c;其文件体积要大一些 2.使用 1.gdb 可执行程序 …

北邮《计算机网络》网络层笔记

文章目录 单词复习网络层前言路由算法&#xff08;构造路由表的算法&#xff09;静态路由算法自适应算法 拥塞控制QoS 服务质量&#xff08;小小的一节&#xff09;网络互联&#xff08;还是小小的一节&#xff09;Internet 单词复习 estimates boot off-line in advance refl…

【PyTorch单点知识】神经元网络模型剪枝prune模块介绍(上,非结构化剪枝)

文章目录 0. 前言1. 剪枝prune主要功能分类2. torch.nn.utils.prune中的方法介绍3. PyTorch实例3.1 BasePruningMethod3.2PruningContainer3.3 identity3.4random_unstructured3.5l1_unstructured 4. 总结 0. 前言 按照国际惯例&#xff0c;首先声明&#xff1a;本文只是我自己…

AI办公自动化:免费批量将英语电子书转成有声书

Edge-TTS是由微软推出的文本转语音Python库&#xff0c;通过微软Azure Cognitive Services转化文本为自然语音。可以作为付费文本转语音TTS服务的替代品&#xff0c;Edge-TTS支持40多种语言和300种声音&#xff0c;提供优质的语音输出 。 edge-tts支持英语、汉语、日语、韩语、…

基于Netron库的PyTorch 2.0模型可视化

【图书推荐】《从零开始大模型开发与微调&#xff1a;基于PyTorch与ChatGLM》_《从零开始大模型开发与微调:基于pytorch与chatglm》-CSDN博客 前面章节带领读者完成了基于PyTorch 2.0的MNIST模型的设计&#xff0c;并基于此完成了MNIST手写体数字的识别。此时可能有读者对我们…

C语言结构体包含结构体

C语言结构体可以包含另一个结构体&#xff1b; 下面通过一个例子看一下&#xff1b; struct Date {int day;int month;int year; };struct Person {char *name;struct Date birthday; }; ...... void CTestView::OnDraw(CDC* pDC) {CTestDoc* pDoc GetDocument();ASSERT_VAL…

C语言 | Leetcode C语言题解之第189题轮转数组

题目&#xff1a; 题解&#xff1a; void swap(int* a, int* b) {int t *a;*a *b, *b t; }void reverse(int* nums, int start, int end) {while (start < end) {swap(&nums[start], &nums[end]);start 1;end - 1;} }void rotate(int* nums, int numsSize, int…

国内邮件推送如何避免拦截?内容优化技巧?

国内邮件推送的平台怎么选择&#xff1f;如何提高邮件推送效果&#xff1f; 邮件营销是企业与客户沟通的重要方式&#xff0c;但在国内邮件推送过程中&#xff0c;邮件被拦截的问题屡见不鲜。为了确保邮件能够顺利送达目标用户&#xff0c;AokSend将探讨一些有效的策略&#x…

【Android】实现图片和视频混合轮播(无限循环、视频自动播放)

目录 前言一、实现效果二、具体实现1. 导入依赖2. 布局3. Banner基础配置4. Banner无限循环机制5. 轮播适配器6. 视频播放处理7. 完整源码 总结 前言 我们日常的需求基本上都是图片的轮播&#xff0c;而在一些特殊需求&#xff0c;例如用于展览的的数据大屏&#xff0c;又想展…

跟着DW学习大语言模型-什么是知识库,如何构建知识库

建立一个高效的知识库对于个人和组织来说非常重要。无论是为了个人学习和成长&#xff0c;还是为了组织的持续创新和发展&#xff0c;一个完善的知识管理系统都是不可或缺的。那么&#xff0c;如何建立一个高效的知识库呢&#xff1f; 在建立知识库之前&#xff0c;首先需要确定…

第3章 小功能大用处-事务与Lua

为了保证多条命令组合的原子性&#xff0c;Redis提供了简单的事务功能以及集成Lua脚本来解决这个问题。 首先简单介绍Redis中事务的使用方法以及它的局限性&#xff0c;之后重点介绍Lua语言的基本使用方法&#xff0c;以及如何将Redis和Lua脚本进行集成&#xff0c;最后给出Red…

项目实训-vue(十三)

项目实训-vue&#xff08;十三&#xff09; 文章目录 项目实训-vue&#xff08;十三&#xff09;1.概述2.处理按钮 1.概述 本篇博客将记录我在图片上传页面中的工作。 2.处理按钮 实现了图片的上传之后&#xff0c;还需要设置具体的上传按钮。 这段代码使用 Element UI 的 …

Spring学习02-[Spring容器核心技术IOC学习]

Spring容器核心技术IOC学习 什么是bean?如何配置bean?Component方式bean配合配置类的方式import导入方式 什么是bean? 被Spring管理的对象就是bean,和普通对象的区别就是里面bean对象里面的属性也被注入了。 如何配置bean? Component方式、bean配合配置类的方式、import…

C语言 | Leetcode C语言题解之第190题颠倒二进制位

题目&#xff1a; 题解&#xff1a; const uint32_t M1 0x55555555; // 01010101010101010101010101010101 const uint32_t M2 0x33333333; // 00110011001100110011001100110011 const uint32_t M4 0x0f0f0f0f; // 00001111000011110000111100001111 const uint32_t M8…

【containerd】Containerd高阶命令行工具nerdctl

前言 对于习惯了使用docker cli的用户来说&#xff0c;containerd的命令行工具ctr使用起来不是很顺手&#xff0c;此时别慌&#xff0c;还有另外一个命令行工具项目nerdctl可供我们选择。 nerdctl是一个与docker cli风格兼容的containerd的cli工具。 nerdctl已经作为子项目加入…

秋招突击——6/24——复习{完全背包问题——买书,状态转换机——股票买卖V}——新作{两数相除,LRU缓存实现}

文章目录 引言复习完全背包问题——买书个人实现 状态转换机——股票买卖V个人实现参考实现 新作两数相除个人实现 新作LRU缓存实现个人实现unordered_map相关priority_queue相关 参考实现自己复现 总结 引言 今天知道拼多多挂掉了&#xff0c;难受&#xff0c;那实习就是颗粒无…

汪汪队短视频:成都柏煜文化传媒有限公司

汪汪队短视频&#xff1a;萌宠与冒险的交织乐章 在数字时代的浪潮中&#xff0c;短视频以其短小精悍、内容丰富的特点&#xff0c;迅速占领了人们的闲暇时光。而在这些琳琅满目的短视频中&#xff0c;有一类作品以其独特的魅力吸引了无数观众的目光&#xff0c;那就是以萌宠为…

单门户上集成多种数据库查询入口

&#xff08;作者&#xff1a;陈玓玏&#xff09; 开源项目&#xff0c;欢迎star哦&#xff0c;https://github.com/tencentmusic/cube-studio 在一家公司&#xff0c;我们通常会有多种数据库&#xff0c;每种数据库因为其特性承担不同的角色&#xff0c;比如mysql这种轻量…