重点讲一下置信度、提升度、失衡率和KULC;
置信度
公式:P(Y|X) = P(XY) / P(X)
置信度从公式含义上就是条件概率,即在X发生的条件下Y发生的概率。如果置信度很高,说明X发生时Y也总是发生。但这能说明是因为X的发生促进了Y的发生吗?未必。设想一种极端情况,Y在无条件下总是发生,这会导致X发生时Y也总是陪伴其左右。因此仅靠这一指标,我们无法下结论说X->Y。
提升度
公式:P(Y|X) / P(Y) = P(XY) / [P(X) * P(Y)]
提升度正是为了解决置信度的这一问题,在置信度的基础上除以了一个P(Y);
直观理解,就是“X发生后对Y发生概率的提升比率”。通过提升度,我们就可以直观地看出X对Y的促进作用。
①如果提升度=1, 意味着P(XY) = P(X) * P(Y), 这就是当X, Y互相独立时概率论中经典的独立概率公式。此时A,B相互独立,没有任何关系。
②如果提升度<1, 说明X发生后,反倒使Y发生的概率下降了,说明X对Y是一个排斥作用。
③如果提升度>1, 说明X发生促进了Y的发生。特别的,我们通常认为提升度>3,X才算是对Y有显著的积极影响。
但是,提升度也存在一个问题。从公式上看,提升度=P(Y|X) / P(Y),P(Y|X)是条件概率,不受整体数据集整体大小的影响。但是P(Y)却受到整体数据集大小的影响。
设想一种极端情况,如果X和Y都不发生的项集非常多,这会使P(Y) = "Y出现的项集 / 项集数" 中 Y出现的项集很少,而项集数很多,导致P(Y)很小,进而导致提升度很高。此时尽管X对Y是由促进作用,但这个促进作用可能并不像提升度显示的那样这么大。
失衡率
公式: P(Y|X) / P(X|Y)
失衡率从公式上看,是两个条件概率做比。由于没有单独的支持度如P(X)或P(Y)作分子或分母,它直接避免了零和事务的影响,能够直观显示A->B的促进大还是B->A的促进作用大。但是,需要注意的是,失衡率反映的只是一种促进的相对程度。
比如,如果X->Y的促进作用很小,但Y->X的促进作用更小,而且小得多。这会使得失衡率从数值上看似乎很大。此时我们如果认为X->Y有明显促进作用,就大错特错了。一定要结合KULC使用!
KULC
公式:0.5 * P(Y|X) + 0.5 * P(X|Y)
KULC就是两个条件概率加总的均值。它的直接作用是看X、Y的关联程度。
当KULC越趋近于1时, X, Y之间的关系越紧密。但是,我们容易观察到,KULC的公式是对称的。因此KULC的值并没有反映是X->Y还是Y->X。要想判断这点,通常需要结合失衡率使用;
为了更直观地理解它,我们举一个例子:
设想一种极端情况。即A的支持度很低,B的支持度很高。这会导致P(B|A)很高,但是P(A|B)很低,于是KULC->0.5; 综合失衡率,我们就清楚的知道A对B没有什么促进作用。
代码实现
代码的实现思路请具体看思维导图里的步骤。特别的,最新版mlxtend里面的association_rules()函数新增了一个num_itersets的关键字参数,其含义是返回频繁项集中满足条件:
metric > min_threshold的条目数。此处我用了一个不痛不痒的数目即返回100条。
import pandas as pd
from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import apriori, association_rules
NUM_ITERSETS = 100
class AssociationRuleMining:
def __init__(self, data_frame: pd.DataFrame, min_support: int = 0.1):
self.data_frame = self.one_hot_encoding(data_frame)
self.frequent_itemsets = self.generate_frequent_itemsets(min_support)
self.rules = self.generate_association_rules()
def one_hot_encoding(self, data_frame: pd.DataFrame):
# 要先将数据转化成: list[list[str]]的形式才能进行独热编码
df_arr = self.transform_to_list(data_frame)
te = TransactionEncoder() # 定义模型
df_tf = te.fit_transform(df_arr)
return pd.DataFrame(df_tf,columns=te.columns_)
def transform_to_list(self, data_frame: pd.DataFrame):
df_arr = data_frame.apply(lambda x: x.dropna().tolist(), axis=1).tolist()
df_arr = [[str(item) for item in row] for row in df_arr]
return df_arr
def generate_frequent_itemsets(self, min_support):
frequent_itemsets = apriori(self.data_frame, min_support=min_support, use_colnames=True)
frequent_itemsets.sort_values(by='support', ascending=False, inplace=True)
return frequent_itemsets
def generate_association_rules(self, metric='confidence', min_threshold=0.7):
rules: pd.DataFrame = association_rules(
self.frequent_itemsets,
num_itemsets=NUM_ITERSETS,
metric=metric,
min_threshold=min_threshold)
rules.sort_values(by=metric, ascending=False, inplace=True)
return rules
总结
我们容易看到,想要判断一个规则是否可靠,主要就看置信度,提升度,失衡率和KULC。
①置信度为我们确定预测成功率。X发生了, 我们有多少的把握Y也发生?答案就是置信度。
②但是是不是因为X导致的Y,我们可以通过直观的提升度判断。
③如果发现提升度很高,可能受到零和事务的影响较大,我们就需要进一步使用失衡率和KULC, 综合判断X和Y之间的因果关系。