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

news2024/11/26 0:57:00

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

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

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

大家共勉!

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

目录

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.coloradmin.cn/o/1873394.html

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

相关文章

华为HCIP Datacom H12-821 卷18

1.问答题 (拖拽题)如图所示,请根据 DHCPv6 的四歩交互流程, 将报文按照顺序拖拽到相应的位置 参考答案: 1--solicit ,2--advertise , 3--equest, 4--reply 解析: DHCPv6的报文交互流程,类似于V4,先组播发现,服

二叉树的方法

目录 一、二叉树的定义 ​编辑 二、二叉树的创建 三、二叉树的遍历 1、前序遍历 2、中序遍历 3、后序遍历 4、层序遍历 四、二叉树遍历方法的使用 五、二叉树的操作 1、节点的个数 2、叶子节点的个数 3、第k层节点的个数 4、二叉树的高度 5、检查值为value的元素…

自动化巡检革命:旗晟双圆管轨道机器人的创新应用

在输煤皮带线和矿山带式输送机的巡检过程中&#xff0c;面临着高湿度、多粉尘、温湿度极端、噪音干扰&#xff1b;设备磨损频繁&#xff0c;难以及时发现问题&#xff1b;传统的人工巡检方式存在劳动强度大、效率低、检测质量不稳定、数据采集和分析滞后&#xff0c;无法实现实…

Promise 类的方法简介

文章目录 Promise.resolve() 和 Promise.reject()resolve()和reject()的参数 Promise.all()Promise.all()案例&#xff1a;多张图片上传Promse.allSettled()Promise.race()Promise.race()举例&#xff1a;图片加载超时Promise.race()举例&#xff1a;网络请求超时Promise.any()…

第4章 客户端-客户端管理

1. 客户端API 1.1client list client list命令能列出与Redis服务端相连的所有客户端连接信息。 127.0.0.1:6379> client list id254487 addr10.2.xx.234:60240 fd1311 name age8888581 idle8888581 flagsN db0 sub0 psub0 multi-1 qbuf0 qbuf-free0 obl0 oll0 omem0 events…

硬件实用技巧:摄像头常用的输出协议类型和输出接口类型

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/140042485 长沙红胖子Qt&#xff08;长沙创微智科&#xff09;博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV…

07-border布局的另一个用处

07-border布局的另一个用处 实现如下的布局: 分析: 1.USERNAME和PASSWORD使用form 2.PASSWORD的文本框使用NewMultiLineEntry 布局1 USERNAME和PASSWORD作为一个form整体&#xff0c;使用border布局&#xff0c;form设置为top&#xff0c;文本框设置为center参数。 packa…

Linux挂载Windows共享文件

一、Windows共享目录 二、Linux挂载 yum install cifs-utils mkdir /aaa/ mount.cifs -o usernamexxx,passwordxxx //172.16.8.121/aaa /aaa/

昇思25天学习打卡营第3天|数据集全攻略:加载、操作与自定义

导入数据集相关库和类 首先&#xff0c;导入了 NumPy 库&#xff0c;并将其简称为 np 。要知道&#xff0c;NumPy 乃是用于科学计算的关键库&#xff0c;作用非凡。接着&#xff0c;从 mindspore.dataset 当中导入了 vision 模块。此外&#xff0c;还从 mindspore.dataset 里引…

感染与疾病,感染的逐步进阶以及伴随的疾病发展

病原微生物和/或有害微生物成功入侵、繁殖并定居于宿主的体内或体内&#xff0c;从而导致健康障碍&#xff0c;称为感染。简单地说&#xff0c;它可以定义为由微生物引起的疾病。感染也被称为传染病或传染病或传染性疾病。 感染每年导致 1300多万 人死亡&#xff1b;2019 年死亡…

Liunx部署java项目Tomcat、Redis、Mysql教程

