Python 在某些情况下,Scipy-Spearman相关系数为NaN

Python 在某些情况下,Scipy-Spearman相关系数为NaN,python,python-3.x,pandas,scipy,correlation,Python,Python 3.x,Pandas,Scipy,Correlation,我在为面试官计算斯皮尔曼相关系数。它适用于面试官。。。我不明白Scipy怎么会打断面试官的话,说他没有相关性/0/nan import pandas as pd from pandas import DataFrame import scipy.stats df = pd.DataFrame({'Interviewer': ['Interviewer_1','Interviewer_1','Interviewer_1','Interviewer_1','Interviewer_1','Int

我在为面试官计算斯皮尔曼相关系数。它适用于面试官。。。我不明白Scipy怎么会打断面试官的话,说他没有相关性/0/nan

import pandas as pd
from pandas import DataFrame
import scipy.stats


df = pd.DataFrame({'Interviewer': ['Interviewer_1','Interviewer_1','Interviewer_1','Interviewer_1','Interviewer_1','Interviewer_1','Interviewer_1','Interviewer_1','Interviewer_1','Interviewer_1','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2','Interviewer_2'],
                    'Score_1': [-1,-1,-1,1,1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,1,-1],
                    'Score_2': [1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]
                    })

df
样本数据产量:

    Interviewer Score_1 Score_2
0   Interviewer_1   -1  1
1   Interviewer_1   -1  -1
2   Interviewer_1   -1  -1
3   Interviewer_1   1   -1
4   Interviewer_1   1   1
5   Interviewer_1   -1  1
6   Interviewer_1   -1  -1
7   Interviewer_1   -1  -1
8   Interviewer_1   1   -1
9   Interviewer_1   1   -1
10  Interviewer_2   -1  -1
11  Interviewer_2   -1  -1
12  Interviewer_2   -1  -1
13  Interviewer_2   -1  -1
14  Interviewer_2   -1  -1
15  Interviewer_2   -1  -1
16  Interviewer_2   -1  -1
17  Interviewer_2   -1  -1
18  Interviewer_2   -1  -1
19  Interviewer_2   -1  -1
20  Interviewer_2   -1  -1
21  Interviewer_2   -1  -1
22  Interviewer_2   -1  -1
23  Interviewer_2   1   -1
24  Interviewer_2   -1  -1
25  Interviewer_2   -1  -1
26  Interviewer_2   -1  -1
27  Interviewer_2   -1  -1
28  Interviewer_2   1   -1
29  Interviewer_2   -1  -1

df.groupby('Interviewer').sum()
得出的总和为:

           Score_1  Score_2
Interviewer     
Interviewer_1   -2  -4
Interviewer_2   -16 -20
使用Scipy:

def applyspearman(row):
    row['Cor'] = scipy.stats.spearmanr(row['Score_1'], row['Score_2'])[0]
    return row

df = df.groupby('Interviewer').apply(applyspearman)

df
    Interviewer Score_1 Score_2 Cor
0   Interviewer_1   -1  1   -0.089087081
1   Interviewer_1   -1  -1  -0.089087081
2   Interviewer_1   -1  -1  -0.089087081
3   Interviewer_1   1   -1  -0.089087081
4   Interviewer_1   1   1   -0.089087081
5   Interviewer_1   -1  1   -0.089087081
6   Interviewer_1   -1  -1  -0.089087081
7   Interviewer_1   -1  -1  -0.089087081
8   Interviewer_1   1   -1  -0.089087081
9   Interviewer_1   1   -1  -0.089087081
10  Interviewer_2   -1  -1  
11  Interviewer_2   -1  -1  
12  Interviewer_2   -1  -1  
13  Interviewer_2   -1  -1  
14  Interviewer_2   -1  -1  
15  Interviewer_2   -1  -1  
16  Interviewer_2   -1  -1  
17  Interviewer_2   -1  -1  
18  Interviewer_2   -1  -1  
19  Interviewer_2   -1  -1  
20  Interviewer_2   -1  -1  
21  Interviewer_2   -1  -1  
22  Interviewer_2   -1  -1  
23  Interviewer_2   1   -1  
24  Interviewer_2   -1  -1  
25  Interviewer_2   -1  -1  
26  Interviewer_2   -1  -1  
27  Interviewer_2   -1  -1  
28  Interviewer_2   1   -1  
29  Interviewer_2   -1  -1
我试着在Excel中手工使用这个公式(秩函数、abs差值、d^2和d^之和),两位面试官得到了不同的结果: p=1-(6∑d^2i)/(n(n^2-1))

采访者_1,p=0.878788

采访者_2,p=0.993985

问题

  • 为什么面试官_2为空?NaN问题是否与排名关系有关
  • 为什么Scipy的结果与我的手工结果不同

  • 不确定中到底发生了什么,但您可以使用pandas的
    Series.rank(method='dense')
    定义您自己的函数,这似乎澄清了问题:

    def spearmanr(x, y):
        """ `x`, `y` --> pd.Series"""
        assert x.shape == y.shape
        rx = x.rank(method='dense')
        ry = y.rank(method='dense')
        d = rx - ry
        dsq = np.sum(np.square(d))
        n = x.shape[0]
        coef = 1. - (6. * dsq) / (n * (n**2 - 1.))
        return coef
    
    grouped.apply(lambda frame: spearmanr(frame['Score_1'], frame['Score_2']))
    Interviewer_1    0.970
    Interviewer_2    0.998
    

    肯定有点奇怪,因为“scipy 0.8.0中的更改:重写以添加领带处理和axis。”旁注-我认为您希望在
    applyspearman
    中返回
    scipy.stats.spearmanr
    的结果,而不是将其作为分组数据框中的附加列分配给每一行?Spearman rank是一个汇总统计,而不是每一行的度量。我将其用作采访者的汇总统计。这就是我为什么应用groupby。稍后在分析中,我将每个面试官的数据框展平到一行,这样我就可以根据spearmanr得分绘制总面试数。@SimonBowly,他使用的函数是正确的。
    。apply
    将函数应用于每个分组的子数据框,因此
    这里就是一个数据框。有关详细信息,请参阅它-我认为只有2个组,所以你得到2个spearman值,但你将这些值复制到组中的每一行上。如果你稍后变平,这是完全有意义的。感谢Hanks@Brad Solomon。从公式的角度来看,一切看起来都很好…我只添加:d=ABS(rx-ry).但我认为斯皮尔曼没有很好地处理平局排名。我在我的完整数据集上尝试了这一点,并且没有得到负值(这应该在-1和1之间变化),这让我相信斯皮尔曼可能不是解决我问题的好方法。我目前正在研究斯皮尔曼的分数排名,并探索肯德尔陶。如果你好奇的话,我使用的是来自的定义。(你可以在样本数据上确认。)我看到它的定义有一些细微的变化,它对输入和排名方法非常敏感,但希望它的结构能有所帮助。