C语言实现K均值聚类

news2024/9/8 23:30:01

K均值聚类(K_means)基础理论

K_means聚类是一种简单且广泛使用的聚类算法,它旨在将数据集中的样本划分为k个不同的聚类,其中k是事先指定的聚类数量,该算法的核心思想是迭代地优化聚类中心,以最小化每个样本与其所属聚类中心之间的距离之和。这个算法的优点是简单易懂、计算效率高,适用于大规模数据集,但是嘞,它需要事先指定聚类数量k,同时这个算法对初始聚类中心的选择敏感,还可能陷入局部最优解,所以在实际使用之前还是需要先考虑使用场景。

计算公式

  • 聚类中心的定义: 对于第 i i i个聚类中心 μ i \mu_i μi,它是一个 d d d维向量,其中 d d d是数据点的维度。在K_means聚类算法中,聚类中心用于表示每个聚类的中心位置,是聚类内所有点的均值。

  • 数据点与聚类中心的距离: 数据点与聚类中心的距离使用欧几里得距离公式计算,即:
    d ( x , μ i ) = ∑ j = 1 d ( x j − μ i j ) 2 d(x, \mu_i) = \sqrt{\sum_{j=1}^{d} (x_j - \mu_{ij})^2} d(x,μi)=j=1d(xjμij)2
    这里:
    x x x是一个 d d d维的数据点,
    μ i \mu_i μi是第 i i i个聚类中心,
    x j x_j xj是数据点 x x x的第 j j j个维度,
    μ i j \mu_{ij} μij是第 i i i个聚类中心的第 j j j个维度。

  • 聚类分配: 对于数据点 x x x,其所属的聚类 c c c是通过计算 x x x与所有聚类中心的距离,并选择距离最小的聚类中心所对应的聚类。具体地,聚类分配满足:
    c = arg ⁡ min ⁡ i d ( x , μ i ) c = \arg\min_{i} d(x, \mu_i) c=argimind(x,μi)
    c c c是使得 d ( x , μ i ) d(x, \mu_i) d(x,μi)最小的 i i i的值。

  • 聚类中心的更新: 在每次迭代中,聚类中心会根据当前聚类内的数据点进行更新。对于第 i i i个聚类,其新的聚类中心 μ i ′ \mu_i' μi是该聚类内所有数据点的均值,即:
    μ i ′ = 1 ∣ C i ∣ ∑ x ∈ C i x \mu_i' = \frac{1}{|C_i|} \sum_{x \in C_i} x μi=Ci1xCix
    其中:
    C i C_i Ci表示第 i i i个聚类内的所有数据点,
    ∣ C i ∣ |C_i| Ci表示第 i i i个聚类内的数据点数量。

  • 算法终止条件: K_Means算法在两种情况下会终止:一是当聚类中心在迭代过程中不再发生变化时,即新的聚类中心与旧的聚类中心相同;二是当达到预定的迭代次数时。在这两种情况下,算法认为已经找到了稳定的聚类结构,并会停止迭代。

选择训练所使用的数据集

