2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Income Dataset】ロジスティック回帰を用いた二値分類

Last updated at Posted at 2023-02-19

目次

1. はじめに
2. 今回の目標
3. データセットと実行環境
4. 実行
  4-1. データの準備
  4-2. 分析の進め方を確認
  4-3. データの特徴を可視化
  4-4. データの整備
  4-5. データを用いた分析
  4-6. データの修正
  4-7. 最終的なコード
5. まとめ
6. 参考記事

1. はじめに

自己紹介

はじめまして!
私はとある製造系ベンチャーで、製造支援や受発注管理などを行っている、26歳の若手社員です。

普段の業務では大量のExcelデータを処理/分析し、工場の方々が少しでも安定的に生産できるように尽力しています。
例えばどんなことをしているかというと、、、

  • 見込み生産数の算出
    • 何でも受注してすぐに作れるわけではなく、事前に材料購入をしたり、生産計画を組む必要があります。
  • 原価計算
    • 製造にかかるコストを最適に算出できるよう、材料/設備/図面のデータを整えています。

機械学習のきっかけ

仕事上では、pivotやグラフを使って、実績推移と経験則で分析/予測をします。
ただ、あくまで人が(私が)予測をしている訳です。

そんな時にふと、機械学習を使えばより高精度な予測が出せるのでは、と思ったことがきっかけでした。
上手くいけば、私の分析業務自体もずいぶん楽になるような気がしました。

Aidemy(データ分析3か月コース)を受講

とはいえ、これまでまったくプログラミングに触れてこなかった私が、
独学で習得するのは不可能と考えました。

そこで、国から「第四次産業革命スキル習得講座」に認定されているAidemyを受講することにしました。
期間内に受講し終わると、受講料の約70%が還付されることが特徴です。

受講を通しての学び

受講前は、機械学習はかなり限定的な用途でしか使えないと思っていました。
(うまくいけば業務で使えるな…くらいの気持ちです)

しかし、データ分析をきっかけに自然言語処理、画像分析、深層学習などに触れる内に、未知のプロダクト開発や社会課題解決にも使える、と理解しました。

今では業務の傍ら、データ分析で教育系の社会課題を解こうと頭をひねっています。
近いうちにデータサイエンティストとして一歩を踏み出せたらと考えています。

2. 今回の目標

今回は学習の総復習をかねて、ロジスティック回帰を用いた二値分類の実行を行います。

私と同じく、まったく初めてデータ分析に触れる方が、この記事を読めば一通り実行までできることが今回の目標です。

3. データセットと実行環境

Kaggleのデータセットおよび環境を使用します。

URL : https://www.kaggle.com/datasets/mastmustu/income

ファイル名は「Income Dataset(年収データ)」です。
学歴/雇用形態/配偶者の有無など、給与が5万ドル以上かどうかを予測するためのデータセットです。

4. 実行

4-1. データの準備

データセットを読み込むためのコードを実行します。

コード

# 使用するライブラリをインポート
import numpy as np  # データ処理用ライブラリ
import pandas as pd # 数列計算用ライブラリ
from pandas import DataFrame # pandasが用意するデータ構造

# 訓練データの読み込み
train_df = pd.read_csv("/kaggle/input/income/train.csv")

# 訓練データの表示
train_df

出力結果

image.png
43,957人の調査データと、15列の年収に関連するデータがあることが確認できました。

欠損値やデータの型も確認します。

コード

# データ内容を確認
train_df.info()

出力結果

image.png
後述しますが、欠損値のあるカラムは今回使用しません。

※また、コンペのsubmitは行わないので、テストデータも使用しません。

4-2. 分析の進め方を確認

今回、学歴/配偶者の関係/所有資産の特徴から、給与が5万ドル以上かを予測するモデルを作成したいと思います。

訓練データの15列目「income_>50K」に1が立つ人の特徴を、1~14列の特定のカラム(列)を用いてモデル構築します。
使用するカラムは以下です。

カラム名 解説 データ型
age 年齢 int64
education 最終学歴 object
marital-status 婚姻状況 object
gender 性別 object
capital-gain 資本利益 int64
capital-loss 資本損益 int64
income_>50K 給与が$50K以上 int64

4-3. データの特徴を可視化

分析に入る前に、データを可視化し特徴を調べてみたいと思います。

コード

# 使用するライブラリをインポート
# どちらもデータを可視化するライブラリです
import matplotlib.pyplot as plt
import seaborn as sns 

まずは年齢と給与の関係性です。
30代から比率が増え、40~50代でもっとも上昇することが分かります。

コード

# Ageについて可視化
fig = sns.FacetGrid(train_df, col="income_>50K", hue="income_>50K", height=4)
fig.map(sns.histplot, "age", bins=30, kde=False)

出力結果

image.png

次に、最終学歴と給与の関係性です。
Doctorate(博士),Masters(修士),Prof-school(専門),bachelor(学士)の比率が高いです。
教育レベルと給与には相関性があると推測できます。

