数据结构-哈希-位图与布隆过滤器

news2024/11/8 18:02:31

位图与布隆过滤器

  • 一,位图
    • 题目分析
    • 位图设计
    • 位图代码
    • 经典题目
  • 二,布隆过滤器
    • 布隆过滤器概念
    • 布隆过滤器的插入
    • 布隆过滤器的结构
    • 布隆过滤器总结
    • 经典题目
  • 三,哈希切割

一,位图

题目分析

🚀给40亿个不重复的无符号整数,没排过序。给一个无符号整数,如何快速判断一个数是否在这40亿个数中。

🚀思路1:排序+二分查找
首先估算一下,40亿个整数的大小为16GB(10亿字节是1GB,40亿整数是4 * 10亿 * 4 字节 = 16GB)。显然,在内存中是完不成排序的,只能将这份数据分散到几个小文件中,然后利用归并排序,即使排序完成后二分查找也是非常困难的,因为二分查找是基于下标的随机访问,显然在文件中是不能随机访问的,所以只能每次局部加载一部分到内存中进行查找。可以看到经过上面的分析,过程是非常复杂且效率低的,如果是查找多个无符号整数,那这种方法更不能考虑。

🚀思路2:将数据存入到红黑树或者哈希表中进行查找
无论是哈希表还是红黑树,内部不仅要存储数据还有维护结点间关系的指针,光数据就要16GB,算上其他开销那就不仅仅是16GB了,要使用这种方法也只能是每次加载一部分进行查找,所以这种方法也不是很好。

🚀思路3:针对这个问题利用位图来解决绝对是再合适不过了,位图就是一种哈希结构,是一种直接定址法,将每个整数映射到一个固定的比特位,检查一个整数存不存在直接查看那个比特位是否为1即可,利用位图结构对于内存来说空间是绝对足够的,因为只需要42亿左右的比特位空间即可(因为无符号整数最大值为42亿多),大概只需要512MB左右的空间(40亿 / 8 = 5 亿字节 = 512 MB),并且位图结构查询效率极高,时间复杂度为O(1)。

下面,看下位图的设计。

位图设计

🚀位图最重要的三个方法:
set(将整数对应的比特位置1),
reset(将整数对应的比特位置0),
test(检测整数对应的比特位是否为1).

在这里插入图片描述
🚀我们用char的数组来模拟位图结构,如何定位一个整数映射到哪一个比特位呢?假设整数为N,第一步,用N / 8 得到N对应的比特位属于第几个char中。第二步,用N % 8得到N对应的比特位数据某个char中的第几个比特位。如果是用int数组模拟的话就是除32和模32。
🚀以13为例,13 / 8 = 1,说明13对应的比特位位于第1个char中(注意char是从0开始计数的),13 % 8 = 5,说明13对应的比特位是第一个char中的第五个比特位。就是上图中13指向的比特位。

template<size_t N> //N代表要开多少比特位
	class bitset
	{
	public:
		bitset()
		{
			_bits.resize(N / 8 + 1, 0);
		}
		void set(size_t N)
		{}
		void reset(size_t N)
		{}
		bool test(size_t N)
		{}
	private:
		vector<char> _bits;
	};

🚀如何将某个比特位置为1:
在这里插入图片描述
例如将上图中绿色格子对应的比特位置为1,在将这一位置1的同时要保证不能破坏其他位的内容,所以只要将这一位 |= 1,其它位 |= 0即可(0 |= 0 还是0,1 |= 0 还是1)。

_bits[i] |= (1 << j);

🚀如何将某个比特位置为0:
与将某个比特位置为1相反,那么用这个比特位 &= 0,其他比特位 &= 1即可(0 &= 1 = 0,1 &= 1 = 1)

_bits[i] &= (~(1 << j));

🚀检测某个比特位是否为1:
假设N对应的比特位是属于某个char的第j位,那么将这个char右移j位再& 1,如果结果是1表示N对应的比特位为1,反之为0.

((_bits[i] >> j) & 1) == 1;

位图代码

