目录

一、核心思想:一个形象的比喻

二、核心思想的具体拆解

步骤一:构建FP-tree(频繁模式树)

步骤二:从FP-tree中挖掘频繁项集

为什么这很高效?

三、总结

核心思想与优势

适用场景与缺点

四、例题

给定数据

第一步:第一次扫描数据库,找出频繁1项集及其支持度

第二步:第二次扫描数据库,构建FP-tree

第三步:挖掘FP-tree,寻找频繁项集

1. 以后缀 A 开始挖掘

步骤 1: 寻找条件模式基 (Conditional Pattern Base)

步骤 2: 构建条件FP-tree (Conditional FP-tree) for A

步骤 3: 挖掘条件FP-tree并生成频繁项集

2. 以后缀 E 开始挖掘

步骤 1: 寻找条件模式基 for E

步骤 2: 构建条件FP-tree for E

步骤 3: 挖掘条件FP-tree for E

3. 以后缀 C 开始挖掘

步骤 1: 寻找条件模式基 for C

步骤 2: 构建条件FP-tree for C

步骤 3: 挖掘条件FP-tree for C

4. 以后缀 B 开始挖掘

步骤 1: 寻找条件模式基 for B

步骤 2: 构建条件FP-tree for B

步骤 3: 挖掘条件FP-tree for B

第四步:汇总所有频繁项集

最终答案


 参考:

Python数据挖掘实战:微课版 - 9.3 FP-growth算法 - 王磊 邱江涛 - 微信读书

19.FpGrowth算法介绍_哔哩哔哩_bilibili
9.2 利用FP-tree挖掘频繁项集的过程

FP-growth(Frequent Pattern Growth,频繁模式增长)算法是用于高效挖掘数据集中频繁项集的一种方法。它极大地改进了传统的Apriori算法,核心目标仍然是找出所有满足最小支持度阈值的项集。

其核心思想可以概括为:“分而治之” 和 “用空间换时间”


一、核心思想:一个形象的比喻

想象一下,你要统计一图书馆里所有书籍的组合借阅情况(比如,同时被借阅的书籍组合)。

  • Apriori算法(传统方法):像一个笨拙的图书管理员。他需要反复穿梭于各个书架之间,每次只关心“2本书的组合”,统计完后再找“3本书的组合”,如此反复。这个过程会产生大量的“候选组合”,并且需要反复扫描整个借阅记录(数据库),非常耗时。

  • FP-growth算法(新方法):像一个聪明的图书管理员。他首先花一点时间,为整个图书馆建立了一个非常精巧的索引目录(FP-tree)这个目录不仅记录了每本书被借阅的次数,还清晰地记录了哪些书经常被一起借阅。当你想查询任何书籍组合时,他无需再跑回书架只需在这个浓缩的目录里进行查找和拼接,就能快速得到结果。

这个“精巧的目录”就是FP-growth算法的精髓。


二、核心思想的具体拆解

FP-growth算法主要分为两个核心步骤,完美体现了其思想:

步骤一:构建FP-tree(频繁模式树)

这是“用空间换时间”和“数据压缩”的体现。

  1. 第一次扫描数据库:统计所有单项(1项集)的支持度,并丢弃那些不频繁的项(低于最小支持度)。

  2. 排序:将剩余的频繁项按照支持度从高到低排序。这样做的好处是,出现频率高的项更靠近树的根部,使得树的深度尽可能小,更加紧凑。

  3. 第二次扫描数据库:开始构建FP-tree。

    • 将每条事务(例如一次购物篮记录 {牛奶,面包,啤酒})中的项按第二步的顺序排序和过滤(例如排序后为 {啤酒,面包,牛奶})。

    • 从树的根节点开始,为这条事务创建一条分支。如果分支的前缀与已有路径共享,则共享节点的计数加1;如果不共享,则创建新的节点。

    • 同时,为了快速访问树中的节点,还维护了一个头指针表,它链接了所有相同名称的节点。

