Julia でふつうの統計解析
共分散分析 ANCOVA (ANalysis of COVAriance)
前のページに戻る
#
# GSwR2 第6章 共分散分析 (ANCOVA)
#
# 笠貝の成長速度の季節と密度による変化
#
# 2019/03/09 Daisuke TOMINGAGA
using CSV, Gadfly, DataFrames, DataFramesMeta, Statistics, HypothesisTests,
Cairo, Fontconfig, GLM, Distributions, Distances, LinearAlgebra
set_default_plot_size(10cm, 8cm)
# データ読み込み、データ形式の確認、要約統計量、プロット
dat = CSV.read("datasets/limpet.csv", allowmissing=:none)
describe(dat)
describe(dat[:SEASON])
p = plot(dat, x = :DENSITY, y = :EGGS, color = :SEASON)
draw(PDF("limpet_1.pdf", 10cm, 8cm), p)
# 線形モデル当てはめ
model = lm(@formula(EGGS ~ DENSITY * SEASON), dat)
# 診断プロット1:Residuals vs Fitted
pred = predict(model)
res = dat[:EGGS] - pred
p = plot(x = pred, y = res, Geom.point,
Guide.title("Residuals vs Fitted"),
Guide.xlabel("Fitted values"), Guide.ylabel("Residuals"))
draw(PDF("limpet_2.pdf", 10cm, 8cm), p)
# 診断プロット2:Normal Q-Q plot
m = mean(res)
N = length(res)
stdRes = (res - m * ones(N)) / (std(res)) # 標準化誤差 = (誤差-平均)/標準偏差
qx = quantile.(Normal(), range(0.5, stop=(N-0.5), length=(N)) / (N + 1))
p = plot(layer(x = qx, y = sort(stdRes), Geom.point),
layer(x = [-3,3], y = [-3,3], Geom.line, style(line_style = [:dot])),
Guide.title("Normal Q-Q plot"),
Guide.xlabel("Theoretical Quantiles"),
Guide.ylabel("Standardized residuals"))
draw(PDF("limpet_3.pdf", 10cm, 8cm), p)
# 診断プロット3:Scale-Location
set_default_plot_size(10cm, 10cm) # ちょっと縦長にしないとyラベルが入らない
sqrtStdRes = sqrt.(abs.(stdRes))
p = plot(x = pred, y = sqrtStdRes, Geom.point,
Guide.title("Scale-Location"),
Guide.xlabel("Fitted values"),
Guide.ylabel("(|Standardized residuals|)1/2"))
draw(PDF("limpet_4.pdf", 10cm, 10cm), p)
set_default_plot_size(10cm, 8cm)
# 診断プロット4:Residuals vs Leverage
x = dat[:DENSITY]
Sxx = sum(x .* x) - sum(x)^2/N
m = mean(x)
leverage = ones(length(res))
for i in 1:N leverage[i] = (x[i] - m)^2 / Sxx + 1/N end
p = plot(x = leverage, y = stdRes, Geom.point,
Guide.xlabel("leverage"), Guide.ylabel("stdRes"))
draw(PDF("limpet_5.pdf", 10cm, 10cm), p)
model
#coef(model)
#stderror(model)
# で、データとモデルと信頼区間のプロット
# まず DENSITY の予測範囲を決め、予測点を生成し、元データと同じ変数名にし、
# DENSITY の値と SEASON の値の全ての組み合わせを生成する -> newx
xmin = describe(dat)[1, :min]
xmax = describe(dat)[1, :max]
x = DataFrame([range(xmin, stop = xmax, length = 10)])
names!(x, [:DENSITY])
v = vec(collect(Base.product(x[:DENSITY], levels(dat[:SEASON]))))
newx = DataFrame(collect.(collect(zip(v...))))
names!(newx, [:DENSITY, :SEASON])
# でその予測点での目的変数の期待値95%信頼区間の上下の値を計算して一つの
# データフレームにまとめる
pred = predict(model, newx, interval = :confidence)
names!(pred, [:P, :L, :U])
insertcols!(pred, 1, DENSITY = newx[:DENSITY])
insertcols!(pred, 1, SEASON = newx[:SEASON])
# でデータと予測直線をプロット
# 先に置いた Geom.point が Geom.line の上に描画される
# ymin と ymax は Geom.ribbon が使う
# プロットをできるだけ日本語化するために、SEASON変数の中身を日本語にする
dat2 = dat[:,:]
pred2 = pred[:,:]
for i in 1:length(dat2[:SEASON])
dat2[i, :SEASON] = ( dat2[i, :SEASON] == "spring" ? "春" : "夏")
end
# 上の for ループと同じことを pred2 に対して違うやり方でやる
pred2[pred2[:SEASON] .== "spring", :SEASON] = "春"
pred2[pred2[:SEASON] .== "summer", :SEASON] = "夏"
names!(dat2, [:DENSITY, :季節, :EGGS])
names!(pred2, [:季節, :DENSITY, :P, :L, :U])
p = plot(layer(dat2, x = :DENSITY, y = :EGGS, color = :季節, Geom.point),
layer(pred2, x = :DENSITY, y = :P, Geom.line,
ymin = :L, ymax = :U, Geom.ribbon,
color = :季節),
Guide.title("カサガイ産卵数に対する生育密度の影響"),
Guide.xlabel("生育密度"),
Guide.ylabel("産卵量"))
draw(PDF("limpet_6.pdf", 10cm, 10cm), p)
2019, © Daisuke TOMINAGA.