使用 pandas,计算 Cramer 的系数矩阵

Posted

技术标签:

【中文标题】使用 pandas,计算 Cramer 的系数矩阵【英文标题】:Using pandas, calculate Cramér's coefficient matrix 【发布时间】:2014-01-20 11:34:43 【问题描述】:

我在pandas 中有一个数据框,其中包含根据***文章计算的指标。两个分类变量 nation 这篇文章是关于哪个国家的,lang 这是从***的哪个语言中提取的。对于单个指标,我想看看国家和语言变量的相关性有多密切,我相信这是使用 Cramer 的统计数据完成的。

index   qid     subj    nation  lang    metric          value
5   Q3488399    economy     cdi     fr  informativeness 0.787117
6   Q3488399    economy     cdi     fr  referencerate   0.000945
7   Q3488399    economy     cdi     fr  completeness    43.200000
8   Q3488399    economy     cdi     fr  numheadings     11.000000
9   Q3488399    economy     cdi     fr  articlelength   3176.000000
10  Q7195441    economy     cdi     en  informativeness 0.626570
11  Q7195441    economy     cdi     en  referencerate   0.008610
12  Q7195441    economy     cdi     en  completeness    6.400000
13  Q7195441    economy     cdi     en  numheadings     7.000000
14  Q7195441    economy     cdi     en  articlelength   2323.000000

我想生成一个矩阵,显示所有国家组合(法国、美国、科特迪瓦和乌干达)['fra','usa','uga'] 和三种语言['fr','en','sw'] 之间的克莱默系数。所以会有一个 4 x 3 矩阵,如:

       en         fr          sw
usa    Cramer11   Cramer12    ... 
fra    Cramer21   Cramer22    ... 
cdi    ...
uga    ...

最终,我将对我正在跟踪的所有不同指标进行此操作。

for subject in list_of_subjects:
    for metric in list_of_metrics:
        cramer_matrix(metric, df)

然后我可以检验我的假设,即语言为***语言的文章的指标会更高。谢谢

【问题讨论】:

你解决了吗? 【参考方案1】:

Cramer 的 V 统计量允许了解一个数据集中两个分类特征之间的相关性。所以,这是你的情况。

要计算 Cramers V 统计量,您需要计算混淆矩阵。所以,解决步骤是: 1. 过滤单个指标的数据 2.计算混淆矩阵 3.计算Cramers V统计量

当然,您可以在帖子中提供的循环嵌套中执行这些步骤。但是在您的开头段落中,您仅提到指标作为外部参数,因此我不确定您是否需要两个循环。现在,我将提供步骤 2-3 的代码,因为过滤很简单,而且正如我所提到的,我不确定您确实需要什么。

第 2 步。在下面的代码中,data 是一个 pandas.dataFrame,由第 1 步中您想要的任何内容过滤。

import numpy as np

confusions = []
for nation in list_of_nations:
    for language in list_of_languges:
        cond = data['nation'] == nation and data['lang'] == language
        confusions.append(cond.sum())
confusion_matrix = np.array(confusions).reshape(len(list_of_nations), len(list_of_languges))

第 3 步。 在下面的代码中,confusion_matrix 是在第 2 步中获得的 numpy.ndarray

import numpy as np
import scipy.stats as ss

def cramers_stat(confusion_matrix):
    chi2 = ss.chi2_contingency(confusion_matrix)[0]
    n = confusion_matrix.sum()
    return np.sqrt(chi2 / (n*(min(confusion_matrix.shape)-1)))

result = cramers_stat(confusion_matrix)

此代码已在我的数据集上进行了测试,但我希望可以在不更改您的案例的情况下使用它。

【讨论】:

【参考方案2】:

在我进行的一些测试中,cramers V 似乎过于乐观了。***推荐一个更正的版本。

import scipy.stats as ss

def cramers_corrected_stat(confusion_matrix):
    """ calculate Cramers V statistic for categorial-categorial association.
        uses correction from Bergsma and Wicher, 
        Journal of the Korean Statistical Society 42 (2013): 323-328
    """
    chi2 = ss.chi2_contingency(confusion_matrix)[0]
    n = confusion_matrix.sum()
    phi2 = chi2/n
    r,k = confusion_matrix.shape
    phi2corr = max(0, phi2 - ((k-1)*(r-1))/(n-1))    
    rcorr = r - ((r-1)**2)/(n-1)
    kcorr = k - ((k-1)**2)/(n-1)
    return np.sqrt(phi2corr / min( (kcorr-1), (rcorr-1)))

另请注意,混淆矩阵可以通过内置的 pandas 分类列方法计算:

import pandas as pd
confusion_matrix = pd.crosstab(df[column1], df[column2])

【讨论】:

这太棒了@Ziggy!请注意,如果混淆矩阵是使用pd.crosstab(df[column1], df[column2]) 计算的,那么n = confusion_matrix.sum() 需要为n = confusion_matrix.sum().sum()numpy 沿所有维度求和,pandas,仅沿一个。很好的答案和非常可读的代码。 我认为上述函数需要一个 2d numpy 数组作为输入,而不是 pandas 对象。它可能适用于confusion_matrix = pd.crosstab(df[column1], df[column2]).to_numpy()【参考方案3】:

来自 Ziggy Eunicien 答案的一些修改功能。 添加了 2 处修改

    检查变量之一是否为常数

    更正 ss.chi2_contingency(conf_matrix, correction=correct) - 如果混淆矩阵为 2x2,则为 FALSE

    将 scipy.stats 导入为 ss 将熊猫导入为 pd 将 numpy 导入为 np def cramers_corrected_stat(x,y):

     """ calculate Cramers V statistic for categorial-categorial association.
         uses correction from Bergsma and Wicher, 
         Journal of the Korean Statistical Society 42 (2013): 323-328
     """
     result=-1
     if len(x.value_counts())==1 :
         print("First variable is constant")
     elif len(y.value_counts())==1:
         print("Second variable is constant")
     else:   
         conf_matrix=pd.crosstab(x, y)
    
         if conf_matrix.shape[0]==2:
             correct=False
         else:
             correct=True
    
         chi2 = ss.chi2_contingency(conf_matrix, correction=correct)[0]
    
         n = sum(conf_matrix.sum())
         phi2 = chi2/n
         r,k = conf_matrix.shape
         phi2corr = max(0, phi2 - ((k-1)*(r-1))/(n-1))    
         rcorr = r - ((r-1)**2)/(n-1)
         kcorr = k - ((k-1)**2)/(n-1)
         result=np.sqrt(phi2corr / min( (kcorr-1), (rcorr-1)))
     return round(result,6)
    

【讨论】:

你好,为什么你需要添加这行代码? phi2corr = max(0, phi2 - ((k-1)*(r-1))/(n-1)) phi2corr = max(0, phi2 - ((k-1)*(r-1))/(n-1)) rcorr = r - ((r-1)**2)/(n-1) kcorr = k - ((k-1)**2)/(n-1) result=np.sqrt(phi2corr / min( (kcorr-1), (rcorr-1))) 根据 wiki,我们可以使用 phi2/ min(k-1,r-1) @R_abcdefg:根据en.wikipedia.org/wiki/Cram%C3%A9r%27s_V进行偏差修正【参考方案4】:

有一个更简单的答案。 所以问题是关于 Cramer 的 V,我会坚持回答这个问题。

对于您的 pandas DataFrame:data,如果您只对语言和国家列感兴趣,您可以使用以下简单的几行轻松获得 Cramer's V 的热图:

# first chose your category columns of interest
df = data[['nation', 'lang']]

# now change this to dummy variables, one-hot encoded:
DataMatrix = pd.get_dummies(df)

# plot as simply as:
plt.figure(figsize=(15,12))  # for large datasets
plt.title('Cramer\'s V comparing nation and language')
sns.heatmap(DataMatrix.corr('pearson'), cmap='coolwarm', center=0)

我可以推荐的替代方案是:2 x 2 卡方比例检验,或不对称归一化互信息(NMI 或 Theil's U)。

【讨论】:

【参考方案5】:

使用Association-metrics python包从pandas.DataFrame对象计算Cramér的系数矩阵很简单,让我告诉你:

首先使用以下方式安装关联度量:

pip install association-metrics

然后,你可以使用下面的伪代码

# Import association_metrics  
import association_metrics as am
# Convert you str columns to Category columns
df = df.apply(
        lambda x: x.astype("category") if x.dtype == "O" else x)

# Initialize a CamresV object using you pandas.DataFrame
cramersv = am.CramersV(df) 
# will return a pairwise matrix filled with Cramer's V, where columns and index are 
# the categorical variables of the passed pandas.DataFrame
cramersv.fit()

Package info

【讨论】:

以上是关于使用 pandas,计算 Cramer 的系数矩阵的主要内容,如果未能解决你的问题,请参考以下文章

pandas删除没有列名的列

pandas删除没有列名的列

常见统计估计概念和区别

用矩阵计算Jaccard相似系数

python pandas 计算相关系数

pandasspark计算相关性系数速度对比