为什么这很巧妙?

  • 压缩数据库原始的数据库被压缩成了一棵FP-tree。事务数据中共享的频繁项被合并到了同一条路径上,大大减少了存储空间。

  • 信息完整:这棵树完整地保留了项集之间的关联和频率信息。


步骤二:从FP-tree中挖掘频繁项集

这是“分而治之”思想的体现。

挖掘过程是递归的。我们不是从整个大树开始挖,而是从小树枝开始。

  1. 从后缀开始:从头指针表中支持度最低的项(即树的枝叶末梢)开始,作为当前的后缀模式(例如 {牛奶})。

  2. 寻找条件模式基:沿着头指针表,找到FP-tree中所有包含此后缀的路径。这些路径去掉后缀后剩下的前缀部分,以及路径上的计数,就构成了条件模式基。这相当于为“牛奶”这个项创建了一个子数据库。

  3. 构建条件FP-tree:以这个条件模式基作为新的“数据库”,重复步骤一的过程,构建一个只与“牛奶”相关的条件FP-tree

  4. 递归挖掘:如果条件FP-tree不是空的(例如一条单路径),则递归地挖掘这棵小树。如果它是一条单路径,则直接生成该路径上所有节点的组合,并与后缀模式合并,即可得到所有频繁项集(例如,从路径 啤酒:3,面包:3 可以得到 {啤酒,面包,牛奶}{啤酒,牛奶}{面包,牛奶})。

  5. 移动指针:处理完一个后缀后,就回头指针表中移动到下一个支持度稍高的项(例如 {面包}),重复步骤2-4,直到处理完所有项。


为什么这很高效?

  • 分治:将挖掘整个大数据集的任务,分解为挖掘多个更小的条件数据库的任务,问题规模指数级减小。

  • 避免候选集生成:它不需要产生大量的候选集(这是Apriori的主要瓶颈),而是通过递归和直接拼接来生成频繁项集

  • 无重复扫描数据库:整个过程中,原始数据库只被扫描了两次(构建FP-tree时)。之后的所有操作都是在内存中对这棵压缩树进行操作,速度极快。


三、总结

核心思想与优势

方面核心思想阐述带来的优势
数据表示用空间换时间:花费内存构建一个高度压缩、信息完整的数据结构(FP-tree)。大幅减少I/O开销:仅需扫描数据库两次,后续操作均在内存中进行。
挖掘策略分而治之:通过递归地构建条件模式基和条件FP-tree,将大问题分解为多个小问题。效率极高:避免了产生海量候选集,算法复杂度通常远低于Apriori。
搜索方法模式增长:从后缀模式出发,通过拼接前缀路径来直接生成频繁模式,而非通过候选和测试。精准高效:没有无效的候选集生成和测试过程。

适用场景与缺点

  • 适用场景:非常适合挖掘稠密数据集(即事务中项之间相关性较强,共享前缀多),能获得很好的压缩效果和性能提升。

  • 缺点

    • 空间消耗:FP-tree及其递归过程中构建的条件FP-tree可能会消耗大量内存,尤其是在处理稀疏数据集或支持度阈值很低时。

    • 实现复杂度:相对于Apriori,其实现更为复杂。

FP-growth算法的核心在于创新地使用树结构来压缩存储数据,并基于此结构采用分而治之的策略进行高效挖掘,从而解决了Apriori算法多次扫描数据库和产生大量候选集的两个主要性能瓶颈。


四、例题

给定数据

TIDItems
10A, C, D
20B, C, E
30A, B, C, E
40B, E

设定最小支持度 (min_sup): 为了演示方便,我们设定最小支持度为 2 (即出现次数 >= 2)。


第一步:第一次扫描数据库,找出频繁1项集及其支持度

我们统计每个商品在所有订单中出现的总次数。

  • A: 出现在T10, T30 → 计数 = 2

  • B: 出现在T20, T30, T40 → 计数 = 3

  • C: 出现在T10, T20, T30 → 计数 = 3

  • D: 出现在T10 → 计数 = 1 (小于min_sup=2,丢弃)

  • E: 出现在T20, T30, T40 → 计数 = 3

