相関係数というものを聞いたのでそれをまとめてみようかなと
(そして、相関係数を計算するクラスをSwift
で作ってしまおうとw
自分なりの解釈なので間違ってましたらご指摘いただけるとありがたいです。
相関係数とは
事柄Aと事柄Bの関係(相関)の強さを表した数値です
- A型の人は、几帳面が多い
- 商品Aを買った人は、商品Bも買う人が多い
- 英語のテストの点数が高い人は、国語のテストの点数も高い人が多い
などの関係を数値化したものです
相関係数の計算
いきなり求めるのは大変なので、相関係数の計算に必要なものから求めていきます
クラスを作っておきます
class CorrelationCoefficient {
}
例題
わかりやすくするため、ある学校のテスト(英語と国語)の点数から相関係数を求める。という問題をやっていきましょう。
以下の表がある学校の英語と国語のテストの点数を表しています。
英語 | 国語 | |
---|---|---|
Aくん | 40 | 38 |
Bさん | 50 | 65 |
Cさん | 44 | 40 |
Dくん | 74 | 87 |
Eさん | 92 | 90 |
英語も国語もやること(計算方法)は同じなので、英語の場合のみ求めていきます
Swift
計算しやすいように配列に入れておきます
let English: [Double] = [40, 50, 44, 74, 92]
let Japanese: [Double] = [38, 65, 40, 87, 90]
平均
まずはテストの平均を求めてみます
テストの点数の合計を人数で割れば良いですね
(40 + 50 + 44 + 74 + 92) ÷ 5 = 60
Swift
計算しやすいように配列にしておいたので、reduce
を使っていきましょう
func average(_ array:[Double]) -> Double {
return array.reduce(0, +) / Double(array.count)
}
偏差
偏差という言葉はあまり聞きなれないかとおもいます
平均から各値がどのくらい離れているかのことです
計算は簡単で、各値と平均の差を求めるだけです
40 - 60 = -20
50 - 60 = -10
44 - 60 = -16
74 - 60 = 14
92 - 60 = 32
Swift
今回も配列なのを利用し、map
メソッドで偏差の配列を返すようにします
func deviation(_ array:[Double]) -> [Double] {
let average = self.average(array)
return array.map({ (value) -> Double in
value - average
})
}
分散
分散はなんとなくわかるかと思いますが、データのばらつきを表します
先ほど求めた偏差の平均を取るのですが、平均は必ず0
になってしまいますw
そこで、偏差の2乗の平均を求めます(平均ではなく合計を個数 - 1
で割ることもあるそうです)
( (-20)^2 + (-10)^2 + (-16)^2 + 14^2 + 32^2 ) ÷ 5 = 395.2
Swift
先ほどの偏差の返り値が配列なのを利用し、reduce
で足していきます
func dispersion(_ array:[Double]) -> Double {
let deviations = deviation(array)
return deviations.reduce(0, { (result, value) -> Double in
result + (value * value)
}) / Double(deviations.count)
}
標準偏差
また聞きなれない言葉が出てきましたねw
分散は各値のばらつきを表していましたね。しかし、都合上各偏差を2乗していました。
そこで、元のデータを単位(次元)を合わせた方が感覚的にわかりやすくなるということで標準偏差というのが用いられます
計算は、分散の正の平方根を求めるだけです
√395.2 = 19.87
**[余談]**ちなみに、国語のテストの点数の標準偏差は22.17
なので、国語のテストの点数の方がばらつきがあると言えます
Swift
平方根は、sqrt()
というメソッドが用意されてるのでそれを使います
func standardDeviation(_ array:[Double]) -> Double {
return sqrt(dispersion(array))
}
一旦休憩
知らない言葉が出てきて疲れたかと思うので、一旦余談で休憩でもはさみましょうw
みなさんご存知、偏差値ですが、ここまで求めた値から出すことができます
頭の良さそうなEさんの英語のテストの偏差値を求めてみましょう
// ((Eさんの点数 - 平均) / 標準偏差) × 10 + 50
((92 - 60) / 19.87) × 10 + 50 = 66.10
偏差値はご存知の通り、真ん中が50なので頭が良いですね
一応、簡単に解説すると、
-
+ 50
-> 値の中心を50にします -
× 10
-> 幅を10までとります
幅を10にするというのは、偏差値40
で平均 - 標準偏差
、偏差値60
で平均 + 標準偏差
の点数になるように調整してます
Swift
偏差値を知りたい時用につくりました
func deviationValue(_ array:[Double],_ value:Double) -> Double {
return ((value - average(array)) / standardDeviation(array)) * 10 + 50
}
共分散
またしても聞きなれない言葉がw
各値の分布を数値化してくれてると考えて大丈夫かと思います....
各テストの偏差の積の平均で求められます(平均ではなく合計を個数 - 1
で割ることもあるそうです)
// (英語のテストの偏差) × (国語のテストの偏差)
(40 - 60) × (38 - 64) = 520
(50 - 60) × (65 - 64) = -10
(44 - 60) × (40 - 64) = 384
(74 - 60) × (87 - 64) = 322
(92 - 60) × (90 - 64) = 832
(520 + (-10) + 384 + 322 + 832) ÷ 5 = 409.6
Swift
2つのデータ配列を受け取れるように引数を2つとります
また、2つの配列の要素の個数が違う場合は、0
を返すようにしてあります
func covariance(_ array1:[Double],_ array2:[Double]) -> Double {
let deviation1 = deviation(array1)
let deviation2 = deviation(array2)
if deviation1.count != deviation2.count {
return 0
}
return deviation1.enumerated().reduce(0) { (result, value) -> Double in
result + value.element * deviation2[value.offset]
} / Double(deviation1.count)
}
相関係数
やっと相関係数を求めます
おまたせしました
共分散と各標準偏差を使用します
// 英語のテストの標準偏差:19.87
// 国語のテストの標準偏差:22.17
// 共分散:409.6
// 共分散 ÷ (英語のテストの標準偏差 × 国語のテストの標準偏差)
409.6 ÷ (19.87 × 22.17) = 0.92
相関関数は、-1以上1以下になります
Swift
今まで作ったメソッドを使えば簡単ですねw
func correlationCoefficient(_ array1:[Double],_ array2:[Double]) -> Double {
return covariance(array1, array2) / (standardDeviation(array1) * standardDeviation(array2))
}
相関係数の意味
相関係数を求めることまではできましたね
しかし、ただ相関係数が0.92だよと言われてもぽかんですよねw
そこで相関係数の持つ意味を解説していきたいと思います(簡単にですが)
相関係数をr
として、下の表に表します
相関係数の値 | 2つの事柄の関係 |
---|---|
r = 1 | 完全な正の関係がある |
0.7 <= r < 1 | 強い正の関係がある |
0.4 <= r < 0.7 | やや強い正の関係がある |
0.2 <= r < 0.4 | やや正の関係がある |
相関係数の値 | 2つの事柄の関係 |
---|---|
-0.2 < r < 0.2 | ほとんど関係がない |
r = 0 | 完全に関係ない |
相関係数の値 | 2つの事柄の関係 |
---|---|
-0.4 < r <= -0.2 | やや負の関係がある |
-0.7 < r <= 0.4 | やや強い負の関係がある |
-1 < r <= 0.7 | 強い負の関係がある |
r = -1 | 完全な負の関係がある |
今回の例題でいうと、
- 正の関係というのは、英語の点数が高い人は国語の点数も高い人が多い
- 負の関係というのは、英語の点数が高い人は国語の点数は低い人が多い
という関係になります。
r=1
で完全な正の関係があるという場合は、英語の点数が高い人は確実に国語の点数も高いとなります
今回は、正の関係になるように例題を作ったのですが、0.92
と予想以上に相関係数が高くなってしまいましたねw
Swift
最終的な相関係数求めるクラス
import Foundation
let English: [Double] = [40, 50, 44, 74, 92]
let Japanese: [Double] = [38, 65, 40, 87, 90]
class CorrelationCoefficient {
func average(_ array:[Double]) -> Double {
return array.reduce(0, +) / Double(array.count)
}
func deviation(_ array:[Double]) -> [Double] {
let average = self.average(array)
return array.map({ (value) -> Double in
value - average
})
}
func dispersion(_ array:[Double]) -> Double {
let deviations = deviation(array)
return deviations.reduce(0, { (result, value) -> Double in
result + (value * value)
}) / Double(deviations.count)
}
func standardDeviation(_ array:[Double]) -> Double {
return sqrt(dispersion(array))
}
func deviationValue(_ array:[Double], value:Double) -> Double {
return ((value - average(array)) / standardDeviation(array)) * 10 + 50
}
func deviationValue(_ array:[Double],_ value:Double) -> Double {
return ((value - average(array)) / standardDeviation(array)) * 10 + 50
}
func covariance(_ array1:[Double],_ array2:[Double]) -> Double {
let deviation1 = deviation(array1)
let deviation2 = deviation(array2)
return deviation1.enumerated().reduce(0) { (result, value) -> Double in
result + value.element * deviation2[value.offset]
} / Double(deviation1.count)
}
func correlationCoefficient(_ array1:[Double],_ array2:[Double]) -> Double {
return covariance(array1, array2) / (standardDeviation(array1) * standardDeviation(array2))
}
}
// Usage
let correlationCoefficient = CorrelationCoefficient()
correlationCoefficient.correlationCoefficient(English, Japanese) // 0.92