namespace gy
{
	template<size_t N>
	class bitset
	{
	public:
		bitset()
		{
			_bits.resize(N / 8 + 1, 0);
		}
		void set(size_t N)
		{
			size_t i = N / 8;
			size_t j = N % 8;
			_bits[i] |= (1 << j);
		}
		void reset(size_t N)
		{
			size_t i = N / 8;
			size_t j = N % 8;
			_bits[i] &= (~(1 << j));
		}
		bool test(size_t N)
		{
			size_t i = N / 8;
			size_t j = N % 8;
			return ((_bits[i] >> j) & 1) == 1;
		}
	private:
		vector<char> _bits;
	};
}

经典题目

  1. 给定100亿个整数,设计算法找到只出现一次的整数?

🚀上面实现的位图结构只能判断某个整数是否出现,不能判断整数出现了几次,但是对上面的结构稍加改造即可,上面的结构是一个整数映射一个比特位,我们可以让一个整数映射2个比特位进而来记录出现的次数。
00:表示没有出现,
01:表示出现了1次,
10:表示出现了两次及以上。
所以直接复用上面的结构即可:

template<size_t N>
class twobitset
{
public:
	twobitset()
	{
		_bs1.resize(N / 8 + 1, 0);
		_bs2.resize(N / 8 + 1, 0);
	}
	void set(size_t N)
	{
		// 00->01
		if (_bs1.test(N) == false && _bs2.test(N) == false) 
		{
			_bs2.set(N);
		}
		//01-> 10
		else if (_bs1.test(N) == false && _bs2.test(N) == true)
		{
			_bs1.set(N);
			_bs2.reset(N);
		}

	}
	bool test(size_t N)
	{
		return _bs2.test(N);
	}
private:
	bitset<N> _bs1; //表示较高的比特位
	bitset<N> _bs2; //表示较低的比特位
};
  1. 给两个文件,分别有100亿个整数,我们只有1G内存,如何找到两个文件交集?

🚀法1:将一个文件中的数据读入到位图结构中,在读取第二个文件的时候每读取一个数据就去位图中检测是否存在,如果存在说明这个数据就是交集,并且在位图中将这个整数对应的比特位置为0。(为了防止交集中出现重复的数据)

例如:第一组数据{1,3,6,8,4,7,2,5,74546,564,87};
第二组数据{2,2,5,6,7,3,3,9,9};
交集应该是{2,3,5,6,7}
如果没有将位图reset这一步的话得到的交集为{2,2,3,3,5,6,7};

🚀法2:分别将两个文件中的数据读入到两个位图中,然后遍历0-无符号整数最大值,如果某个整数N同时存在两个位图中,那么这个N就是交集,并且这种方法不会存在重复的问题。

  1. 位图应用变形:1个文件有100亿个int,1G内存,设计算法找到出现次数不超过2次的所有整数

🚀与问题1类似,本题就是找出出现1次或者2次的整数,我们还是将一个整数映射两个比特位,
00表示没有出现
01表示出现1次
10表示出现两次
11表示出现两次以上
所以只要将上面的set和test逻辑稍做修改即可:

void set(size_t N)
{
	//00->01
	if (_bs1.test(N) == false && _bs2.test(N) == false)
	{
		_bs2.set(N);
	}
	//01->10
	else if (_bs1.test(N) == false && _bs2.test(N) == true)
	{
		_bs1.set(N);
		_bs2.reset(N);
	}
	//10->11
	else if (_bs1.test(N) == true && _bs2.test(N) == false)
	{
		_bs1.set(N);
		_bs2.set(N);
	}
}
bool test(size_t N)
{
	return _bs1.test(N) && !_bs2.test(N)  //10
	|| !_bs1.test(N) && _bs2.test(N);     //01
}

二,布隆过滤器

布隆过滤器概念

🚀布隆过滤器是由布隆在1970年提出的一种紧凑的,比较巧妙的概率型数据结构,特点是高效的插入和查询,可以用来告诉你“某样东西一定不存在或者可能存在”,它是由多个哈希函数,将一个数据映射到位图结构中,此种方式不仅可以提升查询效率,也可以节省大量的内存空间。

布隆过滤器的插入

🚀将某个字符串映射到某个比特位是不能直接实现的,因此需要使用字符串哈希函数将字符串转化为相应的整型,再将其映射到某个比特位。但是如果只是映射到某一个比特位的话,那么产生哈希冲突的概率就会很大,也就是说会产生“误判”,假设下面这种情况,hello存在的信息并没有记录在位图结构中,百度存在的信息存储在了位图结构中,但此时去检测hello是否存在时,就会发生“误判的情况”。
在这里插入图片描述
🚀这种“误判”是无法避免的,但是要尽量减少,所以通常一个字符串会被映射到多个比特位上(根据需而定,本文采用三个)。所以一个字符串要根据多个哈希函数转化出的多个整数来映射到多个比特位上。