常用命令 查看,停止服务 服务进程情况&#xff0c;这里拿redis服务举例,其他服务查询更改名字即可 ps -ef|grep redis端口号是否被占用 lsof -i :6379显示tcp的端口和进程等相关情况 netstat -tnlp强制停止服务 kill -9 pidnum 防火墙 查看是否安装了firewalld sudo system…

Open WebUI升级到最新版本

背景介绍 open-webui是一个用于构建Web用户界面的开源库&#xff0c;它仿照 ChatGPT 的图形化界面&#xff0c;可以非常方便的调试、调用本地大语言模型。 目前该开源库更新较为活跃&#xff0c;从3个月前的版本&#xff08;v0.1.108&#xff09;到截止到2024年6月中旬发布的…

全网最详细Gradio教程系列——Gradio的安装与运行

全网最详细Gradio教程系列——Gradio的安装与运行 前言实战导论&#xff1a;2. Gradio的安装与运行2.1 安装2.1.1 Windows安装Gradio2.1.2 MacOS/Linux安装Gradio 2.2 运行2.2.1 普通方式运行2.2.2 热重载运行2.2.2.1 命令行式热重载2.2.2.2 Notebook热重载2.2.2.3 控制热重载 …

【LLM 论文】Self-Refine:使用 feedback 迭代修正 LLM 的 output

论文&#xff1a;Self-Refine: Iterative Refinement with Self-Feedback ⭐⭐⭐⭐ CMU, NeurIPS 2023, arXiv:2303.17651 Code: https://selfrefine.info/ 论文速读 本文提出了 Self-Refine 的 prompt 策略&#xff0c;可以在无需额外训练的情况下&#xff0c;在下游任务上产…

Python应用开发——30天学习Streamlit Python包进行APP的构建(11)

st.bokeh_chart 显示互动式虚化图。 Bokeh 是 Python 的一个图表库。此函数的参数与 Bokeh 的 show 函数的参数非常接近。有关 Bokeh 的更多信息,请访问 https://bokeh.pydata.org。 要在 Streamlit 中显示 Bokeh 图表,请在调用 Bokeh 的 show 时调用 st.bokeh_chart。 Fu…

Jmeter 进行http接口测试

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 本文主要针对http接口进行测试&#xff0c;使用 jmeter工具实现。 Jmeter工具设计之初是用于做性…

Qt项目实战[MP3音乐播放器搜索引擎]

MP3音乐播放器搜索引擎(设计与实现) 一、MP3音乐播放器搜索引擎(开发环境) 1:操作系统: Windows10 x64专业版。 2:开发工具: Qt 5.12.8。 3:网易云音乐官方API接口: https://neteasecloudmusicapi.js.org/#/?id%e7%99%bb%e5%bd%95 二、MP3音乐播放器搜索引擎(功能模块) …

动手学深度学习(Pytorch版)代码实践 -计算机视觉-40目标检测和边界框

40目标检测和边界框 import torch from PIL import Image import matplotlib.pylab as plt from d2l import torch as d2lplt.figure(catdog) img Image.open(../limuPytorch/images/catdog.jpg) plt.imshow(img) plt.show()# 边界框 #save def box_corner_to_center(boxes):…

HSRP热备份路由协议(VRRP虚拟路由冗余协议)配置以及实现负载均衡

1、相关原理 在网络中&#xff0c;如果一台作为默认网关的三层交换机或者路由器损坏&#xff0c;所有使用该网关为下一跳的主机通信必然中断&#xff0c;即使配置多个默认网关&#xff0c;在不重启终端的情况下&#xff0c;也不能彻底换到新网关。Cisco提出了HSRP热备份路由协…

写一个坏越的小世界(六)

blog基本已经接近尾声了&#xff0c;稍微再润色下。比如天气模块 这边加一个天气小图标&#xff0c;应该会好点吧~ 当不同天气的时候可以显示不同的图标 介绍这边加了个滚球特效。虽然看着还不是很好看&#xff0c;先凑合着吧 整了个开关灯按钮&#xff0c;可以切换黑白主题 …