Вопрос или проблема
В лаборатории, в которой я работаю, мы провели эксперимент, чтобы наблюдать, эффективны ли цианобактерии в изменениях концентрации силикатов в озере. Эксперимент имел 3 различные переменные:
- тип организма
- было ли добавлено силиката в растворе
- тип бульона (только вода из озера Салда или вода из озера Салда, смешанная с бульоном).
Были два повторения для каждой комбинации переменных, в результате чего в эксперименте было 22 образца. Мы проводили наблюдения под микроскопом и измеряли концентрации Mg и Ca для каждого образца (18 ненулевых концентраций).
Я выполнил permutation Kruskal-Wallis тест, чтобы выяснить, можем ли мы получить какую-либо информацию о том, имел ли какой-либо из упомянутых выше факторов значительное влияние на концентрации Mg или Ca. Я провел тест по категориям: тип организма, добавление силиката и тип бульона, и выяснил, что тип организма в растворах был значимым для обоих Mg и Ca, но остальные категории не имели значительных различий.
Когда я выполнил пост-хок тест, используя тест Данна (с поправкой Холма), результаты были похожими, но это не показало значимости для типа организма для Ca. Однако я затем узнал, что из-за размера моей выборки версия теста Данна с permutation может быть более подходящей. Так как я не знаю, как выполнить permutation версию теста Данна (снова с поправкой Холма), я получил предложение кода от Copilot. Однако на этот раз результаты показали значительное различие в типе бульона. Естественно, теперь я рассматриваю, не было ли это ошибкой в коде или один из тестов имел ошибку типа I или типа II. Если с кодом нет проблем, я думаю о проведении теста на размер эффекта. Вы можете найти мой код ниже. Я был бы признателен за любые предложения.
P.S. Я также могу предоставить свой код для permutation Kruskal-Wallis, если это может быть необходимо
# Определение функции permutation
def perm_dunn(data, dv, between, n_perm = 10000, random_state = 42):
"""
Выполняет permutation тест Данна на данном DataFrame.
Параметры:
- data: pandas DataFrame с данными.
- dv: Название столбца зависимой переменной (например, 'Mg' или 'Ca').
- between: Название столбца с категорией группировки.
- n_perm: Количество permutation выполняемых тестов.
- random_state: Начальное значение для воспроизводимости.
Возвращает:
- result: pandas DataFrame с наблюдаемой разницей, p-значением и поправкой Холма.
Исключения:
- Вызывает исключение, если зависимая переменная не является числовой.
- Вызывает исключение, если переменная группировки не является категориальной.
"""
# Проверка, является ли зависимая переменная числовой
if data[dv].dtype not in ['int64', 'float64']:
raise ValueError('Зависимая переменная должна быть числовой.')
# Проверка, является ли переменная группировки категориальной
if data[between].dtype not in ['object', 'category']:
raise ValueError('Переменная группировки должна быть категориальной.')
groups = data[between].unique()
result = {}
for (group1, group2) in it.combinations(groups, 2):
data1 = data[data[between] == group1][dv].values
data2 = data[data[between] == group2][dv].values
observed_diff = np.abs(np.mean(data1) - np.mean(data2))
cmb = np.concatenate([data1, data2])
perm_diffs = []
np.random.seed(random_state)
for _ in range(n_perm):
np.random.shuffle(cmb)
perm_data1 = cmb[:len(data1)]
perm_data2 = cmb[len(data1):]
perm_diffs.append(np.abs(np.mean(perm_data1) - np.mean(perm_data2)))
perm_diffs = np.array(perm_diffs)
p_value = np.sum(perm_diffs >= observed_diff) / n_perm
result[(group1, group2)] = [observed_diff, p_value]
# Сохраните названия групп в виде строк в словаре результатов
result[(group1, group2)].extend([str(group1), str(group2)])
# Применение поправки Холма
p_values = [value[1] for value in result.values()]
reject, p_values_corr, _, _ = smt.multipletests(p_values, method = 'holm')
for i, key in enumerate(result.keys()):
result[key].append(p_values_corr[i])
# Создание DataFrame из результатов
result = pd.DataFrame(result).T
result.columns = ['Observed Difference', 'p-value', 'Group 1', 'Group 2', 'Holm Correction']
# Упорядочить столбцы по Group 1, Group 2, Observed Difference, p-value, Holm Correction
result = result[['Group 1', 'Group 2', 'Observed Difference', 'p-value', 'Holm Correction']]
return result
# Выполнить permutation тест Данна для каждого столбца для Mg и Ca соответственно, используя цикл for
perm_dunn_mg = pd.DataFrame()
perm_dunn_ca = pd.DataFrame()
for col_name in cyano[['Shape', 'Silica', 'Broth']]:
perm_dunn_mg = perm_dunn_mg._append(perm_dunn(data = cyano.drop(columns = ["SampleName", "Replicate"]), dv = 'Mg', between = col_name), ignore_index = True)
perm_dunn_ca = perm_dunn_ca._append(perm_dunn(data = cyano.drop(columns = ["SampleName", "Replicate"]), dv = 'Ca', between = col_name), ignore_index = True)
# Напечатать результаты
print(perm_dunn_mg)
print(perm_dunn_ca)
```
Ответ или решение
В свете вашего вопроса о пост-хок тесте для непараметрических и малых выборок, давайте подробно рассмотрим ситуацию.
Теория
При анализе данных из экспериментов, где распределение может не соответствовать нормальному, часто прибегают к использованию непараметрических тестов, таких как критерий Краскела-Уоллиса. Этот тест, будучи аналогом однофакторного дисперсионного анализа (ANOVA), позволяет оценить, есть ли статистически значимые различия между группами. Однако, когда наблюдается значимый результат, требуется применить пост-хок тест, чтобы определить, какие именно группы различаются.
Для непараметрических данных с малыми объёмами выборок, традиционный тест Данна с поправкой на множественные сравнения, например, по методу Холма, может быть не всегда уместен из-за ограничений в точности при малых выборках. В таком случае рекомендуется применять пермутационные версии этих тестов, которые более устойчивы к специфике малых данных и менее зависят от предположений о распределении данных.
Пример
В вашем случае вы анализировали данные об изменении концентраций Mg и Ca под воздействием различных факторов в экспериментах с цианобактериями. Первоначальные результаты теста Краскела-Уоллиса показали, что тип организма существенно влияет на концентрацию обоих элементов. Однако пост-хок тест Данна (с коррекцией Holm) выявил значимость отличий только для Mg. После применения пермутационного варианта теста Данна результат изменился: показалась значимость не только для типа организма, но и для типа бульона. Это предполагает возможные ошибки типов I или II в одном из тестов, что актуально для подобных малых наборов данных.
Применение
Ваш код для пермутационного теста Данна реализован достаточно полно и позволяет выполнять необходимые вычисления. Тем не менее, для уверенности в корректности результата полезно было бы удостовериться в корректности процесса пермутации и вычисления p-значений. Имейте в виду, что любые ошибки в комментариях (например, отсутствие логического оператора в выражении np.sum(perm_diffs >= observed_diff)
) могут привести к неправильной интерпретации данных. Верно будет использовать np.sum(perm_diffs >= observed_diff)
в контексте Python.
Для дополнительных рекомендаций:
- Проверка кода: Пересмотрите зависимости и требования к данным. Убедитесь, что данные однородны и качественно организованы, чтобы избежать систематических ошибок.
- Анализ мощности теста: Проведите анализ мощности, чтобы оценить вероятность обнаружения настоящих эффектов при данных характеристиках выборки. Это помогает понять, не является ли отсутствие значимости результатом недостаточной статистической мощности.
- Эффект размера: Как и планировали, расчёт эффектов значимости даст вам дополнительное понимание того, насколько сила выявленных различий велика и имеет ли она практическую значимость.
Последний момент: в выборе подходящих статистических методов всегда учитывайте специфику вашей проблемы и экспериментальных данных. Достаточная научная обоснованность методов и инструментов анализа является ключом к достоверным результатам и правильным научным выводам.