筛选并排序后的频繁1项集(按支持度降序排列):

商品支持度
B3
C3
E3
A2

顺序为: B, C, E, A (支持度相同时,顺序可任意,但必须固定)


第二步:第二次扫描数据库,构建FP-tree

我们为每条事务(订单)中的商品按照上一步确定的顺序(B, C, E, A)进行排序,并过滤掉非频繁项(此例中为D)。

  1. T10A, C, D → 过滤D → A, C → 按顺序排序 → C, A (因为C的支持度3 > A的支持度2)

  2. T20B, C, E → 按顺序排序 → B, C, E

  3. T30A, B, C, E → 按顺序排序 → B, C, E, A

  4. T40B, E → 按顺序排序 → B, E


现在,我们开始构建FP-tree。Root是根节点,为空。

插入 T10: C, A

  • 从Root开始,创建子节点 C:1

  • 从 C:1 开始,创建子节点 A:1

插入 T20: B, C, E

  • 从Root开始,没有 B 子节点,创建 B:1

  • 从 B:1 开始,创建子节点 C:1

  • 从 C:1 开始,创建子节点 E:1

插入 T30: B, C, E, A

  • 从Root开始,已有 B 子节点,将其计数加1 → B:2

  • 从 B:2 开始,已有 C 子节点,将其计数加1 → C:2

  • 从 C:2 开始,已有 E 子节点,将其计数加1 → E:2

  • 从 E:2 开始,没有 A 子节点,创建新的子节点 A:1

插入 T40: B, E

  • 从Root开始,已有 B 子节点,将其计数加1 → B:3

  • 从 B:3 开始,没有 E 子节点B的子节点目前是 C:2,不是 E),因此创建一个新的子节点 E:1


最终构建的FP-tree如下图所示:
(为了清晰,我们同时维护一个头指针表,将相同名称的节点链接起来)

        Root/    \B:3    C:1/   \      \E:1   C:2    A:1\E:2\A:1

头指针表 (Header Table):

  • B → 链接到 (B:3)

  • C → 链接到 (C:1) -> (C:2)

  • E → 链接到 (E:1) -> (E:2)

  • A → 链接到 (A:1) -> (A:1)


第三步:挖掘FP-tree,寻找频繁项集

我们从头指针表底部的支持度最低的项开始(即A),然后向上是E,C,最后是B。

1. 以后缀 A 开始挖掘
  • 步骤 1: 寻找条件模式基 (Conditional Pattern Base)
    • 在FP-tree中,找到所有以 A 结尾的路径。

    • 路径1: C:1 -> A:1 (来自T10 C, A)

      • 前缀路径: C:1

    • 路径2: B:3 -> C:2 -> E:2 -> A:1 (来自T30 B, C, E, A)

      • 前缀路径: B:3, C:2, E:2

    • A 的条件模式基是 {C:1} 和 {B:3, C:2, E:2}

  • 步骤 2: 构建条件FP-tree (Conditional FP-tree) for A
    • 以条件模式基作为新的事务数据库。

    • 事务1: C (计数为1)

    • 事务2: B, C, E (计数为路径上的最小值,即 A 的计数1?这里需要修正:计数应取路径末尾目标节点A的计数,即每条前缀路径的计数应等于该路径上A节点的计数)

      • 修正:路径 C:1 -> A:1,A的计数是1,所以前缀路径 C 的计数是1。

      • 路径 B:3, C:2, E:2 -> A:1,A的计数是1,所以前缀路径 B, C, E 的计数是1。

    • 现在统计这个新“数据库”中项的支持度:

      • C: 1 (来自事务1) + 1 (来自事务2) = 2

      • B: 1 (来自事务2) = 1 (< min_sup=2,丢弃)

      • E: 1 (来自事务2) = 1 (< min_sup=2,丢弃)

    • 频繁项只有 C:2

    • 条件FP-tree for A 是一条单路径 C:2

  • 步骤 3: 挖掘条件FP-tree并生成频繁项集
    • 条件FP-tree是单路径 C:2

    • 该路径上所有项的非空组合与后缀 A 合并,即可得到频繁项集:

      • {C} + {A} = {C, A} (支持度 = min(2, ...) ,通常取条件模式基中计数的汇总,这里 {C,A} 的支持度是 C:1路径的1 + B,C,E:1路径的1? 更准确的做法:项集的支持度是其条件FP-tree根节点的计数? 这里我们最终看原始计数)

      • 从原始数据看,{C, A} 出现在T10和T30,支持度确实是2。

    • 所以,以后缀 A 挖掘出的频繁项集是: {C, A} (支持度2)。

