<jupyter_start><jupyter_text>Stratified Analyses> Return the stratum-specific, crude, and weighted odds ratio for a stratified cohort and case-control study, and perform a test of no association (Mantel–Haenszel test) and a test of homogeneity (Tarone's test).- toc: true- badges: true- comments: true- categories: [m249, medicalstats]- permalink: /2022/05/02/stratified_analyses/  Dependencies<jupyter_code>import numpy as np
import pandas as pd
from statsmodels import api as sm<jupyter_output><empty_output><jupyter_text>Inputs/Outputs Inputs- *married* (`NDArry`), the "married" stratum with shape `(2, 2)`- *not married* (`NDArry`), the "not married" stratum with shape `(2, 2)` Intermediate- *ctables* (`StratifiedAnalysis`), a `4x2` contingency table Outputs- *stratum specific odds ratios* (`DataFrame`), straum-specific odds ratios- *crude odds ratio* (`Series`), unweighted aggregate odds ratio- *adjusted odds ratio* (`Series`), weighted aggregate odds ratio, the Mantel–Haenszel odds ratio- *combined measures* (`DataFrame`), combined unadjusted and adjusted odds ratios- *null res* `(Series`), results of a test of no association (Mantel–Haenszel test)- *homog res* (`Series`), results of a test of homogeneity (Tarone's test)  Initialise the observationsThe data comes from a stratified case-control study researching the association between alocohol consumption and fatal car accidents in New York.The data was stratified by marital status, which was believed to be a possible confounder.The exposure $E$ is a blood alcohol level of 100mg% or greater.Cases are drivers who were killed in car accidents for which they were considered to be responsible, and controls are selected drivers passing the locations where the accidents of the cases occurred, at the same time of day and on the same day of the week.The data is stratified by marital status, either married or not married.The results were as follows.| Married             | cases (+)   | controls (-) || ------------------- | ----------: | -----------: || **exposed (+)**     | 4           | 5            || **not exposed (-)** | 5           | 103          || Not married         | cases (+)   | controls (-) || ------------------- | ----------: | -----------: || **exposed (+)**     | 10          | 3            || **not exposed (-)** | 5           | 43           |<jupyter_code>married = np.array([[4, 5], [5, 103]])
not_married = np.array([[10, 3], [5, 43]], dtype=int)<jupyter_output><empty_output><jupyter_text>Initialise StratifiedTable<jupyter_code>ctables = sm.stats.StratifiedTable([married, not_married])
ctables.table<jupyter_output><empty_output><jupyter_text>Odds ratios  Stratum-specific odds ratios<jupyter_code>stratum_specific_odds_ratios = pd.DataFrame(index=['point est', 'lcb', 'ucb'])
levels = {'married': married, 'not married': not_married}
for level, table in levels.items():
    ctable = sm.stats.Table2x2(table)
    stratum_specific_odds_ratios[level] = (ctable.oddsratio,
                                           ctable.oddsratio_confint()[0],
                                           ctable.oddsratio_confint()[1])
stratum_specific_odds_ratios<jupyter_output><empty_output><jupyter_text>Crude odds ratio<jupyter_code>ctab = sm.stats.Table2x2(married + not_married)
crude_odds_ratio = pd.Series(
    data={
        'point est': ctab.oddsratio,
        'lcb': ctab.oddsratio_confint()[0],
        'ucb': ctab.oddsratio_confint()[1]
     },
    name='crude odds ratio'
)
crude_odds_ratio<jupyter_output><empty_output><jupyter_text>Adjusted odds ratio (Mantel–Haenszel odds ratio)<jupyter_code>adj_odds_ratio = pd.Series(
    data={
        'point est': ctables.oddsratio_pooled,
        'lcb': ctables.oddsratio_pooled_confint()[0],
        'ucb': ctables.oddsratio_pooled_confint()[1]
     },
    name='adjusted odds ratio'
)
adj_odds_ratio<jupyter_output><empty_output><jupyter_text>Combined unadjusted and adjusted odds ratios<jupyter_code>pd.DataFrame([crude_odds_ratio, adj_odds_ratio])<jupyter_output><empty_output><jupyter_text>Test of no association (Mantel–Haenszel chi-squared test)<jupyter_code>null_test = ctables.test_null_odds(correction=True)
null_res = pd.Series(
    data={
        'statistic': null_test.statistic.round(5),
        'pval': null_test.pvalue.round(5)
    },
    name='test of no association'
)
null_res<jupyter_output><empty_output><jupyter_text>Test of homogeneity (Tarone's test)<jupyter_code>homog_res = ctables.test_equal_odds(adjust=True)
pd.Series(
    data={
        'statistic': homog_res.statistic.round(5),
        'pval': homog_res.pvalue.round(5)
    },
    name='test of homogeneity'
)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1314886314886315, 'fraction_numerical': 0.012441012441012441, 'mean_word_length': 3.9501061571125264, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 38, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '231157', 'license': 'MIT', 'n_tokens_mistral': 1561, 'n_tokens_neox': 1423, 'n_words': 393, 'path': '_notebooks/2022-05-02-stratified_analyses.ipynb', 'repo_name': 'ljk233/blog', 'size': '4662'}