目次
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
✓ 出力結果
43,957人の調査データと、15列の年収に関連するデータがあることが確認できました。
欠損値やデータの型も確認します。
✓ コード
# データ内容を確認
train_df.info()
✓ 出力結果
※また、コンペの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)
✓ 出力結果
次に、最終学歴と給与の関係性です。
Doctorate(博士),Masters(修士),Prof-school(専門),bachelor(学士)の比率が高いです。
教育レベルと給与には相関性があると推測できます。
✓ コード
# educationについて可視化。
plt.figure(figsize=(20,10))
sns.countplot(x="education", hue="income_>50K", data=train_df)
✓ 出力結果
では、婚姻状況はどうでしょうか。
未婚者や離婚者よりも、婚姻関係にある人の方が給与が5万ドル以上の比率が高いです。
✓ コード
# 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(資本利益)です。
一定数の人が、資本利益のみで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)
✓ 出力結果
最後に、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)
✓ 出力結果
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()
✓ 出力結果
② 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()
✓ 出力結果
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))
✓ 出力結果
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))
✓ 出力結果
警告が消えました。
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))
✓ 出力結果
警告が消えました。
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のアンカーリンクがうまく使えなかった時、参考にした記事です▽