结论:包含A的频繁项集为 {A} (2), {C,A} (2)。 ({A} 本身是频繁1项集)

 

(应该是:由于项目{B},{E}不满足最小支持度计数阈值,所以被删除。)


2. 以后缀 E 开始挖掘

  • 步骤 1: 寻找条件模式基 for E
    • 在FP-tree中,找到所有以 E 结尾的路径。

    • 路径1: B:3 -> C:2 -> E:2 (来自T20和T30 B,C,E)

      • 前缀路径: B:3, C:2 (计数为 E 的计数2)

    • 路径2: B:3 -> E:1 (来自T40 B,E)

      • 前缀路径: B:3 (计数为 E 的计数1)

    • E 的条件模式基是 {B:3, C:2} (计数2) 和 {B:3} (计数1)。

  • 步骤 2: 构建条件FP-tree for E
    • 事务1: B, C (计数2)

    • 事务2: B (计数1)

    • 统计新数据库支持度:

      • B: 2 + 1 = 3 (>=2,保留)

      • C: 2 (>=2,保留)

    • 按支持度降序排序:BC

    • 构建条件FP-tree:

      • 插入 B, C (计数2): Root -> B:2 -> C:2

      • 插入 B (计数1): Root -> B:2 (计数+1=3)

    • 最终的条件FP-tree for E:

      Root|B:3|C:2
  • 步骤 3: 挖掘条件FP-tree for E————(看不懂?)末尾有解释
    • 条件FP-tree不是空树也不是单路径,需要递归挖掘。

    • 首先,以后缀 {C, E} 开始挖掘 (从条件FP-tree的底部项C开始)

      • 寻找 {C, E} 的条件模式基: 在 E 的条件FP-tree中,找到所有以 C 结尾的路径。路径:B:3 -> C:2

        • 前缀路径: B:3 (计数为 C 的计数2)

      • 构建 {C, E} 的条件FP-tree:

        • 事务: B (计数2)

        • 统计支持度:B:2 (>=2,保留)

        • 条件FP-tree for {C,E} 是单路径 B:2

      • 挖掘 {C,E} 的条件FP-tree:

        • 生成组合: {B} + {C,E} = {B, C, E} (支持度2? 原始数据中出现在T20和T30,支持度2)

      • 所以,包含 {C,E} 的频繁项集: {C,E}{B,C,E}

        • {C,E} 的支持度:从其条件模式基 B:3(计数2) 可以看出计数为2。原始数据中出现在T20和T30,支持度2。

    • 然后,处理后缀 {E} 本身:条件FP-tree中有 B:3,所以 {B, E} 是频繁的。

    • 最终,包含 E 的频繁项集:

      • {E} (3)

      • {B, E} (3) (来自条件FP-tree中的 B:3)

      • {C, E} (2) (来自上面的挖掘)

      • {B, C, E} (2) (来自上面的挖掘)