在这里插入图片描述

布隆过滤器的结构

template<size_t N,typename K = std::string,
typename Hash1 = BKDRHash,
typename Hash2 = APHash,
typename Hash3 = DJBHash>
class BloomFilter
{
public:
    void set(const K& key)
    {}
    void test(const K& key)
    {}
private:
    const int _rate = 5;
    bitset<N * _rate> _bs;
};

🚀布隆过滤器的大多数使用场景都是针对字符串的,所以模板参数K给的缺省参数就是string,并且对应的三个Hash函数都是字符串Hash函数。
🚀非类型模板参数不再代表开多少比特位,而是代表要存储多少个K类型的对象,N的个数和哈希函数的个数能够推断出具开多少比特位是较为合适的,参考博客: 布隆过滤器。

template<size_t N,typename K = std::string,
typename Hash1 = BKDRHash,
typename Hash2 = APHash,
typename Hash3 = DJBHash>
class BloomFilter
{
public:
    void set(const K& key)
    {
        size_t len = N * _rate;
        size_t hash1 = Hash1()(key) % len;
        size_t hash2 = Hash2()(key) % len;
        size_t hash3 = Hash3()(key) % len;
        _bs.set(hash1);
        _bs.set(hash2);
        _bs.set(hash3);
    }
    bool test(const K& key)
    {
        size_t len = N * _rate;
        size_t hash1 = Hash1()(key) % len;
        size_t hash2 = Hash2()(key) % len;
        size_t hash3 = Hash3()(key) % len;
        //有一个位置不是1就表示不存在
        if (_ba.test(hash1) == false) return false;
        if (_ba.test(hash2) == false) return false;
        if (_ba.test(hash3) == false) return false;
        return true;
    }
private:
    const int _rate = 5;
    bitset<N * _rate> _bs;
};

🚀布隆过滤器一般是不支持删除的,因为删除一个元素时,可能会影响到其他元素。可以通过给位图结构中的比特位扩展成一个小的计数器,由原来的判断是否存在0还是1,转化为出现的次数。在插入元素的时候由哈希函数计算出的k个整型值对应的k个比特位做+1操作,相应删除时做-1操作。
如果为每个比特位增加一个引用计数的话,可能会引发计数回绕的问题。

🚀例如,由原来1个位置只有1个比特位,转化位1个位置存在3个比特位(能表示0 - 7),在插入的时候:
000->001
001->010
010->011
011->100
100->101
101->110
110->111
删除时做相反操作,这样就能支持基本的删除操作了。但这种做法仍然存在缺陷,因为判断一个元素存在是不准确的,那么代表着删除某个不存在的元素就势必会影响到真正存在的元素。

布隆过滤器总结

🚀使用布隆过滤器判断一个元素是否存在时,如果检测到一个元素不存在那么代表真的不存在,如果检测到一个元素存在是不准确的存在“误判“的情况。

🚀布隆过滤器的优点:

  1. 增加和查询元素的时间复杂度为O(K),K代表使用的哈希函数的个数,与数据量大小无关,效率很高。
  2. 哈希函数相互之间没有关系,方便硬件并行运算。
  3. 布隆过滤器不需要存储元素本身,在某些对保密要求比较严格的场合有很大优势
  4. 在能够承受一定的误判时,布隆过滤器比其他数据结构有这很大的空间优势
  5. 数据量很大时,布隆过滤器可以表示全集,其他数据结构不能
  6. 使用同一组散列函数的布隆过滤器可以进行交、并、差运算

🚀布隆过滤器的缺点:

  1. 有误判率,即存在假阳性(False Position),即不能准确判断元素是否在集合中(补救方法:再建立一个白名单,存储可能会误判的数据)。
  2. 不能获取元素本身
  3. 一般情况下不能从布隆过滤器中删除元素
  4. 如果采用计数方式删除,可能会存在计数回绕问题

