LoginSignup
10
16

More than 1 year has passed since last update.

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

Last updated at Posted at 2020-03-23

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

 CSVファイルの準備

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

他のファイルを使う場合

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

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

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

 CSVファイルの読み込み

 ライブラリを使わずに 直接読み込む方法もありますが、以降の作業を楽にするため、この記事では pandasを使った方法を紹介します。
 (pandasがまだインストールされていない場合は、この記事 等を参考に行って下さい。)

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で絶対パスと相対パスを相互変換・判定

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

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"以外の文字・記号」「単位付きの数字」等 そのままでは分析に不適当な値が入っていることがよくあります。

こちらの記事 等を参考に、適切な処理(特徴量エンジニアリング)をして下さい。

 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は説明変数の項目数です)

 結び

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

10
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
16