LoginSignup
1
1

More than 5 years have passed since last update.

Rをはじめよう 生命科学のためのRStudio入門のデータセット(ここにある)を使って、線形回帰をやるJuliaコード。データを読み込み、図で結論を予想し、モデルの健全性を診断し、検定し、図を仕上げる。コードや出力の説明などは技術書典6(2019/04/14)で頒布予定。

plant.jl
using CSV, Gadfly, DataFrames, DataFramesMeta, Statistics, HypothesisTests,
      Cairo, Fontconfig, GLM, Distributions, Distances, LinearAlgebra

# データ読み込み
dat = CSV.read("datasets/plant.growth.rate.csv", allowmissing=:none)
# カラム名に . が入ってるとあとでうまく扱えないので、名前を変える
names!(dat, [:moisture, :growth]);

# データは要するに二群、各群でのオゾン濃度の平均値と分散
describe(dat)
var(dat[:moisture])
var(dat[:growth])

draw(PDF("fig/plant_1.pdf", 10cm, 8cm),
     hstack(plot(dat, y = :moisture, Geom.boxplot),
            plot(dat, y = :growth, Geom.boxplot)))
draw(PDF("fig/plant_2.pdf", 10cm, 8cm),
     plot(dat, x = :moisture, y = :growth, Geom.point))

# 線形回帰して、モデルの値(期待値)を計算し、診断プロットを描く
model = lm(@formula(growth ~ moisture), dat)
pred = predict(model)

# 診断プロット1:Residuals vs Fitted
res = dat[:growth] - pred
draw(PDF("fig/plant_3.pdf", 10cm, 8cm),
     plot(x = pred, y = res, Geom.point,
          Guide.title("Residuals vs Fitted"),
          Guide.xlabel("Fitted values"), Guide.ylabel("Residuals")))

# 診断プロット2:Normal Q-Q plot
N = length(res)
stdRes = (res .- mean(res) .* ones(N)) ./ (std(res)) # 標準化残差
qx = quantile.(Normal(), range(0.5, stop=(N-0.5), length=(N)) / (N + 1))
draw(PDF("fig/plant_4.pdf", 10cm, 8cm),
     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")))

# 診断プロット3:Scale-Location
sqrtStdRes = sqrt.(abs.(stdRes))
draw(PDF("fig/plant_5.pdf", 10cm, 8cm),
     plot(x = pred, y = sqrtStdRes, Geom.point,
          Guide.title("Scale-Location"),
          Guide.xlabel("Fitted values"),
          Guide.ylabel("|Standardized residuals|<sup>1/2</sup>")))

# 診断プロット4:Residuals vs Leverage
x = dat[:moisture]
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
draw(PDF("fig/plant_6.pdf", 10cm, 8cm),
     plot(x = leverage, y = stdRes, Geom.point,
          Guide.xlabel("leverage"), Guide.ylabel("stdRes")))

# で、データとモデルと信頼区間のプロット
# まずx軸の範囲を決める、データの範囲を探して、50点に区切る
# データフレームに入れて、回帰時の変数名と同じ変数名を付けないと、
# predict が受け取ってくれない
xmin = describe(dat)[1, :min]
xmax = describe(dat)[1, :max]
newx = DataFrame([range(xmin, stop = xmax, length = 50)])
names!(newx, [:moisture])
# で予測値を計算して、結果のデータフレームにxの値を挿入
pred = predict(model, newx, interval=:confidence)
insertcols!(pred, 1, moisture=newx[:moisture])
# でデータと予測直線をプロット
# 先に置いた Geom.point が Geom.line の上に描画される
# ymin と ymax は Geom.ribbon が使う
draw(PDF("fig/plant_7.pdf", 10cm, 8cm),
     plot(layer(dat, x = :moisture, y = :growth, Geom.point),
          layer(pred,x = :moisture, y = :prediction,
                     ymin = :lower, ymax = :upper,
                     Geom.line, Geom.ribbon),
          Coord.cartesian(xmin=0.2, xmax=2.0),
          Guide.title("土壌水分量と生育速度"),
          Guide.xlabel("土壌水分量"),
          Guide.ylabel("生育速度")))
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1