🚀布隆过滤器适用场景:
比如我们在注册某个网站时要输入一个昵称,电话号码,邮箱等等,往往是我们输入昵称后系统就会返回一个结果告诉我们这个昵称是否被别人使用过,这就是布隆过滤器典型的应用场景,因为如果一个昵称不存在,那就是真的不存在用户可以使用这个昵称。而,一个昵称显示存在的时候,其实它不一定真的存在但用户是感知不到的,也就是说这种场景下的误判是可接受的。
对于电话号码和邮箱这种,用户是清楚自己的手机号还有邮箱是否存在注册记录的,所以对于手机号这种出现误判是不能接受的,对于这种场景起到的是过滤的作用,如果手机号或邮箱不存在那么就是真的不存在,返回给用户电话号码或者邮箱可用。如果检测手机号或邮箱存在,那么再去数据库中查询,看是否真正的存在。可以减少数据库的访问提高效率,这种场景起到的是过滤作用。

经典题目

给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?近似算法

🚀近似算法就可以利用布隆过滤器来完成,首先将一个文件的query的数据存入一个布隆过滤器中,再依次读取出另一个文件中的query去布隆过滤器中检测是否存在,如果存在就是交集。

三,哈希切割

给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?精确算法

🚀由于是找到交集的精确算法就不能使用布隆过滤器这种位图结构来完成了。假设每个query的大小是50字节,那么100亿个query就是5000亿字节 = 500GB。500GB肯定是不能同时加载到内存中的,所以要对其进行切割,假设切割1000份每份为500MB。

在这里插入图片描述
如果采用平均切割的方式,那么在寻找交集的过程中就要进行暴力的匹配,任何两个Ai小文件,Bi小文件都要进行依次匹配,这样的效率的很低的。所以有人提出哈希切割这种方式,对于大文件中的每个query都先经过哈希函数进行计算,将计算的结果模1000,得到的结果就是哪个小文件的下标,对于A,B文件来说,如果是相同的query,那么经过同一个哈希函数必定会映射到相同下标的小文件中,于是只需两个下标相同的小文件求交集,最终再汇总即可。

🚀但是,由于不是平均切割,就可能会造成某个小文件的体积过大已经超过内存的大小,那么它就不能被加载到内存中,后续的工作就不能继续运行。单个小文件体积过大有两种可能:
1,文件中存在大量重复的query。
2,文件中有大量不冲突的query。
针对这两种情况,我们可以将这个小文件加载到红黑树或者哈希表中,如果在加载的过程中,出现了抛出了内存的异常,那么就表示为情况2,此时就需要换一个新的哈希函数对此小文件继续切割。如果在加载过程中并没有出现异常那么就表明为情况1,那么直接依次加载下标相同的另一个小文件的query,在红黑树或者是哈希表中查找是否存在,如果存在就是交集。

给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址?与上题条件相同,如何找到top K的IP?如何直接用Linux系统命令实现?

🚀此问题与上个问题的解法类似,都是采用哈希切割的方式,100GB的文件哈希切割成若干份,但是同样会出现某个小文件的体积过大的问题:
1,文件中存在大量重复的IP。
2,文件中有大量不冲突的IP。
解决方法也是类似的,由于本题是统计出出现次数最多的IP地址,那么就将小文件加载到map中统计次数,如果加载成功没有抛出内存的异常表示为情况1,直接找出次数最多的即可。如果在加载过程中抛出内存异常,那么就需要换一个哈希函数继续切割此文件。

🚀如果是找到TopK个IP,只需建立一个大小为K的小堆即可,将每个IP出现的次数与堆顶元素比较,如果比堆顶元素大那么就进堆,这样就可以找到出现次数TopK的IP。

🚀如果用Linux指令来切割的话,使用sort指令配合uniq指令就能完成。首先使用sort对文件进行排序,在使用uniq进行去重(uniq只能处理相邻文本),uniq指令搭配-c选项使用,- c:显示出重复出现的次数,最终在使用依次sort -nr指令,
-n :依照数值大小排序,
-c:按降序方式排序。
如果是取出现次数最多的数据再配head -1 指令即可。如果是取TopK的数据 搭配head -K 即可。如果需要将得到的字符串再保存到文件中直接重定向到指定文件即可。

sort test.txt | uniq -c | sort -nr | head -1

下面是随便造的一些字符串。对上面的指令做测试使用。

