-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e56925c
commit 5e508e8
Showing
8 changed files
with
327 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
name = "SimpleANOVA" | ||
uuid = "fff527a3-8410-504e-9ca3-60d5e79bb1e4" | ||
authors = ["Nicholas Bauer <[email protected]>"] | ||
version = "0.5.2" | ||
version = "0.6.0" | ||
|
||
[deps] | ||
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
|
||
pvalue(dist, x) = min(2 * min(cdf(dist, x), ccdf(dist, x)), 1.0) | ||
|
||
""" | ||
contrast(anovaresult::AnovaResult, groupassignment::Vector{Int}) | ||
Calculate a single-factor contrast against the groups specified in `groupassignment`. | ||
Valid groups are "0", "1", and "2", where "0" excludes the group from the comparison. | ||
Note: If you do nonorthogonal contrasts, use the Bonferroni or Šidák correction to adjust the | ||
α level (the level at which you consider a result likely to be true): | ||
Bonferroni: α′ = α/c for c contrasts | ||
Šidák: α′ = 1 - (1 - α)^(1 / c) (slightly better) | ||
where c = number of contrasts | ||
Note: Effect size is calcluated using the error term associated with the factor. Other choices are possible, | ||
including average of each group error; or the error associated with a control. | ||
""" | ||
function contrast(anovaresult::AnovaData, groupassignment::Vector{Int}, factorindex::Int = 1) | ||
0 < factorindex ≤ anovaresult.ncrossedfactors || error("factor index must be a valid crossed factor") | ||
all(0 .≤ groupassignment .≤ 2) || error("valid groups are 0, 1, and 2") | ||
length(groupassignment) == anovaresult.ncrossedfactorlevels[factorindex] || error("each level must be assigned to a group") | ||
|
||
lowerfactorlevels = prod(anovaresult.ncrossedfactorlevels[1:(factorindex-1)]) | ||
upperfactorlevels = prod(anovaresult.ncrossedfactorlevels[(factorindex+1):anovaresult.ncrossedfactors]) | ||
|
||
# factorindex is in the order the factors appear in the result | ||
# but the crossedcellmeans dimensions are in reverse order (as input) | ||
group1levels = repeat(groupassignment .== 1, outer = upperfactorlevels, inner = lowerfactorlevels) | ||
group2levels = repeat(groupassignment .== 2, outer = upperfactorlevels, inner = lowerfactorlevels) | ||
group1count = count(group1levels) | ||
group2count = count(group2levels) | ||
|
||
contrastcoefficients = zeros(anovaresult.ncrossedfactorlevels[factorindex] * lowerfactorlevels * upperfactorlevels) | ||
contrastcoefficients[group1levels] .= 1 / group1count | ||
contrastcoefficients[group2levels] .= -1 / group2count | ||
|
||
errorfactor = anovaresult.crossedfactorsdenominators[factorindex] | ||
ψ = sum(contrastcoefficients .* anovaresult.crossedcellmeans) | ||
contrast = anovaresult.npercrossedcell * ψ ^ 2 | ||
error = sum(contrastcoefficients .^ 2) * errorfactor.ms | ||
|
||
f = contrast / error | ||
fdist = FDist(1, errorfactor.df) | ||
p = ccdf(fdist, f) | ||
|
||
effectsize = sqrt(f / (f + errorfactor.df)) # t^2 == f | ||
#cohen's d: effectsize = ψ / sqrt(errorfactor.ms) ; preferred when group sizes very different | ||
|
||
AnovaContrastResult(contrast, errorfactor.df, f, p, effectsize) | ||
end | ||
|
||
""" | ||
differencecontrast(anovaresult::AnovaData, factorindex = 1, reverseorder = false) | ||
Compute orthogonal contrasts on the factor levels in the original order. Forward direction also known as | ||
a "Helmert" contrast; revere direction may also be called "Difference" (as in SPSS). See `contrast` | ||
function for more. | ||
""" | ||
function differencecontrasts(anovaresult::AnovaData, reverseorder::Bool = false, factorindex::Int = 1) | ||
0 < factorindex ≤ anovaresult.ncrossedfactors || error("factor index must be a valid crossed factor") | ||
|
||
levels = anovaresult.ncrossedfactorlevels[1] | ||
groupassignments = [[repeat([0], i - 1); 1; repeat([2], levels - i)] for i ∈ 1:(levels - 1)] | ||
reverseorder && reverse!.(groupassignments) | ||
|
||
AnovaContrastResults(contrast.(Ref(anovaresult), groupassignments, factorindex)) | ||
end | ||
|
||
""" | ||
repeatedcontrast(anovaresult::AnovaData, factorindex = 1) | ||
Compute contrasts between neighboring levels. Non-orthogonal. See `contrast` function for more. | ||
""" | ||
function repeatedcontrasts(anovaresult::AnovaData, factorindex::Int = 1) | ||
0 < factorindex ≤ anovaresult.ncrossedfactors || error("factor index must be a valid crossed factor") | ||
|
||
levels = anovaresult.ncrossedfactorlevels[factorindex] | ||
groupassignments = [[repeat([0], i - 1); 1; 2; repeat([0], levels - i - 1)] for i ∈ 1:(levels - 1)] | ||
|
||
AnovaContrastResults(contrast.(Ref(anovaresult), groupassignments, factorindex)) | ||
end | ||
|
||
""" | ||
simplecontrast(anovaresult::AnovaData, controlindex = 1, factorindex = 1) | ||
Compute contrasts of each level to a single level (control). Non-orthogonal. See `contrast` function for more. | ||
""" | ||
function simplecontrasts(anovaresult::AnovaData, controlindex::Int = 1, factorindex::Int = 1) | ||
0 < factorindex ≤ anovaresult.ncrossedfactors || error("factor index must be a valid crossed factor") | ||
0 < controlindex ≤ anovaresult.ncrossedfactorlevels[factorindex] || error("index must be for a valid factor level") | ||
|
||
levels = anovaresult.ncrossedfactorlevels[factorindex] | ||
groupassignments = [zeros(Int, levels) for i ∈ 1:(levels - 1)] | ||
otherlevels = (1:levels)[Not(controlindex)] | ||
for i ∈ 1:(levels - 1) | ||
groupassignments[i][controlindex] = 1 | ||
groupassignments[i][otherlevels[i]] = 2 | ||
end | ||
|
||
AnovaContrastResults(contrast.(Ref(anovaresult), groupassignments, factorindex)) | ||
end | ||
|
||
#= To do this one, need to be able to code a factor level as in both groups | ||
""" | ||
deviationcontrasts(anovaresult::AnovaData, controlindex = 1, factorindex = 1) | ||
Compute contrasts of each level except one (control) to all levels. Non-orthogonal. | ||
See `contrast` function for more. | ||
""" | ||
function deviationcontrast(anovaresult::AnovaData, controlindex = 1, factorindex = 1) | ||
0 < factorindex ≤ anovaresult.ncrossedfactors || error("factor index must be a valid crossed factor") | ||
0 < controlindex ≤ anovaresult.ncrossedfactorlevels[1] || error("index must be for a valid factor level") | ||
levels = anovaresult.ncrossedfactorlevels[1] | ||
groupassignments = [zeros(Int, levels) for i ∈ 1:(levels - 1)] | ||
otherlevels = (1:levels)[Not(controlindex)] | ||
for i ∈ 1:(levels - 1) | ||
groupassignments[i][controlindex] = 1 | ||
groupassignments[i][otherlevels[i]] = 2 | ||
end | ||
[groupassignments[i][i] = 1 for i ∈ (1:levels)[Not(controlindex)]] | ||
[groupassignments[i][i] = 1 for i ∈ (1:levels)[Not(controlindex)]] | ||
contrast.(Ref(anovaresult), groupassignments) | ||
end | ||
=# |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
""" | ||
AnovaValue <: AnovaEffect | ||
A set of values for an Anova item for which a mean square is not required. | ||
`contrast` - the contrast value | ||
`df` - degrees of freedom | ||
`f` - the F statistic | ||
`p` - the probability of a Type I error (incorrect rejection of null hypothesis) | ||
`r` - the effect size | ||
""" | ||
struct AnovaContrastResult <: AnovaEffect | ||
contrast::Float64 | ||
df::Float64 | ||
f::Float64 | ||
p::Float64 | ||
r::Float64 | ||
end | ||
|
||
struct AnovaContrastResults | ||
results::Vector{AnovaContrastResult} | ||
end | ||
|
||
import Base.isapprox | ||
isapprox(x::AnovaContrastResults, y::AnovaContrastResults) = x.results .≈ y.results | ||
isapprox(x::AnovaContrastResult, y::AnovaContrastResult) = | ||
x.contrast ≈ y.contrast && | ||
x.df ≈ y.df && | ||
x.f ≈ y.f && | ||
x.p ≈ y.p && | ||
x.r ≈ y.r | ||
|
||
import Base.show | ||
show(io::IO, acr::AnovaContrastResult) = show(io, AnovaContrastResults([acr])) | ||
function show(io::IO, acr::AnovaContrastResults) | ||
colnames = ["Contrast", "DF", "F", "p", "r"] | ||
nrows = length(acr.results) | ||
|
||
compactshow(x) = sprint(show, x, context=:compact=>true) | ||
|
||
contrast = [e.contrast |> compactshow for e ∈ acr.results] | ||
df = [e.df |> Int |> compactshow for e ∈ acr.results] | ||
f = [e.f |> compactshow for e ∈ acr.results] | ||
p = [e.p |> compactshow for e ∈ acr.results] | ||
r = [e.r |> compactshow for e ∈ acr.results] | ||
|
||
ndec = [length.(last.(split.(values, "."))) for values ∈ [contrast, f, p, r]] | ||
maxndec = maximum.(ndec) | ||
rpadding = [maxndec[i] .- ndec[i] for i ∈ 1:4] | ||
|
||
ss = [rpad(contrast[i], rpadding[1][i] + length(contrast[i])) for i ∈ 1:nrows] | ||
f = [rpad(f[i], rpadding[2][i] + length(f[i])) for i ∈ 1:nrows] | ||
p = [rpad(p[i], rpadding[3][i] + length(p[i])) for i ∈ 1:nrows] | ||
r = [rpad(r[i], rpadding[4][i] + length(r[i])) for i ∈ 1:nrows] | ||
|
||
colwidths = [length.(values) |> maximum for values ∈ [[colnames[1]; contrast], | ||
[colnames[2]; df], | ||
[colnames[3]; f], | ||
[colnames[4]; p], | ||
[colnames[5]; r]]] | ||
colwidths[2:end] .+= 2 | ||
|
||
headerrow = join(lpad.(colnames, colwidths)) | ||
separator = repeat("-", sum(colwidths)) | ||
rows = [lpad(contrast[i], colwidths[1]) * | ||
lpad(df[i], colwidths[2]) * | ||
lpad(f[i], colwidths[3]) * | ||
lpad(p[i], colwidths[4]) * | ||
lpad(r[i], colwidths[5]) for i ∈ 1:nrows] | ||
|
||
println(io) | ||
println(io, "Analysis of Variance Contrast Results") | ||
println(io) | ||
println(io, headerrow) | ||
println(io, separator) | ||
foreach(i -> println(io, rows[i]), 1:length(rows)) | ||
end |
Oops, something went wrong.