Mix.install([
{:kino, "~> 0.7"},
{:kino_vega_lite, "~> 0.1.13"},
{:pythonx, "~> 0.4.2"},
{:anova, "~> 0.6.1"},
{:kino_pythonx, "~> 0.1.0"}
])[project]
name = "project"
version = "0.0.0"
requires-python = "==3.13.*"
dependencies = ["scipy==1.16.1"]Preparing input
We have a series of measurements grouped by stimuli. We applied the same stimulus on the first group, the second group is the baseline:
groups =
[
[12394, 8802, 11233, 9523, 10351, 10063, 8181, 9665, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0],
[500, 700, 800, 800, 200, 1000, 300, 600]
]Analysis
Our hypothesis is that the stimulus cause measurable and significant effect. It follows that the null hypothesis is that there is no significant difference between the two groups.
We will test it using ANOVA, using the significance level (α - the probability that the null hypothesis is true) 0.05:
alpha = 0.05
anova_results =
groups
|> ANOVA.one_way()
|> TukeyHSD.test(alpha)As you have seen, we have disproved the null hypothesis, the difference is significant.
Visualization
effect_data =
anova_results.post_hoc_test.pairwise_comparisons
|> Enum.map(fn comp ->
{group1, group2} = comp.groups
%{
comparison: "Group#{group1} vs Group#{group2}",
effect_size: comp.effect_size,
significance: if(comp.significant?, do: "Significant", else: "Not Significant"),
p_value: comp.p_value
}
end)
VegaLite.new(width: 400, height: 300, title: "Effect Size (Cohen's d)")
|> VegaLite.data_from_values(effect_data)
|> VegaLite.mark(:bar, width: 50)
|> VegaLite.encode_field(:x, "comparison", type: :nominal, title: "Comparison")
|> VegaLite.encode_field(:y, "effect_size", type: :quantitative, title: "Effect Size")
|> VegaLite.encode(:color, field: "significance", type: :nominal, title: "Significance",
scale: [domain: ["Significant", "Not Significant"],
range: ["#d62728", "#2ca02c"]]
)
|> VegaLite.encode(:tooltip, [
[field: "effect_size", type: :quantitative, title: "Effect Size"],
[field: "p_value", type: :quantitative, title: "p-value", format: ".2e"],
[field: "significance", type: :nominal, title: "Significance"]
])Verification of correctness
We compare the results of scipy.stats.f_oneway and our implementation.
from scipy.stats import f_oneway, tukey_hsd
F, p = f_oneway(groups[0], groups[1], groups[2])
print(F, p)
tukey_res = tukey_hsd(groups[0], groups[1], groups[2])
print(tukey_res)