Bootstrap-t-student/bootstrap-t.ipynb

21 KiB
Raw Blame History

Projekt - Test t studenta

  • Marcin Kostrzewski
  • Krystian Wasilewski
  • Mateusz Tylka

Test t studenta

Metoda statystyczna służącą do porównania dwóch średnich między sobą gdy znamy liczbę badanych próbek, średnią arytmetyczną oraz wartość odchylenia standardowego lub wariancji. Jest to jeden z mniej skomplikowanych i bardzo często wykorzystywanych testów statystycznych używanych do weryfikacji hipotez. Dzięki niemu możemy dowiedzieć się czy dwie różne średnie są różne niechcący (w wyniku przypadku) czy są różne istotnie statystycznie (np. z uwagi na naszą manipulację eksperymentalna). Wyróżniamy 3 wersję testu t:

  1. test t Studenta dla jednej próby
  2.  test t Studenta dla prób niezależnych
  3.  test t Studenta dla prób zależnych

Wszystkie rodzaje testów są testami parametrycznymi, a co za tym idzie nasze mierzone zmienne ilościowe powinny mieć rozkład normalny.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from enum import Enum
from scipy.stats import ttest_ind, ttest_1samp, ttest_rel, shapiro
dataset = pd.read_csv('experiment_data.csv')
class Alternatives(Enum):
    LESS = 'less'
    GREATER = 'greater'
def calculate_t_difference(t_stat_sample, t_stat_list, alternative):
    """
    Funkcja oblicza procent statystyk testowych powstałych z prób bootstrapowych, 
    które róznią się od statystyki testowej powstałej ze zbioru według hipotezy alternatywnej.
    """
    all_stats = len(t_stat_list)
    stats_different_count = 0
    for t_stat_boot in t_stat_list:
        if alternative is Alternatives.LESS and t_stat_boot < t_stat_sample:
            stats_different_count += 1 
        elif alternative is Alternatives.GREATER and t_stat_boot > t_stat_sample:
            stats_different_count += 1
    return stats_different_count / all_stats
def t_test_1_samp(sample_1, population_mean=None, alternative=Alternatives.LESS):
    """
    Funkcja przeprowadza test T-studenta dla jednej zmiennej.
    """
    t_stat_from_sample, _ = ttest_1samp(a=sample_1, popmean=population_mean, alternative=alternative.value)
    t_stat_list = get_t_stats(sample_1, t_stat_fn=ttest_1samp, alternative=alternative, population_mean=population_mean)

    p = calculate_t_difference(t_stat_from_sample, t_stat_list, alternative)

    return p, t_stat_from_sample, t_stat_list
def t_test_ind(sample_1, sample_2, alternative=Alternatives.LESS):
    """
    Funkcja przeprowadza test T-studenta dla dwóch zmiennych niezależnych.
    """
    t_stat_from_sample, _ = ttest_ind(sample_1, sample_2, alternative=alternative.value)
    t_stat_list = get_t_stats(sample_1, sample_2, alternative=alternative, t_stat_fn=ttest_ind)

    p = calculate_t_difference(t_stat_from_sample, t_stat_list, alternative)

    return p, t_stat_from_sample, t_stat_list
def t_test_dep(sample_1, sample_2, alternative=Alternatives.LESS):
    """
    Funkcja przeprowadza test T-studenta dla dwóch zmiennych zależnych.
    """
    t_stat_list = get_t_stats(sample_1, sample_2, alternative=alternative, t_stat_fn=ttest_rel)
    t_stat_from_sample, _ = ttest_rel(sample_1, sample_2, alternative=alternative.value)

    p = calculate_t_difference(t_stat_from_sample, t_stat_list, alternative)

    return p, t_stat_from_sample, t_stat_list
