前のページではデータフレーム、data.tableの列(変数)の処理について解説したが、今度は行の抽出、並べ替え、サンプリング、分割といった行の処理についてまとめる。
目次
行の削除(抽出)
データフレーム
adlog <- adlog[adlog$imp>1000 & adlog$click<10, , drop=F]
adlog <- with(adlog, adlog[imp>1000 & click<10, , drop=F])
上下は同じ。with()
関数はバッチの中でも使えるので便利。
データフレームの抽出・絞り込みでは第3添字にdrop=FALSE
を付けること!
行列の添え字にdrop=FALSE
を付けないと1行(列)のみマッチの場合にベクトルとして返す。そうなるとデータフレームを想定してその後の処理にrbind()
をしていたのができなくなるなど、行列処理に思わぬ不具合をきたすことになる。
drop=FALSE
を付けて1行n列の行列を返すように。
ただしtapply()
などで使う1列取得の際は付けてはならない。ベクトルとして処理する必要がある。
data.table
n_purchase < 10
の行を抽出
# dplyrのパイプを使う場合
x.dt %>%
filter(n_purchase < 10) -> x.dt
# 添字を使う場合
x.dt[n_purchase < 10,] -> x.dt
n_purchase < 10
の行を削除
# dplyrのパイプを使う場合
x.dt %>%
filter(!n_purchase < 10) -> x.dt
# 添字を使う場合
x.dt[!n_purchase < 10,] -> x.dt
複数条件(AND)
dplyrのパイプを使う場合
# dplyrのパイプを使う場合
x.dt %>%
filter(n_purchase < 10, interval_latest_purchase > 30) -> x.dt
# 添字を使う場合
x.dt[n_purchase < 10 & interval_latest_purchase > 30,] -> x.dt
filter()
を使う場合でも&
で条件を結合していい。
複数条件(OR)
dplyrのパイプを使う場合
# dplyrのパイプを使う場合
x.dt %>%
filter(n_purchase < 10 | interval_latest_purchase > 30) -> x.dt
# 添字を使う場合
x.dt[n_purchase < 10 | interval_latest_purchase > 30,] -> x.dt
いずれも|
で条件を結合する。
行の並べ替え(ソート)
データフレーム/行列
行列を第n列をキーに昇順に並び替え
x[order(x[,n]), ]
行列を第n列をキーに降順に並び替え
x[order(x[,n], decreasing=F),]
カラムimp
(最優先), click
(次に優先)をキーに昇順に並び替え
adlog <- adlog[order(adlog$imp, adlog$click),]
下記と同じ
adlog <- with(adlog, adlog[order(imp, click),])
adlog <- adlog[adlog$click,]
adlog <- adlog[adlog$imp,]
並べ替えの際は第3添字のdrop=F
は不要(そもそも複数行が前提)。
data.table
カラムn_purchase
(最優先), interval_latest_purchase
(次に優先)をキーに昇順に並び替え
# dplyrのパイプを使う場合
x.dt %>%
arrange(n_purchase, interval_latest_purchase) -> x.dt
# 添字を使う場合
x.dt[order(n_purchase, interval_latest_purchase)] -> x.dt
カラムn_purchase
をキーに降順(最優先)、interval_latest_purchase
をキーに昇順(次に優先)に並び替え
# dplyrのパイプを使う場合
x.dt %>%
arrange(-n_purchase, interval_latest_purchase) -> x.dt
# 添字を使う場合
x.dt[order(-n_purchase, interval_latest_purchase),] -> x.dt
characterに対してソートはできない。
arrange()
を使ってfactorに対して降べきの順を指定する場合にはマイナス符号を使えず、列名をdesc()
で囲んでarrange(desc(列名))
のようにする。
サンプリング
単純なサンプリング
それなりに大きいデータではサンプリングして分析することになる。
Rのbaseではsample()
関数、dplyrをインストールしている場合は便利なsample_n()
関数とsample_frac()
関数が使える。
(データフレーム、data.table共通)
使い方は
sample(母集団のサイズ, サンプルサイズ)
母集団のデータフレーム %>% sample_n(サンプルサイズ)
母集団のデータフレーム %>% sample_frac(サンプル率)
である。
サンプルの大きさ(行数)を指定する
データセットclicklog
から1000行を抽出する場合
sample()
関数では
# set.seed(1234)
row.sampled <- sample(nrow(clicklog), 1000)
clicklog.sampled <- clicklog[row.sampled, , drop=F]
sample_n()
関数を使うと
# set.seed(1234)
click_log %>% sample_n(10) -> click_log.sampled
となる。
サンプルの抽出率を指定する
データセットclicklog
から抽出率20%で無作為抽出する場合、
sample()
関数では
nr <- nrow(clicklog)
# set.seed(1234)
row.sampled <- sample(nr, floor(nr * 0.2))
clicklog.sampled <- clicklog[row.sampled, , drop=F]
sample_frac()
関数を使うと
# set.seed(1234)
click_log %>% sample_frac(0.2) -> click_log.sampled
確かにこちらのほうが簡単である。
IDでサンプリング
ユーザマスタ-/行動履歴などデータフレームが分かれている場合、行動履歴もユーザマスタのIDに基づいてサンプリングすることになる。
userId
を抽出率20%で無作為抽出し、そのuserId
に基づいてclick_log
を抽出する。
- マスタのオブジェクト:
user
- データのオブジェクト:
click_log
- 連携しているID(マスタのプライマリキー):
userId
という場合
nr <- nrow(user)
# set.seed(1234)
row.sampled <- sample(nr, floor(nr * 0.2))
user.sampled <- user[row.sampled,]
click_log.sampled <- clicklog[is.element(click_log$userId, userId.sampled), , drop=F]
userIdを列名にしている場合
nr <- nrow(user)
# set.seed(1234)
row.sampled <- sample(nr, floor(nr * 0.2))
user.sampled <- rownames(user)[row.sampled]
click_log.sampled <- clicklog[is.element(click_log$userId, userId.sampled), , drop=F]
clicklog
テーブルだけで抽出してしまう場合
# set.seed(1234)
userId.unique <- unique(click_log$userId)
userId.sampled <- sample(userId.unique, floor(length(userId.unique) * 0.2))
click_log.sampled <- clicklog[is.element(click_log$userId, userId.sampled), , drop=F]
分割
学習用と検証用とでデータセットを分割する
nr <- nrow(dat)
# set.seed(1234)
row.train <- sample(nr, floor(0.5 * nr))
dat.train <- dat[row.train,]
dat.test <- dat[-row.train,]
データの加工や分析で使うRの使い方 の記事一覧