使用pandas计算Cramér系数矩阵

2024-04-27 19:54:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我在pandas中有一个数据帧,其中包含在维基百科文章中计算的度量。两个分类变量nation这篇文章是关于哪个国家的,以及lang这篇文章来自哪个语言的维基百科。对于一个指标,我想看看国家和语言变量之间有多密切的联系,我相信这是用克莱默的统计数据来完成的。

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

我想生成一个矩阵,显示所有国家(法国、美国、科特迪瓦和乌干达)和三种语言的组合之间的Cramer系数。所以会有一个4乘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)

然后我可以检验我的假设,即对于语言为维基百科语言的文章,度量标准会更高。谢谢


Tags: 语言lang度量文章国家fr指标metric
3条回答

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

要计算Cramers V统计量,需要计算混淆矩阵。所以,解决的步骤是:
一。为单个度量筛选数据
2。计算混淆矩阵
三。计算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)

这段代码已经在我的数据集上测试过了,但是我希望在不改变您的情况下使用它是可以的。

在我做的几次测试中,克莱默斯五世似乎过于乐观了。维基百科推荐一个正确的版本。

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-Eunicien答案中稍微修改了一点函数。 添加了2个修改 1) cheching一个变量是常量 2) 修正ss.chi2_列联(conf_matrix,correction=correct)-如果混淆矩阵是2x2,则为FALSE

import scipy.stats as ss
import pandas as pd
import numpy as 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)

相关问题 更多 >