离散(分类)变量之间的相关性度量
Theil’s U,也被称为不确定性系数或熵系数,用于衡量两个名义变量之间的关联强度。该指标评估了知道一个变量的值能减少多少关于另一个变量的不确定性,提供了一个介于 0 到 1 之间的关联度量。值越高,表示两者间的关系越强,因此 Theil’s U 在统计学和数据科学领域特别有用,尤其是在分析分类数据之间的关系。
towardsdatascience.com/calculating-the-uncertainty-coefficient-thiels-u-in-python-fce72a02431b?source=collection_archive---------6-----------------------#2024-10-18
理论背景
Theil’s U 是一种基于信息熵概念的名义关联度量方法。假设有两个离散随机变量 X 和 Y 的样本。
X 的熵定义如下:
而给定 Y 的 X 的条件熵则定义为:
通过联合分布(分子)与 X 或 Y 的边缘概率结合,可以分别计算出给定 Y 的 X 的条件分布(分母)或给定 X 的 Y 的条件分布,具体如下所示:
给定 y 的 x 的条件分布:
给定 x 的 y 的条件分布:
这些计算结果捕捉了一个变量在已知另一个变量值时的概率变化。我们可以通过使用 X 和 Y 的联合概率——即 X 和 Y 不同组合出现的概率——以及 Y 的边缘概率来计算给定 Y 的 X 的概率。随后,将这些比值代入 H(X) 公式,得出:
理论部分介绍完毕;接下来,我们将展示如何在 Python 中计算给定 Y 的 X 的条件熵。
from typing import List, Union
from collections import Counter
import math
def conditional_entropy(
x: List[Union[int, float]],
y: List[Union[int, float]]
) -> float:
""" 计算条件熵 """
# 统计唯一值的数量
y_counter = Counter(y) # 统计 y 中的唯一值数量
xy_counter = Counter(list(zip(x, y))) # 统计 (x, y) 对中的唯一值数量
# 计算 y 值的总出现次数
total_occurrences = sum(y_counter.values())
# 初始化熵为 0
entropy = 0
对于每一对唯一的 x 和 y 值:
for xy in xy_counter.keys():
# x 和 y 的联合概率
p_xy = xy_counter[xy] / total_occurrences
# y 的边缘概率
p_y = y_counter[xy[1]] / total_occurrences
# 给定 y 的 x 的条件概率
p_x_given_y = p_xy / p_y
# 计算条件熵 H(X|Y)
entropy += p_xy * math.log(p_x_given_y, 2) # 使用以2为底数,而不是自然对数(以 e 为底数)
当我们计算出给定 Y 的 X 的条件熵之后,就可以计算 Theil’s U。最后一步是计算 X 的熵,这是我们之前定义的。随后,不确定系数或熟练度可以按照以下方式进行计算:

从理论到实践,这可以通过以下 Python 代码来实现:
import scipy.stats as ss
def theil_u(
x: List[Union[int, float]],
y: List[Union[int, float]]
) -> float:
""" 计算 Theil U """
# 计算 x 和 y 的条件熵
H_xy = conditional_entropy(x, y)
# 统计唯一值
x_counter = Counter(x)
# 计算 x 值的总和
total_occurrences = sum(x_counter.values())
# 将 x_counter 中所有 x 值的绝对计数转换为概率
p_x = list(map(lambda count: count / total_occurrences, x_counter.values()))
# 计算单一分配 x 的熵
H_x = ss.entropy(p_x)
return (H_x - H_xy) / H_x if H_x != 0 else 0
最后,我们可以定义一个函数,用于计算数据集中每个特征组合的 Theil 值。这可以通过以下 Python 代码来实现:
import itertools
import pandas as pd
def get_theils_u_for_df(df: pd.DataFrame) -> pd.DataFrame:
""" 对输入 df 中的每个特征组合计算 Theil's U """
# 创建一个空的数据框来填充
theilu = pd.DataFrame(index=df.columns, columns=df.columns)
# 将 Theil U 值插入空数据框
for var1, var2 in itertools.combinations(df, 2):
u = theil_u(df[var1], df[var2])
theilu[var1][var2] = round(u, 2) # 填充下三角
u = theil_u(df[var2], df[var1])
theilu[var2][var1] = round(u, 2) # 填充上三角
# 当行索引 + 列索引 == n - 1 时,在对角线上设置 1
for i in range(0, len(theilu.columns)):
for j in range(0, len(theilu.columns)):
if i == j:
theilu.iloc[i, j] = 1
转换 DataFrame 中的所有值为浮点数
返回 theilu.map(float)
代码示例
我们将使用著名的鸢尾花数据集来演示代码的功能。此数据集不仅包含数字变量,还有一个分类变量“物种”。传统的相关性度量方法,如皮尔逊相关性,在捕捉分类变量与数值特征间的关系上存在局限。然而,Theil’s U 能够有效测量“物种”与其他数值特征间的关联程度。
import pandas as pd
import seaborn as sns
import itertools
import matplotlib.pyplot as plt
# 从 seaborn 加载鸢尾花数据集
df = sns.load_dataset('iris')
# 计算输入 df 中每对特征的 Theil's U
theilu = get_theils_u_for_df(df)
# 创建 Theil's U 值的热力图
plt.figure(figsize=(10, 4))
sns.heatmap(theilu, annot=True, cmap='Reds', fmt='.2f')
plt.title('所有变量对的 Theil’s U 热图')
plt.show()
最终生成的是所有变量对的 Theil’s U 热图。值得注意的是,这种度量是非对称的,即两个变量间的关系会根据分析的方向不同而有所差异。例如,Theil’s U 可以量化 X 对 Y 的信息贡献,但 Y 对 X 的信息贡献可能会有所不同。
热图显示,花瓣长度和花瓣宽度与分类变量“物种”的关联最为显著,两者的 Theil’s U 值均为 0.91。这表明,花瓣的大小能高度反映花卉的种类。相比之下,萼片长度与“物种”的关联度适中,值为 0.55,意味着它也能提供一定的物种信息,但不如花瓣尺寸信息丰富。而萼片宽度与“物种”的关联最弱,值为 0.33,表明其提供的关于花卉种类的信息较少。这些结果与鸢尾花数据集的已知特征相符,强调了花瓣尺寸在预测花卉种类时的重要性。
结论
在这篇文章中,我们介绍了如何计算 Theil’s U 以评估分类变量和数值变量之间的关系。通过对鸢尾花数据集的应用,我们证明了花瓣尺寸对于预测花卉种类的重要性,同时展示了 Theil’s U 相较于传统相关性度量方法的优势。
参考文献
Theil, H. (1958): 经济预测与政策. 阿姆斯特丹: North Holland.
Theil, H. (1966): 应用经济预测. 芝加哥: Rand McNally.
Bliemel, F. (1973): Theil 的预测准确度系数:澄清. 市场研究杂志 10(4),第 444-446 页
注:除非另有说明,所有图片均由作者提供。