Nishikaコンペに参加してデータ分析した日記①

# はじめに
私はもともと理学療法士として働いていて現在はWebアプリ開発のITエンジニアをしています。

理学療法士の頃も病院のデータ集計や、治療データをまとめて学会で発表するのが好きでしたので、今回そういった興味でNishikaのコンペに参加してみたので、記念にデータ分析の流れについて記録しようと思います。

Webアプリ開発ではフロントエンドを主に担当しておりデータ分析に関しては完全に初心者ですが、蓄積された膨大な情報を使って新しいアイディアや解釈を得る方法について興味があります。

※本記事は主に日記ですがどこか間違っていたらすみません。  
※何も知らない私のような初心者でもデータ分析を体験できるという事が他の人の後押しになればと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/ac3738a1-a444-e206-aa4c-349dcadd4b64.png)


# Nishika登録からデータ分析の流れ
## 1. Nishikaに登録する
Nishika：https://competition.nishika.com/

## 2. トレーニングコンペに参加する
私は学習サイトやUdemuyの動画を参考に中古マンションの価格予測に参加しました。
Udemy動画：https://www.udemy.com/course/python-data
学習サイト：https://toukei-lab.com/achademy
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/f5b39e88-8c33-b0ce-8423-c91ee62f3aad.png)


## 3. CSVデータを取得する
参加したコンペページのデータタブでCSV形式の膨大なデータを取得します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/89400b4d-6966-d7f0-004d-961a8a57baa2.png)

## 4. Pythonの実行環境を用意する
私は以下の方法で行っています。