3. 以后缀 C 开始挖掘
  • 步骤 1: 寻找条件模式基 for C
    • 在FP-tree中,找到所有以 C 结尾的路径。

    • 路径1: B:3 -> C:2 (来自T20和T30 B,C,...)

      • 前缀路径: B:3 (计数为 C 的计数2)

    • 路径2: Root -> C:1 (来自T10 C,...)

      • 前缀路径: {} (空,计数为 C 的计数1)

    • C 的条件模式基是 {B:3} (计数2) 和 {} (计数1)。

  • 步骤 2: 构建条件FP-tree for C
    • 事务1: B (计数2)

    • 事务2: {} (空集,计数1) //空集无法形成项集,忽略

    • 统计支持度:B:2 (>=2,保留)

    • 条件FP-tree for C 是单路径 B:2

  • 步骤 3: 挖掘条件FP-tree for C
    • 条件FP-tree是单路径 B:2

    • 生成组合: {B} + {C} = {B, C} (支持度2)

    • 所以,包含 C 的频繁项集:

      • {C} (3)

      • {B, C} (2)


4. 以后缀 B 开始挖掘
  • 步骤 1: 寻找条件模式基 for B
    • 在FP-tree中,找到所有以 B 结尾的路径。B 是直接挂在Root下的。

    • 路径: Root -> B:3

      • 前缀路径: {} (空,计数为 B 的计数3)

    • B 的条件模式基是空。

  • 步骤 2: 构建条件FP-tree for B
    • 条件模式基是空,因此条件FP-tree为空。

  • 步骤 3: 挖掘条件FP-tree for B
    • 无法生成新的频繁项集。

    • 包含 B 的频繁项集只有它自己: {B} (3)。


第四步:汇总所有频繁项集

将所有步骤中找到的频繁项集汇总,并去重({A}{B}{C}{E} 在第一步已得到)。

频繁1项集 (Frequent 1-itemsets):

  • {A}: 2

  • {B}: 3

  • {C}: 3

  • {E}: 3

频繁2项集 (Frequent 2-itemsets):

  • {C, A}: 2

  • {B, E}: 3

  • {C, E}: 2

  • {B, C}: 2

频繁3项集 (Frequent 3-itemsets):

  • {B, C, E}: 2

频繁4项集 (Frequent 4-itemsets):

至此,我们使用FP-growth算法完整地找出了给定数据集中的所有频繁项集。整个过程的核心在于构建FP-tree并通过递归挖掘条件模式基来避免生成大量的候选集。

最终答案

Python数据挖掘实战:微课版 - 9.3 FP-growth算法 - 王磊 邱江涛 - 微信读书

细节补充

我们现在的任务是从 E的条件FP-tree 里挖宝贝。这棵树长这样:

(Root)|
(B:3)|
(C:2)

目标:找到所有带 E 的宝贝组合(比如 {B,E}{C,E}{B,C,E})。


第一步:看树,直接拿到第一个宝贝

  • 树上写着 B:3

  • 意思是:B 和 E 一起出现了 3 次。

  • ✅ 所以,我们找到了第一个宝贝:{B, E}


第二步:处理树上的下一个点 C

树上还有一个 C:2挂在 B 下面。我们不能直接用它,需要“放大镜”看仔细。

为什么要为 {C,E} 再建一棵树?
答:为了搞清楚 C 是和谁一起出现的,这样才能拼出更大的宝贝。

怎么做?3个小步:

  1. 找 C 的路径:在 E 的树里,找到通到 C 的路。只有一条:B -> C

  2. 看这条路的意思:这条路 B -> C 计数是2。

    • 翻译BCE 这三个家伙一起出现了 2 次

  3. 建新树:我们就为 C 和 E 这个组合,建一棵超小的新树,只记录和它俩一起玩的人。

    • 这棵新树只有:(B:2)

    • 意思:和 C、E 一起玩的,只有 B,而且玩了2次。


第三步:挖这棵超小的新树

