从pandas DataFrame

时间:2018-05-02 14:23:15

标签: python pandas dataframe scipy statistics

我有一个带有Multindex的DataFrame统计数据和8个样本(这里只显示了两个),每个样本有8个基因。

 In[13]:stats
    Out[13]: 
                       ARG/16S                                            \
                         count          mean           std           min   
    sample      gene                                                       
    Arnhem      IC        11.0  2.319050e-03  7.396130e-04  1.503150e-03   
                Int1      11.0  7.243040e+00  6.848327e+00  1.364879e+00   
                Sul1      11.0  3.968956e-03  9.186019e-04  2.499074e-03   
                TetB       2.0  1.154748e-01  1.627663e-01  3.816936e-04   
                TetM       4.0  1.083125e-04  5.185259e-05  5.189226e-05   
                blaOXA     4.0  4.210963e-06  3.783235e-07  3.843571e-06   
                ermB       4.0  4.111081e-05  7.894879e-06  3.288865e-05   
                ermF       4.0  2.335210e-05  4.519758e-06  1.832037e-05   
    Basel       Aph3a      4.0  7.815592e-06  1.757242e-06  5.539389e-06   
                IC        11.0  5.095161e-03  5.639278e-03  1.302205e-03   
                Int1      12.0  1.333068e+01  1.872207e+01  4.988048e-02   
                Sul1      11.0  1.618617e-02  1.988817e-02  2.970397e-03   

我正在尝试计算每个样本的p值(学生t检验),比较它们之间的每个基因。

我使用过scipy.stats.ttest_ind_from_stats,但我设法获得了一个基因的不同样本的p值,只得到了相邻的样本的p值。

Experiments = list(values1_16S['sample'].unique())
for exp in Experiments:
    if Experiments.index(exp)<len(Experiments)-1:
        second = Experiments[Experiments.index(exp)+1]
    else:
        second = Experiments[0]
    tstat, pvalue = scipy.stats.ttest_ind_from_stats(stats.loc[(exp,'Sul1')]['ARG/16S','mean'],
                                    stats.loc[(exp,'Sul1')]['ARG/16S','std'],
                                    stats.loc[(exp,'Sul1')]['ARG/16S','count'],
                                    stats.loc[(second,'Sul1')]['ARG/16S','mean'],
                                    stats.loc[(second,'Sul1')]['ARG/16S','std'],
                                    stats.loc[(second,'Sul1')]['ARG/16S','count'])
    d.append({'loc1':exp, 'loc2':second, 'pvalue':pvalue})


stats_Sul1 = pd.DataFrame(d)
stats_Sul1

如何获得所有样本之间的p值?有没有办法一次性为所有基因做这个,而不是逐个为每个基因运行代码?

1 个答案:

答案 0 :(得分:3)

假设您对Y样本有相同的X基因。我尝试使用X = 3和Y = 2的方法,但我想你可以推广。我开始时:

df1 = 
             count       mean        std       min
sample gene                                       
Arnhem IC       11   0.002319   0.000740  0.001503
       Int1     11   7.243040   6.848327  1.364879
       Sul1     11   0.003969   0.000919  0.002499
Basel  IC       11   0.005095   0.005639  0.001302
       Int1     12  13.330680  18.722070  0.049880
       Sul1     11   0.016186   0.019888  0.002970

请注意,基因需要处于相同的顺序。 首先reset_index()df_reindex = df1.reset_index(),我不确定我可以使用多索引做什么:

df_reindex =
   sample  gene  count       mean        std       min
0  Arnhem    IC     11   0.002319   0.000740  0.001503
1  Arnhem  Int1     11   7.243040   6.848327  1.364879
2  Arnhem  Sul1     11   0.003969   0.000919  0.002499
3   Basel    IC     11   0.005095   0.005639  0.001302
4   Basel  Int1     12  13.330680  18.722070  0.049880
5   Basel  Sul1     11   0.016186   0.019888  0.002970

我创建了一个滚动的DF并将其加入df_reindex

nb_genes = 3
df_rolled = pd.DataFrame(pd.np.roll(df_reindex,nb_genes,0), columns = df_reindex.columns)
df_joined = df_reindex.join(df_rolled, rsuffix='_')
# rsuffix='_' is to be able to perform the join

现在位于同一行,我有计算pvalue所需的所有数据并使用apply创建列:

df_joined['pvalue'] = df_joined.apply(lambda x: stats.ttest_ind_from_stats(x['mean'],x['std'],x['count'], x['mean_'],x['std_'],x['count_'])[1],axis=1)

最后,我使用您想要的数据创建DF并重命名列:

df_output = df_joined[['sample','sample_','gene','pvalue']].rename(columns = {'sample':'loc1', 'sample_':'loc2'})

