Pandas groupby: получи лучшее zscore для количества () каждой группы - PullRequest
0 голосов
/ 13 июня 2018

У меня есть объект pandas groupby, который возвращает счетчики каждого типа гена, примерно как показано ниже (заголовки столбцов отформатированы вручную для ясности):

counts = df.groupby(["ID", "Gene"]).size()

counts
ID      Gene      Count
1_1_1   SMARCB1     1
        smad       12
1_1_10  SMARCB1     2
        smad       17
1_1_100 SMARCB1     3

Мне нужно получить внутреннюю группу zscore, изатем верните Джин с самым высоким zscore.

Я пробовал следующее, но, похоже, он вычисляет zscores по всему набору данных и не возвращает правильное значение zscore:

zscore = lambda x: (x - x.mean()) / x.std()
counts = df.groupby(["ID", "Match"]).size().pipe(zscore)

Я пытался с помощью transform и получилте же результаты.

Я пытался:

counts = match_df.groupby(["ID", "Match"]).size().apply(zscore)

Что выдает мне следующую ошибку:

'int' object has no attribute 'mean'

Что бы я ни пытался, это не дает правильного вывода.Zscores для первых двух строк должно быть [-1,1], и в этом случае я бы вернул строку для 1_1_1 SMARCB1.И т.д. Спасибо!

Обновление

Благодаря помощи @ZaxR и переходу на среднее значение и стандартное отклонение, я смог решить эту проблему, как показано ниже.Это решение также предоставляет итоговый фрейм данных необработанных подсчетов и zscores для каждого гена:

# group by id and gene match and sum hits to each molecule
counts = df.groupby(["ID", "Match"]).size()

# calculate zscore by feature for molecule counts
# features that only align to one molecule are given a score of 1
zscore = lambda x: (x - np.mean(x)) / np.std(x) 
zscores = counts.groupby('ID').apply(zscore).fillna('1').to_frame('Zscore')

# group results back together with counts and output to 
# merge with positions and save to file 
zscore_df = zscores.reset_index()
zscore_df.columns = ["ID", "Match", "Zscore"]
count_df = counts.reset_index()
count_df.columns = ["ID", "Match", "Counts"]
zscore_df["Counts"] = count_df["Counts"]

# select gene with best zscore meeting threshold
max_df = zscore_df[zscore_df.groupby('ID')['Zscore'].transform(max) \
                       == zscore_df['Zscore']]

1 Ответ

0 голосов
/ 13 июня 2018

Причина , почему df.groupby(["ID", "Gene"]).size().transform(zscore) не работает, заключается в том, что последняя группа представляет собой серию только с одним элементом, поэтому, когда вы пытаетесь применить лямбда-функцию zscore к одному [целому числу], выполучите ошибку 'int' object has no attribute 'mean'.Обратите внимание, что x.mean () ведет себя не так, как «средний» панд.

Обновление

Я думаю, что это должно сделать это:

# Setup code
df = pd.DataFrame({"ID": ["1_1_1", "1_1_1", "1_1_10", "1_1_10", "1_1_100"],
                   "Gene": ["SMARCB1", "smad", "SMARCB1", "smad", "SMARCB1"],
                   "Count": [1, 12, 2, 17, 3]})
df = df.set_index(['ID', 'Gene'])

# Add standard deviation for every row
# Note: .transform(zscore) would also work
df['std_dev'] = df.groupby('ID')['Count'].apply(zscore)

# Find the max standard deviation for each group and
# use that as a mask for the original df
df[df.groupby('ID')['std_dev'].transform(max) == df['std_dev']]

Out:
                  Count   std_dev
ID       Gene
1_1_1    smad     12      0.707107
1_1_10   smad     17      0.707107
...