Directorio de artículos
0 Ideas para el concurso
(Compartir en CSDN tan pronto como salgan las preguntas de la competencia)
https://blog.csdn.net/dc_sinor?type=blog
1 Introducción al algoritmo
El nombre completo del algoritmo FP-Tree es el algoritmo FrequentPattern Tree, que es el algoritmo de árbol de patrones frecuentes.Al igual que el algoritmo Apriori, también se usa para extraer conjuntos de elementos frecuentes, pero la diferencia es que el algoritmo FP-Tree es una optimización proceso del algoritmo Apriori Resuelve el Apriori El algoritmo generará una gran cantidad de conjuntos de candidatos en el proceso, mientras que el algoritmo FP-Tree encuentra patrones frecuentes sin generar conjuntos de candidatos. Pero después de extraer los patrones frecuentes, los pasos para generar reglas de asociación siguen siendo los mismos que a priori.
Hay dos algoritmos comunes para extraer conjuntos de elementos frecuentes, uno es el algoritmo Apriori y el otro es el crecimiento de FP. A priori extrae conjuntos de elementos frecuentes mediante la construcción continua de conjuntos de candidatos y la selección de conjuntos de candidatos. Necesita escanear los datos originales varias veces. Cuando los datos originales son grandes, los tiempos de E/S del disco son demasiados y la eficiencia es relativamente baja. FPGrowth es diferente de la estrategia de "sondeo" de Apriori. El algoritmo solo necesita escanear los datos originales dos veces y comprimir los datos originales a través de la estructura de datos del árbol FP, que es más eficiente.
FP significa patrón frecuente, y el algoritmo se divide principalmente en dos pasos: construcción de árboles FP y extracción de conjuntos de elementos frecuentes.
Representación de árbol de 2 FP
El árbol de FP se construye leyendo las transacciones una por una y asignando las transacciones a una ruta en el árbol de FP. Dado que diferentes transacciones pueden tener varios elementos idénticos, sus rutas pueden superponerse parcialmente. Cuanto más se superpongan las rutas entre sí, mejor será el efecto de compresión obtenido al usar la estructura de árbol de FP; si el árbol de FP es lo suficientemente pequeño para almacenarse en la memoria, los conjuntos de elementos frecuentes se pueden extraer directamente de la estructura en la memoria sin tener que escanear repetidamente los datos almacenados en el disco duro.
En la siguiente figura se muestra un árbol de FP:
Por lo general, el tamaño del árbol de FP es más pequeño que el de los datos sin comprimir, porque las transacciones de los datos a menudo comparten algunos elementos comunes. En el mejor de los casos, todas las transacciones tienen el mismo conjunto de elementos. , FP El árbol contiene solo una ruta de nodo; cuando cada transacción tiene un conjunto de elementos único, lo que lleva al peor de los casos, dado que las transacciones no contienen elementos comunes, el tamaño del árbol FP es efectivamente el mismo que el tamaño del original datos.
El nodo raíz del árbol FP está representado por φ, y los nodos restantes incluyen un elemento de datos y el soporte del elemento de datos en este camino; cada camino es un conjunto de elementos de datos que cumple con el soporte mínimo en los datos de entrenamiento; el FP El árbol también incluye todos Los mismos elementos están conectados en una lista vinculada, que se representa con una línea azul en la figura anterior.
Para acceder rápidamente al mismo elemento en el árbol, también es necesario mantener una lista de punteros (headTable) que conecta los nodos con el mismo elemento.Cada elemento de la lista incluye: elemento de datos, el soporte mínimo global del elemento y un lista de enlaces que apunta al elemento en el puntero del árbol FP del encabezado.
3 Construir árbol FP
Ahora tenga los siguientes datos:
El algoritmo de crecimiento de FP necesita escanear el conjunto de entrenamiento original dos veces para construir el árbol de FP.
En el primer escaneo, se filtran todos los artículos que no cumplen con el soporte mínimo, para los artículos que cumplen con el soporte mínimo, se ordenan de acuerdo con el soporte mínimo global. ordenados de nuevo según las palabras clave de los elementos.
El segundo escaneo construye el árbol FP.
Participar en el escaneo son los datos filtrados. Si se encuentra un elemento de datos por primera vez, cree el nodo y agregue un puntero al nodo en la tabla de cabecera; de lo contrario, busque el nodo correspondiente al elemento de acuerdo con la ruta y modifique el nodo. información. El proceso específico es el siguiente:
De lo anterior se puede ver que el headTable no se crea junto con el FPTree, sino que se ha creado en el primer escaneo Al crear el FPTree, solo necesita apuntar el puntero al nodo correspondiente. A partir de la transacción 004, es necesario crear una conexión entre los nodos para que los mismos elementos en diferentes rutas se conecten en una lista enlazada.
4 Código de implementación
def loadSimpDat():
simpDat = [['r', 'z', 'h', 'j', 'p'],
['z', 'y', 'x', 'w', 'v', 'u', 't', 's'],
['z'],
['r', 'x', 'n', 'o', 's'],
['y', 'r', 'x', 'z', 'q', 't', 'p'],
['y', 'z', 'x', 'e', 'q', 's', 't', 'm']]
return simpDat
def createInitSet(dataSet):
retDict = {
}
for trans in dataSet:
fset = frozenset(trans)
retDict.setdefault(fset, 0)
retDict[fset] += 1
return retDict
class treeNode:
def __init__(self, nameValue, numOccur, parentNode):
self.name = nameValue
self.count = numOccur
self.nodeLink = None
self.parent = parentNode
self.children = {
}
def inc(self, numOccur):
self.count += numOccur
def disp(self, ind=1):
print(' ' * ind, self.name, ' ', self.count)
for child in self.children.values():
child.disp(ind + 1)
def createTree(dataSet, minSup=1):
headerTable = {
}
#此一次遍历数据集, 记录每个数据项的支持度
for trans in dataSet:
for item in trans:
headerTable[item] = headerTable.get(item, 0) + 1
#根据最小支持度过滤
lessThanMinsup = list(filter(lambda k:headerTable[k] < minSup, headerTable.keys()))
for k in lessThanMinsup: del(headerTable[k])
freqItemSet = set(headerTable.keys())
#如果所有数据都不满足最小支持度,返回None, None
if len(freqItemSet) == 0:
return None, None
for k in headerTable:
headerTable[k] = [headerTable[k], None]
retTree = treeNode('φ', 1, None)
#第二次遍历数据集,构建fp-tree
for tranSet, count in dataSet.items():
#根据最小支持度处理一条训练样本,key:样本中的一个样例,value:该样例的的全局支持度
localD = {
}
for item in tranSet:
if item in freqItemSet:
localD[item] = headerTable[item][0]
if len(localD) > 0:
#根据全局频繁项对每个事务中的数据进行排序,等价于 order by p[1] desc, p[0] desc
orderedItems = [v[0] for v in sorted(localD.items(), key=lambda p: (p[1],p[0]), reverse=True)]
updateTree(orderedItems, retTree, headerTable, count)
return retTree, headerTable
def updateTree(items, inTree, headerTable, count):
if items[0] in inTree.children: # check if orderedItems[0] in retTree.children
inTree.children[items[0]].inc(count) # incrament count
else: # add items[0] to inTree.children
inTree.children[items[0]] = treeNode(items[0], count, inTree)
if headerTable[items[0]][1] == None: # update header table
headerTable[items[0]][1] = inTree.children[items[0]]
else:
updateHeader(headerTable[items[0]][1], inTree.children[items[0]])
if len(items) > 1: # call updateTree() with remaining ordered items
updateTree(items[1:], inTree.children[items[0]], headerTable, count)
def updateHeader(nodeToTest, targetNode): # this version does not use recursion
while (nodeToTest.nodeLink != None): # Do not use recursion to traverse a linked list!
nodeToTest = nodeToTest.nodeLink
nodeToTest.nodeLink = targetNode
simpDat = loadSimpDat()
dictDat = createInitSet(simpDat)
myFPTree,myheader = createTree(dictDat, 3)
myFPTree.disp()
El código anterior no ordena los elementos filtrados de cada dato de entrenamiento después del primer escaneo, pero coloca la clasificación en el segundo escaneo, lo que puede simplificar la complejidad del código.
Información de la consola: