macOS Sierra 10.12.6
ターミナル
Anaconda
Python 3.6.4
Anacondaをインストールすればデータサイエンスに必要なライブラリが使えるので、
ぜひインストールしましょう。
Anacondaのインストール手順についてはこちら
→MacにAnacondaをインストールする
国際連合のデータを参照します。Population by Age Groups - Both Sexes (XLSX, 10.31 MB)というところからダウンロードしました。
https://esa.un.org/unpd/wpp/Download/Standard/Population/
(2018年3月20日に利用)
当記事では、各国の2015年の人口データ(男女合わせた)を使います。
相関係数は-1から1の間となります。
-1だと完全に関係ない、1だと完全に関係あるということです。
たとえば2つのリストで考えてみます。
[1, 2, 3]と[1, 2, 3]という2つのリストの相関係数は1となります。
[1, 2, 3]と[1, 2, 4]では、0.9819805060619659という結果が出ました。
[1, 2, 3]と[1, 2, 4]はかなり似ている、正の相関関係があります。
Pythonで相関係数を求めることができます。
そのプログラムを下記にまとめました。
モジュール名はcorrelation.pyです。
from statistics import mean import math # xというリストの要素と、xリストの平均との差をリスト化 def de_mean(x): x_bar = mean(x) return [x_i - x_bar for x_i in x] # nの各要素の2乗を返す def sum_of_squares(n): return sum(i**2 for i in n) # 分散を求める def variance(x): n = len(x) deviations = de_mean(x) return sum_of_squares(deviations) / (n - 1) # v,wというリストの各要素の積の和 def dot(v, w): return sum(v_i * w_i for v_i, w_i in zip(v, w)) # 共分散を求める def covariance(x, y): n = len(x) return dot(de_mean(x), de_mean(y)) / (n - 1) # 標準偏差を求める def standard_deviation(x): return math.sqrt(variance(x)) # 相関係数を求める。結局我々が実行すればいい関数はこれだけ。 def correlation(x, y): stdev_x = standard_deviation(x) stdev_y = standard_deviation(y) if stdev_x > 0 and stdev_y > 0: return covariance(x, y) / stdev_x / stdev_y else: return 0
実行の仕方は簡単。比較したい2つのリストを引数に渡すだけ。
>>> import correlation >>> correlation.correlation([1, 2, 3], [4, 5, 6]) 1.0 >>> correlation.correlation([11, 2, 3], [4, 5, 6]) -0.8108848540793832
結論のコードから書きます。
上記で書いたcorrelation.pyをインポートして使っています。
モジュール名はcorjp.pyとしました。
日本の人口と相関関係の高い国から順番に表示し、相関係数もあらわします。
import correlation population_dict = { 'America': [19851, 20904, 20713, 21297, 22952, 22436, 21257, 20133, 20065, 20853, 22139, 21562, 18929, 15704, 11185, 8100, 5732, 3871, 1729, 456, 62], 'Canada': [1944, 1949, 1852, 2117, 2494, 2451, 2528, 2388, 2345, 2420, 2791, 2627, 2240, 1924, 1374, 989, 745, 493, 219, 53, 7], 'Australia': [1545, 1521, 1416, 1480, 1664, 1763, 1753, 1574, 1656, 1560, 1569, 1452, 1282, 1154, 844, 629, 467, 303, 135, 29, 4], 'Ecuador': [1610, 1568, 1507, 1499, 1442, 1356, 1220, 1097, 993, 875, 745, 630, 520, 363, 287, 200, 128, 69, 27, 7, 1], 'Colombia': [3738, 3905, 4070, 4070, 4198, 4094, 3933, 3553, 3154, 3196, 2807, 2285, 1831, 1315, 862, 574, 358, 188, 75, 18, 3], 'Brazil': [14875, 15132, 16355, 17405, 17211, 17490, 17682, 16069, 14875, 15132, 16355, 17405, 17211, 17490, 17682, 16069, 14174, 13168, 12040, 9936, 8029, 5973, 4172, 3047, 1800, 974, 343, 77, 10], 'Argentina': [3718, 3639, 3582, 3438, 3457, 3336, 3189, 3222, 2693, 2360, 2193, 2031, 1815, 1513, 1173, 874, 617, 368, 153, 40, 6], 'Mexico': [11533, 11399, 11653, 11762, 11269, 10552, 9770, 9403, 9000, 7009, 5709, 4768, 3903, 2720, 2097, 1433, 1001, 581, 251, 65, 11], 'Germany': [3518, 3508, 3693, 4102, 4571, 5213, 5058, 4782, 5191, 6805, 6921, 5998, 5092, 4217, 4226, 4194, 2464, 1460, 587, 92, 15], 'Belgium': [645, 653, 622, 631, 695, 716, 738, 741, 763, 799, 816, 758, 665, 598, 431, 396, 324, 200, 84, 13, 2], 'France': [3874, 3978, 3922, 3801, 3713, 3907, 4046, 3945, 4365, 4369, 4330, 4070, 3930, 3777, 2407, 2168, 1873, 1238, 632, 94, 20], 'Spain': [2169, 2457, 2290, 2096, 2239, 2475, 3071, 3895, 3976, 3723, 3538, 3126, 2584, 2356, 1986, 1612, 1462, 889, 364, 79, 10], 'Italy': [2554, 2810, 2804, 2788, 2909, 3053, 3345, 3947, 4663, 4843, 4691, 4083, 3708, 3643, 2931, 2758, 2035, 1266, 554, 101, 17], 'Greece': [504, 579, 549, 559, 566, 620, 785, 868, 869, 877, 793, 763, 647, 608, 463, 483, 388, 208, 71, 14, 2], 'Switzerland': [427, 405, 398, 435, 510, 565, 600, 558, 589, 677, 652, 548, 458, 445, 362, 273, 209, 136, 58, 12, 2], 'Austria': [407, 402, 416, 457, 552, 576, 594, 547, 603, 712, 702, 600, 475, 442, 433, 322, 215, 147, 65, 9, 1], 'NewZealand': [309, 316, 297, 319, 339, 316, 288, 274, 312, 313, 320, 287, 249, 227, 165, 118, 81, 56, 22, 5, 1], 'Ireland': [353, 356, 313, 270, 254, 295, 364, 383, 370, 310, 304, 260, 245, 214, 155, 115, 74, 40, 18, 4, 0], 'SaudiArabia': [2960, 2765, 2479, 2339, 2542, 2819, 3103, 3389, 2892, 2088, 1537, 990, 689, 381, 270, 166, 91, 41, 13, 2, 0], 'Jordan': [1202, 1102, 996, 922, 836, 763, 704, 602, 534, 437, 329, 226, 161, 128, 102, 66, 34, 12, 2, 0, 0], 'Iraq': [5603, 4867, 4215, 3804, 3299, 2877, 2482, 2170, 1823, 1463, 976, 725, 702, 403, 331, 212, 110, 41, 10, 2, 0], 'Turkey': [6740, 6619, 6665, 6670, 6315, 6312, 6303, 5937, 5375, 4701, 4115, 3536, 2877, 2145, 1627, 1185, 770, 299, 70, 9, 1], 'Armenia': [206, 199, 174, 182, 238, 272, 240, 194, 166, 168, 207, 209, 144, 97, 54, 89, 43, 26, 6, 1, 0], 'Singapore': [264, 281, 313, 353, 377, 356, 392, 429, 456, 444, 458, 424, 342, 257, 147, 114, 73, 37, 15, 4, 1], 'Philippines': [11434, 10889, 10459, 10208, 9610, 8315, 7329, 6666, 5906, 5323, 4498, 3675, 2755, 1943, 1235, 849, 435, 150, 32, 5, 0], 'Myanmar': [4553, 4858, 5197, 4845, 4501, 4216, 4067, 3859, 3543, 3142, 2672, 2291, 1870, 1152, 744, 484, 276, 105, 23, 3, 0], 'Indonesia': [24592, 23651, 23677, 22512, 21859, 21243, 21054, 19553, 18215, 16189, 13611, 11051, 7803, 5273, 3760, 2432, 1114, 466, 98, 11, 1], 'Pakistan': [24712, 22056, 19552, 19355, 18337, 16799, 13910, 11516, 9606, 8332, 7109, 5602, 4000, 3228, 2487, 1564, 817, 312, 75, 10, 1], 'India': [121415, 126977, 126752, 123333, 118180, 112809, 104208, 91299, 81036, 71138, 62323, 52822, 42980, 29093, 20166, 13256, 7129, 3001, 918, 194, 27], 'China': [85885, 82367, 78821, 80820, 101287, 129735, 102116, 96078, 118700, 124372, 102186, 79973, 79509, 52347, 34699, 24878, 14730, 6203, 1869, 401, 51] } # 日本と他国との相関係数を調べるため、日本は別枠でリスト化 Japan = [5396, 5560, 5670, 5980, 6139, 6756, 7609, 8481, 10046, 8722, 7988, 7661, 8674, 9627, 7704, 6255, 4876, 3073, 1328, 372, 58] cor_dict = {} for name, data in population_dict.items(): # 日本と他国との相関係数を、各国名をキーとした辞書要素に格納する cor = correlation.correlation(Japan, data) cor_dict[f'{name}'] = cor # 相関係数の大きい順にcor_dictをソートする。相関係数は小数点以下3桁にまとめる。 sorted_nations = sorted(cor_dict.items(), key=lambda x: x[1], reverse=True) for i, n in enumerate(sorted_nations): print(f'{i + 1}位は{sorted_nations[i][0]}で、相関係数は{sorted_nations[i][1]:.3f}')
$ python corjp.py などとして実行。
結果は、
統計を利用したいと考えた時に、一番に思いついたのが人口でした。1次情報にあたりたかったので、総務省統計局のサイトを観ていると国際連合が世界の人口の統計を出していました。
データには種類があり、今回は男女合わせた人口で5歳刻み(0-4歳,5-9歳など)の人口リストを使用しました。
30カ国は任意に選びました。
単位は千人です。
たとえば日本の人口で見てみると、
Japan = [5396, 5560, 5670, 5980, 6139, 6756, 7609, 8481, 10046, 8722,
7988, 7661, 8674, 9627, 7704, 6255, 4876, 3073, 1328, 372, 58]
これは0-4歳は5,396,000人、すなわち539万6000人いるということです。続きは順に5-9歳、10-14歳、...となります。もし年齢別のリストをつくるなら
age = ["0-4歳", "5-9歳", "10-14歳", "15-19歳", "20-24歳", "25-29歳", "30-34歳",
"35-39歳", "40-44歳", "45-49歳", "50-54歳", "55-59歳", "60-64歳",
"65-69歳", "70-74歳", "75-79歳", "80-84歳", "85-89歳", "90-94歳",
"95-99歳", "100歳以上"]
のようになるでしょう。
当記事で扱った相関係数は、この5歳刻みの数字をもとに比較し導いた結果です。
今回では0歳から100歳以上まですべての年齢層を対象に5歳刻みの数字で比較していますが、
アプローチの仕方は無数にあると言っても過言ではないでしょう。
最初つくっていたときは、各国の名称を変数に利用したリストにしていました。
しかし、国名を表示したいと思った時に(たとえば「1位はItalyで」の部分)変数名を表示するよりも、辞書で文字列のキーに国名を据えるほうが簡単でわかりやすいと思い書き直しました。
冒頭では相関係数を求めるcorrelation.pyをインポートしています。
キーが各国の名称で、値が人口のリストである辞書をpopulation_dictと定義しました。
この辞書に日本を加えてしまうと、日本と日本を比べることになり無意味なので、日本は別でJapanという変数名のリストにしました。
空の辞書cor_dictを作成します。for文で各国の名称と相関係数を格納するためです。
for文で回し終えると、キーが各国の名称で値が相関係数の辞書cor_dictが出来上がります。
しかしこのcor_dictはソートされておらず、それぞれの国がただ相関係数を持っているだけの状態です。
日本との相関関係を調べ、どの国が最も相関関係が高いのかなどの順位を出したいので、
相関係数を基準に降順(大きい順)でcor_dictをソートします。
ソートにはsorted()関数を使い、keyをlambdaに設定します。keyはソートするにあたって使うロジックですね。
こちらも参考にして下さい→ http://pycarnival.com/dict/
ソートした結果できたリストがsorted_nationsです。
このリストの内容を順番に表示させて1位2位などもあらわすため、インデックスを使用します。
インデックスを利用するということはEnumerate関数を使うということですね。
Enumerate関数についてはこちらも参考にして下さい→ http://pycarnival.com/enumerate/
この30カ国の中で、日本の5歳刻みの人口分布と最も相関関係があるのはイタリアでした。
イタリアの高齢化を調べてみると、このような記事が→ イタリアで昨年の出生数が過去最低に、高齢化も進む
意外だったのですが、イタリアの出生率はとても下がっていて問題となっているようです。
思考回路としては、
前提知識:日本は少子高齢化など人口問題を抱えている
相関係数を見れば:日本と似たような状況の国がわかるかも
結果:えっ、イタリアが一番近いの!?
2位はギリシャでした。これまた調べてみると、、、年金大変そう、、、などと事情がわかる。
Pythonでデータを活用して、いろんな物事の見方ができるのは素晴らしいですね!