- [Google Colaboratory](https://colab.research.google.com/github/chainer/tutorials/blob/master/ja/02_Basics_of_Python.ipynb)  
Python JupyterLabがブラウザ上で実行できる。  早く簡単に始めたい場合はこちらがいいと思います。  
今回は分析対象データの容量が多くGoogle Driveを圧迫するため使用しない。

- デスクトップ版のアプリ
他の言語でもそうですが私はこの方法で環境を用意すると管理できず自分のPC環境が散らかってしまいます。  

- Docker
個人的にはDockerで用意するとコンテナごと破壊したり作り直したりできるため管理がし易いです。私は今回もDockerを使いました。
親切な方がたくさん記事を出してくれます。　　
[Google検索](https://www.google.com/search?q=jupyter+notebook+Doccker)

私が使ったDockerFileのPythonに関する設定
```dockerfile
FROM python:3.9.7-buster
# JupyterLab関連のパッケージ
RUN python3 -m pip install --upgrade pip \
&&  pip install --no-cache-dir \
    black \
    jupyterlab \
    jupyterlab_code_formatter \
    jupyterlab-git \
    lckr-jupyterlab-variableinspector \
    jupyterlab_widgets \
    ipywidgets \
    import-ipynb

# 基本パッケージ
RUN pip install --no-cache-dir \
    numpy \
    pandas \
    scipy \
    scikit-learn \
    pycaret \
    matplotlib \
    japanize_matplotlib \
    mlxtend \
    seaborn \
    plotly \
    requests \
    beautifulsoup4 \
    Pillow \
    opencv-python

# 追加パッケージ
RUN pip install --no-cache-dir \
    pydeps \
    graphviz \
    pandas_profiling \
    shap \
    umap \
    xgboost \
    lightgbm
```
親切な方が色々なライブラリを準備してくれていましたが、今回の分析で使用したのは下記になります。  
- pandas
- numpy
- matplotlib
- seaborn
- lightgbm

## 5. 分析する
### コンペの目的を思い出す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/d1f2b908-d257-2a86-5522-55b76a38eec2.png)
[[Training]中古マンション価格予測・評価方法]( https://competition.nishika.com/competitions/mansion_pra/summary#evaluation)
目的変数は中古マンションの取引価格について常用対数を取った数値です。 
コンペでは何かの情報からマンションの取引価格を予測しその精度を競うようです。
なぜ取引価格について10を底とした対数をとるのか謎は深まるばかりです。

### 分析のための材料を見る
Dockerコンテナを起動し、Jupyterを使用して取得したサンプルデータの中身を確認する。
Pythonライブラリ読み込み、サンプルデータ読み込み、結合、データフレーム化した後に…
```python
# 欠損データ数とデータタイプの表示
df.info()
```
```
<class 'pandas.core.frame.DataFrame'>
Int64Index: 637351 entries, 1060685 to 47003572
Data columns (total 27 columns):
 #   Column        Non-Null Count   Dtype  
---  ------        --------------   -----  
 0   種類            637351 non-null  object 
 1   地域            0 non-null       float64
 2   市区町村コード       637351 non-null  int64  
 3   都道府県名         637351 non-null  object 
 4   市区町村名         637351 non-null  object 
 5   地区名           637060 non-null  object 
 6   最寄駅：名称        634732 non-null  object 
 7   最寄駅：距離（分）     614306 non-null  object 
 8   間取り           615609 non-null  object 
 9   面積（㎡）         637351 non-null  object 
 10  土地の形状         0 non-null       float64
 11  間口            0 non-null       float64
 12  延床面積（㎡）       0 non-null       float64
 13  建築年           619117 non-null  object 
 14  建物の構造         623423 non-null  object 
 15  用途            591214 non-null  object 
 16  今後の利用目的       275091 non-null  object 
 17  前面道路：方位       0 non-null       float64
 18  前面道路：種類       0 non-null       float64
 19  前面道路：幅員（ｍ）    0 non-null       float64
 20  都市計画          618786 non-null  object 
 21  建ぺい率（％）       614848 non-null  float64
 22  容積率（％）        614848 non-null  float64
 23  取引時点          637351 non-null  object 
 24  改装            580431 non-null  object 
 25  取引の事情等        18275 non-null   object 
 26  取引価格（総額）_log  637351 non-null  float64
dtypes: float64(10), int64(1), object(16)
memory usage: 136.2+ MB
```
サンプルデータにはマンションについての各種情報と、予測目標である取引価格が入っているようです。 

### 何をしたらいいか整理する
目的と材料が分かってきましたが何をすれば予測ができるのか分かりません。  
Udemy動画や学習サイトではCRISP-DMというデータ分析プロセスが紹介されています。
[【5分で分かる】「CRISP-DM」の流れをデータサイエンティストが徹底解説！](https://toukei-lab.com/crisp-dm)
※この辺でこのサイトが気に入り学習プラン(980円/月)に登録しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/b02f0401-3ee3-f73d-c8c9-5afcbd9bd46b.png)
[Cross-industry standard process for data mining](https://en.wikipedia.org/wiki/Cross-industry_standard_process_for_data_mining)

1. Business Understanding：ビジネス理解
※コンペなので何かのビジネス課題の解決方法としてマンション価格予測が必要となった訳ではないです。
しかしデータ分析を本来の目的である事業での価値創出に結びつけるにはそもそものビジネス理解が必要だと思われます。


2. Data Understanding：データ理解
3. Data Preparation：前加工・前処理
4. Modeling：モデル構築
※今回勉強したのはPythonでデータ理解と前処理を繰り返し最後にモデル構築を行うというものです。

5. Evaluation：モデル評価
※Nishikaが提出された予測値を評価して投稿者に順位を付けてくれます。
コンペのページをよく見ると評価方法にMAEと記載されてます。
(MAE：Mean Absolute Error/平均絶対値誤差　真の値と予測値の差の絶対値の平均）
本来はモデル評価で答え合わせをするためのデータも必要なのではと感じました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/30215024-ab09-ad8b-eff9-c484de1575f3.png)

6. Deployment：ビジネスへの落とし込み
※本来の目的はデータを何かに生かす事なので一番大切な気がします。

### データ理解・前処理
前処理には以下の工程があるらしい
- 欠損値処理
- ダミー変数化
- 外れ値除去
- テーブルデータの結合
- 特徴量作成

今回はUdemyの動画の先生に言われるがままデータ項目の性質を考えた上で下記を行いました。
- 全てが欠損値であったり、データ種類が１つしかないカラムを削除した
- データの意味が重複しているカラムを削除した
→市町村名と市町村コードがあったので一方を削除
※多重共線性
重回帰分析という複数の説明変数から数値を予測する回帰という方法を利用する際、説明変数同士に相関が高い組み合わせが存在すると良くないらしい
- 和暦や最寄り駅までの時間など本来数値型のものを変換した
1.5h→90や、平成3年→1991など

### 統計量の作成やデータの視覚化
統計量を見るとそのデータの性質が見えてくるらしいですが私には分かりません。
Pandasで算出しました。

#### 統計量
mean: 算術平均
std: 標準偏差
min: 最小値
max: 最大値
Min-Max:四分位数

```python
df.describe()
```
```
       市区町村コード  最寄駅：距離（分） 面積（㎡）     建築年
count  637351.000000  614306.000000  637351.000000  619117.000000   
mean    18513.985300      11.731487      58.663570      25.959221   
std      9596.722442      12.197090      26.712019      11.431670   
min      1101.000000       0.000000      10.000000       1.000000   
25%     13106.000000       5.000000      45.000000      17.000000   
50%     14104.000000       8.000000      65.000000      25.000000   
75%     27114.000000      14.000000      75.000000      34.000000   
max     47213.000000     120.000000    2000.000000      75.000000   

       建ぺい率（％）  容積率（％）  取引時点   取引価格（総額）_log  
count  614848.000000  614848.000000  637351.000000  637351.000000  
mean       67.601944     301.601876    2013.633153       7.217424  
std        10.402295     148.105400       3.884546       0.353935  
min        30.000000      50.000000    2005.750000       2.653213  
25%        60.000000     200.000000    2010.500000       7.000000  
50%        60.000000     200.000000    2013.750000       7.255273  
75%        80.000000     400.000000    2016.990000       7.447158  
max        80.000000    1300.000000    2019.990000       9.934498  
```

#### ヒストグラム
データの分布をヒストグラムで視覚化すると、データの偏りやばらつきが見えるらしいです。
不思議な話ですが社会現象あるいは自然現象の中に現れるばらつきの多くは正規分布と呼ばれる釣鐘型の分布になるそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/f17b4356-16a1-e6ea-20f2-8aa49d00e522.png)
[正規分布の分かりやすいまとめ](https://ai-trend.jp/basic-study/normal-distribution/normal-distribution/)

普通に考えて駅近、広い、新しいは高額マンションの条件のように思えます。
この３つについて分布を確認しました。
```python
# matplotlibでヒストグラムを表示
fig, axes = plt.subplots(2, 2, figsize=(20, 10))
# binsで区画数を指定,set_xlimでｘ最大/最小値を設定
axes[0][0].hist(df["最寄駅：距離（分）"], bins=20)
axes[0][0].set_xlabel('最寄駅：距離（分）')

axes[0][1].hist(df["面積（㎡）"], bins=200)
axes[0][1].set_xlabel('面積（㎡）')
axes[0][1].set_xlim(0, 250)

axes[1][0].hist(df["建築年"], bins=20)
axes[1][0].set_xlabel('建築年')

axes[1][1].hist(df["取引価格（総額）_log"], bins=20)
axes[1][1].set_xlabel('取引価格（総額）_log')
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/f1a2d9ba-3dc6-cec9-79c9-93ec291e47b6.png)
最寄り駅については以外とほとんどの物件が徒歩10～15分圏内でした。
今さらですがこれは本当に全国のマンション情報でしょうか。私の実家はマンションではないですが駅から徒歩20分はあります。

```python
pd.set_option('display.max_rows', 40)
df["市区町村名"].value_counts()
```
マンションがある市区町村を物件数順に並べるとトップ5が全て東京のようです。
多分トップ5以下を含めても全体的に東京の環境に偏ったデータになってそうです。
```
大田区       12269
江東区       11591
世田谷区      10747
港区        10580
新宿区       10055
          ...  
田川郡糸田町        1
行橋市           1
大川市           1
粕屋郡宇美町        1
安芸郡坂町         1
Name: 市区町村名, Length: 618, dtype: int64
```

```python
fig, axes = plt.subplots(2, 1, figsize=(20, 10))
sns.countplot(x="取引年", data=df.sort_values("取引年"), ax=axes[0])
sns.countplot(x="取引時点", data=df, ax=axes[1])
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/42d913e0-d983-5c3b-063e-1a1f8498b34c.png)
この辺で取引時点というパラメータを取引年に変換しました。
2020年第一期→2020.25→2020のように文字型データから数値に変換して最後は年数の少数部分を丸めました。

#### 散布図
取引価格に対してそれぞれ最寄り駅距離、面積、築年数を指定して散布図を作成しました。
駅近、広い、新しいが取引価格と相関があるか気になります。
```python
fig, axes = plt.subplots(3, 1, figsize=(10, 15))
axes[0].scatter(df["最寄駅：距離（分）"], df["取引価格（総額）_log"], alpha=0.1)
axes[0].set_xlabel("最寄駅：距離（分）")
axes[0].set_ylabel("取引価格（総額）_log")

axes[1].scatter(df["面積（㎡）"], df["取引価格（総額）_log"], alpha=0.1)
axes[1].set_xlabel("面積（㎡）")

axes[2].scatter(df["建築年"], df["取引価格（総額）_log"], alpha=0.1)
axes[2].set_xlabel("建築年")
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/601137/04bf509b-8587-a4f3-f083-cdad7b53160a.png)
面積は正の相関がありそう
築年数は負の相関がありそう
最寄駅：距離（分）は負の相関がありそうな気がしますがよく分からないです

#### 相関係数
```python
df[["取引価格（総額）_log", "最寄駅：距離（分）","面積（㎡）","建築年"]].corr()
```
```
              取引価格（総額）_log  最寄駅：距離（分）     面積（㎡）       建築年
取引価格（総額）_log  1.000000  -0.215520  0.382755 -0.541508
最寄駅：距離（分）    -0.215520   1.000000  0.151880  0.118339
面積（㎡）            0.382755   0.151880  1.000000 -0.067965
建築年               -0.541508   0.118339 -0.067965  1.000000
```
取引価格に対して
- 建築年は弱いが負の相関がある
- 面積はもっと弱いが正の相関がある
- 最寄駅：距離（分）との相関はほとんどない

また
- 変数同士に強い相関関係は見られない

結局、取引価格に明らかに相関が高い変数はなかったと感じました。  
しかし勉強サイトの続きを見ると機械学習用のライブラリがこれらの情報から適格な予測をしている事が伺えます。
```
count    637351.000000
mean          7.217424
std           0.353935
min           2.653213
25%           7.000000
50%           7.255273
75%           7.447158
max           9.934498
Name: 取引価格（総額）_log, dtype: float64
```

実際投稿したデータのMAE評価結果が0.0783なので、 平均7.217424の取引価格_logにおいて正解データとの誤差平均が0.0783という事になりかなり正確に予測しているのではないかと思います(本当？)


## まとめ
Data Understanding：データ理解
Data Preparation：前加工・前処理
という工程でデータの構造を視覚化したり適切なデータ型に変換したりしました。  
私はUdemyの動画の先生のマネをしただけですが、データ分析ができる人はこの工程でデータ項目の不足を補ったり、目的変数に影響を与える要因を見抜いたりして、次のモデル構築に有利になるようにデータを加工していくのだと思います。


## 次回モデル作成
続きは加工したデータをもとに上記のマンションの取引価格を予測するためのモデルを作成する工程になります。
pythonの機械学習用ライブラリのLightGBMがデータをすごい勢いで分析してくれるのですが、何が行われているか私には分かりません。  
こうしてデータ分析の流れを体験しながら理論についても勉強を進めたいです。
[機械学習と統計学の違いについて](https://toukei-lab.com/machinelearning-statistics)