Предположим, у вас есть те же самые гены Х для образцов Y. Я пробую свой метод с 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()
, я не уверен, что то, что я делаю, возможно с multiindex:
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
С помощью функции pivot_table
вы можете изменить свои данные, например:
df_pivot = df.pivot_table(values = ['count','mean','std'], index = 'gene',
columns = 'sample', fill_value = 0)
В этом df_pivot
(я не печатаю его здесь для удобства чтения, но в конце нового столбца) вы можете создать столбец для каждой пары (sample1, sample2), используя 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)
Я думаю, что этот метод не зависит от количества образцов, генов, и если гены не одинаковы, вы получите df_pivot
, например:
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
Дайте мне знать, если это работает
РЕДАКТИРОВАТЬ2: чтобы ответить на комментарий, я думаю, вы можете сделать это:
Без изменений для df_pivot
, а затем вы создаете мультииндекс DF 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
для реализации данных в этом df_multi
:
for 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
и unstack
на уровне 1, чтобы получить то, что вы спрашиваете (или закрываете, если я неправильно понял)
df_output = df_multi.transpose().unstack(level=[1]).fillna(1)
Вы увидите, что у вас нет последнего образца в индексах и первого образца в столбцах (потому что они не существуют так, как я построил все), если вы хотите их, вам нужно заменить itertools.combinations
на itertools.combinations_with_replacement
как в создании df_multi
, так и в цикле for
(я не пробовал, но должно работать)