はじめに
deepblueインターン生の中山です。
【列分割・NA操作・サンプリング】PythonとRのデータフレーム操作比較 vol.4の続きです。
今回は短い内容ですが、学習データとテストデータの分割について、tidyverse
を用いたRとPythonの比較をしたいと思います。
連載
- 下記5記事のまとめ:PythonのpandasとRのdplyrを用いたデータフレーム操作比較
- 【読み込み、要約統計量、行・列選択、代入】PythonとRのデータフレーム操作比較 vol.1
- 【列追加、重複削除、列名変更、結合、マージ、集約】PythonとRのデータフレーム操作比較 vol.2
- 【集計、ソート、縦持ち・横持ち変換】PythonとRのデータフレーム操作比較 vol.3
- 【列分割・NA操作・サンプリング】PythonとRのデータフレーム操作比較 vol.4
- 【train/test分割】PythonとRのデータフレーム操作比較 vol.5
使ったデータ
使ったデータは、irisデータです。
3クラスの分類を行いたかったので、irisにしました。
データ読み込み
Python
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df["Target"] = iris.target_names[iris.target]
R
library(tidyverse)
library(caret)
df <- iris %>%
rename(Target = Species)
データの分割
データの分割方法に関しては、いくつかありますが、ここでは以下の2つを用いて説明します。
Pythonはsklearn
のtrain_test_split
が有名で、Rはcaret
のcreateDataPartition
が有名です。
ここでは、学習データ数を全体の20とし、irisのSpeciesの比率が元データと同じになるように設定しております。
Python: train_test_species
train_test_species
では、train_size
を引数に取ることで、学習データ数を指定できます。また、train_size
は比率と数どちらにも対応しており、下記コードの0.2
の箇所に、数字を入れても同じような操作を実行できます。
また、train_size
をtest_size
と変更しても、テストデータに対して同じ操作を実行できます。
そして、stratify
(層別化の意味)にy
を入れることで、y
の比率を一定にできます。
X = df.drop("Target", axis=1)
y = df[["Target"]]
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size = 0.2, stratify = y)
# 下記でも実行可能
# X_train, X_test, y_train, y_test = train_test_split(X, y, train_size = 30, stratify = y)
R: createDataPartition
createDataPartition
では、p
を引数に取ることで、学習データの比率を指定できます。
また、list
はデフォルトではTRUE
となっているため、FALSE
に変更することで、train_id
をlist
ではなく、matrix
型として得ることができます。今回はmatrix
にしようと思うので、下記ではlist = F
としています。
そして、times
はtrain_id
を得る回数です。times = k
の時、train_id
はk
列のmatrix
として得ることができます。複数回のシミュレーションを実行したいときは便利です。
train_id <- df$Target %>%
createDataPartition(p = 0.2, list = F, times = 1)
X_train <- df[train_id, !(colnames(df) %in% "Target")]
X_test <- df[-train_id, !(colnames(df) %in% "Target")]
y_train <- df[train_id, "Target"]
y_test <- df[-train_id, "Target"]
PythonとRでの差異
- データを
X
とy
に分ける箇所が異なります。PythonではX
とy
に分けてから、抽出を実行します。一方で、Rではデータフレームをそのまま分割できます。 - 学習データ数を指定できるかが変わります。Pythonでは、比率に加えて、
int
型の値を入れることで学習データ数を指定できます。ただ、Rでは数字を入れることはできず、比率のみの設定となります。 - 繰り返しの回数が異なります。Pythonでは、毎回
train_test_split
を実行しますが、createDataPartition
であればtimes
に回数を指定する事で、データを得ることができます。
この2つの違いは小さなものなので、正直そこまで気にするほどではないと思います。
注意点
詳細は割愛しますが、Rのirisは、Speciesがfactor
型となっています。ゆえに、下記のように2つのSpeciesだけを取得して実行してもエラーが出てしまいます。
df <- iris %>%
rename(Target = Species) %>%
filter(Target == "setosa"|Target == "versicolor")
train_id <- df$Target %>%
createDataPartition(p = 0.2, list = F, times = 1)
X_train <- df[train_id, !(colnames(df) %in% "Target")]
X_test <- df[-train_id, !(colnames(df) %in% "Target")]
y_train <- df[train_id, "Target"]
y_test <- df[-train_id, "Target"]
# createDataPartition(., p = 0.2, list = FALSE, times = 1) で:
# Some classes have no records ( virginica ) and these will be ignored
このような時は、Targetの型をchr
型に変更すると回避できます。
具体的には、下記コードをtrain_id
の前に挿入します。
他にもいくつか回避法はありますが、ここでは一例だけ示しておきます。
df$Target <- as.character(df$Target)
結果の確認方法
Python: value_counts()
y
の中に含まれるクラスの数をカウントします。
value_counts()
でdataframe
の中を数えることができます。
print(y_train.value_counts(), "\n")
print(y_test.value_counts())
# Target
# virginica 10
# versicolor 10
# setosa 10
# dtype: int64
# Target
# virginica 40
# versicolor 40
# setosa 40
# dtype: int64
R: fct_count
y
の中に含まれるクラスの数をカウントします。
fct_count()
でカウントできます。fct
とありますが、factor
だけでなくcharacter
にも適用できます。他にもtable
を使うことで、数え上げることもできます。
fct_count(y_train)
fct_count(y_test)
# f n
# 1 setosa 10
# 2 versicolor 10
# 3 virginica 10
# A tibble: 3 x 2
# f n
# 1 setosa 40
# 2 versicolor 40
# 3 virginica 40