scikit-learnでirisなどの付属データセットではなく、独自データやインターネット上の外部データを読み込む方法

　書籍やネット上のscikit-learn教材には、irisやcancer等の付属データセットを使った解説が多いです。もちろん手軽で 同じ結果が得られる安心感もある一方、予定調和的で 深い学びが得にくいと感じる方も多いのではないかと思います。
　この記事では、自作データやネット上にある外部データを読み込んで、scikit-learnで分析する方法をご紹介します。
（検証環境：Windows10, Anaconda3, Python3.7.6, Jupyter Notebook6.0.3）初稿公開2020/3/23

##　CSVファイルの準備
　この記事では、例として機械学習・データサイエンス コミュニティーである [Kaggle](https://www.kaggle.com/) が公開しているデータ　[World Happiness Report←リンク](https://www.kaggle.com/unsdsn/world-happiness)　を使います。機械学習に使いやすいデータセットが揃っているので、ユーザー登録が必要ですが Kaggleを選択しました。
　`Download (79 KB)` というボタンからダウンロードして下さい。zipファイルを解凍すると 5つのCSVファイルが見つかりますが、ここでは 2019.csv を使います。

#### 他のファイルを使う場合
- 2019.csv はPythonデータ分析ライブラリである **pandas**で読み込み易いような「一行目に特徴量の名前、二行目以降にデータ」という配置になっています。そうでないデータは、エクセルの行削除などで成型して下さい。

- エクセルファイル(.xls) など形式が違う場合は、エクセル等で読み込んだ後「ファイル－別名で保存」を行い、CSVファイル形式を選択します。区切り記号が選択可能な場合は　,(カンマ)にしておきます。

- 保存場所はPythonの実行ファイル（pyやipynbファイル）があるフォルダにしておくと楽です。

##　CSVファイルの読み込み
　ライブラリを使わずに 直接読み込む方法もありますが、以降の作業を楽にするため、この記事では pandasを使った方法を紹介します。
　（pandasがまだインストールされていない場合は、[この記事]
(https://www.sejuku.net/blog/75508) 等を参考に行って下さい。）

```
import pandas as pd
df = pd.read_csv('2019.csv')
```
　区切り記号がタブの場合は引数sep='\t'を、日本語が入っている場合は引数encoding='shift_jis'を加えます
`df = pd.read_csv('ファイル名.csv', sep='\t', encoding='shift_jis')`

　実行ファイルと別の場所にデータファイルを置く場合は `df=pd.read_csv('data/2019.csv')` と相対パスを加えるなどします。参考→[Python, pathlibで絶対パスと相対パスを相互変換・判定](https://note.nkmk.me/python-pathlib-absolute-relative/)

##　特徴量名とデータ数の確認

```
print("データセットのキー（特徴量名）の確認==>:\n", df.keys())
print('dataframeの行数・列数の確認==>\n', df.shape)
```

上記のコマンドを実行すると、

```
データセットのキー（特徴量名）の確認==>:
 Index(['Overall rank', 'Country or region', 'Score', 'GDP per capita',
       'Social support', 'Healthy life expectancy',
       'Freedom to make life choices', 'Generosity',
       'Perceptions of corruption'],
      dtype='object')
dataframeの行数・列数の確認==>
 (156, 9)
```
と9つの特徴量があるサンプル数156のデータが読み込めたことが確認できます。

##　欠損値等の処理をする（特徴量エンジニアリング）

　データ中に欠損値（Null）が無いか、またデータ型を確認し、整数値のみ（int）／小数を含む数値（float）／文字列または文字列と数値の混在（object）なのかを見ます。

```
# dataframe各列の欠損値でないデータ数、データ型を確認
df.info()
```

```
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 156 entries, 0 to 155
Data columns (total 9 columns):
 #   Column                        Non-Null Count  Dtype  
---  ------                        --------------  -----  
 0   Overall rank                  156 non-null    int64  
 1   Country or region             156 non-null    object 
 2   Score                         156 non-null    float64
 3   GDP per capita                156 non-null    float64
 4   Social support                156 non-null    float64
 5   Healthy life expectancy       156 non-null    float64
 6   Freedom to make life choices  156 non-null    float64
 7   Generosity                    156 non-null    float64
 8   Perceptions of corruption     156 non-null    float64
dtypes: float64(7), int64(1), object(1)
memory usage: 11.1+ KB
```

　Nullではないデータが156個⇒**欠損値なし**　と確認できます。
　Overall rankは整数、Country or regionは文字列、それ以外は小数を含む数値　と意図通りのデータ型になっています。
　数値が入っているはずの列が objectになってしまっている場合は、

```
# 数値ではない型の要素の抽出
objectlist = df[['特徴量名を入れる']][df['特徴量名を入れる'].apply(lambda s:pd.to_numeric(s, errors='coerce')).isnull()]
objectlist
```

↑ を実行すると、文字列扱いになっているデータが抽出できます。

　このデータに文字列と数値の混在や欠損値はありませんでしたが、他のデータには様々な理由で、「空欄」「ゼロを意味する"0"以外の文字・記号」「単位付きの数字」等 そのままでは分析に不適当な値が入っていることがよくあります。

[こちらの記事](https://newtechnologylifestyle.net/python_detanan/) 等を参考に、適切な処理（特徴量エンジニアリング）をして下さい。

##　Scikit-learn用のデータクラスを持つオブジェクト（空のデータセット）を作る

```
import sklearn
worldhappiness = sklearn.utils.Bunch()
```

`worldhappiness`の部分はデータセット名を表すよう、適宜変えて下さい。

##　データセットにデータを入れていく

```
# 'Score'(幸福スコア)を目的変数'target'とする
worldhappiness['target'] = df['Score']
```

```
# 説明変数を'data'に入れる
worldhappiness['data'] = df.loc[:, ['GDP per capita',
       'Social support', 'Healthy life expectancy',
       'Freedom to make life choices', 'Generosity',
       'Perceptions of corruption']]
```

↑ 最初の3列（目的変数および ID等の分析に使わない特徴量）以外の6列を指定します。「特徴量名の確認」で出力したデータをコピペすると楽です。

```
# 特徴量の名前も入れておくと、グラフの凡例等に使えます（無くても可）
worldhappiness['feature_names'] = ['GDP per capita',
       'Social support', 'Healthy life expectancy',
       'Freedom to make life choices', 'Generosity',
       'Perceptions of corruption']
```

##　訓練セットとテストセットに分割

```
# 訓練セットとテストセットに分割
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
    worldhappiness['data'], worldhappiness['target'], random_state=0)
print("X_train shape:", X_train.shape)
print("X_test shape:", X_test.shape)
```

```
X_train shape: (117, 6)
X_test shape: (39, 6)
```

訓練データ117個、テストデータ39個　に分割できました。（6は説明変数の項目数です）

##　結び
　これで機械学習に進めると思います。間違い指摘・質問等ございましたら、お気軽にコメント下さい。