Numpyで平均差とジニ係数を求める
検索しても微妙なものしかなかったので自分用メモとして
定義
1次元データ $x_1, x_2, x_3, \cdots , x_n$の散らばりの尺度として、データの各対ごとの隔たり$|x_i - x_j|$の平均
$$\sum_{i}\sum_{j}|x_i - x_j| /n^2 \tag{1}$$
を考え、これを平均差という.また、平均差と平均値$\overline{x}\times2$の比を
$$\sum_{i}\sum_{j}|x_i - x_j| /2n^2\overline{x} \tag{2}$$
のように定義し、ジニ係数という
式展開
ここで$\sum_{j}|x_i - x_j|$について考えてみる
展開すると
$$
\sum_{j}|x_i - x_j|=|x_i -x_1| + |x_i -x_2| +|x_i -x_2| + \cdots |x_i -x_j|\tag{3}
$$
となる
次に$\sum_{i}\sum_{j}|x_i - x_j|$の各項目を並べてみる
\sum_{i}\sum_{j}|x_i - x_j| \\
= |x_1 -x_1| + |x_1 -x_2| +|x_1 -x_3| + \cdots + |x_1 -x_j| \\
+|x_2 -x_1| + |x_2 -x_2| +|x_2 -x_3| + \cdots + |x_2 -x_j| \\
+|x_3 -x_1| + |x_3 -x_2| +|x_3 -x_3| + \cdots + |x_3 -x_j| \\
\vdots\\
+|x_i -x_1| + |x_i -x_2| +|x_i -x_3| + \cdots + |x_i -x_j|\tag{4}\\
このことから次の行列の各要素を足したものを求めれば(4)式が求まる
\begin{pmatrix}
|x_1 -x_1| & |x_1 -x_2| &|x_1 -x_3| & \cdots &|x_1 -x_j| \\
|x_2 -x_1| & |x_2 -x_2| &|x_2 -x_3| & \cdots &|x_2 -x_j| \\
|x_3 -x_1| & |x_3 -x_2| &|x_3 -x_3| & \cdots &|x_3 -x_j| \\
&&\vdots\\
|x_i -x_1| & |x_i -x_2| &|x_i -x_3| & \cdots &|x_i -x_j|\tag{5}
\end{pmatrix}
ところで(5)式は絶対値を外せば
\begin{pmatrix}
x_1 -x_1 & x_1 -x_2 &x_1 -x_3 & \cdots &x_1 -x_j \\
x_2 -x_1 & x_2 -x_2 &x_2 -x_3 & \cdots &x_2 -x_j \\
x_3 -x_1 & x_3 -x_2 &x_3 -x_3 & \cdots &x_3 -x_j \\
&&\vdots\\
x_i -x_1 & x_i -x_2 &x_i -x_3 & \cdots &x_i -x_j
\end{pmatrix}
\\
=\begin{pmatrix}
x_1 & x_1 & x_1 & \cdots & x_1 \\
x_2 & x_2 & x_2 & \cdots & x_2 \\
x_3 & x_3 & x_3 & \cdots & x_3 \\
&&\vdots\\
x_i & x_i & x_i & \cdots & x_i
\end{pmatrix}
-
\begin{pmatrix}
x_1 & x_2 & x_3 & \cdots & x_j \\
x_1 & x_2 & x_3 & \cdots & x_j \\
x_1 & x_2 & x_3 & \cdots & x_j \\
& & \vdots \\
x_1 & x_2 &x_3 & \cdots & x_j
\end{pmatrix}\tag{6}
となる。ここで
$$
A =\begin{pmatrix} x_1 & x_2 & x_3 & \cdots & x_n \end{pmatrix}\
$$
とすれば(6)式は
$$
X =
\begin{pmatrix}
A, A, A, \cdots, A
\end{pmatrix} -
{}^t
\begin{pmatrix}
A, A, A, \cdots, A
\end{pmatrix}\tag{7}
$$
となるこれから、これらをnumpyを用いて求めると以下のようになる(コメントは無駄に多めになっています)
import numpy as np
# a = np.array([x1, x2, x3, x4, ..., xn])
# ここでは仮に(0,1,2,3,5,5,7,8,9,10)とする
# A を定義
A = np.array([0, 1, 2, 3, 5, 5, 7, 8, 9, 10])
def ave_diff_pre(a) -> int:
"""
平均差やジニ係数の分子部分の計算
:param a:配列
:return:
"""
n = len(a)
# ここでrepeatを使いn回増やし、reshapeでn×n行の行列に変形し、(7)の右辺の1項目を求める
x_1 = a.repeat(n).reshape(n, n)
# X_1の転置行列を求め、(7)のXを求める
x_2 = x_1.T
x = x_1 - x_2
# ユニバーサル関数を使用し、Xの各要素の絶対値を取った(5)式を出す
b = np.abs(x)
# 各要素の和(4)を求める
c = b.sum()
return c
def ave_diff(a) -> int:
"""
平均差を求める
:param a:平均差を求めたい配列
:return:平均差
"""
mol = ave_diff_pre(a)
# n^2で割る
n = len(a)
return mol / n ** 2
def gini(a) -> int:
"""
ジニ係数を求める
:param a:ジニ係数を求めたい配列
:return:ジニ係数
"""
mol = ave_diff_pre(a)
n = len(a)
return mol / (2 * n ** 2 * np.average(a))
print(f"平均差は{ave_diff(A)}です")
print(f"ジニ係数は{gini(A)}です")