如标题中所述,从stats.mannwhitneyu
估计scipy
时,我遇到了一种奇怪的情况。
玩具数据和代码:
import numpy as np
import pandas as pd
from scipy import stats
# data
np.random.seed(0)
df = pd.DataFrame(np.random.randint(0,100,size=(100, 2)), columns=['col_1','col_2'])
df['group_l1'] = ['A']*50 + ['B']*50
df['group_l2'] = ['x']*25 + ['y']*25 + ['x']*25 + ['y']*25
[如test
部分中所示,当我使用group_l2
时,我将被col_1
分割的数据用作两个样本,以便为每个col_2
组中的group_l1
和ttest_ind
进行测试。作为测试:
# test
df[['col_1','col_2','group_l1','group_l2']].groupby('group_l1').\
apply(lambda x: stats.ttest_ind(x.groupby('group_l2')[['col_1','col_2']].get_group('x'),
x.groupby('group_l2')[['col_1','col_2']].get_group('y'))[1])
结果是:
group_l1
A [0.7746267572903867, 0.9459142110158605]
B [0.7016762873007549, 0.09047806237946462]
这就是我想要的,但是当我使用mannwhitneyu
时,结果是:
df[['col_1','col_2','group_l1','group_l2']].groupby('group_l1').\
apply(lambda x: stats.mannwhitneyu(x.groupby('group_l2')[['col_1','col_2']].get_group('x'),
x.groupby('group_l2')[['col_1','col_2']].get_group('y'))[1])
group_l1
A 3.412244e-35
B 7.872898e-33
似乎只计算了一列,任何人都知道为什么会这样吗?
发生这种情况的原因有两个,在ttest_ind()
中为一个原因,在manwhitneyu()
中为一个原因。
在ttest_ind()
中,签名的默认值为axis=0
:https://github.com/scipy/scipy/blob/41763e3ea532fc0e9305dde87a48ab3b4d14eac8/scipy/stats/stats.py#L5124
然后在文档字符串之后,该函数调用_chk2_asarray(a,b,axis)
以确保参数a,b
与数组相似。https://github.com/scipy/scipy/blob/41763e3ea532fc0e9305dde87a48ab3b4d14eac8/scipy/stats/stats.py#L5220现在_chk2_asarray()
得到了axis=0
的默认值,这意味着a,b
都在这里通过np.asarray()
传递:https://github.com/scipy/scipy/blob/41763e3ea532fc0e9305dde87a48ab3b4d14eac8/scipy/stats/stats.py#L235-L237所以一切都很好。但是,如果您将axis
替换为ttest_ind()
中的默认axis=None
参数,则您将碰到另一个代码路径_chk2_asarray()
,您将遍历np.ravel(a)
和类似的b
参数。这将“拆栈”您的阵列并破坏分组。例如,使用帖子中提供的数据:
>>> df[['col_1','col_2','group_l1','group_l2']].groupby('group_l1').\
... apply(lambda x: stats.ttest_ind(x.groupby('group_l2')[['col_1','col_2']].get_group('x'),
... x.groupby('group_l2')[['col_1','col_2']].get_group('y'), axis=None)[1])
group_l1
A 0.138643
B 0.942884
dtype: float64
现在,在mannwhitneyu()
函数中,必须对数据进行排名以计算测试统计量。 scipy排名方法适用于单个数组,使用scipy.stats
中的一个称为rankdata()
的数组,这是到源的链接:
https://github.com/scipy/scipy/blob/41763e3ea532fc0e9305dde87a48ab3b4d14eac8/scipy/stats/stats.py#L7307函数内部的数组a
立即在此处ravel()
-ed:https://github.com/scipy/scipy/blob/41763e3ea532fc0e9305dde87a48ab3b4d14eac8/scipy/stats/stats.py#L7363这会破坏熊猫数据框参数中的结构。
解决方法是手动分离两个数据框并在每个数据框上运行,例如一个具有col_1
的数据帧,另一个具有col_2
的数据帧。当然,除非您希望所有内容都一起作为结果在两个数组中聚合。
我不确定是否可以通过更改代码来适应您想做的简单工作。您可以随时向scipy-dev电子邮件列表发送查询以提出更改,但是对我来说这尚不明显。您需要在每一列中进行排名,因此这将需要不同的(或自定义)排名功能。
希望这可以帮助您了解正在发生的事情,这里发生的事情并不明显,这让我有所挖掘。