コード

# educationについて可視化。
plt.figure(figsize=(20,10))
sns.countplot(x="education", hue="income_>50K", data=train_df) 

出力結果

image.png

では、婚姻状況はどうでしょうか。
未婚者や離婚者よりも、婚姻関係にある人の方が給与が5万ドル以上の比率が高いです。

コード

# marital-statusについて可視化。
plt.figure(figsize=(20,10))
sns.countplot(x="marital-status", hue="income_>50K", data=train_df) 

出力結果

image.png

性別についても確認します。
男性の方が比率が高いようです。

コード

# genderについて可視化。
sns.countplot(x="gender", hue="income_>50K", data=train_df) 

出力結果

image.png

次はcapital-gain(資本利益)です。
一定数の人が、資本利益のみで5万ドル以上の収入があるようです。

コード

# capital-gainについて可視化。
fig = sns.FacetGrid(train_df, col="income_>50K", hue="income_>50K", height=4)
fig.map(sns.histplot, "capital-gain", bins=30, kde=False)

出力結果

image.png

最後に、capital-loss(資本損益)を確認します。
ほとんど人が0ですが、一定の人が2,000ドル周辺で損失を出しているようです。

コード

# capital-lossについて可視化。
fig = sns.FacetGrid(train_df, col="income_>50K", hue="income_>50K", height=4)
fig.map(sns.histplot, "capital-loss", bins=30, kde=False)

出力結果

image.png

4-4. データの整備

ここまでで各カラムの特徴と、給与との相関性を確認しました。
モデル構築にあたり、データの整備が必要です。

① 異常値の処理(ビン分割)

capital-gainとcapital-lossは、ほとんどの人が0のため、このまま分析に使用するとデータに悪影響します。
そこで、カテゴリーで分けることにします。

コード

# capital-gainは3つのカテゴリーにビン分割しラベリングします。
# capital-gainが、0:ない、less than 50K:5万ドル未満、over 50K:5万ドル以上
pd.cut(train_df['capital-gain'],[-1,0,50000,99999],
       labels = ['0','less than 50K', 'over 50K'])

# capital-gainをビン分割したカラムを追加します。
train_df['capital-gain_bins'] = pd.cut(train_df['capital-gain'],[-1,0,50000,99999],
                                      labels = ['0','less than 50K', 'over 50K'])

# capital-lossは2つのカテゴリーにビン分割しラベリングします。
# capital-lossが、not:ない、have:ある
pd.cut(train_df['capital-loss'], [-1,0,5000],
       labels = ['not','have'])

# capital-lossをビン分割したカラムを追加します。
train_df['capital-loss_bins'] = pd.cut(train_df['capital-loss'], [-1,0,5000],
                                      labels = ['not','have'])

# データを確認
train_df.head()

出力結果

image.png
右にカラムが追加されたことが確認できました。

② One-Hot Encoding

先ほど追加した2カラムと、使用予定のeducation,marital-status,genderはカテゴリカル変数です。
カテゴリカル変数に対しては、One-Hot Encodingを施して、モデルが扱えるよう変換します。

コード

# capital-gain_bins、capital-loss_binsをOne-Hot_Encodingで変換
train_df = pd.get_dummies(train_df, columns= ["capital-gain_bins",
                                              "capital-loss_bins",
                                             ])

# education,marital-status,genderをOne-Hot_Encodingで変換
train_df = pd.get_dummies(train_df, columns= ["education",
                                        "marital-status",
                                        "gender"
                                        ])
# データを確認
train_df.head()

出力結果

image.png
右にカラムが追加されたことが確認できました。

4-5. データを用いた分析

特徴量作成が完了したので、訓練データをさらに訓練データと検証データに分けます。
そして、実際にロジスティック回帰を行います。

コード

# 使用するライブラリをインポート
from sklearn.model_selection import train_test_split # 訓練データと検証データを作成

# 訓練データのincome_>50Kをtargetにする
target = train_df['income_>50K']

# 今回学習に用いないカラムを削除
drop_col = [
    'workclass',
    'fnlwgt',
    'educational-num',
    'occupation',
    'race',
    'relationship',
    'capital-gain',
    'capital-loss',
    'hours-per-week',
    'native-country',
    'income_>50K'
    ]

train = train_df.drop(drop_col, axis=1)

# 訓練用と検証用に分ける
X_train ,X_val ,y_train ,y_val = train_test_split(
    train, target, 
    test_size=0.2, shuffle=True, random_state=0
    )

# 使用するライブラリをインポート
# 予測モデルを構築。今回はロジスティック回帰を用います。
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

# モデルを定義し学習
model = LogisticRegression() 
model.fit(X_train, y_train)

# 訓練データに対しての予測を行い、正答率を算出
y_pred = model.predict(X_train)
print(accuracy_score(y_train, y_pred))

出力結果

image.png

4-6. データの修正

