ExcelファイルをPythonでデータ分析する (4.ランキングチャート)

**ExcelファイルをPythonでデータ分析する**
[1.Excelファイルの読み込み](https://qiita.com/toyohisa/items/d8d7c8179adb708476d6) - [2.グラフ](https://qiita.com/toyohisa/items/74e2893da8a88ee47743) - [3.度数分布](https://qiita.com/toyohisa/items/a2e93c01436390675a0b) - 4.ランキングチャート - [5.相関](https://qiita.com/toyohisa/items/f3a1016111ef430484b6) - [6.ディシジョンツリー](https://qiita.com/toyohisa/items/51382f24c04bfcd31654)

「ExcelファイルをPythonでデータ分析する」は上のような一連の記事になっており、2～6までは事前に1.Excelファイルの読み込みと事前処理が行われていることを前提としています。

# 都道府県の人口ランキングチャート

ランキングチャートとは、1位、2位といった順位の変動を示すものです。ここでは人口の多さをランキングとして表し、1920年から2020年までのその順位変動をグラフ化してみたいと思います。

### ランキングの列を新たにDaraFrameに追加する

全データのdf0をそのまま使用しても良いのですが、何かあって元に戻す時、再度Excelファイルを読み込むのは面倒なので、df0は変更せずに新たにdf1を作成したいと思います。

以下のプログラムは、prefsで指定された県の、yearsで指定された年の人口のみをdf1として抽出するものです。

```python: 総数のみを抜き出す
prefs = ["新潟県","宮城県","長野県"]
years = ['1920年_総数', '1925年_総数', '1930年_総数', '1935年_総数', '1940年_総数', '1945年_総数', '1950年_総数',
         '1955年_総数', '1960年_総数', '1965年_総数', '1970年_総数', '1975年_総数', '1980年_総数', '1985年_総数',
         '1990年_総数', '1995年_総数', '2000年_総数', '2005年_総数', '2010年_総数', '2015年_総数', '2020年_総数']

# 総数だけを抜き出した data0 を作成する。
df1 = df0.loc[prefs,years]
print(df1)
```

実行すると以下のように表示されます。

```console
     1920年_総数  1925年_総数  1930年_総数  1935年_総数  1940年_総数   1945年_総数  1950年_総数  \
新潟県   1776474   1849807   1933326   1995777   2064402  2389653.0   2460997   
宮城県    961768   1044036   1142784   1234801   1271238  1462254.0   1663442   
長野県   1562722   1629217   1717118   1714000   1710729  2121050.0   2060831   

     1955年_総数  1960年_総数  1965年_総数  ...  1975年_総数  1980年_総数  1985年_総数  \
新潟県   2473492   2442037   2398931  ...   2391938   2451357   2478470   
宮城県   1727065   1743195   1753126  ...   1955267   2082320   2176295   
長野県   2021292   1981433   1958007  ...   2017564   2083934   2136927   

     1990年_総数  1995年_総数  2000年_総数  2005年_総数  2010年_総数  2015年_総数  2020年_総数  
新潟県   2474583   2488364   2475733   2431459   2374450   2304264   2201272  
宮城県   2248558   2328739   2365320   2360218   2348165   2333899   2301996  
長野県   2156627   2193984   2215168   2196114   2152449   2098804   2048011  

[3 rows x 21 columns]
```

次に、ランキングを計算します。計算した結果は、df1の新しい列として保存します。

```python:ランキングの列を新たに追加する
for year in years:
  for i,row in enumerate(df1.sort_values(by=year,ascending=False).iterrows()):
    df1.loc[row[0],f"{year}_ranking"] = i+1
print(df1)
```

ランキングは各年で計算されるため、まずyearsでループします。2つ目のfor文のdf1.sort_valuesが人口でソートする処理です。by=yearによってソート対象の年を指定し、ascending=Falseで降順（大きい順）にします。iterrowsはその順番でソートされたデータを順番に取り出すというものです。取り出された順位が i , 県の名前が rowに入っています。そしてdf1.locによって新しいデータを追加しています。

実行すると次のように表示されます。

```console
     1920年_総数  1925年_総数  1930年_総数  1935年_総数  1940年_総数   1945年_総数  1950年_総数  \
新潟県   1776474   1849807   1933326   1995777   2064402  2389653.0   2460997   
宮城県    961768   1044036   1142784   1234801   1271238  1462254.0   1663442   
長野県   1562722   1629217   1717118   1714000   1710729  2121050.0   2060831   

     1955年_総数  1960年_総数  1965年_総数  ...  1975年_総数_ranking  1980年_総数_ranking  \
新潟県   2473492   2442037   2398931  ...               1.0               1.0   
宮城県   1727065   1743195   1753126  ...               3.0               3.0   
長野県   2021292   1981433   1958007  ...               2.0               2.0   

     1985年_総数_ranking  1990年_総数_ranking  1995年_総数_ranking  2000年_総数_ranking  \
新潟県               1.0               1.0               1.0               1.0   
宮城県               2.0               2.0               2.0               2.0   
長野県               3.0               3.0               3.0               3.0   

     2005年_総数_ranking  2010年_総数_ranking  2015年_総数_ranking  2020年_総数_ranking  
新潟県               1.0               1.0               2.0               2.0  
宮城県               2.0               2.0               1.0               1.0  
長野県               3.0               3.0               3.0               3.0  
```
df1に新しく列を追加したので、前からあった1920年_総数、などの列に加えて、xxxx年_総数_rankingという列が追加されています。1.0, 2.0, 3.0 のそれぞれの数値がランキングです。

最後にラインキングを描画します。
```python
import matplotlib.pyplot as plt
import japanize_matplotlib

plot_data = df1.loc[:,filter(lambda l:"ranking" in l,df1.columns)].transpose().sort_values(by="2020年_総数_ranking",axis="columns")
print(plot_data)

fig,ax = plt.subplots(figsize=(6,4))
ax.plot(plot_data)
ax.set_xticks(range(len(years)))
ax.set_xticklabels(years,rotation=90)
ax.invert_yaxis()
ax.legend(plot_data.columns,bbox_to_anchor=(1.1,0.97))
plt.show()
```

まずはプロット用データとしてplot_dataを作成しています。これは、df1からランキングの列だけを抽出し、かつ、転置(transpose)をしています。転置とは行列の行と列を入れ替える処理です。さらに最後の年である2020年_総数_rankingでソートしています。このソートをしている理由は、ランキングチャートを描画したとき、グラフの最も右側になる最新のランキングの順番で各都道府県が並んでいた方が見やすいからです。

実行するとまず、描画用データ(plot_data)が表示されます。

```console
                  宮城県  新潟県  長野県
1920年_総数_ranking  3.0  1.0  2.0
1925年_総数_ranking  3.0  1.0  2.0
1930年_総数_ranking  3.0  1.0  2.0
1935年_総数_ranking  3.0  1.0  2.0
1940年_総数_ranking  3.0  1.0  2.0
1945年_総数_ranking  3.0  1.0  2.0
1950年_総数_ranking  3.0  1.0  2.0
1955年_総数_ranking  3.0  1.0  2.0
1960年_総数_ranking  3.0  1.0  2.0
1965年_総数_ranking  3.0  1.0  2.0
1970年_総数_ranking  3.0  1.0  2.0
1975年_総数_ranking  3.0  1.0  2.0
1980年_総数_ranking  3.0  1.0  2.0
1985年_総数_ranking  2.0  1.0  3.0
1990年_総数_ranking  2.0  1.0  3.0
1995年_総数_ranking  2.0  1.0  3.0
2000年_総数_ranking  2.0  1.0  3.0
2005年_総数_ranking  2.0  1.0  3.0
2010年_総数_ranking  2.0  1.0  3.0
2015年_総数_ranking  1.0  2.0  3.0
2020年_総数_ranking  1.0  2.0  3.0
```

そしてそのあとにランキングチャートが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275020/cc2be7ab-a4c1-1c52-0c28-10aa7cba9099.png)