您最终获得了数据:

df_output = 
     loc1    loc2  gene    pvalue
0  Arnhem   Basel    IC  0.121142
1  Arnhem   Basel  Int1  0.321072
2  Arnhem   Basel  Sul1  0.055298
3   Basel  Arnhem    IC  0.121142
4   Basel  Arnhem  Int1  0.321072
5   Basel  Arnhem  Sul1  0.055298

您可以根据需要重新编制索引。

如果你想每个样本相互对照,我认为循环for可以做到。

编辑:使用pivot_table,我认为有一种更简单的方法。

您的输入stats仅作为ARG/16S的多索引表(不知道如何处理此级别),所以我从(可能是您的stats['ARG/16S'])开始:

df=
               count       mean           std       min
sample gene                                            
Arnhem IC         11   0.002319  7.396130e-04  0.001503
       Int1       11   7.243040  6.848327e+00  1.364879
       Sul1       11   0.003969  9.186019e-04  0.002499
       TetB        2   0.115475  1.627663e-01  0.000382
       TetM        4   0.000108  5.185259e-05  0.000052
       blaOXA      4   0.000004  3.783235e-07  0.000004
       ermB        4   0.000041  7.894879e-06  0.000033
       ermF        4   0.000023  4.519758e-06  0.000018
Basel  Aph3a       4   0.000008  1.757242e-06  0.000006
       IC         11   0.005095  5.639278e-03  0.001302
       Int1       12  13.330680  1.872207e+01  0.049880
       Sul1       11   0.016186  1.988817e-02  0.002970

使用[{1}}功能,您可以重新排列数据,例如:

pivot_table

在此df_pivot = df.pivot_table(values = ['count','mean','std'], index = 'gene', columns = 'sample', fill_value = 0) 中(我不打印此处以获取可读性,但最后打印新列),您可以使用{{1}为每对(sample1,sample2)创建一列}和df_pivot

itertools

我认为这种方法与样本,基因的数量无关,如果基因不完全相同,最终会得到apply,如:

import itertools
for sample1, sample2 in itertools.combinations(df.index.levels[0],2):
    # itertools.combinations create all combinations between your samples
    df_pivot[sample1+ '_' + sample2 ] = df_pivot.apply(lambda x: stats.ttest_ind_from_stats(x['mean'][sample1],x['std'][sample1],x['count'][sample1], 
                                                                                        x['mean'][sample2 ],x['std'][sample2 ],x['count'][sample2 ],)[1],axis=1).fillna(1)

让我知道它是否有效

EDIT2:回复评论,我想你可以这样做:

df_pivot没有变化,然后您创建了一个多索引DF count mean std Arnhem_Basel sample Arnhem Basel Arnhem Basel Arnhem Basel gene Aph3a 0 4 0.000000 0.000008 0.000000e+00 0.000002 1.000000 IC 11 11 0.002319 0.005095 7.396130e-04 0.005639 0.121142 Int1 11 12 7.243040 13.330680 6.848327e+00 18.722070 0.321072 Sul1 11 11 0.003969 0.016186 9.186019e-04 0.019888 0.055298 TetB 2 0 0.115475 0.000000 1.627663e-01 0.000000 1.000000 TetM 4 0 0.000108 0.000000 5.185259e-05 0.000000 1.000000 blaOXA 4 0 0.000004 0.000000 3.783235e-07 0.000000 1.000000 ermB 4 0 0.000041 0.000000 7.894879e-06 0.000000 1.000000 ermF 4 0 0.000023 0.000000 4.519758e-06 0.000000 1.000000 来编写结果:

df_pivot

然后使用循环df_multi来实现此df_multi = pd.DataFrame(index = df.index.levels[1], columns = pd.MultiIndex.from_tuples([p for p in itertools.combinations(df.index.levels[0],2)])).fillna(0)

中的数据
for

最后,您可以在第1级使用df_multifor sample1, sample2 in itertools.combinations(df.index.levels[0],2): # itertools.combinations create all combinations between your samples df_multi.loc[:,(sample1,sample2)] = df_pivot.apply(lambda x: stats.ttest_ind_from_stats(x['mean'][sample1],x['std'][sample1],x['count'][sample1], x['mean'][sample2 ],x['std'][sample2 ],x['count'][sample2 ],)[1],axis=1).fillna(1) 来获取您的提问方式(如果我误解,可以关闭)

transpose

你会看到你没有索引中的最后一个样本和列中的第一个样本(因为它们不存在我如何构建所有内容)如果你想要它们,你需要替换{{1 unstack创建df_output = df_multi.transpose().unstack(level=[1]).fillna(1) 和循环itertools.combinations中的itertools.combinations_with_replacement {我没试过但它应该有效}