在这里插入图片描述
🚀测试取出现次数最多的字符串

sort test.txt | uniq -c | sort -nr | head -1

在这里插入图片描述
🚀取出现次数前三多的数据。

sort test.txt | uniq -c | sort -nr | head -3

在这里插入图片描述

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

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

相关文章

【UE 从零开始制作坦克】11-坦克炮塔机枪

效果 步骤 1. 复制一份坦克炮弹的蓝图&#xff0c;重命名为“MachineGunBullets”&#xff0c;作为坦克炮塔机枪子弹的蓝图 2. 打开“MachineGunBullets”&#xff0c;由于美M2勃朗宁重机枪的口径是12.7毫米&#xff0c;这里取12毫米&#xff0c;也就是1.2cm&#xff0c;半径是…

Stream流中Map方法的使用

map函数的作用就是针对管道流中的每一个数据元素进行转换操作。 主要有三种用法 一、Stream管道流map的基础用法 将集合中的每个字符串&#xff0c;全部转化成大写&#xff01; 不使用流 List<String> list Arrays.asList("Monkey", "Lion", &…

你知道免费mp3格式转换器有哪些吗

小明是一个音乐爱好者&#xff0c;经常下载一些高质量的无损音频文件。但他发现有些音频文件格式并不支持他的播放器&#xff0c;这让他很苦恼。有一天&#xff0c;他听说了mp3格式转换器这个神奇的工具&#xff0c;可以将音频文件格式转换成mp3&#xff0c;从而方便他在各种设…

Jetpack Compose:构建现代Android应用的BottomNavigation

Jetpack Compose是Google推出的一种全新的声明式UI框架&#xff0c;它引领了Android开发的新风潮。在这篇博客中&#xff0c;我将详细介绍如何使用Jetpack Compose来构建一个具有底部导航栏&#xff08;BottomNavigation&#xff09;的现代Android应用。 首先&#xff0c;让我们…

【C++学习】内联函数 | nullptr空指针 | 初步认识面向对象 | 类访问限定符 | 封装 | 类对象的内存对齐

写在前面&#xff1a; 上一篇文章我介绍了引用和auto相关的知识&#xff0c; 如果有兴趣的话可以去看看&#xff1a;http://t.csdn.cn/j6jsI 这篇文章大概能够讲完C入门的一些语法&#xff0c;开始类和对象的学习之旅。 目录 写在前面&#xff1a; 1. 内联函数 2. nullp…

用Python带你制作小时候玩的“大富翁”(文末赠书)

名字&#xff1a;阿玥的小东东 学习&#xff1a;Python、C/C 主页链接&#xff1a;阿玥的小东东的博客_CSDN博客-python&&c高级知识,过年必备,C/C知识讲解领域博主 目录 首先 接下来需要定义各种类型的物业&#xff0c;包括普通物业、铁路、公用事业等等。 接下来需…

【Spring 】项目创建和使用

哈喽&#xff0c;哈喽&#xff0c;大家好~ 我是你们的老朋友&#xff1a;保护小周ღ 谈起Java 圈子里的框架&#xff0c;最年长最耀眼的莫过于 Spring 框架啦&#xff0c;如今已成为最流行、最广泛使用的Java开发框架之一。不知道大家有没有在使用 Spring 框架的时候思考过这…

强化学习从基础到进阶-常见问题和面试必知必答[5]::梯度策略、添加基线(baseline)、优势函数、动作分配合适的分数(credit)

【强化学习原理项目专栏】必看系列&#xff1a;单智能体、多智能体算法原理项目实战、相关技巧&#xff08;调参、画图等、趣味项目实现、学术应用项目实现 专栏详细介绍&#xff1a;【强化学习原理项目专栏】必看系列&#xff1a;单智能体、多智能体算法原理项目实战、相关技巧…

Spring Cloud - Nacos 注册发现、分级模型、配置集群、环境隔离、原理

目录 一、Nacos 安装和配置 二、Nacos 服务注册发现 2.1、将服务注册到 nacos 中 2.2、执行效果 三、Nacos 的服务分级模型及配置 3.1、分级模型 3.2、配置集群 3.3、配置 Nacos 负载均衡策略 3.4、Nacos 服务实例的权重设置 3.5、环境隔离——namespace 四、Nacos注…

