地価公示データをGoogleColabで整形する

# やりたいこと
国土交通省が公開している[地価公示データ](https://nlftp.mlit.go.jp/ksj/old/datalist/old_KsjTmplt-L01.html)を機械学習の特徴量に使いたい。
市区町村コードごとに1983年〜2021年までの各年の公示地価（m^2の単価）の平均を出します。

SHIFT-JIS CSVの読み込みと、DataFrameの整形についてメモを兼ねて解説します。

# 環境
Google Colabo　-> 書いたコードは[こちら](https://colab.research.google.com/drive/15aCeDEjLW3gHnPkP37Mn6CEzrXRFYt4_?usp=sharing)

# 手順の目次
1. 最新（令和3年）の公示CSVをダウンロード。GoogleDriveにアップします。
1. DataFrameにCSVを読み込み
1. DataFrameを整形
1. DataFrameをCSVにGoogleDriveに出力（そのまま特徴量として学習データに取り込んでもよいです）

```python
from google.colab import drive
drive.mount('/content/drive')
```
GoogleDriveをマウント。
認証URLが出てくるのでGoogleアカウントを選択して、キーをColaboに入力。

```python
import numpy as np
import pandas as pd
from pandas import DataFrame, Series

# 公示地価格を取り込む（1983〜2021データ）
LP_PATH='~~~~~/LP/L01-2021P-2K.csv'
pl_df = pd.read_csv(LP_PATH,encoding="SHIFT_JIS")
```
NumPyとPandasを使うのでImportしておきます。
公示地価は2021年のCSVに1983年〜2021年までのデータが入っているので1つのCSVでOKです。
`LP_PATH`はご自身のCSVをおいたDriveパスに読み替えてください。

`pd.read_csv()`で読み込みます。
公示地価はShift-JISなので`encoding="SHIFT_JIS"'のパラメータを指定。


```python
pl_df.info(verbose=True,null_counts=True)
```
読み込んだDataFrameをinfo()で確認します。
列数が多いとカラム名やデータタイプ、欠損値の数が出てこないので、
`verbose=True`と`null_counts=True`のパラメータを指定します。
（列数が少ないと`.info()`だけで情報が出てくるようです）
下記のように表示されます。

```
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 25993 entries, 0 to 25992
Data columns (total 119 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   経度           25993 non-null  float64
 1   緯度           25993 non-null  float64
 2   所在地コード       25993 non-null  int64  
 3   用途           25993 non-null  int64  
 4   連番           25993 non-null  int64  
 5   年次           25993 non-null  int64  
 6   前年所在地コード     25993 non-null  int64  
 7   前年用途         25993 non-null  int64  
 8   前年連番         25993 non-null  int64  
 9   市区町村名        25993 non-null  object 
...
```

```py
colm = (["経度","緯度","用途", "連番","年次","前年所在地コード","前年用途",
         "前年連番","市区町村名","住居表示","行政","地積","利用の現況","利用状況表示",
         "建物構造","施設","形状区分","間口（比率）","奥行（比率）","階層（地上）","階層（地下）",
         "前面道路区分","前面道路の方位区分","前面道路の幅員","前面道路の駅前区分","前面道路の舗装状況","側道区分","側道方位区分",
         "交通施設との近接区分","周辺の土地の利用の現況","駅名","駅距離","用途区分","防火区分",
         "都市計画区分","森林区分","公園区分","建蔽率","容積率","共通地点区分","選定年次ビット",
         "属性移動Ｓ５９","属性移動Ｓ６０","属性移動Ｓ６１","属性移動Ｓ６２","属性移動Ｓ６３","属性移動Ｈ１","属性移動Ｈ２",
         "属性移動Ｈ３","属性移動Ｈ４","属性移動Ｈ５","属性移動Ｈ６","属性移動Ｈ７","属性移動Ｈ８","属性移動Ｈ９",
         "属性移動Ｈ１０","属性移動Ｈ１１","属性移動Ｈ１２","属性移動Ｈ１３","属性移動Ｈ１４","属性移動Ｈ１５",
         "属性移動Ｈ１６","属性移動Ｈ１７","属性移動Ｈ１８","属性移動Ｈ１９","属性移動Ｈ２０","属性移動Ｈ２１",
         "属性移動Ｈ２２","属性移動Ｈ２３","属性移動Ｈ２４","属性移動Ｈ２５","属性移動Ｈ２６","属性移動Ｈ２７",
         "属性移動Ｈ２８","属性移動Ｈ２９","属性移動Ｈ３０","属性移動Ｈ３１","属性移動Ｒ２","属性移動Ｒ３"])
pl_df = pl_df.drop(columns=colm)
pl_df.info() #列数が少なくなると.info()だけでOK
```
市区町村コードと各年の公示地価以外の列を削除する。

```py
# 0をNanに変換
def zero_to_nan(x):
  if x == 0:
    return np.nan
  else:
    return x

array = ['Ｓ５８価格','Ｓ５９価格','Ｓ６０価格','Ｓ６１価格','Ｓ６２価格','Ｓ６３価格','Ｈ１価格','Ｈ２価格',
         'Ｈ３価格','Ｈ４価格','Ｈ５価格','Ｈ６価格','Ｈ７価格','Ｈ８価格','Ｈ９価格','Ｈ１０価格',
         'Ｈ１１価格','Ｈ１２価格','Ｈ１３価格','Ｈ１４価格','Ｈ１５価格','Ｈ１６価格','Ｈ１７価格',
         'Ｈ１８価格','Ｈ１９価格','Ｈ２０価格','Ｈ２１価格','Ｈ２２価格','Ｈ２３価格','Ｈ２４価格',
         'Ｈ２５価格','Ｈ２６価格','Ｈ２７価格','Ｈ２８価格','Ｈ２９価格','Ｈ３０価格','Ｈ３１価格',
         'Ｒ２価格','Ｒ３価格']

for arr in array:
  pl_df.loc[:,arr] = pl_df.loc[:,arr].apply(zero_to_nan)
pl_df.head(2)
```
各年の公示価格のうち0となっている箇所をNaNにします。
（市町村ごとの各年の平均地価を出すときに含まれないようにするため）

```py
#所在地コードでGroupbyして平均値を出す（NaNは平均値に含まれない）
pl_df = pl_df.groupby('所在地コード').mean(numeric_only=True)
```
`pl_df.groupby('所在地コード')`で市区町村コード(=所在地コード)ごとにGroupByします。更に`.mean()`でGroupごとの平均値を出します。
mean()の`numeric_only=True`のパラメータで、数値のみを対象にします（NaNを無視する）

```py
# 価格をLogに変換
for arr in array:
  pl_df.loc[:,arr] = np.log(pl_df.loc[:,arr])
```
桁数が大きくなると特徴量として扱いにくい気がしたので、Log10をかけてます。
`np.log()`で変換。

```py
# 列名の和暦を西暦に変更
colm_names = []
for num in range(1983,2022):
  colm_names.append(num)

pl_df.columns = colm_names
```
和暦だと使いにくいので西暦に直してます。
Pythonの`for n in range(X,Y):`は`X ≦ n < Y`を満たすときという条件です。
下限は≦、上限は＜。

```py
pl_df.head(2)
```
ちゃんと市区町村コードをキーに各年ごとの地価平均がLOGで出てたらOKです。

```py
pl_df.to_csv('~~~/pl.csv')
```
`.to_csv(PATH)`でCSV出力します。PATHは保存先のCSV名を指定。

以上です。