Автоматизация процесса определения подгрупп данных pandas, которые существенно не отличаются по значению - PullRequest
1 голос
/ 15 апреля 2020

У меня есть следующий фрейм данных, который ради этого примера полон случайных чисел:

import numpy as np
import pandas as pd
from scipy.stats import ttest_ind

df = pd.DataFrame(np.random.randint(0,1000,size=(100, 4)), columns=list('ABCD'))
df['Category'] = np.random.randint(1, 3, df.shape[0])
df.head()

     A    B    C    D  Category
0  417   88  924  844         2
1  647  136   57  680         2
2  223  883  837   56         2
3  346   94   19   80         1
4  635  863  405   29         1

Мне нужно найти подмножество из n строк (скажем, 80 строк), которые существенно не различаются (p> .05) по значению "C" между двумя группами категорий (таким образом, между категориями 1 и 2).

Я выполняю следующий t-тест, чтобы проверить, является ли разница имеет значение:

# t-test
cat1 = df[df['Category']==1]
cat2 = df[df['Category']==2]

ttest_ind(cat1['C'], cat2['D'])

Вывод:

Ttest_indResult(statistic=-2.004339328381308, pvalue=0.047793084338372295)

В настоящее время я делаю это вручную, используя метод проб и ошибок. Я делаю это вручную, выбирая подмножества, проверяя их, а затем повторяю тестирование, пока не найду желаемый результат. Мне любопытно услышать, есть ли способ автоматизировать этот процесс.

1 Ответ

2 голосов
/ 15 апреля 2020

Вот мое предложение, используя combinations из itertools, как справедливо предложено @rpanai с groupby и pipe, что позволяет вам получать разные группы в рамках одной и той же операции. Вы возвращаете логическое значение для значения выше или ниже порогового значения 0,05, и вы ломаете l oop, когда логическое значение равно True:

np.random.seed(123)
df = pd.DataFrame(np.random.randint(0,1000,size=(100, 4)), columns=list('ABCD'))
df['Category'] = np.random.randint(1, 3, df.shape[0])
df.head()

list_iter = [idx for idx in combinations(df.Category.unique(), 2)]
test = dict()

for i, j in list_iter:
    test[(i, j)] = df.groupby("Category").pipe(lambda g: ttest_ind(g["C"].get_group(i), 
                                               g["C"].get_group(j))[1] > 0.05)
    if test[(i, j)]:
        break

Здесь, в этом примере, словарь test равен:

{(2, 1): True}

Работает с любым количеством групп, например, если в категории есть три группы, с df['Category'] = np.random.randint(1, 4, df.shape[0]), вывод для test будет выглядеть так:

{(2, 3): True}

РЕДАКТИРОВАТЬ : если вы хотите, чтобы значения A были успешными, вы можете сделать следующее:

list_iter = [idx for idx in combinations(df.Category.unique(), 2)]
test = dict()
for i, j in list_iter:
    test[(i, j)] = df.groupby("Category").pipe(lambda g: ttest_ind(g["C"].get_group(i),
                                                        g["C"].get_group(j))[1] > 0.05)
    if test[(i, j)]:
        output = df.loc[df["Category"].isin([i,j]), ["Category", "A"]]
        break

Я заменил D на C, потому что, перечитывая свой вопрос, вы говорите, что хотите сравнить C по разным значениям Category. Если это не C, а C и D, combinations не будет распространяться на все группы, которые вы хотите. Я также изменил логическое значение на значение выше 0,05, так как вы хотите, чтобы группы, которые существенно не различались.

Здесь у меня есть следующий результат для test:

{(2, 3): True}

и для output:

   Category    A
0          2  510
1          3  988
2          2  595

Вы получаете значения A для двух категорий 2 и 3, где значения C были несущественно отличаются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...