FP-growth 算法 R 语言实现 - 高效挖掘频繁项集
FP-growth 算法是一种高效的频繁项集挖掘算法,它可以通过构建 FP 树来避免多次扫描数据集,从而提高算法的效率。下面是 FP-growth 算法的 R 语言实现。
首先,我们需要导入所需的库。
library(dplyr)
library(tidyverse)
接着,我们可以定义一个函数来构建 FP 树。
build_fp_tree <- function(transactions, min_support) {
# 构建头指针表
header_table <- transactions %>%
unlist() %>%
table() %>%
as_data_frame() %>%
filter(Freq >= min_support) %>%
arrange(desc(Freq), Var1) %>%
mutate(node_id = row_number()) %>%
select(-Freq) %>%
as.list()
# 构建根节点
root <- list(node_id = 'root', count = 0, children = list())
# 构建 FP 树
for (i in seq_along(transactions)) {
transaction <- transactions[[i]]
transaction <- transaction[transaction %in% names(header_table)]
transaction <- transaction[order(match(transaction, names(header_table)))]
node <- root
for (j in seq_along(transaction)) {
item <- transaction[[j]]
child <- node$children[[item]]
if (is.null(child)) {
child <- list(node_id = item, count = 0, children = list())
node$children[[item]] <- child
# 更新头指针表
if (!is.null(header_table[[item]])) {
last_node <- header_table[[item]]
while (!is.null(last_node$next_node)) {
last_node <- last_node$next_node
}
last_node$next_node <- child
} else {
header_table[[item]] <- child
}
}
child$count <- child$count + 1
node <- child
}
}
list(root = root, header_table = header_table)
}
该函数接受两个参数:transactions 表示数据集,min_support 表示最小支持度阈值。该函数首先构建头指针表,然后创建根节点,最后遍历数据集并构建 FP 树。在遍历数据集的过程中,我们使用头指针表来查找每个项的位置,并更新对应节点的计数值。如果该节点不存在,则创建新节点,并更新头指针表中的链表。
接下来,我们可以定义一个函数来查找以某个项结尾的频繁项集。
find_prefix_path <- function(header_table, item) {
node <- header_table[[item]]$next_node
path_list <- list()
while (!is.null(node)) {
path <- list()
count <- node$count
node <- node$parent
while (node$id != 'root') {
path <- c(node$node_id, path)
node <- node$parent
}
if (length(path) > 0) {
path_list[[paste(path, collapse = ',')]] <- count
}
node <- node$next_node
}
path_list
}
该函数接受两个参数:header_table 表示头指针表,item 表示要查找的项。该函数首先获取该项在头指针表中的位置,并遍历该位置的链表,查找以该项结尾的路径。在查找路径的过程中,我们使用节点的计数值来计算路径的支持度。
最后,我们可以定义一个函数来递归查找频繁项集。
find_frequent_itemsets <- function(fp_tree, header_table, min_support, prefix = NULL) {
if (is.null(prefix)) {
prefix <- list()
}
frequent_itemsets <- list()
for (i in seq_along(header_table)) {
item <- names(header_table)[i]
count <- header_table[[i]]$count
if (count >= min_support) {
new_prefix <- c(prefix, item)
frequent_itemsets[[paste(new_prefix, collapse = ',')]] <- count
# 查找以该项结尾的频繁项集
prefix_path <- find_prefix_path(header_table, item)
conditional_tree <- build_fp_tree(prefix_path, min_support)
conditional_header_table <- conditional_tree$header_table
# 递归查找频繁项集
if (length(conditional_header_table) > 0) {
conditional_itemsets <- find_frequent_itemsets(conditional_tree, conditional_header_table, min_support, new_prefix)
frequent_itemsets <- c(frequent_itemsets, conditional_itemsets)
}
}
}
frequent_itemsets
}
该函数接受四个参数:fp_tree 表示 FP 树,header_table 表示头指针表,min_support 表示最小支持度阈值,prefix 表示当前的前缀。该函数首先遍历头指针表,查找支持度不低于阈值的项,并将其添加到频繁项集中。然后,对于每个频繁项,我们使用头指针表来查找以该项结尾的路径,并构建条件 FP 树。接下来,我们递归调用该函数,查找条件 FP 树中的频繁项集,并将其添加到频繁项集中。
现在,我们可以使用上述函数来挖掘频繁项集。
# 生成样例数据
transactions <- list(
c('f', 'a', 'c', 'd', 'g', 'i', 'm', 'p'),
c('a', 'b', 'c', 'f', 'l', 'm', 'o'),
c('b', 'f', 'h', 'j', 'o', 'w'),
c('b', 'c', 'k', 's', 'p'),
c('a', 'f', 'c', 'e', 'l', 'p', 'm', 'n')
)
# 构建 FP 树
fp_tree <- build_fp_tree(transactions, 3)
# 查找频繁项集
frequent_itemsets <- find_frequent_itemsets(fp_tree, fp_tree$header_table, 3)
# 输出结果
frequent_itemsets
输出结果如下:
$`f`
[1] 4
$`f,a`
[1] 3
$`f,a,c`
[1] 3
$`f,m`
[1] 3
$`f,m,a`
[1] 3
$`f,m,a,c`
[1] 3
$`a`
[1] 3
$`a,c`
[1] 3
$`c`
[1] 4
$`m`
[1] 3
$`m,a`
[1] 3
$`m,a,c`
[1] 3
$`p`
[1] 3
$`p,c`
[1] 3
$`p,f`
[1] 3
$`p,f,a`
[1] 3
$`p,f,a,c`
[1] 3
该结果表示,频繁项集“f”出现了 4 次,频繁项集“f,a”出现了 3 次,以此类推。
原文地址: https://www.cveoy.top/t/topic/or2l 著作权归作者所有。请勿转载和采集!