真实企业做自动化测试做法,从测试用例到测试报告...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 首先&#xff0c;…

SAP MM 组织结构配置

1.定义公司代码 创建公司代码一般来说是财务去配置&#xff0c;但是我们需要去有一个基本的了解&#xff0c;这样&#xff0c;你才能理清公司代码和MM 组织的关系 配置&#xff1a;SAP IMG Enterprise Structure -》Definition -> Financial Accounting -> Edit, Copy, …

深度学习(26)——YOLO系列(5)

深度学习&#xff08;26&#xff09;——YOLO-v7&#xff08;5&#xff09; 文章目录 深度学习&#xff08;26&#xff09;——YOLO-v7&#xff08;5&#xff09;絮絮叨叨1. conv和BN的融合2. 3*3卷积的替换&#xff08;1&#xff09;1*1卷积有什么作用&#xff1f;&#xff08…

解决方案 | 照明行业数字化营销CRM平台

“数字中国”作为二十大报告的“关键词”&#xff0c;也成为各行各业的高质量发展的主旋律&#xff0c;历史悠久的中国照明产业也积极拥抱“数字化”&#xff0c;以驱动高质量发展 。作为照明行业的领军企业&#xff0c;某照明行业客户很早就意识到企业数字化转型的重要性&…

Spring事务源码详解-spring原码(二)

上篇文章介绍了事务开启&#xff0c;前面介绍了解析adviors。 spring事务源码详解-spring原码&#xff08;一&#xff09;https://blog.csdn.net/ke1ying/article/details/131360060 事务源码 先从缓存里获取&#xff0c;主要是判断循环依赖是否创建动态代理 进去wrapIfNeces…

【MOOC 作业】第3章 传输层

不是标答也不是参考答案 仅从个人理解出发去做题 1、(20分) ‍主机甲和主机乙之间已建立一个 TCP 连接&#xff0c;TCP 最大段长度为 1000 字节&#xff0c;若主机甲的当前拥塞窗口为 5000 字节&#xff0c;在主机甲向主机乙连接发送 2 个最大段后&#xff0c;成功收到主机乙发…

Java微服务金融项目智牛股 项目简介与金融知识介绍及技术特点

项目简介 金融交易平台服务于金融衍生产品&#xff0c; 包含外汇、贵金属、期货、股票。 各产品具有不同属性与交易规则&#xff0c; 本项目对标MT4等大型交易平台&#xff0c; 遵循FIX全球最广泛的金融市场通用协议。 实现从证券注册开户、行情订阅与呈现&#xff0c; 股票撮合…

JAVA 日期类Date SimpleDateFormat Calendar

1、Date日期类 类 Date 表示一个特定的瞬间&#xff0c;精确到毫秒 1.1 Date的构造函数 Date() 分配一个 Date 对象&#xff0c;以表示分配它的时间&#xff08;精确到毫秒&#xff09; Date(long date) 分配一个 Date 对象&#xff0c;表示自从标准基准时间起指定时间的毫秒数…

2023最新AI创作系统/ChatGPT商业运营版网站程序源码+支持GPT4+支持ai绘画(MJ)+实时语音识别输入+免费更新版本

2023最新AI创作系统/ChatGPT商业运营版网站程序源码支持ai绘画支持GPT4.0实时语音识别输入文章资讯发布功能用户会员套餐免费更新版本 一、AI创作系统二、系统介绍三、系统程序下载四、安装教程五、主要功能展示六、更新日志 一、AI创作系统 1、提问&#xff1a;程序已经支持G…

论洗碗哥在CSDN摸滚打爬的256个日夜

目录 机缘 收获 成就 憧憬 机缘 创作初心了为了记录一下自己的日常学习过程&#xff0c;方便自己日后去总结&#xff0c;或者遇到类似的问题的时候就可以翻阅自己的文章了。也可以加深自己的印象。其实一开始我是一个不太善于总结的人&#xff0c;机缘之下&#xff0c;听到…

机器学习之PCA算法

目录 PCA算法 PCA目标 PCA原理推导 基于最大可分性推导 基于最近重构误差推导 PCA算法流程 PCA优点 PCA缺点 基于PCA的人脸识别 PCA算法 PCA&#xff0c;即主成分分析&#xff08;Principal Component Analysis&#xff09;&#xff0c;是一种常用的降维技术&#x…