正答率は出せましたが、エラーが表記されました。
意味は「収束に失敗したため、反復回数を増やすかデータをスケーリングしてください」とのことです。

解決方法①
エラーの原因は、モデルが収束していないためでした。
そこで、反復回数(max_iter)を明示的に設定して、反復回数を増やします。

コード

# モデルを定義し学習。今回は反復回数を1000とする。
model = LogisticRegression(max_iter = 1000) 
model.fit(X_train, y_train)

# 訓練データに対しての予測を行い、正答率を算出
y_pred = model.predict(X_train)
print(accuracy_score(y_train, y_pred))

出力結果

image.png
警告が消えました。
max_iterの初期値は100ですが、今回は1,000にしました。

======
解決方法②
次に別のsolverを指定します。

コード

# モデルを定義し学習
model = LogisticRegression(solver='liblinear') 
model.fit(X_train, y_train)

# 訓練データに対しての予測を行い、正答率を算出
y_pred = model.predict(X_train)
print(accuracy_score(y_train, y_pred))

y_fix = model.predict(X_val)
print(accuracy_score(y_val, y_fix))

出力結果

image.png
警告が消えました。
solverの初期設定はlbfgsですが、今回はliblinearにしました。

なお、他にもnewton-cgやsagやsagaなどと色々あるようです。
※sagとsagaは試してみた結果、収束しませんでした。

4-7. 最終的なコード

すべてのコードをまとめたものはこちらです
# 使用するライブラリをインポート
import numpy as np  
import pandas as pd 
from pandas import DataFrame 
import matplotlib.pyplot as plt
import seaborn as sns 

# 訓練データの読み込み
train_df = pd.read_csv("/kaggle/input/income/train.csv")

# Ageについて可視化
fig = sns.FacetGrid(train_df, col="income_>50K", hue="income_>50K", height=4)
fig.map(sns.histplot, "age", bins=30, kde=False)

# educationについて可視化
plt.figure(figsize=(20,10))
sns.countplot(x="education", hue="income_>50K", data=train_df) 

# marital-statusについて可視化
plt.figure(figsize=(20,10))
sns.countplot(x="marital-status", hue="income_>50K", data=train_df) 

# genderについて可視化
sns.countplot(x="gender", hue="income_>50K", data=train_df) 

# capital-gainについて可視化
fig = sns.FacetGrid(train_df, col="income_>50K", hue="income_>50K", height=4)
fig.map(sns.histplot, "capital-gain", bins=30, kde=False)

# capital-lossについて可視化
fig = sns.FacetGrid(train_df, col="income_>50K", hue="income_>50K", height=4)
fig.map(sns.histplot, "capital-loss", bins=30, kde=False)

# capital-gainとcapital-lossをビン分割したカラムを追加
train_df['capital-gain_bins'] = pd.cut(train_df['capital-gain'],[-1,0,50000,99999],
                                      labels = ['0','less than 50K', 'over 50K'])

train_df['capital-loss_bins'] = pd.cut(train_df['capital-loss'], [-1,0,5000],
                                      labels = ['not','have'])

# カテゴリカル関数をOne-Hot_Encodingで変換
train_df = pd.get_dummies(train_df, columns= ["capital-gain_bins",
                                              "capital-loss_bins"
                                             ])

train_df = pd.get_dummies(train_df, columns= ["education",
                                              "marital-status",
                                              "gender"
                                             ])

# 使用するライブラリをインポート
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score

# 訓練データのincome_>50Kをtargetにする
target = train_df['income_>50K']

# 今回学習に用いないカラムを削除
drop_col = [
    'workclass',
    'fnlwgt',
    'educational-num',
    'occupation',
    'race',
    'relationship',
    'capital-gain',
    'capital-loss',
    'hours-per-week',
    'native-country',
    'income_>50K'
    ]

train = train_df.drop(drop_col, axis=1)

# 訓練用と検証用に分ける
X_train ,X_val ,y_train ,y_val = train_test_split(
    train, target, 
    test_size=0.2, shuffle=True, random_state=0
    )

# モデルを定義し学習
# 反復回数を増やしてエラーを回避します
model = LogisticRegression(max_iter = 1000) 
model.fit(X_train, y_train)

# 訓練データに対しての予測を行い、正答率を算出
y_pred = model.predict(X_train)
print(accuracy_score(y_train, y_pred))

5. まとめ

いかがでしたでしょうか?
基礎的な内容ですが、ロジスティック回帰で実行までできました。

ここまで自力で出来るようになったのもAidemyの教材のおかげです。

もしこの記事でデータ分析に興味を持っていただけたなら、
ぜひ受講をおすすめします!

6. 参考記事

▽同じデータセットを使用されている記事です▽

【文系出身初心者】年収について結婚・独身の関係性を予測してみた

▽Qiitaのアンカーリンクがうまく使えなかった時、参考にした記事です▽

Qiitaの記事でページ内リンクを使う

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?