新树 (B:2) 非常简单,一眼就能看穿。

  • 它告诉我们两件事:

    1. ✅ {C, E} 这个组合自己出现了 2 次。(因为 B 出现2次的前提是 C 和 E 肯定也在)

    2. ✅ {B, C, E} 这个更大的组合出现了 2 次。(就是 B 自己加上 C 和 E


最终我们找到了所有带 E 的宝贝:

从 E 的树本身:{B, E} (3次)

从为 {C,E} 建的小树里:{C, E} (2次),{B, C, E} (2次)

(再加上最开始就知道的 {E} 自己)


FP-growth算法经典面试题

1. 请简要说明FP-growth算法的核心思想是什么?

高分回答:
“FP-growth算法的核心思想是‘分而治之’和‘用空间换时间’。它通过两次扫描数据库,构建一个高度压缩的数据结构——FP树(Frequent Pattern Tree),将原始数据完整的频次信息压缩存储在其中。后续的挖掘过程不再需要反复访问原始数据库,而是通过递归地在FP树上构建条件模式基和条件FP树来挖掘全部的频繁项集。这种方法完美避免了Apriori算法中耗时的候选集生成与测试过程。”

关键词: 分而治之、空间换时间、FP树、两次扫描、条件模式基、递归挖掘、避免候选集生成。


2. 和Apriori算法相比,FP-growth有什么优缺点?

高分回答:
“优点是效率非常高。主要体现在两方面:第一,它通常只需要扫描两次数据库,而Apriori需要扫描K+1次(K为最长频繁项集长度),I/O开销大大减少。第二,它不产生候选集,彻底避免了Apriori中候选集数量爆炸的问题。

缺点主要是空间消耗可能较大FP-tree及其递归构建的条件FP-tree需要存储在内存中,数据集非常稀疏或最小支持度设置得很低时,树的规模可能会很大,对内存是一个考验。”

背诵模板:

  • 优点:快。 扫描次数少(2次 vs. K+1次),无候选集。

  • 缺点:可能占内存。 树结构在密集数据下压缩性好,但稀疏数据下可能内存消耗大。


3. 解释一下什么是“条件模式基”(Conditional Pattern Base)?

高分回答:
“条件模式基是FP-growth算法递归挖掘过程中的一个核心概念。当我们要挖掘以某个项(比如项X)为后缀的所有频繁项集时,我们需要在FP树中找到所有包含X的路径。这些路径中,去掉后缀项X之后的前缀部分,以及路径的计数信息,就共同构成了项X的条件模式基。它本质上是一个子数据库,记录了所有与X频繁共现的项及其频次,是构建更小子树(条件FP-tree)的基础。”

关键词: 包含X的路径、去掉X后的前缀、子数据库、构建条件FP-tree的基础。


4. FP-growth算法在什么情况下效率会下降?

高分回答:
“主要在两种情况下效率会相对下降:

  1. 数据集非常稀疏时:这意味着事务中物品的共同前缀很少,导致构建出的FP-tree分支很多,压缩效果不佳,树会变得又宽又浅,占用大量内存,递归挖掘的效率也会降低。

  2. 最小支持度阈值设置得非常低时:这会导致大量非频繁的项变成频繁项,使得FP-tree的规模变得非常大,同样会消耗大量内存和计算资源。”

关键词: 数据稀疏、支持度阈值低、树结构庞大、内存消耗大。


5. (可选) 能画一下FP-tree的基本结构吗?

如果问到,你可以画一个简单的示意图并解释:

        Root/  \B:3   C:1/   \     \C:2   E:1    A:1\E:2\A:1

解释: “从上到下表示项的先后顺序,节点上的数字是计数。从根节点到任意一个节点就形成一条路径,代表一个项集的出现模式。比如 B:3 -> C:2 -> E:2 这条路径,表示项集 {B, C, E} 出现了2次。”


面试实战技巧
  1. 先总后分:先一句话总结核心思想,再应要求展开细节。

  2. 对比突出:谈到FP-growth,必提Apriori,用对比凸显你的理解深度。

  3. 扬长避短:问优缺点时,先说优点,再“诚实”地提到缺点,并说明在什么情况下缺点会成为问题。

  4. 自信背诵:把这些答案背熟,面试时就能脱口而出,显得非常熟练。

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

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

相关文章

在IDEA中DEBUG调试时查看MyBatis-Plus动态生成的SQL语句

在IDEA中DEBUG调试时查看MyBatis-Plus动态生成的SQL语句前言&#xff1a;动态SQL调试的痛与解决方案一、准备工作&#xff1a;调试前的检查清单二、基础方法&#xff1a;SqlSessionTemplate断点调试步骤1&#xff1a;定位SqlSessionTemplate类步骤2&#xff1a;在invoke方法上设…

Linux 文本处理三剑客:awk、grep、sed 完全指南

Linux 文本处理三剑客&#xff1a;awk、grep、sed 完全指南 1. 概述 Linux 系统提供了三个强大的文本处理工具&#xff1a;awk、grep 和 sed&#xff0c;它们各有所长&#xff0c;结合使用可以高效地处理文本数据。 awk&#xff1a;擅长文本分析和格式化输出&#xff0c;是一…

pyecharts可视化图表组合组件_Grid:打造专业数据仪表盘

pyecharts可视化图表组合组件_Grid&#xff1a;打造专业数据仪表盘 目录pyecharts可视化图表组合组件_Grid&#xff1a;打造专业数据仪表盘引言图表1&#xff1a;Grid-Overlap-多X/Y轴示例代码解析1. 图表创建2. 多轴配置3. 图表重叠4. Grid布局效果与应用图表2&#xff1a;Gri…

【电气工程学习】

三极管中&#xff1a;集电极C,基极B&#xff0c;发射极E接线&#xff1a;棕正蓝负黑信号NPN开关输出的是我们的0V,也叫低电平PNP开关输出的是24V,也就是高电平&#xff08;NPN开关导通时&#xff0c;相当于把输出端“拉”到0V&#xff08;低电平&#xff09;&#xff0c;称为“…

【嵌入式】CAN通信

CAN 总线最初由博世于1980年代为汽车行业开发&#xff0c;能够简化复杂的布线网络&#xff0c;还确保可靠和安全的数据传输。 1.CAN技术解释 CAN网络中的每个节点&#xff0c;都是平等的&#xff0c;没有主次之分&#xff0c;这一点和SPI和I2C不同。每个节点都可以在需要的时…

Apache ShenYu网关与Nacos的关联及如何配合使用

Apache ShenYu 网关与 Nacos 之间的关系可以概括为 “协作互补”:Nacos 作为 服务注册与配置中心,为 ShenYu 提供动态的服务发现和配置管理能力,而 ShenYu 作为 流量网关,依赖 Nacos 实现路由信息的动态更新和实时生效。以下是详细解析: 1. 核心关系图解 拉取服务列表/路…

【CPP】一个CPP的Library(libXXXcore)和测试程序XXX_main的Demo

一个CPP的Library和测试程序Demo 1. 思路描述 目录结构 总控CMakeList.txt文件 2. Library代码实现 2.1 XXXLib.hpp文件(对外的接口定义文件)和XXXLib.cpp文件 2.1.1 XXXLib.hpp文件 2.1.2 XXXLib.cpp文件 2.2 CXXXLibApi.hpp文件和CXXXLibApi.cpp文件(内部的API基类) 2.2.1 CX…

【YashanDB认证】学习YashanDB的探索之路:从入门到实践

在国产数据库蓬勃发展的浪潮中&#xff0c;选择了YashanDB作为技术学习的切入点。这不仅让我深入了解了数据库的核心技术&#xff0c;也让我深刻体会到国产数据库在性能、可靠性和生态适配上的创新价值。以下是我在学习YashanDB过程中的经验与感悟。 一、YashanDB基础介绍 Ya…

element UI 和 element plus 在组件上有哪些不同

Element UI 和 Element Plus 都是基于 Vue 的桌面端 UI 组件库&#xff0c;由同一团队&#xff08;饿了么前端团队&#xff09;开发和维护。Element Plus 是 Element UI 的升级版&#xff0c;专为 Vue 3 设计&#xff0c;而 Element UI 仅支持 Vue 2。以下是它们在组件层面的主…

【3D重建技术】如何基于遥感图像和DEM等数据进行城市级高精度三维重建?

城市级高精度三维重建是融合多源空间数据&#xff08;遥感图像、DEM、GIS矢量等&#xff09;、计算机视觉与地理信息处理技术的复杂过程&#xff0c;核心目标是构建包含“地形地物&#xff08;建筑、道路、植被等&#xff09;”的真实、高精度三维场景。其流程可分为数据准备、…

【unitrix数间混合计算】3.4 无符号小数部分标记trait(bin_unsigned.rs)

一、源码 这段代码定义了一个类型级二进制小数系统&#xff0c;用于在编译时表示和验证二进制小数部分的有效性。 use crate::number::{F0, BFrac, Bit};/// 标记合法的二进制小数部分类型 pub trait BinFrac: Copy Default static {}// 空小数部分&#xff08;表示值为0&…

从一次 DDoS 的“死亡回放”看现代攻击链的进化

本文记录的是作者上周在测试环境真实踩到的坑。为了让读者能复现并亲手体验防御思路&#xff0c;文末给出了一份最小可运行的 Go 脚本&#xff0c;支持本地压测 日志回放&#xff0c;方便对比加防护前后的差异。攻击现场还原 周一凌晨 2:14&#xff0c;监控群里突然弹出告警&a…

LeetCode热题100--101. 对称二叉树--简单

1. 题目 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a;输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true 示例 2&#xff1a;输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false 2. 题解 /*** Definition for…

Pub/Sub是什么意思

Pub/Sub&#xff08;发布/订阅模式&#xff09;​​ 是一种异步消息通信范式&#xff0c;用于分布式系统中不同组件之间的解耦通信。它的核心思想是将消息的发送方&#xff08;发布者&#xff09;​​ 和接收方&#xff08;订阅者&#xff09;​​ 分离&#xff0c;通过一个中间…

Redisson3.14.1及之后连接阿里云redis代理模式,使用分布式锁:ERR unknown command ‘WAIT‘

文章目录一、问题背景1、问题原因2、阿里云对Redisson的支持二、解决方案1、继续使用Redisson3.14.0版本2、阿里云redis改为直连模式3、升级Redisson版本到 3.47.0一、问题背景 1、问题原因 阿里云Redis分直连和代理模式&#xff0c;其中代理模式是不支持WAIT命令的。 目前尝…

Linux: RAID(磁盘冗余阵列)配置全指南

Linux&#xff1a;RAID&#xff08;磁盘冗余阵列&#xff09;配置一、RAID 核心概念 RAID&#xff08;Redundant Array of Independent Disks&#xff0c;磁盘冗余阵列&#xff09;通过将多个物理磁盘组合为一个逻辑存储设备&#xff0c;实现提升读写性能、增强数据安全性或平衡…

《GPT-OSS 模型全解析:OpenAI 回归开源的 Mixture-of-Experts 之路》

目录 一、引言 二、GPT-OSS 模型简介 1. 版本与定位 2. 架构设计与技术亮点 2.1 Mixture-of-Experts&#xff08;MoE&#xff09;架构 2.2 高效推理机制与优化技术 2.3 模型对比 三、模型部署 1. 安装相关依赖 1.1 uv 安装 1.2 conda 安装 1.3 Transformers 运行 g…

【力扣热题100】双指针—— 接雨水

题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 注意&#xff1a;答案中不可以包含重复的三元组。输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由…

51单片机拼接板(开发板积木)

一、前言 1.1 背景 读书那会儿&#xff08;2013年左右&#xff09;网上接了很多51单片机的设计。 当时有个痛点: 每张板子都是定制的&#xff0c;画板子&#xff0c;打样&#xff0c;写代码需要花费很多时间。 希望有一张板子&#xff0c;能够实现绝大多数单片机的功能&#xf…

使用segment-anything将目标检测label转换为语义分割label

使用segment-anything将目标检测label转换为语义分割label一、segment-anything简介二、segment-anything安装2.1安装方法2.2预训练模型下载三、将目标检测label转换为语义分割label3.1示例代码3.2代码说明一、segment-anything简介 segment-anything是facebookresearch团队开…