### 完成版のプログラム

以下のプログラムは、すべての都道府県、すべての年におけるランキングチャートを描画するものです。prefs、years変数をデータ(df0)から抽出しています。グラフを描画するときには、xxxx年_rankingという列だけを抽出し、横軸が年、縦軸が順位となるようにデータを転置（行と列を入れ替えること）します。そして凡例とグラフ上の線との対応付けが少しでも分かりやすくなるようにグラフの右端になる2020年のランキングでデータをソートし、その順序で列になっている都道府県をソートします。

```python:ランキングチャート
import matplotlib.pyplot as plt
import japanize_matplotlib
import re

# 全国を除外した都道府県名を作成する。
prefs = list(filter(lambda l:"全国" not in l,df0.index))
# 人口総数の取得年を作成する。
years = list(map(lambda l:re.findall(r"(.*)_.*",l)[0],
                 filter(lambda l:"総数" in l,df0.columns)))

# 都道府県ごとの人口総数のデータを抽出する。
data = df0.loc[prefs,filter(lambda l:"総数" in l,df0.columns)]

# 年ごとの人口ランキングを作成する。
for year in years:
  # DataFrame.sort_valuesによって指定された年(year)の総数でソートする。
  for i,row in enumerate(data.sort_values(by=f"{year}_総数",ascending=False).iterrows()):
    # DataFrameに例えば1920年の人口ランキングならば「1920年_ranking」という名前の列を作成し、順位をセットする。
    data.loc[row[0],f"{year}_ranking"] = i+1

# ここでDataFrameを確認すると、xxxx年_rankingという列が1920年から2020年までのが作成され、順位が数値として与えられている。
# print(data.head())
# print(data.loc[:,"2020年_ranking"].sort_values())

# 描画するためのデータは、rankingという名前の入った列を抽出してデータを転置する。
# 転置する前に列だったxxxx年_rankingは行になり、列は各都道府県となる。
# データは最後の年である2020年のランキングに従って列名（都道府県名）をソートする。これによりグラフ凡例との対応がしやすくなる。
plot_data = data.loc[:,filter(lambda l:"ranking" in l,data.columns)].transpose().sort_values(by="2020年_ranking",axis="columns")
# print(plot_data.head())

# ランキングチャートを描画する。
fig,ax = plt.subplots(figsize=(18,14))
ax.plot(plot_data)
# タイトルを設定する。
ax.set_title("人口の多さランキングチャート")
# x軸の軸メモリを設定する。
ax.set_xticks(range(len(years)))
ax.set_xticklabels(years,rotation=90)
# y軸ラベルは1と10の倍数とし、また反転してランキング上位が上になるようにする。
ax.set_yticks([1]+[10*(n+1) for n in range(int(len(prefs)/10))])
ax.invert_yaxis()
ax.set_ylabel("ランキング")
# 縦の補助線を入れる。
ax.grid(axis="x")
# 凡例を表示する。
ax.legend(plot_data.columns,bbox_to_anchor=(1.1,0.97))
plt.show()
```

実行すると次のようなグラフが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275020/00405468-d710-3b7b-450d-9d79f86215ab.png)

東京都は1945年に一度だけ2位になっていますがそれ以外は1位をキープしています。2020年の2位である神奈川県は、1965年ごろから順位が上がり2010年にそれまで2位をキープしていた大阪府を抜いていることが分かります。