Module stikpetP.tests.test_ham_owa
Expand source code
import pandas as pd
from scipy.stats import f
def ts_ham_owa(nomField, scaleField, categories=None):
'''
Hartung-Agac-Makabi One-Way ANOVA
------------------------------
Tests if the means (averages) of each category could be the same in the population.
If the p-value is below a pre-defined threshold (usually 0.05), the null hypothesis is rejected, and there are then at least two categories who will have a different mean on the scaleField score in the population.
This test is a modification of the Welch one-way ANOVA.
There are quite some alternatives for this, the stikpet library has Fisher, Welch, James, Box, Scott-Smith, Brown-Forsythe, Alexander-Govern, Mehrotra modified Brown-Forsythe, Hartung-Agac-Makabi, Özdemir-Kurt and Wilcox as options. See the notes from ts_fisher_owa() for some discussion on the differences.
Parameters
----------
nomField : pandas series
data with categories
scaleField : pandas series
data with the scores
categories : list or dictionary, optional
the categories to use from catField
Returns
-------
Dataframe with:
* *n*, the sample size
* *k*, the number of categories
* *statistic*, the test statistic (F value)
* *df1*, degrees of freedom 1
* *df2*, degrees of freedom 2
* *p-value*, the p-value (significance)
Notes
-----
The formula used (Hartung et al., 2002, pp. 206-207):
$$ F_{HAM} = \\frac{\\frac{1}{k-1}\\times\\sum_{j=1}^k w_j^*\\times\\left(\\bar{x}_j - \\bar{y}_w^*\\right)^2}{1 + \\frac{2\\times\\left(k-2\\right)}{k^2-1}\\times \\lambda^*}$$
$$ df_1 = k - 1$$
$$ df_2 = \\frac{k^2-1}{3\\times\\lambda^*}$$
$$ F_{HAM}\\sim F\\left(df_1, df_2\\right)$$
With:
$$ \\bar{y}_w^* = \\sum_{j=1}^k h_j^*\\times \\bar{x}_j$$
$$ h_j^* = \\frac{w_j^*}{w^*}$$
$$ w_j^* = \\frac{n_j}{s_j^2}\\times\\frac{1}{\\varphi_j}$$
$$ w^* = \\sum_{j=1}^k w_j^*$$
$$ \\varphi_j = \\frac{n_j + 2}{n_j + 1}$$
$$ \\bar{x}_j = \\frac{\\sum_{j=1}^{n_j} x_{i,j}}{n_j}$$
$$ s_j^2 = \\frac{\\sum_{i=1}^{n_j} \\left(x_{i,j} - \\bar{x}_j\\right)^2}{n_j - 1}$$
$$ \\lambda^* = \\sum_{j=1}^k \\frac{\\left(1 - h_j^*\\right)^2}{n_j - 1}$$
*Symbols used:*
* \\(k\\), for the number of categories
* \\(x_{i,j}\\), for the i-th score in category j
* \\(n_j\\), the sample size of category j
* \\(\\bar{x}_j\\), the sample mean of category j
* \\(s_j^2\\), the sample variance of the scores in category j
* \\(w_j^*\\), the modified weight for category j
* \\(h_j^*\\), the adjusted modified weight for category j
* \\(df_i\\), i-th degrees of freedom
* \\(\\varphi_j\\), the modification factor.
Note that the R-library 'doex' uses \\( \\varphi_j = \\frac{n_j - 1}{n_j - 3}\\). The original article though states that these are unbalanced weights of the Welch test and in their experience, using these makes the test too conservative. In the original article they find from their simulation experience that using \\( \\varphi_j = \\frac{n_j + 2}{n_j + 1}\\) gives reliable results for small sample sizes, and a large number of populations.
References
----------
Hartung, J., Argaç, D., & Makambi, K. H. (2002). Small sample properties of tests on homogeneity in one-way anova and meta-analysis. *Statistical Papers, 43*(2), 197–235. doi:10.1007/s00362-002-0097-8
Author
------
Made by P. Stikker
Companion website: https://PeterStatistics.com
YouTube channel: https://www.youtube.com/stikpet
Donations: https://www.patreon.com/bePatron?u=19398076
'''
if type(nomField) == list:
nomField = pd.Series(nomField)
if type(scaleField) == list:
scaleField = pd.Series(scaleField)
data = pd.concat([nomField, scaleField], axis=1)
data.columns = ["category", "score"]
#remove unused categories
if categories is not None:
data = data[data.category.isin(categories)]
#Remove rows with missing values and reset index
data = data.dropna()
data.reset_index()
#overall n, mean and ss
n = len(data["category"])
m = data.score.mean()
sst = data.score.var()*(n-1)
#sample sizes, variances and means per category
nj = data.groupby('category').count()
sj2 = data.groupby('category').var()
mj = data.groupby('category').mean()
#number of categories
k = len(mj)
pj = (nj + 2)/(nj + 1)
wj = nj/(pj*sj2)
w = float(wj.sum())
hj = wj/w
ym = float((hj*mj).sum())
lm = float(((1 - hj)**2/(nj - 1)).sum())
fVal = float((wj*(mj - ym)**2).sum()/((k - 1) + 2*(k - 2)*1/(k+1)*lm))
df1 = k - 1
df2 = float((k**2 - 1)/(3*lm))
pVal = f.sf(fVal, df1, df2)
#results
res = pd.DataFrame([[n, k, fVal, df1, df2, pVal]])
res.columns = ["n", "k", "statistic", "df1", "df2", "p-value"]
return res
Functions
def ts_ham_owa(nomField, scaleField, categories=None)-
Hartung-Agac-Makabi One-Way ANOVA
Tests if the means (averages) of each category could be the same in the population.
If the p-value is below a pre-defined threshold (usually 0.05), the null hypothesis is rejected, and there are then at least two categories who will have a different mean on the scaleField score in the population.
This test is a modification of the Welch one-way ANOVA.
There are quite some alternatives for this, the stikpet library has Fisher, Welch, James, Box, Scott-Smith, Brown-Forsythe, Alexander-Govern, Mehrotra modified Brown-Forsythe, Hartung-Agac-Makabi, Özdemir-Kurt and Wilcox as options. See the notes from ts_fisher_owa() for some discussion on the differences.
Parameters
nomField:pandas series- data with categories
scaleField:pandas series- data with the scores
categories:listordictionary, optional- the categories to use from catField
Returns
Dataframe with:
- n, the sample size
- k, the number of categories
- statistic, the test statistic (F value)
- df1, degrees of freedom 1
- df2, degrees of freedom 2
- p-value, the p-value (significance)
Notes
The formula used (Hartung et al., 2002, pp. 206-207): F_{HAM} = \frac{\frac{1}{k-1}\times\sum_{j=1}^k w_j^*\times\left(\bar{x}_j - \bar{y}_w^*\right)^2}{1 + \frac{2\times\left(k-2\right)}{k^2-1}\times \lambda^*} df_1 = k - 1 df_2 = \frac{k^2-1}{3\times\lambda^*} F_{HAM}\sim F\left(df_1, df_2\right)
With: \bar{y}_w^* = \sum_{j=1}^k h_j^*\times \bar{x}_j h_j^* = \frac{w_j^*}{w^*} w_j^* = \frac{n_j}{s_j^2}\times\frac{1}{\varphi_j} w^* = \sum_{j=1}^k w_j^* \varphi_j = \frac{n_j + 2}{n_j + 1} \bar{x}_j = \frac{\sum_{j=1}^{n_j} x_{i,j}}{n_j} s_j^2 = \frac{\sum_{i=1}^{n_j} \left(x_{i,j} - \bar{x}_j\right)^2}{n_j - 1} \lambda^* = \sum_{j=1}^k \frac{\left(1 - h_j^*\right)^2}{n_j - 1}
Symbols used:
- k, for the number of categories
- x_{i,j}, for the i-th score in category j
- n_j, the sample size of category j
- \bar{x}_j, the sample mean of category j
- s_j^2, the sample variance of the scores in category j
- w_j^*, the modified weight for category j
- h_j^*, the adjusted modified weight for category j
- df_i, i-th degrees of freedom
- \varphi_j, the modification factor.
Note that the R-library 'doex' uses \varphi_j = \frac{n_j - 1}{n_j - 3}. The original article though states that these are unbalanced weights of the Welch test and in their experience, using these makes the test too conservative. In the original article they find from their simulation experience that using \varphi_j = \frac{n_j + 2}{n_j + 1} gives reliable results for small sample sizes, and a large number of populations.
References
Hartung, J., Argaç, D., & Makambi, K. H. (2002). Small sample properties of tests on homogeneity in one-way anova and meta-analysis. Statistical Papers, 43(2), 197–235. doi:10.1007/s00362-002-0097-8
Author
Made by P. Stikker
Companion website: https://PeterStatistics.com
YouTube channel: https://www.youtube.com/stikpet
Donations: https://www.patreon.com/bePatron?u=19398076Expand source code
def ts_ham_owa(nomField, scaleField, categories=None): ''' Hartung-Agac-Makabi One-Way ANOVA ------------------------------ Tests if the means (averages) of each category could be the same in the population. If the p-value is below a pre-defined threshold (usually 0.05), the null hypothesis is rejected, and there are then at least two categories who will have a different mean on the scaleField score in the population. This test is a modification of the Welch one-way ANOVA. There are quite some alternatives for this, the stikpet library has Fisher, Welch, James, Box, Scott-Smith, Brown-Forsythe, Alexander-Govern, Mehrotra modified Brown-Forsythe, Hartung-Agac-Makabi, Özdemir-Kurt and Wilcox as options. See the notes from ts_fisher_owa() for some discussion on the differences. Parameters ---------- nomField : pandas series data with categories scaleField : pandas series data with the scores categories : list or dictionary, optional the categories to use from catField Returns ------- Dataframe with: * *n*, the sample size * *k*, the number of categories * *statistic*, the test statistic (F value) * *df1*, degrees of freedom 1 * *df2*, degrees of freedom 2 * *p-value*, the p-value (significance) Notes ----- The formula used (Hartung et al., 2002, pp. 206-207): $$ F_{HAM} = \\frac{\\frac{1}{k-1}\\times\\sum_{j=1}^k w_j^*\\times\\left(\\bar{x}_j - \\bar{y}_w^*\\right)^2}{1 + \\frac{2\\times\\left(k-2\\right)}{k^2-1}\\times \\lambda^*}$$ $$ df_1 = k - 1$$ $$ df_2 = \\frac{k^2-1}{3\\times\\lambda^*}$$ $$ F_{HAM}\\sim F\\left(df_1, df_2\\right)$$ With: $$ \\bar{y}_w^* = \\sum_{j=1}^k h_j^*\\times \\bar{x}_j$$ $$ h_j^* = \\frac{w_j^*}{w^*}$$ $$ w_j^* = \\frac{n_j}{s_j^2}\\times\\frac{1}{\\varphi_j}$$ $$ w^* = \\sum_{j=1}^k w_j^*$$ $$ \\varphi_j = \\frac{n_j + 2}{n_j + 1}$$ $$ \\bar{x}_j = \\frac{\\sum_{j=1}^{n_j} x_{i,j}}{n_j}$$ $$ s_j^2 = \\frac{\\sum_{i=1}^{n_j} \\left(x_{i,j} - \\bar{x}_j\\right)^2}{n_j - 1}$$ $$ \\lambda^* = \\sum_{j=1}^k \\frac{\\left(1 - h_j^*\\right)^2}{n_j - 1}$$ *Symbols used:* * \\(k\\), for the number of categories * \\(x_{i,j}\\), for the i-th score in category j * \\(n_j\\), the sample size of category j * \\(\\bar{x}_j\\), the sample mean of category j * \\(s_j^2\\), the sample variance of the scores in category j * \\(w_j^*\\), the modified weight for category j * \\(h_j^*\\), the adjusted modified weight for category j * \\(df_i\\), i-th degrees of freedom * \\(\\varphi_j\\), the modification factor. Note that the R-library 'doex' uses \\( \\varphi_j = \\frac{n_j - 1}{n_j - 3}\\). The original article though states that these are unbalanced weights of the Welch test and in their experience, using these makes the test too conservative. In the original article they find from their simulation experience that using \\( \\varphi_j = \\frac{n_j + 2}{n_j + 1}\\) gives reliable results for small sample sizes, and a large number of populations. References ---------- Hartung, J., Argaç, D., & Makambi, K. H. (2002). Small sample properties of tests on homogeneity in one-way anova and meta-analysis. *Statistical Papers, 43*(2), 197–235. doi:10.1007/s00362-002-0097-8 Author ------ Made by P. Stikker Companion website: https://PeterStatistics.com YouTube channel: https://www.youtube.com/stikpet Donations: https://www.patreon.com/bePatron?u=19398076 ''' if type(nomField) == list: nomField = pd.Series(nomField) if type(scaleField) == list: scaleField = pd.Series(scaleField) data = pd.concat([nomField, scaleField], axis=1) data.columns = ["category", "score"] #remove unused categories if categories is not None: data = data[data.category.isin(categories)] #Remove rows with missing values and reset index data = data.dropna() data.reset_index() #overall n, mean and ss n = len(data["category"]) m = data.score.mean() sst = data.score.var()*(n-1) #sample sizes, variances and means per category nj = data.groupby('category').count() sj2 = data.groupby('category').var() mj = data.groupby('category').mean() #number of categories k = len(mj) pj = (nj + 2)/(nj + 1) wj = nj/(pj*sj2) w = float(wj.sum()) hj = wj/w ym = float((hj*mj).sum()) lm = float(((1 - hj)**2/(nj - 1)).sum()) fVal = float((wj*(mj - ym)**2).sum()/((k - 1) + 2*(k - 2)*1/(k+1)*lm)) df1 = k - 1 df2 = float((k**2 - 1)/(3*lm)) pVal = f.sf(fVal, df1, df2) #results res = pd.DataFrame([[n, k, fVal, df1, df2, pVal]]) res.columns = ["n", "k", "statistic", "df1", "df2", "p-value"] return res