Topic 13

目次

1) 線形代数の復習と必要なJulia 関数 2) 回帰分析 Regression 3) 最小二乗法の公式:線形代数で導く 4) 最小二乗法: 乱数関数を用いて検証 5) 最小二乗法: データを用いて実践(課題) 6) ビッグデータ & Missing データ 7) 実践:全世界のコロナの感染データ (課題4:基礎) 8) 実践:全世界のコロナの感染データ (課題5:日付けの範囲) Topic 12 へ移動Topic Report へ移動共通資料:Plots全体目次

データサイエンス CDS009    (チェン leechuin@yamanashi.ac.jp) 更新日: 2022-10-01


線形回帰 & ビグデータ

今回の実習課題について:

 • 課題:5問

 • 提出ファイル1(Word .docx)

        ► 説明付きで、作成したコードの内容、出力画面とグラフのまとめ。

        ► 形式は自由ですが、読みやすくようにお願いします。

次の Julia パケージを使います:

        ► DataFrames 表データの取り扱い

        ► CSV テキストファイルをDataFrameに読み込む

        ► Plots グラフの作成

        ► Statistics 平均値、標本標準偏差、相関係数など

        ► Random ランダムの乱数

        ► LinearAlgebra 線形代数、転置

        ► Dates 年月日のフォーマット

各自のプログラムの最初の所に下記のコードを挿入する。

using DataFrames
using CSV
using Plots
using Statistics
using Random
using LinearAlgebra
using Dates

1. 線形代数の復習と必要なJulia 関数

ベクトルの内積

\[\begin{aligned}\mathbf{a} \bullet \mathbf{b} &= a_1 b_1 + a_2 b_2 + \cdots + a_n b_n\\\\ &= \begin{pmatrix} a_1 &a_2 &\cdots &a_n\end{pmatrix}\begin{pmatrix} b_1\\b_2\\ \vdots \\b_n\end{pmatrix}\\\\ &= \mathbf{a}^T \mathbf{b}\\\\ &= \mathbf{b}^T \mathbf{a}\\\\\end{aligned}\]

二乗の和を線形代数で表す

\[ \mathbf{a}^T \mathbf{a} = a_1^2 + a_2^2 + \cdots + a_n^2\]

転置の演算

\[ (\mathbf{a} + \mathbf{b})^T = \mathbf{a}^T + \mathbf{b}^T \]

\[ (\mathbf{a}\mathbf{b})^T = \mathbf{b}^T \mathbf{a}^T \]

hcat 関数で配列を水平に連結

julia> a = [1,2,3]
3-element Array{Int64,1}:
 1
 2
 3

julia>  b = [7,8,9]
3-element Array{Int64,1}:
 7
 8
 9

julia> hcat(a,b)
3×2 Array{Int64,2}:
 1  7
 2  8
 3  9

sort 関数でソーティングをする

julia> a = rand(1:9, 10)
10-element Array{Int64,1}:
 7
 5
 5
 8
 6
 6
 3
 4
 7
 1

julia> sort(a)
10-element Array{Int64,1}:
 1
 3
 4
 5
 5
 6
 6
 7
 7
 8

julia> sort(a, rev = true)
10-element Array{Int64,1}:
 8
 7
 7
 6
 6
 5
 5
 4
 3
 1


2. 回帰分析 Regression

 • 元々は生物学的現象を表す方法。

 • 英語 regression の直訳は「後退」という意味で、ばらついたデータが「平均への回帰」という現象を表す。

 • 現在では「データのモデルを当てはめる」のことを表す。

例:データYとXをf 関数で表す。

\[\mathbf{Y} = f(\mathbf{X}) \]

図1:15名の学生の身長(cm)と体重のデータ (相関係数 = 0.8)

図2:花 Iris の花弁の幅 (petal width) と 長さ (petal length)のデータ (相関係数 = 0.96)

関連情報(wikipedia):

最小二乗法について

線形回帰について


3. 最小二乗法の公式:線形代数で導く

\[y = f(x) + \epsilon\]

誤差 ϵ の二乗の和を最小にする。

線形回帰の場合:

\[\begin{aligned}y_1 &= x_{11}b_1 + x_{12}b_2 + \cdots + x_{1m}b_m + \epsilon_1 \\y_2 &= x_{21}b_1 + x_{21}b_2 + \cdots + x_{2m}b_m + \epsilon_2 \\\vdots\\y_n &= x_{n1}b_1 + x_{n1}b_2 + \cdots + x_{nm}b_m + \epsilon_n \\\end{aligned}\]

行列で表すと:

\[\begin{pmatrix}y_1\\y_2\\\vdots\\y_n\end{pmatrix} = \begin{pmatrix}x_{11} & x_{12} &\cdots &x_{1m} \\x_{21} & x_{22} &\cdots &x_{2m} \\\vdots & \vdots &\cdots &\vdots \\x_{n1} & x_{n2} &\cdots &x_{nm} \\\end{pmatrix}\begin{pmatrix}b_1\\b_2\\\vdots\\b_m\end{pmatrix} + \begin{pmatrix}\epsilon_1\\\epsilon_2\\\vdots\\\epsilon_n\end{pmatrix}\]

コンパクで表すと:

\[\mathbf{Y} = \mathbf{X} \mathbf{b} + \mathbf{e}\]

誤差のベクトル:

\[\mathbf{e} = \mathbf{Y} - \mathbf{X}\mathbf{b}\]

行列の微分:

\[\frac{\partial \mathbf{e}}{\partial \mathbf{b}} = -\mathbf{X}\]

誤差の二乗の和とその微分

\[S = \epsilon_1^2 + \epsilon_2^2 + \cdots \epsilon_n^2 = \mathbf{e}^T \mathbf{e}\]

\[\begin{aligned}\Delta S &= \frac{\partial S}{\partial \epsilon_1} \Delta \epsilon_1 + \cdots + \frac{\partial S}{\partial \epsilon_n} \Delta \epsilon_n\\\\&= \begin{pmatrix} 2\epsilon_1 &2\epsilon_2 &\cdots &2\epsilon_n\end{pmatrix}\begin{pmatrix}\Delta \epsilon_1 \\\Delta \epsilon_2\\\vdots\\\Delta \epsilon_n\end{pmatrix}\end{aligned}\]

整理したら:

\[\frac{\partial S}{\partial \mathbf{e}} = \frac{\Delta S}{\Delta \mathbf{e}} = 2\mathbf{e}^T\]

誤差の二乗の和 S を最小にすには:

\[\frac{\partial S}{\partial \mathbf{b}} = \mathbf{0}\]

上記の微分を求めるために、次の関係を利用する。

\[\frac{\partial S}{\partial \mathbf{b}} = \frac{\partial S}{\partial \mathbf{e}} ~ \frac{\partial e}{\partial \mathbf{b}}\]

\[\begin{aligned}\frac{\partial S}{\partial \mathbf{b}} &= - 2\mathbf{e}^T \mathbf{X}\\&= -2(\mathbf{Y} - \mathbf{X}\mathbf{b})^T \mathbf{X}\end{aligned}\]

では、dS/db = 0 にする。

\[\begin{aligned}(\mathbf{Y}^T - \mathbf{b}^T\mathbf{X}^T) \mathbf{X} = \mathbf{0}\\\mathbf{Y}^T\mathbf{X} - \mathbf{b}^T\mathbf{X}^T \mathbf{X} = \mathbf{0}\end{aligned}\]

整理したら:

\[\begin{aligned}\mathbf{b}^T\mathbf{X}^T \mathbf{X} &= \mathbf{Y}^T\mathbf{X}\\\end{aligned}\]

両側を転置したら:

\[\begin{aligned}\mathbf{X}^T \mathbf{X}\mathbf{b} &= \mathbf{X}^T\mathbf{Y}\\\end{aligned}\]

最後は:

\[\begin{aligned}\mathbf{b} &= (\mathbf{X}^T \mathbf{X})^{-1}\mathbf{X}^T\mathbf{Y}\\\end{aligned}\]


4. 最小二乗法: 乱数関数を用いて検証

主な式はこちら:

b = inv(transpose(X)*X) * transpose(X) * Y

練習:モデル y = b1*x + b2

下記のモデルを使います:

\[\begin{aligned}y_1 &= x_1 b_1 + b_2\\\vdots &= \vdots\\y_n &= x_n b_1 + b_2\end{aligned}\]

行例で表す:

\[\begin{aligned}\mathbf{Y} &= \mathbf{X}\mathbf{b}\\\\&=\begin{pmatrix}x_1 & 1\\\vdots & \vdots\\x_n &1 \end{pmatrix}\begin{pmatrix}b_1 \\b_2 \end{pmatrix}\end{aligned}\]

乱数を用いて検証する:

# モデル: y = a1*x + a2 
a = [2, 4]  # 真値: a1 = 2, a2=4
x = Array(0:0.1:5)
N = length(x)
Noise = randn(N) #ノイズ:正規分布乱数

#行列の形にする
X = hcat(x, ones(N))
Y =  X*a  .+ Noise

scatter(x, Y, legend = false, size = (400,300))

##最小二乗法:
b = inv(transpose(X)*X) * transpose(X) * Y
println("モデル: y = ",a[1],"x + ",a[2])
println("最小二乗法で求めた線形回帰係数の結果:")
println("b1 = ", b[1])
println("b2 = ", b[2])

Y2 = X*b
plot!(x, Y2, linewidth = 2)

出力:

モデル: y = 2x + 4
最小二乗法で求めた線形回帰係数の結果:
b1 = 2.029151596748406
b2 = 3.937559023888329

*実習課題:モデル y = b1*x^2 + b2*x + b3

下記のモデルを使います:

\[\begin{aligned}y_1 &= x_1^2 b_1 + x_1 b_2 + b_3\\\vdots &= \vdots\\y_n &= x_n^2 b_1 + x_1 b_2 + b_3\end{aligned}\]

\[\begin{aligned}\mathbf{Y} &= \mathbf{X}\mathbf{b}\\\\&=\begin{pmatrix}x_1^2 & x_1 & 1\\\vdots & \vdots\\x_n^2 &x_n &1 \end{pmatrix}\begin{pmatrix}b_1 \\b_2\\b_3 \end{pmatrix}\end{aligned}\]

乱数を用いて検証する:

# モデル: y = a1*x^2 + a2*x + a3 
a = [2, 4, 2]  #値を変えてみる
x = Array(-3:0.1:2)
N = length(x)
Noise = randn(N)  #randn は -inf 〜 0〜 +infの乱数を作成

#行列の形にする
X = hcat(x.^2, x, ones(N))
Y =  X*a  .+ Noise

scatter(x, Y, legend = false, size = (400,300))

#最小二乗法:
b = inv(transpose(X)*X) * transpose(X) * Y
println("モデル: y = ",a[1],"x^2 + ",a[2],"x + ", a[3])
println("最小二乗法で求めた線形回帰係数の結果:")
println("b1 = ", b[1])
println("b2 = ", b[2])
println("b3 = ", b[3])

Y2 = X*b
plot!(x, Y2, linewidth = 2)

出力:

デル: y = 2x^2 + 4x + 2
最小二乗法で求めた線形回帰係数の結果:
b1 = 1.9094574006719474
b2 = 3.8823305012426026
b3 = 2.4072598480843497

5. 最小二乗法: データを用いて実践(課題)

*実習課題2:十五人の学生の体重と身長の関係

次のコードを完成させる、最小二乗法を用いた回帰曲線を作成する。

身長 = [178, 165, 168, 152, 175,
        175, 165, 162, 164, 170,
        169, 155, 153, 162, 168]

体重 = [63, 62, 69, 41, 71,
        61, 62, 48, 52, 55,
        69, 48, 44, 49, 69]
Y = 体重
X = hcat(身長, ones(length(体重)))
scatter(身長, 体重, 
        legend = false, 
        xlabel = "Height (cm)",
        ylabel = "Weigth (kg)",
        size = (400,300))

#また未完成です

出力:

身長と体重の相関係数は:0.7967368727051103
求めた線形回帰係数 b:[1.0200559701493237, -111.18392412936413]

グラフ:

*実習課題3:花 Iris の花弁

 • 目的:花 Iris の花弁の幅と長さの関係の線形モデルを立てる。

 • データファイル:iris.txt

 • DataFrameの使い方について、第11回の授業資料を参照してください。

次のコードを完成させる、最小二乗法を用いた回帰曲線を作成する。

A=CSV.read("iris.txt", DataFrame)
show(A)
xx = A.petal_width
Y = A.petal_length
X = hcat(xx, ones(length(xx)))
#また未完成です

出力:

グラフ:


6. ビッグデータ & Missing データ

Big data ビッグデータ

図の出典

 • とても「大きい」データ

 • ICT企業さんが考えた定義:従来の統計ソフトウエアで処理できないデータ

Missing データについて

 • 現実のデータベースに「未入力」、「未知」なデータだ入っている。

 • Julia では、そういうデータを「Mising」というデータの型で扱っている。

julia> a = [1, 2, missing]
3-element Array{Union{Missing, Int64},1}:
 1
 2
  missing

julia> a + a
3-element Array{Union{Missing, Int64},1}:
 2
 4
  missing

julia> a*transpose(a)
3×3 Array{Union{Missing, Int64},2}:
 1         2         missing
 2         4         missing
  missing   missing  missing

julia> transpose(a)*a
missing

練習:DataFrame:Missingが入っている行を排除する

dropmissing(表データ) を使って missing のある行をdropする。

練習 例1:

julia> a = [1, 2, 3, 4]
4-element Vector{Int64}:
 1
 2
 3
 4

julia> b = [9, missing, 7, 6]
4-element Vector{Union{Missing, Int64}}:
 9
  missing
 7
 6

julia> df = DataFrame(x = a, y = b)
4×2 DataFrame
 Row │ x      y       
     │ Int64  Int64?  
─────┼────────────────
   11        9
   22  missing 
   33        7
   44        6

julia> dropmissing(df)
3×2 DataFrame
 Row │ x      y     
     │ Int64  Int64 
─────┼──────────────
   11      9
   23      7
   34      6

練習 例2:

julia> c = [missing, missing, missing, missing]
4-element Vector{Missing}:
 missing
 missing
 missing
 missing

julia> dg = DataFrame(x = a, y = b, z = c)
4×3 DataFrame
 Row │ x      y        z       
     │ Int64  Int64?   Missing 
─────┼─────────────────────────
   11        9  missing 
   22  missing  missing 
   33        7  missing 
   44        6  missing 

julia> dropmissing(dg) # missingが入ったらデータを全部排除する
0×3 DataFrame

julia> dropmissing(dg, :y) #y列に missingがあったら排除する
3×3 DataFrame
 Row │ x      y      z       
     │ Int64  Int64  Missing 
─────┼───────────────────────
   11      9  missing 
   23      7  missing 
   34      6  missing 


7. 実践:全世界のコロナの感染データ (課題4:基礎)

全世界のコロナの感染データ

小規模な big data として、「学術に使って良い」Covid-19 の感染データを扱ってみます。

ホームページはこちら: https://ourworldindata.org/coronavirus-data

 • データファイル: owid-covid-data.csv

 • データが毎日更新される。

 • ファイルサイズ >40 MB (2022年1月16日の時点)

 • Afghanistan から Zimbabwe まで、毎日の感染データが収録される。

 • 「World」という「世界全体」のデータも入っている。

 • よく使う列の項目:

        ► location 場所「国または自治区」

        ► date 年月日

        ► total_cases 日総感染件数

        ► new_cases 日新感染件数

        ► total_deaths 日総死者件数

        ► new_deaths 日新死者件数

        ► new_tests 日新検査件数

*実習課題4:全世界のコロナの感染データを分析してみる

 • 2020年から2022年1月6日までのデータはこちら

        ► owid-covid-data_2022_01_16.csv (43.6 MB)

上記のファイル、またはホームページから最新のデータを作業フォルダーに保存する。

ファイルを読み込む:

生データ = CSV.read("owid-covid-data_2022_01_16.csv", DataFrame)
show(生データ)

「世界」のデータを読み込まない:

#location = World 「世界」という「全体の合計データ」も入っている。
#そのほか、国別ではないデータも排除する。
A = 生データ[ 生データ.location .!= "World" ,:] #「全世界」を排除する
A = A[A.location .!= "High income", :] #「高所得国」を排除する
A = A[A.location .!= "Upper middle income", :] #「中高収入」
A = A[A.location .!= "middle income", :] #「中所得国」
A = A[A.location .!= "Lower middle income", :] #「低中所得国」
A = A[A.location .!= "Lower income", :] #低所得国」
A = A[A.location .!= "Europe", :]
A = A[A.location .!= "North America", :]
A = A[A.location .!= "Asia", :]
A = A[A.location .!= "European Union", :]
A = A[A.location .!= "South America", :]
A = A[A.location .!= "Africa", :]

日本のデータを抽出する:

#日本のデータだけ抽出する
日本 = A[A.location .== "Japan", :]

#日本のデータをプロットする
plot(
    plot(日本.date, 日本.new_cases, 
        title = "new cases"),
    plot(日本.date, 日本.total_cases/10000, title = "total cases", ylabel = "x 10^4"),
    layout = (2,1), legend=false
)

アメリカ、マレシアのデータを抽出する:

US = A[A.location .== "United States", :]
MY = A[A.location .== "Malaysia", :]
plot(
    plot(日本.date, 日本.new_cases/1000, label = "JP"),
    plot(US.date, US.new_cases/1000, label = "US"),
    plot(MY.date, MY.new_cases/1000, label = "MY"),
    layout = (3,1), legend = :topleft,
    ylabel = "x 1000"
)

8. 実践:全世界のコロナの感染データ (課題5:日付けの範囲)

*実習課題5

日付けの関数 Date() を用いる実習:

ある日のデータだけ抽出する

現時点 = A[A.date .== Date(2022,1,6), :]

現時点の新規感染件数(多い国から)を表示する

#new_cases でソーティングを行う。逆順:多いから並ぶ
Top = sort(現時点, :new_cases, rev = true)

missing のデータを排除して、Top 15を抽出する

Top = dropmissing(Top, :new_cases)
Top = Top[1:15, :]
bar(Top.location, Top.new_cases/10000,
    legend = false,
    ylabel = "x 10^4",
    xrotation = 45,
    )

日付け範囲を絞って、日本のデータをもう一度プロットする:

日本 = A[A.location .== "Japan", :]
B = 日本[(日本.date .>= Date(2021,7,1)) .& (日本.date .<= Date(2022, 1, 15)), : ]
bar(B.date, B.new_cases, 
    legend = false, 
    title = "2021/7/1 ~ 2022/1/15 (Japan)")