Я хочу добавить столбцы со значениями для указанных списков выборок в один df (df_sets
) в соответствии с заголовками столбцов из второго df (df_counts
), в зависимости от параметра gene_id
, и вычислить среднее значение.
Небольшая часть моих входных данных:
import pandas as pd
d_sets = {'gene_id': ['g0', 'g2', 'g3'],
'set_1': [['P1-12', 'P1-25', 'P1-28',], ['P1-6', 'P1-12', 'P1-25'], ['P1-6', 'P1-25', 'P1-28']]}
df_sets = pd.DataFrame.from_dict(data=d_sets)
d_counts = {'gene_id': ['g0', 'g1', 'g2', 'g3'],
'P1-6': [1, 2, 5, 7],
'P1-12': [2, 4, 6, 5],
'P1-25': [5, 1, 2, 6],
'P1-28': [3, 8, 1, 2]}
df_counts = pd.DataFrame.from_dict(data=d_counts)
Я начал с разделения списков образцов на отдельные столбцы и объединения dfs в gene_id
:
df_sets[['1_1', '1_2', '1_3']] = pd.DataFrame(df_sets.set_1.tolist(), index=df_sets.index)
df_merged = df_sets.merge(df_counts, on='gene_id')
и это выглядит так:
gene_id set_1 1_1 1_2 1_3 P1-6 P1-12 P1-25 P1-28
0 g0 [P1-12, P1-25, P1-28] P1-12 P1-25 P1-28 1 2 5 3
1 g2 [P1-6, P1-12, P1-25] P1-6 P1-12 P1-25 5 6 2 1
2 g3 [P1-6, P1-25, P1-28] P1-6 P1-25 P1-28 7 5 6 2
но я понятия не имею, как сделать шаг вперед, или, может быть, это неправильный способ достижения желаемого результата:
gene_id set_1 P1-6 P1-12 P1-25 P1-28 mean_set_1
0 g0 [P1-12, P1-25, P1-28] NaN 2 5 3 3.3333
1 g2 [P1-6, P1-12, P1-25] 5 6 2 NaN 4.3333
2 g3 [P1-6, P1-25, P1-28] 7 NaN 6 2 5.0
Вот один из подходов:
out = df_sets.merge(df_counts, on='gene_id', how='left')
m = out['set_1'].str.join('|').str.get_dummies().astype(bool)
out.loc[:, m.columns] = out.loc[:, m.columns].where(m)
out['mean_set_1'] = out.loc[:, m.columns].mean(axis=1)
Выход:
gene_id set_1 P1-6 P1-12 P1-25 P1-28 mean_set_1
0 g0 [P1-12, P1-25, P1-28] NaN 2.0 5 3.0 3.333333
1 g2 [P1-6, P1-12, P1-25] 5.0 6.0 2 NaN 4.333333
2 g3 [P1-6, P1-25, P1-28] 7.0 NaN 6 2.0 5.000000
Объяснение / Промежуточные продукты
on='gene_id'
и how='left'
.'set_1'
, используя Series.str.join + Series.str.get_dummies + Series.astype.m
P1-12 P1-25 P1-28 P1-6 # note that col order is (probably) not yet correct!
0 True True True False
1 True True False True
2 False True True True
(Если производительность вызывает беспокойство, проверьте здесь, чтобы найти альтернативные методы для этого шага.)
NaN
где False
.axis=1
.Н.Б. Если вы рискуете, что set_1
не будет соответствовать одному или нескольким столбцам 'P1-*'
, обязательно используйте df.reindex. Например. предположим, мы имеем:
d_counts = {'gene_id': ['g0', 'g1', 'g2', 'g3'],
'P1-6': [1, 2, 5, 7],
'P1-12': [2, 4, 6, 5],
'P1-25': [5, 1, 2, 6],
'P1-28': [3, 8, 1, 2],
'P1-30': [3, 8, 1, 2], # < not present in `set_1`
}
df_counts = pd.DataFrame.from_dict(data=d_counts)
Тогда вы можете добавить:
# ...
m = out['set_1'].str.join('|').str.get_dummies().astype(bool)
m = m.reindex(df_counts.columns[1:], axis=1)
# ...
Очень хороший ответ. Если имеется много дублирующихся Gene_id, возможно, было бы более эффективно сначала сгенерировать фиктивные значения для уникальных значений, присутствующих в двух входных данных, а затем выполнить слияние.