import numpy as np
import pandas as pd
from scipy.stats import levene as lev
raw_data = {'IDs': ['G1', 'G2', 'G3', 'G4', 'G5'],
'Sample1': [102.2, 2310.4, 123.4, 213.0, 1234.2],
'Sample2': [112.8, 1910.4, 36.3, 188.2, 1271.2],
'Sample3': [32.2, 1290.3, 121.4, 212.3, 1333.5],
'Sample4': [52.1, 2210.1, 155.2, 244.7, 1987.1]}
raw_data2 = {'IDs': ['S1', 'S2', 'S3', 'S4', 'S5'],
'Sample1': [1, 2, 1, 0, 2],
'Sample2': [2, 1, 2, 1, 2],
'Sample3': [2, 0, 1, 0, 1],
'Sample4': [1, 2, 1, 2, 1]}
df1 = pd.DataFrame(raw_data, columns = ['IDs', 'Sample1', 'Sample2', 'Sample3', 'Sample4'])
df2 = pd.DataFrame(raw_data2, columns = ['IDs', 'Sample1', 'Sample2', 'Sample3', 'Sample4'])
我一直在尝试找到一种方法来对df1的每一行执行一次levenes测试,每行df2定义要拆分的组。例如,每当进行一次levenes测试时,df1的第一行将按df2的每一行进行分组。显然,我可以使用诸如以下的嵌套循环来实现它(必须包含if语句,因为并非所有行都将包含所有组):
for i in range(0, df1.shape[0]):
for j in range(0, df2.shape[0]):
tmp1=df1.ix[i,:]
tmp2=df2.ix[i,:]
group1 = tmp1[tmp2==0]
group2 = tmp1[tmp2==1]
group3 = tmp1[tmp2==2]
if len(group1) <= 1:
lev(group2,group3) # and some how return the output to a new df
elif len(group2) <= 1:
lev(group1,group3) # and some how return the output to a new df
elif len(group3) <=1:
lev(group1,group2) # and some how return the output to a new df
else:
lev(group1,group2,group3) # and some how return the output to a new df
样本在数据帧中的顺序相同,但是一个df有一些额外的描述符列(为输出保留重要)。
由于我将要进行数百万次比较,因此使用循环来进行比较是不切实际的,我的第一次尝试将花费120年的时间...我已经对其进行了改进,但是需要删除循环以真正改善它。< / p>
我一直在阅读有关尝试使用向量化的信息,我在R中使用apply函数对它有些熟悉。我想熊猫,麻木等会有一种优雅的方式,但是还没有破解。
为了更清楚地说明预期的输出结果是类似的(抱歉,尚未计算出lev测试,因此没有实际数字-到达计算机时会更新):
DF1-ID DF2-ID Lev.stat Lev.pvalue
G1 S1 float float
G1 S2 float float
G1 S3 float float
G1 S4 float float
G2 S1 float float
.
.
.
G4 S4 float float
答案 0 :(得分:0)
此解决方案不是特别优雅,并且有点脆弱,这意味着它在某些情况下会失败。但是,如果您的数据没有任何异常情况,它将起作用。
首先,此解决方案假定IDs
和df1
中的df2
列是同构的(G1
= S1
等)。其次,该解决方案假定仅对2或3组数据进行Levene的测试。 (对于您的示例数据而言,这是正确的。)第三,您的示例数据没有很多数据,有时这会引发Levene测试-在这些情况下,Scipy会抱怨(尽管它只返回Inf
完成执行)。
简而言之,过程是:
melt()
从宽到长格式df1
和df2
groupby
列出分组值lev()
第一:
# merge data
df2.IDs = df2.IDs.str.replace("S", "G")
merged = df1.melt(id_vars="IDs").merge(df2.melt(id_vars="IDs"), on=["IDs", "variable"])
# group values into lists
lev_data = merged.groupby(["IDs", "value_y"]).value_x.agg(list).reset_index()
lev_data
IDs value_y value_x
0 G1 1 [102.2, 52.1]
1 G1 2 [112.8, 32.2]
2 G2 0 [1290.3]
3 G2 1 [1910.4]
4 G2 2 [2310.4, 2210.1]
5 G3 1 [123.4, 121.4, 155.2]
6 G3 2 [36.3]
7 G4 0 [213.0, 212.3]
8 G4 1 [188.2]
9 G4 2 [244.7]
10 G5 1 [1333.5, 1987.1]
11 G5 2 [1234.2, 1271.2]
下一步:
# run lev() on two- or three-group sets
def do_lev(vals):
if len(vals) == 2:
return lev(vals.iloc[0,2], vals.iloc[1,2])
return lev(vals.iloc[0,2], vals.iloc[1,2], vals.iloc[2,2])
lev_data.groupby("IDs").apply(do_lev)
输出:
IDs
G1 (1.84254995447e+31, 5.42726126677e-32) # (test statistic, p-value)
G2 (inf, 0.0)
G3 (0.300123996469, 0.638777548242)
G4 (inf, 0.0)
G5 (inf, 0.0)
dtype: object
注意:由于scipy.stats.levene()
requires每个样本要单独输入,而不是接受向量列表,因此在某种程度上阻止了完全向量化。这意味着需要对样本进行分解并逐个输入lev()
,这会使向量化变得复杂。