У меня есть такой фрейм данных
df = pd.DataFrame({'patient': ['patient1', 'patient1', 'patient1','patient2', 'patient2', 'patient3','patient3','patient4'],
'gene':['TYR','TYR','TYR','TYR','TYR','TYR','TYR','TYR'],
'variant': ['buu', 'luu', 'stm','lol', 'bla', 'buu', 'lol','buu'],
'genotype': ['hom', 'het', 'hom','het', 'hom', 'het', 'het','het']})
df
patient gene variant genotype
0 patient1 TYR buu hom
1 patient1 TYR luu het
2 patient1 TYR stm hom
3 patient2 TYR lol het
4 patient2 TYR bla hom
5 patient3 TYR buu het
6 patient3 TYR lol het
7 patient4 TYR buu het
Я хочу выявить пациентов, у которых есть buu и дополнительные варианты, НО не luu. Итак, ожидаемый результат должен быть таким
patient gene variant genotype
patient3 TYR buu het
patient3 TYR lol het
Как я могу это сделать?
set
операции:# aggregate the variants as sets
g = df.groupby('patient')['variant'].agg(set)
# keep the patients with more than "buu" but not "luu"
keep = g.index[g.gt({'buu'}) & ~g.ge({'luu'})]
# ['patient3']
# index rows of the above patients
out = df[df['patient'].isin(keep)]
Выход:
patient gene variant genotype
5 patient3 TYR buu het
6 patient3 TYR lol het
Промежуточные продукты:
g
patient
patient1 {buu, stm, luu}
patient2 {bla, lol}
patient3 {buu, lol}
patient4 {buu}
Name: variant, dtype: object
g.gt({'buu'}) # g > {'buu'}
patient
patient1 True
patient2 False
patient3 True
patient4 False
Name: variant, dtype: bool
~g.ge({'luu'}) # ~(g> = {'luu'})
patient
patient1 False
patient2 True
patient3 True
patient4 True
Name: variant, dtype: bool
m = (
df.assign(has_buu=df['variant'].eq('buu'),
not_luu=df['variant'].ne('luu'),
other=~df['variant'].isin(['buu', 'luu'])
)
.groupby('patient')
.agg({'has_buu': 'any', 'not_luu': 'all', 'other': 'any'})
)
out = df[df['patient'].isin(m.index[m.all(axis=1)])]
Выход:
patient gene variant genotype
5 patient3 TYR buu het
6 patient3 TYR lol het
Средний:
m
has_buu not_luu other
patient
patient1 True False True
patient2 False True True
patient3 True True True
patient4 True True False
Вероятно, существует однострочное решение, но я бы предпочел построить его, чтобы вы могли понять его логику. Вы хотите получить всех пациентов, у которых нет варианта «luu». В мире баз данных более простым подходом было бы получить все, что имеет «luu», и разделить его из исходного db.
1. Получить пациентов с вариантом «луу»:
patients = list(df[df['variant'] == 'luu']['patient'])
Это вернет список пациентов, у которых есть вариант «luu».
Получить все записи, принадлежащие другим пациентам:
df = df[~df.patient.isin(patients)]
За ваш вклад вы получите:
df
patient gene variant genotype
3 patient2 TYR lol het
4 patient2 TYR bla hom
5 patient3 TYR buu het
6 patient3 TYR lol het
7 patient4 TYR buu het
С этого момента я не совсем уверен, как вы можете ожидать ожидаемого результата от «Я хочу идентифицировать пациентов, у которых есть buu и дополнительные варианты, НО не luu». Но если вы хотите получить сразу несколько выражений, вы можете сделать что-то вроде:
df[~df.patient.isin(patients)][df.genotype == 'het']
Для этого он вернет:
patient gene variant genotype
3 patient2 TYR lol het
5 patient3 TYR buu het
6 patient3 TYR lol het
7 patient4 TYR buu het
Вы также можете попробовать следующее решение:
import pandas as pd
# First we filter out those groups that have only 1 observations
g = df.groupby('patient').filter(lambda x: len(x) > 1)
# Then we apply both of our desired conditions
m = (g.groupby('patient')['variant'].transform(lambda x: x.eq('buu').any() & (~ x.eq('luu').any())))
g.loc[m]
patient gene variant genotype
5 patient3 TYR buu het
6 patient3 TYR lol het
Были ли проблемы с моим ответом?