記事ディレクトリ
0 個の質問のアイデア
(コンテストの質問が出たらすぐに CSDN で共有します)
https://blog.csdn.net/dc_sinor?type=blog
1 アルゴリズムの紹介
FP-Tree アルゴリズムの正式名は、FrequentPattern Tree アルゴリズムです。これは、頻出パターン ツリー アルゴリズムです。Apriori アルゴリズムと同様に、頻出アイテム セットのマイニングにも使用されます。ただし、違いは、FP-Tree アルゴリズムがApriori アルゴリズムの最適化。Apriori の問題を解決します。アルゴリズムはプロセス中に多数の候補セットを生成しますが、FP-Tree アルゴリズムは候補セットを生成せずに頻繁なパターンを発見します。ただし、頻繁なパターンがマイニングされた後、相関ルールを生成する手順は Apriori と同じです。
頻繁に使用されるアイテムセットをマイニングするためのアルゴリズムには 2 つの一般的なタイプがあります。1 つは Apriori アルゴリズムで、もう 1 つは FP-growth です。Apriori は、候補セットの構築とフィルタリングを継続的に行うことによって、頻繁に使用されるアイテム セットをマイニングします。これには、元のデータを複数回スキャンする必要があります。元のデータが大きい場合、ディスク I/O の数が多すぎて、効率が比較的低くなります。FPGrowth は Apriori の「トライアル」戦略とは異なり、アルゴリズムは元のデータを 2 回スキャンし、FP ツリー データ構造を通じて元のデータを圧縮するだけで済み、より効率的です。
FP は Frequent Pattern の略で、アルゴリズムは主に FP ツリーの構築と頻出項目セットのマイニングの 2 つのステップに分かれます。
2 FP ツリー表現
FP ツリーは、トランザクションを 1 つずつ読み込み、トランザクションを FP ツリー内のパスにマッピングすることによって構築されます。異なるトランザクションには複数の同一のアイテムがある可能性があるため、それらのパスが部分的に重複する可能性があります。パスが互いに重なり合うほど、FP ツリー構造を使用して得られる圧縮効果は高くなります。FP ツリーがメモリに格納できるほど小さい場合は、頻繁に使用されるアイテムのセットをメモリ内構造から直接抽出することができます。ハードドライブ上のメモリに保存された構造データを繰り返しスキャンします。
FP ツリーは次の図に示されています:
一般に、データのトランザクションはいくつかの共通項目を共有することが多いため、FP ツリーのサイズは非圧縮データのサイズよりも小さくなります。最良の場合、すべてのトランザクションは同じ項目セット (FP を持ちます)ツリーにはノード パスが 1 つしか含まれていません。各トランザクションに固有の項目セットがある場合、最悪のケースが発生します。トランザクションには共通の項目が含まれていないため、FP ツリーのサイズは実際には元のデータのサイズと同じになります。
FP ツリーのルート ノードは φ で表され、残りのノードにはデータ項目とこのパス上のデータ項目のサポートが含まれます。各パスはトレーニング データ内の最小サポートを満たすデータ項目のセットです。 FP ツリーには、上の図の青い接続で表されているように、リンクされたリストに接続されているすべての同一の項目も含まれています。
ツリー内の同じ項目にすばやくアクセスするには、同じ項目を持つノードを接続するポインターのリスト (headTable) を維持することも必要です。各リスト要素には、データ項目、項目のグローバル最小サポート、およびFP ツリー内のネックレスを指すリスト、ヘッダーのポインター。
3 FPツリーの構築
これで、次のデータが得られました。
FP 成長アルゴリズムは、FP ツリーを構築するために元のトレーニング セットを 2 回スキャンする必要があります。
最初のスキャンでは、最小サポートを満たさないすべての項目がフィルターで除外されます。最小サポートを満たす項目については、グローバル最小サポートに従って並べ替えられます。これに基づいて、処理の便宜上、並べ替えることもできます。アイテムのキーワードに従ってもう一度。
2 回目のスキャンでは、FP ツリーが構築されます。
スキャンに参加するのは、フィルタリングされたデータです。データ項目が初めて見つかった場合は、ノードが作成され、そのノードへのポインタが headTable に追加されます。それ以外の場合は、項目に対応するノードが、パスとノードが変更された情報。具体的なプロセスは次のとおりです。
上記からわかるように、headTable は FPTree と一緒に作成されるのではなく、最初のスキャン時に作成されるため、FPTree を作成するときは、対応するノードにポインタを指定するだけで済みます。トランザクション 004 から開始して、異なるパス上の同じ項目がリンク リストに接続されるように、ノード間の接続を作成する必要があります。
4 実装コード
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()
上記のコードは、最初のスキャン後に各トレーニング データのフィルタリングされた項目を並べ替えませんが、2 番目のスキャンで並べ替えを行うため、コードの複雑さを簡素化できます。
コンソール情報:
モデリング情報
データ共有: 最強のモデリングデータ