iris数据集,全称为安德森鸢尾花卉数据集(Anderson's Iris dataset),是R语言中一个非常经典且广泛使用的数据集,该数据集最初由迷糊老师(Teacher MiHu)收集,用于统计分类和聚类分析。iris数据集包含了150个样本,每个样本代表了不同种类的鸢尾花(Iris)的四个测量值:萼片长度(Sepal.Length)、萼片宽度(Sepal.Width)、花瓣长度(Petal.Length)和花瓣宽度(Petal.Width),以及对应的鸢尾花种类(Species),共有三种:山鸢尾(Setosa)、变色鸢尾(Versicolor)和维吉尼亚鸢尾(Virginica)。
由于iris数据集包含三个不同种类的鸢尾花,且这些种类在特征空间中存在明显的区分,因此非常适合用于练习k_means聚类算法。在实际应用中,k_means聚类算法需要事先指定聚类数k,而在iris数据集中,由于已知存在三个种类,因此可以设定k=3来进行聚类,从而验证聚类效果。
iris数据集的内容如下:
在这里插入图片描述

C语言实现

定义一个结构体iris,包含不同种类的鸢尾花(Iris)的四个测量值:萼片长度(sepal_length)、萼片宽度(sepal_width)、花瓣长度(petal_length)和花瓣宽度(petal_width)和 簇( cluster)

typedef struct {
    double sepal_length;
    double sepal_width;
    double petal_length;
    double petal_width;
    int cluster;
} Iris;

定义一个名为calculate_distance的函数,这个函数接收两个指向 Iris 结构体的指针作为参数,并返回这两个实例之间的欧几里得距离。

double calculate_distance(const Iris *a, const Iris *b) {
    return sqrt(pow(a->sepal_length - b->sepal_length, 2) +
                pow(a->sepal_width - b->sepal_width, 2) +
                pow(a->petal_length - b->petal_length, 2) +
                pow(a->petal_width - b->petal_width, 2));
}

随后定义一个名为assign_to_clusters的函数,将数据集data中的每个数据点分配到最近的聚类中心(centroid),代码中的centroids是一个指向iris结构体数组的指针,该数组包含了当前的聚类中心位置data_size是数据点的总数k聚类中心的数量。

void assign_to_clusters(Iris *data, Iris *centroids, int data_size, int k) {
    for (int i = 0; i < data_size; i++) {
        double min_distance = INFINITY;
        int closest_cluster = 0;
        for (int j = 0; j < k; j++) {
            double distance = calculate_distance(&data[i], &centroids[j]);
            if (distance < min_distance) {
                min_distance = distance;
                closest_cluster = j;
            }
        }
        data[i].cluster = closest_cluster;
    }
}

这段代码定义一个名为update_centroids的函数,其目的是更新K-means聚类算法中的聚类中心位置。

void update_centroids(Iris *data, Iris *centroids, int data_size, int k) {
    int *cluster_counts = (int *)malloc(k * sizeof(int));
    memset(cluster_counts, 0, k * sizeof(int));
    for (int i = 0; i < k; i++) {
        centroids[i].sepal_length = 0;
        centroids[i].sepal_width = 0;
        centroids[i].petal_length = 0;
        centroids[i].petal_width = 0;
    }

    for (int i = 0; i < data_size; i++) {
        int cluster = data[i].cluster;
        centroids[cluster].sepal_length += data[i].sepal_length;
        centroids[cluster].sepal_width += data[i].sepal_width;
        centroids[cluster].petal_length += data[i].petal_length;
        centroids[cluster].petal_width += data[i].petal_width;
        cluster_counts[cluster]++;
    }

    for (int i = 0; i < k; i++) {
        if (cluster_counts[i] > 0) {
            centroids[i].sepal_length /= cluster_counts[i];
            centroids[i].sepal_width /= cluster_counts[i];
            centroids[i].petal_length /= cluster_counts[i];
            centroids[i].petal_width /= cluster_counts[i];
        }
    }

    free(cluster_counts);
}

定义一个k_means函数初始化聚类中心。通过随机选择数据集中的点作为初始聚类中心,这里使用了srand(time(NULL))来初始化随机数生成器,但通常建议在程序开始时只调用一次srand,而不是在每次调用k_means时都调用。
迭代过程:

  • 使用一个do-while循环来重复执行以下步骤,直到达到最大迭代次数或聚类中心不再发生变化。
  • 使用memcpy复制当前聚类中心到old_centroids,以便后续比较。
  • 调用assign_to_clusters函数,将每个数据点分配到最近的聚类中心。
  • 调用update_centroids函数,根据当前分配更新聚类中心的位置。
  • 通过比较old_centroids和centroids检查聚类中心是否发生了变化。
  • 释放old_centroids占用的内存。
void k_means(Iris *data, Iris *centroids, double *cluster_ss, int data_size, int k, int max_iterations) {
    Iris *old_centroids = (Iris *)malloc(k * sizeof(Iris));
    int *cluster_counts = (int *)malloc(k * sizeof(int));

    srand(time(NULL));
    for (int i = 0; i < k; i++) {
        int index = rand() % data_size;
        // 确保选择不同的质心
        while (i > 0 && calculate_distance(&centroids[i], &data[index]) == 0.0) {
            index = rand() % data_size;
        }
        centroids[i] = data[index];
    }


    int iteration = 0;
    do {
        memcpy(old_centroids, centroids, k * sizeof(Iris));
        assign_to_clusters(data, centroids, cluster_counts, cluster_ss, data_size, k);
        update_centroids(data, centroids, cluster_counts, data_size, k);
        iteration++;
    } while (iteration < max_iterations &&
             (memcmp(old_centroids, centroids, k * sizeof(Iris)) != 0));

    free(old_centroids);
    free(cluster_counts);
}

定义一个calculate_global_mean函数计算给定数据集的全局平均值(即所有特征的平均值)。
函数的主要步骤如下:

  • 初始化一个Iris结构体变量global_mean,其所有特征值都设置为0。
  • 遍历数据集,累加每个数据点的特征值到global_mean中。
  • 将累加后的特征值除以数据点的数量,计算出平均值。
  • 返回计算得到的全局平均值。
Iris calculate_global_mean(Iris *data, int data_size) {
    Iris global_mean = {0};
    for (int i = 0; i < data_size; i++) {
        global_mean.sepal_length += data[i].sepal_length;
        global_mean.sepal_width += data[i].sepal_width;
        global_mean.petal_length += data[i].petal_length;
        global_mean.petal_width += data[i].petal_width;
    }
    global_mean.sepal_length /= data_size;
    global_mean.sepal_width /= data_size;
    global_mean.petal_length /= data_size;
    global_mean.petal_width /= data_size;
    return global_mean;
}

定义函数print_cluster_means用于打印聚类中心的均值

void print_cluster_means(Iris *centroids, int k) {  
    printf("集群均值:\n");  
    for (int i = 0; i < k; i++) {  
        printf("集群 %d: Sepal Length: %.2f, Sepal Width: %.2f, Petal Length: %.2f, Petal Width: %.2f\n",  
               i, centroids[i].sepal_length, centroids[i].sepal_width, centroids[i].petal_length, centroids[i].petal_width);  
    }  
}  

定义函数calculate_within_cluster_ss计算所有聚类内部的平方和(Within-Cluster Sum of Squares, WCSS)

double calculate_within_cluster_ss(Iris *data, Iris *centroids, int data_size, int k) {  
    double within_ss = 0.0;  
    for (int i = 0; i < data_size; i++) {  
        within_ss += calculate_distance(&data[i], &centroids[data[i].cluster]) * calculate_distance(&data[i], &centroids[data[i].cluster]);  
    }  
    return within_ss;  
}  

定义calculate_total_ss 函数计算数据集的总平方和(Total Sum of Squares, TSS)

double calculate_total_ss(Iris *data, Iris global_mean, int data_size) {  
    double total_ss = 0.0;  
    for (int i = 0; i < data_size; i++) {  
        total_ss += calculate_distance(&data[i], &global_mean) * calculate_distance(&data[i], &global_mean);  
    }  
    return total_ss;  
}  

定义函数calculate_between_cluster_ss函数计算聚类间的平方和(Between-Cluster Sum of Squares, BSS)

double calculate_between_cluster_ss(Iris *centroids, Iris global_mean, int k) {  
    double between_ss = 0.0;  
    for (int i = 0; i < k; i++) {  
        between_ss += calculate_distance(&centroids[i], &global_mean) * calculate_distance(&centroids[i], &global_mean);  
    }  
    return between_ss;  
}  

加入main主函数的完整版代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

typedef struct {
    double sepal_length;
    double sepal_width;
    double petal_length;
    double petal_width;
    int cluster;
} Iris;

double calculate_distance(const Iris *a, const Iris *b) {
    return sqrt(pow(a->sepal_length - b->sepal_length, 2) +
                pow(a->sepal_width - b->sepal_width, 2) +
                pow(a->petal_length - b->petal_length, 2) +
                pow(a->petal_width - b->petal_width, 2));
}

void assign_to_clusters(Iris *data, Iris *centroids, int *cluster_counts, double *cluster_ss, int data_size, int k) {
    memset(cluster_counts, 0, k * sizeof(int));  
    memset(cluster_ss, 0, k * sizeof(double));  

    for (int i = 0; i < data_size; i++) {
        double min_distance = INFINITY;
        int closest_cluster = -1;
        
        for (int j = 0; j < k; j++) {
            double distance = calculate_distance(&data[i], &centroids[j]);
            if (distance < min_distance) {
                min_distance = distance;
                closest_cluster = j;
            }
        }

        data[i].cluster = closest_cluster;
        cluster_ss[closest_cluster] += min_distance * min_distance;  // 累加每个集群的平方和
        cluster_counts[closest_cluster]++;
    }
}

void update_centroids(Iris *data, Iris *centroids, int *cluster_counts, int data_size, int k) {
    for (int i = 0; i < k; i++) {
        centroids[i].sepal_length = 0;
        centroids[i].sepal_width = 0;
        centroids[i].petal_length = 0;
        centroids[i].petal_width = 0;
    }

    for (int i = 0; i < data_size; i++) {
        int cluster = data[i].cluster;
        centroids[cluster].sepal_length += data[i].sepal_length;
        centroids[cluster].sepal_width += data[i].sepal_width;
        centroids[cluster].petal_length += data[i].petal_length;
        centroids[cluster].petal_width += data[i].petal_width;
    }

    for (int i = 0; i < k; i++) {
        if (cluster_counts[i] > 0) {
            centroids[i].sepal_length /= cluster_counts[i];
            centroids[i].sepal_width /= cluster_counts[i];
            centroids[i].petal_length /= cluster_counts[i];
            centroids[i].petal_width /= cluster_counts[i];
        }
    }
}

void k_means(Iris *data, Iris *centroids, double *cluster_ss, int data_size, int k, int max_iterations) {
    Iris *old_centroids = (Iris *)malloc(k * sizeof(Iris));
    int *cluster_counts = (int *)malloc(k * sizeof(int));

    srand(time(NULL));
    for (int i = 0; i < k; i++) {
        int index = rand() % data_size;
        // 确保选择不同的质心
        while (i > 0 && calculate_distance(&centroids[i], &data[index]) == 0.0) {
            index = rand() % data_size;
        }
        centroids[i] = data[index];
    }


    int iteration = 0;
    do {
        memcpy(old_centroids, centroids, k * sizeof(Iris));
        assign_to_clusters(data, centroids, cluster_counts, cluster_ss, data_size, k);
        update_centroids(data, centroids, cluster_counts, data_size, k);
        iteration++;
    } while (iteration < max_iterations &&
             (memcmp(old_centroids, centroids, k * sizeof(Iris)) != 0));

    free(old_centroids);
    free(cluster_counts);
}

Iris calculate_global_mean(Iris *data, int data_size) {
    Iris global_mean = {0};
    for (int i = 0; i < data_size; i++) {
        global_mean.sepal_length += data[i].sepal_length;
        global_mean.sepal_width += data[i].sepal_width;
        global_mean.petal_length += data[i].petal_length;
        global_mean.petal_width += data[i].petal_width;
    }
    global_mean.sepal_length /= data_size;
    global_mean.sepal_width /= data_size;
    global_mean.petal_length /= data_size;
    global_mean.petal_width /= data_size;
    return global_mean;
}

void read_csv(char *filename, Iris *data, int data_size) {
    FILE *file = fopen(filename, "r");
    if (file == NULL) {
        fprintf(stderr, "无法打开文件 '%s'\n", filename);
        exit(EXIT_FAILURE);
    }

    // 声明行缓冲区
    char line[256];

    // 跳过标题行
    if (fgets(line, sizeof(line), file) == NULL) {
        fprintf(stderr, "错误:无法读取标题行。\n");
        fclose(file);
        exit(EXIT_FAILURE);
    }

    int i = 0;
    while (fgets(line, sizeof(line), file) != NULL && i < data_size) {
        if (sscanf(line, "%lf,%lf,%lf,%lf", 
                   &data[i].sepal_length, &data[i].sepal_width,
                   &data[i].petal_length, &data[i].petal_width) == 4) {
            i++;
        } else {
            fprintf(stderr, "读取行时出错: %s", line);
            break;
        }
    }

    if (feof(file)) {
    } else {
        perror("读取文件时出错");
    }
    fclose(file);
}

void print_cluster_means(Iris *centroids, int k) {  
    printf("簇均值:\n");  
    for (int i = 0; i < k; i++) {  
        printf("簇 %d: Sepal Length: %.2f, Sepal Width: %.2f, Petal Length: %.2f, Petal Width: %.2f\n",  
               i, centroids[i].sepal_length, centroids[i].sepal_width, centroids[i].petal_length, centroids[i].petal_width);  
    }  
}  

double calculate_within_cluster_ss(Iris *data, Iris *centroids, int data_size, int k) {  
    double within_ss = 0.0;  
    for (int i = 0; i < data_size; i++) {  
        within_ss += calculate_distance(&data[i], &centroids[data[i].cluster]) * calculate_distance(&data[i], &centroids[data[i].cluster]);  
    }  
    return within_ss;  
}  

double calculate_total_ss(Iris *data, Iris global_mean, int data_size) {  
    double total_ss = 0.0;  
    for (int i = 0; i < data_size; i++) {  
        total_ss += calculate_distance(&data[i], &global_mean) * calculate_distance(&data[i], &global_mean);  
    }  
    return total_ss;  
}  

double calculate_between_cluster_ss(Iris *centroids, Iris global_mean, int k) {  
    double between_ss = 0.0;  
    for (int i = 0; i < k; i++) {  
        between_ss += calculate_distance(&centroids[i], &global_mean) * calculate_distance(&centroids[i], &global_mean);  
    }  
    return between_ss;  
}  

int main() {
    int data_size = 150;
    Iris *data = (Iris *)malloc(data_size * sizeof(Iris));
    read_csv("iris_dataset.csv", data, data_size);
    int k = 3;
    int max_iterations = 100;
    srand(time(NULL));

    Iris *centroids = (Iris *)malloc(k * sizeof(Iris));
    double cluster_ss[k];

    k_means(data, centroids, cluster_ss, data_size, k, max_iterations);

    Iris global_mean = calculate_global_mean(data, data_size);

    // 输出聚类大小
    int *cluster_sizes = (int *)malloc(k * sizeof(int));
    memset(cluster_sizes, 0, k * sizeof(int));
    for (int i = 0; i < data_size; i++) {
        cluster_sizes[data[i].cluster]++;
    }

    printf("\nK-means聚类有 %d 簇:", k);
    for (int i = 0; i < k; i++) {
        printf("%d, ", cluster_sizes[i]);
    }
    printf("\b\b\n");

    // 输出聚类中心
    print_cluster_means(centroids, k);

    // 输出聚类向量
    printf("\n聚类向量:\n");
    for (int i = 0; i < data_size; i++) {
        printf(" %d", data[i].cluster);
        if ((i + 1) % 10 == 0) {
            printf("\n");
        }
    }
    
    // 输出within SS 和 between SS 比率
    double within_ss = calculate_within_cluster_ss(data, centroids, data_size, k);
    double total_ss = calculate_total_ss(data, global_mean, data_size);
    double between_ss = calculate_between_cluster_ss(centroids, global_mean, k);
    printf("\n聚类内各聚类平方和:\n");
    for (int i = 0; i < k; i++) {
        printf("[%d] %.3f\n", i + 1, cluster_ss[i]);
    }
    if (total_ss == 0.0) {
        printf("(between_SS / total_SS = undefined)\n");
    } else {
        printf("(between_SS / total_SS = %.1f %%)\n", (between_ss / total_ss) * 100);
    }
    
    
    free(data);
    free(centroids);
    free(cluster_sizes);
    return 0;
}

代码运行后输出:


K-means聚类有 3:62, 38, 50, 
簇均值:0: Sepal Length: 5.90, Sepal Width: 2.75, Petal Length: 4.39, Petal Width: 1.431: Sepal Length: 6.85, Sepal Width: 3.07, Petal Length: 5.74, Petal Width: 2.072: Sepal Length: 5.01, Sepal Width: 3.43, Petal Length: 1.46, Petal Width: 0.25

聚类向量:
 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2
 2 2 2 2 2 2 2 2 2 2
 0 0 1 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 1 0 0
 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0
 1 0 1 1 1 1 0 1 1 1
 1 1 1 0 0 1 1 1 1 0
 1 0 1 0 1 1 0 0 1 1
 1 1 1 0 1 1 1 1 0 1
 1 1 0 1 1 1 0 1 1 0

聚类内各聚类平方和:
[1] 39.821
[2] 23.879
[3] 15.151
(between_SS / total_SS = 2.0 %)

R语言和Python实现

相较于C语言来说,R语言实现就非常简洁,在设置好随机种子set.seed()后,直接使用内置的kmeans函数就可以轻松实现:

data(iris)
X <- iris[, 1:4]
set.seed(123)
kmeans_value <- kmeans(X, centers = 3)
print(kmeans_value)

Python实现需要提前安装好scikit-learn库和pandas库:

import pandas as pd  
from sklearn.cluster import KMeans  
  
data = pd.read_csv('iris_dataset.csv')  
X = data.iloc[:, :-1].values  
kmeans = KMeans(n_clusters=3, random_state=0).fit(X)  
labels = kmeans.labels_  
centroids = kmeans.cluster_centers_  
print(centroids)  

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

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

相关文章

数据仓库中的DIM层-定义、设计与最佳实践

在当今数据驱动的商业环境中,构建高效的数据仓库架构至关重要。本文将深入探讨数据仓库中的维度层(DIM层),帮助您了解其定义、重要性以及设计最佳实践。 目录 什么是DIM层?DIM层的重要性DIM层设计最佳实践1. 选择适当的粒度2. 实施慢速变化维度(SCD)3. 使用代理键4. 规范化v…

x264编解码库 -介绍和使用示例

目录 1&#xff1a;X264简单介绍 1.1&#xff1a;编译x264 1.2&#xff1a;x264简单介绍 1.3&#xff1a;x264的优势 1.4&#xff1a;x264与FFmpeg的关系 1.5&#xff1a;x264 编解码原理 1.6 进一步学习资源 2&#xff1a;demo效果 3&#xff1a;完整代码 4&#xff1a;附件…

Vite + Vue3 + TS项目配置前置路由守卫

在现代前端开发中&#xff0c;使用 Vue 3 和 TypeScript 的组合是一种流行且高效的开发方式。Vite 是一个极速的构建工具&#xff0c;可以显著提升开发体验。本文博主将指导你如何在 Vite Vue 3 TypeScript 项目中配置前置路由守卫&#xff08;Navigation Guards&#xff09;…

学习日记:数组

1. 概念 一组相同类型的数据的集合&#xff0c;也是一种数据类型。 2. 一维数组 2.1 语法 类型说明符 数组名 [常量表达式] &#xff08;1&#xff09; &#xff08;2&#xff09; &#xff08;3&#xff09; &#xff08;1&#xff09;类型说明符&#x…

Leetcode - 周赛407

目录 一&#xff0c;3226. 使两个整数相等的位更改次数 二&#xff0c;3227. 字符串元音游戏 三&#xff0c;3228. 将 1 移动到末尾的最大操作次数 四&#xff0c;3229. 使数组等于目标数组所需的最少操作次数 一&#xff0c;3226. 使两个整数相等的位更改次数 本题可以暴力…

刷题了:144.二叉树的前序遍历心|145.二叉树的后序遍历心|94.二叉树的中序遍历己

递归遍历 文章讲解:https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E9%80%92%E5%BD%92%E9%81%8D%E5%8E%86.html#%E6%80%9D%E8%B7%AF 视频讲解:https://www.bilibili.com/video/BV1Wh411S7xt/?spm_id_from333.788&vd_sourcee70917aa6392827d1ccc8d85e1…

ubuntu20.04安装nginx,mysql8,php7.4详细教程,包成功

目录 1.更新索引 2.安装 Nginx 1.安装 Nginx&#xff1a; 2.启动 Nginx 服务并设置为开机自启&#xff1a; 3.开放防火墙的 80 端口&#xff1a; 4.检查 Nginx 是否正常运行&#xff1a; 3.安装 MySQL 8.0 1.首先&#xff0c;安装 MySQL 的仓库&#xff1a; 安装过程中你会看…

Python --Pandas库基础方法(2)

文章目录 Pandas 变量类型的转换查看各列数据类型改变数据类型 重置索引删除行索引和切片seriesDataFrame取列按行列索引选择loc与iloc获取 isin()选择query()的使用排序用索引排序使用变量值排序 修改替换变量值对应数值的替换 数据分组基于拆分进行筛选 分组汇总引用自定义函…

TinyVue 组件库官网焕然一新!

本文由体验技术团队Kagol原创~ 之前有一些朋友吐槽我们 TinyVue 组件库的 UI 不够美观&#xff0c;于是我们请了设计师小姐姐给我们的组件和网站进行优化&#xff0c;经过设计师小姐姐和我们的开发兄弟们一个多月的努力&#xff0c;终于完成网站第一版的优化。 优化点 主要优…

学习react-登录状态验证

1.创建三个页面LoginPage, HomePage,NotFoundPage用于Router 创建LoginPage.tsx用于做登录页面 // LoginPage.tsx const LoginPage (props:LoginProp) > {const navigate useNavigate();return( <h1 onClick{ ()>{navigate("/");}}>Hello Login, {pr…

如何在Selenium Webdriver中点击SVG元素?

我们将在URL上单击下面突出显示的SVG元素&#xff1a;https&#xff1a;//testkru.com/Elements/SVGelemnts。 有几种方法可以点击SVG元素&#xff0c;我们将在这篇文章中讨论它们&#xff0c;并讨论它们之间应该首选哪一种。 使用 WebElement Click() 通过使用Action Click() …

前端JS特效第53集:带声音的烟花模拟绽放特效插件

带声音的烟花模拟绽放特效插件&#xff0c;先来看看效果&#xff1a; 部分核心的代码如下(全部代码在文章末尾)&#xff1a; <!DOCTYPE html> <html lang"en" > <head><meta charset"UTF-8"><title>Firework Simulator v2&…

五、SpringIoC/DI的使用

1. 类注解、方法注解 告诉spring管理bean—>bean的存储 1、类注解&#xff1a;五大注解 Controller&#xff08;控制器存储&#xff09;、 Service&#xff08;服务存储&#xff09;、 Repository&#xff08;仓库存储&#xff09;、 Component&#xff08;组件存储&#xf…

一种多策略改进黑翅鸢智能优化算法IBKA(2024年新出优化算法)种群初始化精英反向+透镜成像反向学习+黄金正弦变异策略

一种多策略改进黑翅鸢智能优化算法IBKA&#xff08;2024年新出优化算法&#xff09; 种群初始化精英反向策略透镜成像反向学习策略黄金正弦变异策略 文章目录 前言一种多策略改进黑翅鸢智能优化算法IBKA&#xff08;2024年新出优化算法&#xff09; 种群初始化精英反向策略透镜…

35_YOLOX网络详解

1.1 简介 YOLOX是YOLO系列&#xff08;You Only Look Once&#xff09;目标检测模型的一个最新变种&#xff0c;由阿里云团队和旷视科技在2021年提出。YOLO系列以其快速、准确的目标检测能力而闻名&#xff0c;而YOLOX在此基础上进行了多方面的改进和优化&#xff0c;旨在提供…

获取手机当前信号强度(dbm/asu值)解决 getGsmSignalStrength()总是返回99问题

能看到这篇文章说明网上哪些获取 &#xff08;dbm/asu值&#xff09;不适合你&#xff0c;不是他们的代码不正确&#xff0c;而是不符合你的情况 比如安卓6获取android手机信号强度 可以看这篇文章 https://blog.csdn.net/sinat_31057219/article/details/81134030 当然如果你…

计算机三级嵌入式(三)——嵌入式系统硬件组成

目录 考点1 嵌入式最小硬件系统 考点2 基于 ARM 内核的典型嵌入式应用系统硬件组成 考点3 ARM 的 AMBA 总线体系结构及标准 考点4 基于 ARM 内核的嵌入式芯片的硬件组成 考点5 存储器层次结构 考点6 存储器分类 考点7 存储器主要性能指标 考点8 片内存储器 考点9 外部…

Perfectly Clear WorkBench中文绿色版,让每一张照片都完美无瑕

软件简介 你是否曾经为了一张不完美的照片而感到遗憾&#xff1f;是否曾经因为照片中的小瑕疵而不得不花费大量时间进行后期处理&#xff1f;现在&#xff0c;有了Perfectly Clear WorkBench&#xff0c;这些问题都将迎刃而解。作为全球领先的智能图像校正技术商推出的图像清晰…

【C++高阶数据结构】红黑树:全面剖析与深度学习

目录 &#x1f680; 前言&#xff1a;红黑树与AVL树的比较一&#xff1a; &#x1f525; 红黑树的概念二&#xff1a; &#x1f525; 红黑树的性质 三&#xff1a; &#x1f525; 红黑树节点的定义和结构&#x1f680; 3.1 基本元素&#x1f680; 3.2 节点颜色&#x1f680; 3.…

Java中static静态变量--继承等相关知识

目录 static 继承&#xff1a; 继承的特点&#xff1a; 案例&#xff1a;自己设计一个继承体系练习&#xff1a; 设计思想&#xff1a; 代码&#xff1a; 子类到底能继承父类的哪些类容&#xff1f; 成员变量内存的继承情况&#xff1a; 成员方法的内存继承情况&#x…