def get_t_stats(sample_1, sample_2=None, t_stat_fn=ttest_1samp, alternative=Alternatives.LESS, population_mean=None):
    """Funkcja oblicza listę statystyk testowych dla każdej próbki bootstrapowej wybranej na podstawie danych sample_1 i sample_2"""
    t_stat_list = []

    # One sample test
    if t_stat_fn is ttest_1samp and sample_2 is None:
        if not population_mean:
            raise Exception("population_mean not provided")
        for bootstrap in generate_bootstraps(sample_1):
            stat, _ = t_stat_fn(bootstrap, population_mean, alternative=alternative.value)
            t_stat_list.append(stat)
        return t_stat_list

    # Two sample test
    for bootstrap_sample in generate_bootstraps(pd.concat((sample_1, sample_2), ignore_index=True)):
        bootstrap_1 = bootstrap_sample.iloc[: len(bootstrap_sample) // 2]
        bootstrap_2 = bootstrap_sample.iloc[len(bootstrap_sample) // 2 :]
        stat, _ = t_stat_fn(bootstrap_1, bootstrap_2, alternative=alternative.value)
        t_stat_list.append(stat)
    return t_stat_list
def pretty_print_test(p, t_stat_from_sample, t_stat_list, thesis, alternative, max_print=5):
    print('Wyniki bootstrapowej wersji testu T-studenta')
    print()
    print(f'Hipoteza: {thesis}')
    if alternative is Alternatives.LESS:
        print(f'Hipoteza alternatywna: średnia jest mniejsza')
    else:
        print(f'Hipoteza alternatywna: średnia jest większa')
    print()
    print(f'p: {p}')
    print(f'Wartość statystyki testowej z próby: {t_stat_from_sample}')
    print(f'Wartości statystyk z prób boostrapowych:')

    t_stat_list_len = len(t_stat_list)
    for i in range(min(max_print, t_stat_list_len)):
        print(f'{t_stat_list[i]}, ', end='')
    if max_print < t_stat_list_len:
        remaining = t_stat_list_len - max_print
        print(f'... (i {remaining} pozostałych)')

    print()
    print()

Test Shapiro Wilka

Wszystkie rodzaje testów są testami parametrycznymi, a co za tym idzie nasze mierzone zmienne ilościowe powinny mieć rozkład normalny.

ALPHA = 0.05
female_heights = dataset['Female height'].to_numpy()
shapiro_test = shapiro(female_heights)

if shapiro_test.pvalue >  ALPHA:
    print("Female height: Dane mają rozkład normalny.")
else:
    print("Female height: Dane nie mają rozkładu normalnego.")

male_heights = dataset['Male height'].to_numpy()
shapiro_test = shapiro(male_heights)

if shapiro_test.pvalue >  ALPHA:
    print("Male height: Dane mają rozkład normalny.")
else:
    print("Male height: Dane nie mają rozkładu normalnego.")

weights_before = dataset['Weight before'].to_numpy()
shapiro_test = shapiro(weights_before)

if shapiro_test.pvalue >  ALPHA:
    print("Weight before: Dane mają rozkład normalny.")
else:
    print("Weight before: Dane nie mają rozkładu normalnego.")

weights_after = dataset['Weight after'].to_numpy()
shapiro_test = shapiro(weights_after)

if shapiro_test.pvalue >  ALPHA:
    print("Weight after: Dane mają rozkład normalny.")
else:
    print("Weight after: Dane nie mają rozkładu normalnego.")


Female height: Dane mają rozkład normalny.
Male height: Dane mają rozkład normalny.
Weight before: Dane mają rozkład normalny.
Weight after: Dane mają rozkład normalny.

Testowanie hipotez metodą bootstrap

Bootstrap – metoda szacowania (estymacji) wyników poprzez wielokrotne losowanie ze zwracaniem z próby. Polega ona na utworzeniu nowego rozkładu wyników, na podstawie posiadanych danych, poprzez wielokrotne losowanie wartości z posiadanej próby. Metoda ze zwracaniem polega na tym, że po wylosowaniu danej wartości, “wraca” ona z powrotem do zbioru.

Metoda bootstrapowa znajduje zastosowanie w sytuacji, w której nie znamy rozkładu z populacji z której pochodzi próbka lub w przypadku rozkładów małych lub asymetrycznych. W takim wypadku, dzięki tej metodzie, wyniki testów parametrycznych i analiz opartych o modele liniowe są bardziej precyzyjne. Zazwyczaj losuje się wiele próbek, np. 2000 czy 5000.

def generate_bootstraps(data, n_bootstraps=100):
    data_size = data.shape[0]
    for _ in range(n_bootstraps):
        indices =  np.random.choice(len(data), size=data_size)
        yield data.iloc[indices, :]

Test t studenta dla jednej próby

Test t Studenta dla jednej próby wykorzystujemy gdy chcemy porównać średnią “teoretyczną” ze średnią, którą faktycznie możemy zaobserwować w naszej bazie danych. Średnia teoretyczna to średnia pochodząca z innych badań lub po prostu bez większych uzasadnień pochodząca z naszej głowy.

Wyobraźmy sobie, że mamy dane z takimi zmiennymi jak wzrost pewnej grupy ludzi. Dzięki testowi t Studenta dla jednej próby możemy dowiedzieć się np. czy wzrost naszego młodszego brata wynoszący 155cm odbiega znacząco od średniej wzrostu tej grupy. Hipoteza zerowa w takim badaniu wyglądałaby następująco H0: Badana próba została wylosowana z populacji, w której wzrost osób wynosi średnio 155cm. Z kolei hipoteza alternatywna będzie brzmiała H1: Badana próba nie została wylosowana z populacji gdzie średni wzrost wynosi 155cm

def bootstrap_one_sample(sample, population_mean, alternative=Alternatives.LESS):
    p, t, ts = t_test_1_samp(
        sample_1=sample,
        population_mean=population_mean,
        alternative=alternative,
    )
    
    pretty_print_test(p, t, ts, f'średnia jest równa {population_mean}', alternative)
    print()
    return p, t, ts

Sprawdzenie czy osoba o wzroście 165cm pasuje do populacji (nie jest odmieńcem)

dummy = pd.DataFrame([1, 2, 3, 4, 5])
dummy2 = pd.DataFrame([4, 5, 6, 7, 8])
dummy3 = pd.DataFrame([1, 3 , 3, 4, 6])
#TODO: poprawić kod aby można było podawać kolumny

p, t, ts = bootstrap_one_sample(dummy, 165)
Wyniki bootstrapowej wersji testu T-studenta

Hipoteza: średnia jest równa 165
Hipoteza alternatywna: średnia jest mniejsza

p: 0.72
Wartość statystyki testowej z próby: [-229.1025971]
Wartości statystyk z prób boostrapowych:
[-239.4457368], [-201.5], [-176.97470898], [-256.14449047], [-436.1703468], ... (i 95 pozostałych)



TODO: Wniosek

Test t studenta dla prób niezależnych

Test t Studenta dla prób niezależnych jest najczęściej stosowaną metodą statystyczną w celu porównania średnich z dwóch niezależnych od siebie grup. Wykorzystujemy go gdy chcemy porównać dwie grupy pod względem jakiejś zmiennej ilościowej. Na przykład gdy chcemy porównać średni wzrost kobiet i mężczyzn w danej grupie.

Zazwyczaj dwie średnie z różnych od siebie grup będą się różnić. Test t Studenta powie nam jednak czy owe różnice są istotne statystycznie czy nie są przypadkowe. Hipoteza zerowa takiego testu będzie brzmiała H0: Średni wzrost w grupie mężczyzn jest taki sam jak średni w grupie kobiet. Hipoteza alternatywna z kolei H1: Kobiety będą różnić się od mężczyzn pod wzrostu. Jeśli wynik testu t Studenta będzie istotny na poziomie p < 0,05 możemy odrzucić hipotezę zerową na rzecz hipotezy alternatywnej.

def bootstrap_independent(sample_1, sample_2, alternative=Alternatives.LESS):
    p, t, ts = t_test_ind(
        sample_1=sample_1,
        sample_2=sample_2,
        alternative=alternative,
    )
    
    pretty_print_test(p, t, ts, 'średnie są takie same', alternative)
    return p, t, ts

TODO: Wniosek

Test t studenta dla prób zależnych

W odróżnieniu od testu t Studenta dla prób niezależnych, gdzie porównujemy dwie grupy, ten rodzaj testu stosujemy gdy poddajemy analizie tą samą pojedynczą grupę, ale dwukrotnie w czasie. Na przykład gdy chcemy porównać średnie wagi grupy osób przed dietą oraz po diecie, aby sprawdzić czy dieta spowodowała istotne zmiany statystyczne.

Hipoteza zerowa takiego testu będzie brzmiała H0: Średnia waga osób po diecie jest taka sama jak przed dietą. Hipoteza alternatywna z kolei H1: Dieta znacząco wpłynęła na średnią wagę danej grupy.

def bootstrap_dependent(sample_1, sample_2, alternative=Alternatives.LESS):
    p, t, ts = t_test_dep(
        sample_1=sample_1,
        sample_2=sample_2,
        alternative=alternative,
    )
    
    pretty_print_test(p, t, ts, 'średnie są takie same', alternative)
    return p, t, ts

TODO: Wyciągnąć wagi przed dietą i po oraz poprawić kod aby można było podawać kolumny

t_stat, df, cv, p, _ = bootstrap_dependent(dataset, dataset) pretty_print_full_stats(t_stat, df, cv, p)

TODO: Wniosek

Wykresy

def draw_distribution(stats):
    """
    Funkcja rysuje rozkład statystyki testowej
    @param stats: lista statystyk testowych
    """
    plt.hist(stats)
    plt.xlabel('Test statistic value')
    plt.ylabel('Frequency')
    plt.show()

Testy

# Testy z bootstrappowaniem

print('Statystyki dla jednej próby:')
p, t, ts = bootstrap_one_sample(dummy, 2)
Statystyki dla jednej próby:
Wyniki bootstrapowej wersji testu T-studenta

Hipoteza: średnia jest równa 2
Hipoteza alternatywna: średnia jest mniejsza

p: 0.35
Wartość statystyki testowej z próby: [1.41421356]
Wartości statystyk z prób boostrapowych:
[2.44948974], [3.13785816], [1.72328087], [0.27216553], [1.17669681], ... (i 95 pozostałych)



print('Statystyki dla dwóch prób zależnych:')
p, t, ts = bootstrap_dependent(dummy2, dummy3)
Statystyki dla dwóch prób zależnych:
Wyniki bootstrapowej wersji testu T-studenta

Hipoteza: średnie są takie same
Hipoteza alternatywna: średnia jest mniejsza

p: 1.0
Wartość statystyki testowej z próby: [10.61445555]
Wartości statystyk z prób boostrapowych:
[-2.66666667], [-0.14359163], [0.21199958], [0.11470787], [0.76696499], ... (i 95 pozostałych)


print('Statystyki dla dwóch prób niezależnych:')
p, t, ts = bootstrap_independent(dummy2, dummy3)
Statystyki dla dwóch prób niezależnych:
Wyniki bootstrapowej wersji testu T-studenta

Hipoteza: średnie są takie same
Hipoteza alternatywna: średnia jest mniejsza

p: 0.95
Wartość statystyki testowej z próby: [2.4140394]
Wartości statystyk z prób boostrapowych:
[-2.20937908], [0.13187609], [-0.81110711], [-0.94280904], [-0.77151675], ... (i 95 pozostałych)