ローデータから分析対象とする変数のみ抽出し(個人情報など、保持すべきでない変数を削除するなど)、情報を失わない範囲で分析するためのデータセットを作る。分析プロジェクトにおけるローデータと同じ量の情報を持つ、整形された(扱いやすい)データセットを作るのである。
この後のデータクレンジング以降で、データの加工方法を変更するなどで手戻りが発生することもある。その際ローデータの読み込みまで戻るのは大変なので、ローデータを同じ情報を持つ、整形された状態のデータを作っておくのが重要である。データクレンジングで手戻りが発生しても、ここで整形したデータセットまで戻ればいい。
カテゴリ変数の型となるfactor型の扱い
目次
変数の型
データの型確認
関数str()
を使う。これはデータフレーム、data.table同様に使える関数である。
データフレーム
str(customer.df)
data.table
str(customer.dt)
customer.dt %>% str
基本的なデータの型の種類
boolean
logical
: TRUE
or FALSE
、短縮してT
or F
としても可能
数値
- 整数は
integer
明示的にinteger
として扱うにはx <- 5L
のようにL
を付ける - 小数を含めると
numeric
- bigint相当は
library(bit64)
を使うとinteger64
として指定できる。fread()
で読み込んだdata.tableではデフォルトで整数型はinteger64
で扱われる(as.data.table()
で生成されたdata.tableでは元の形式がそのまま適用される)。
文字列の扱い
- 単純な文字列
character
- カテゴリカル変数として扱うには
factor
- 順序つきカテゴリカル変数として扱う場合
ordered
分析対象とする列の抽出、列名の変更
列の抽出、削除
データフレーム
指定した列を削除する
customer.df$firstname <- NULL
data.table
customer.dt %>%
dplyr::select(列名, ...) %>% ...
select()
関数名が他のパッケージと重複するので、必ずdplyr::select()
と指定するのがいい。
列名の変更
データフレーム
データフレームの列名変更はできない。
data.table
customer.dt %>%
rename(新列名 = 旧列名) %>% ...
列の型変換
データフレーム
customer.df$reg_store<- as.factor(customer.df$reg_store)
customer.df$older <- as.logical(customer.df$age>40)
data.table
customer.dt %>%
mutate(x = 変換処理の関数(x)) %>% ...
# customer.dt$x <- 変換処理の関数(customer.dt$x) と同じ
列の型変換の細かいTips
欠損値処理、「NULL」をNA
に変換
customer.df$reg_store[customer.df$reg_store=='NULL'] <- NA
factor型
自動で変換されるfactor型の扱い
read.table()
などでファイルを読み込む際、その列の全行の値が数字であれば数値型/整数型として扱われるが、一部文字列が入っているとfactor
型として読み込んでしまう。それを数値に戻す。そのままas.numeric()
すると水準(レベル)を数値にしてしまうため、一旦文字列にしてから数値にする。
customer.df$customer_grp <- as.numeric(as.character(customer.df$customer_grp))
複数のデータフレーム間でfactorの水準(レベル)を統一する
データフレームが変われば同じ意味(都道府県など)のfactor変数でも水準が変わるため、まったく別の変数扱いになってしまう。分析で使う際にはそれらを合わせておく必要がある。
データフレームdf1
の列prefecture
(factor型)の水準をdf2
の列prefecture
の水準に合わせる。
df1$prefecture <- factor(df1$prefecture, levels=levels(df2$prefecture))
日付、日時
日付はDate
型。as.Date()
関数を使う。日時はPOSIXct
がスカラなので分かりやすい(エポック秒のスカラ)。POSIXlt
はリストで要素が複数あるのでややこしい。
customer.df$reg_date <- as.POSIXct(customer.df$reg_date, format = '%Y/%m/%d')
customer.df$latest_datetime <- as.POSIXct(customer.df$latest_datetime, format='%Y/%m/%d %H:%M:%S')
※ただし遅いので速さを求めるならライブラリ{lubridate}を使う手もある。
http://qiita.com/hoxo_m/items/6f18b163946f6f41deca
ライブラリ{data.table}のIDate(日付)やITime(時刻)形式も高速。この形式はdata.tableの中でない普通のベクトルやデータフレームの中でも使える。
日付
as.IDate('2020-01-01') # ハイフン区切りならそのまま
as.IDate('20200101', format="%Y%m%d") # フォーマットも指定できる
customer.df$reg_date <- as.IDate(customer.df$reg_date, format = '%Y/%m/%d') # データフレームで扱う場合
customer.dt[,reg_date:=as.IDate(reg_date, format = '%Y/%m/%d')] # data.tableの中で扱う場合
時刻
as.ITime('09:23:15') # コロン区切りならそのまま
as.ITime('09:23') # 時分のみでもOK
as.ITime('092315', format="%H%M%S") # フォーマットも指定できる
customer.df$reg_time <- as.ITime(customer.df$reg_time, format = '%H%M%S') # データフレームで扱う場合
customer.dt[,reg_time:=as.ITime(reg_time, format = '%H%M%S')] # data.tableの中で扱う場合
日付と時刻を合わせた日時形式は存在しない。その場合はPOSIXct形式を使う。なおPOSIXctは以下のようにして生成できる。
as.POSIXct('2020-01-01') + as.ITime('09:23')
Rのdata.table形式で日時データを扱う際はPOSIXltを使わない。
データフレームで数字列を日時に変換する。
> head(x.df)
date
1 20151122
2 20151118
3 20151123
4 20150330
5 20151106
6 20150801
このようなデータに対して、以下の3通りの方法で日時データに変換する。
strptime()
のみ実行strptime()
してからas.POSIXlt()
strptime()
してからas.POSIXct()
> x.df$date2 <- strptime(as.character(x.df$date), format="%Y%m%d")
> x.df$date3 <- as.POSIXlt(strptime(as.character(x.df$date), format="%Y%m%d"))
> x.df$date4 <- as.POSIXct(strptime(as.character(x.df$date), format="%Y%m%d"))
>
> head(x.df)
date date2 date3 date4
1 20151122 2015-11-22 2015-11-22 2015-11-22
2 20151118 2015-11-18 2015-11-18 2015-11-18
3 20151123 2015-11-23 2015-11-23 2015-11-23
4 20150330 2015-03-30 2015-03-30 2015-03-30
5 20151106 2015-11-06 2015-11-06 2015-11-06
6 20150801 2015-08-01 2015-08-01 2015-08-01
strptime()
はPOSIXltを返すのでdate2とdate3は同じだが比較のため。
POSIXltもPOSIXctも日時データだが、POSIXltでは内部で日時をリスト型変数として、POSIXctは数値型変数として格納している。
これに対してdata.tableでは
> head(x.dt)
date
1: 20151122
2: 20151118
3: 20151123
4: 20150330
5: 20151106
6: 20150801
> x.dt %>% mutate(
date2 = strptime(as.character(date), format="%Y%m%d"),
date3 = as.POSIXlt(strptime(as.character(date), format="%Y%m%d")),
date4 = as.POSIXct(strptime(as.character(date), format="%Y%m%d"))
) -> x.dt
警告メッセージ:
1: `[.data.table`(`_dt`, , `:=`(date2, strptime(as.character(date), で:
Supplied 11 items to be assigned to 344 items of column 'date2' (recycled leaving remainder of 3 items).
2: `[.data.table`(`_dt`, , `:=`(date3, as.POSIXlt(strptime(as.character(date), で:
Supplied 11 items to be assigned to 344 items of column 'date3' (recycled leaving remainder of 3 items).
>
> head(x.dt)
date date2 date3 date4
1: 20151122 0,0,0,0,0,0, 0,0,0,0,0,0, 2015-11-22
2: 20151118 0,0,0,0,0,0, 0,0,0,0,0,0, 2015-11-18
3: 20151123 0,0,0,0,0,0, 0,0,0,0,0,0, 2015-11-23
4: 20150330 22,18,23,30, 6, 1, 22,18,23,30, 6, 1, 2015-03-30
5: 20151106 10,10,10, 2,10, 7, 10,10,10, 2,10, 7, 2015-11-06
6: 20150801 115,115,115,115,115,115, 115,115,115,115,115,115, 2015-08-01
変な警告とともにPOSIXlt形式をそのままリストとして扱ってしまう。POSIXlt形式は内部ではリストなのだが、日付としてのラッパーが外れてしまうのである。
ということでdata.table内ではPOSIXltは扱えない。気を付けよう。
factor型に順序(Sでいうところのordered型にする)や基準となる水準を与える
factor型には順序を指定することができる。
また順序があってもなくても、回帰係数などの基準となる水準を指定することができる。
Rでは回帰分析の際、factor型の場合には自動でダミー変数を作って係数を推定するが、その係数は先頭の水準をベースとして、それに対する相対的な効果を表している(水準==aの効果をゼロとした場合のに対して、水準==bの効果がどの程度か)。特定の水準を基準として係数の大きさやp値を見たい場合には、先頭の水準を変更することによってそれが可能になる。
- 先頭の水準を指定する:
relevel(変更前のfactor型変数名, ref = '先頭の水準のラベル')
- 順序全体を指定する:
factor(変更前のfactor型変数名, levels = ラベルを順番に並べたベクトル)
データフレーム
# category == 'news'を基準にする
x.dt$category <- relevel(x.dt$category, ref = 'news')]
# 'small', 'medium', 'large'の順に並べる
x.dt$size <- factor(x.dt$size, levels = c('small', 'medium', 'large'))]
data.table
x.dt %>%
mutate(
# category == 'news'を基準にする
category = relevel(category, ref = 'news'),
# 'small', 'medium', 'large'の順に並べる
size = factor(size, levels = c('small', 'medium', 'large'))
) %>%
# (参考)添字を使う場合
x.dt[,category := relevel(category, ref = 'news')]
x.dt[,size := factor(size, levels = c('small', 'medium', 'large'))]
分析対象とする列の抽出、列名の変更、列の型変換をdata.tableでまとめて行う
処理が定型的なのでdplyrのパイプを使ってまとめて行うといい。
customer.dt %>%
# 列の抽出
dplyr::select(
`顧客ID`,
`メルマガ登録`,
`登録店舗`,
`登録日時`,
`性別`,
`生年月日`
) %>%
# 列名の変更
rename(
customer_id = `顧客ID`,
send_mail_magazine = `メルマガ登録`,
reg_store = `登録店舗`,
reg_datetime = `登録日時`,
sex = `性別`,
birthday = `生年月日`
) %>%
# 型変換
mutate_at(vars(customer_id), funs(as.integer64)) %>% # integer64型に変換
mutate_at(vars(send_mail_magazine), funs(.==1)) %>% # 0/1の2値変数をlogical型に変換
mutate_at(vars(reg_store, sex), funs(as.factor)) %>% # factor型に変換
mutate_at(vars(reg_datetime), funs(as.POSIXct(., format='%Y/%m/%d %H:%M:%S'))) %>% # 日時データをPOSIXct型に変換
mutate_at(vars(birthday), funs(as.Date(., format = '%Y/%m/%d'))) %>% # 日付データをDate型に変換
as.data.table -> customer.dt # 途中でdata.table型でなくなる場合があるので最後に直す
select()
関数は他のパッケージと衝突することがあるので、dplyrのselect()
関数は常にパッケージ名を添えてdplyr::select()
とするのが安全である。列名を指定する際、スペースや日本語を含む列名はバッククォート「“`」で囲む。
日次データはPOSIXctを使う。POSIXltを使うとデータが壊れるので絶対に使わないこと。
型変換はmutate_at(vars(列名) ,funs(関数))
が便利。vars()
の指定方法は列名以外にも
- 前方一致:
vars(starts_with('date_'))
- 後方一致:
vars(ends_with('_id'))
- 部分一致:
vars(contains('_t_'))
- 正規表現一致:
vars(matches('^type[0-9]'))
などが使える。vars()
で指定する列の数が1個であればmutate()
関数でもいいのだが、
rename(
:
) %>%
mutate(
customer_id = as.integer64(customer_id),
send_mail_magazine = send_mail_magazine == 1,
reg_store = as.factor(reg_store),
reg_datetime = as.POSIXct(reg_datetime, format='%Y/%m/%d %H:%M:%S'),
sex = as.factor(sex),
birthday = as.Date(birthday, format = '%Y/%m/%d')
) %>%
as.data.table -> customer.dt
同様の処理をする列が複数になるとコピペの嵐になる(処理の内容を1箇所書き換えるときに列の数だけ書き換える必要が出てくる)ので、mutate_at()
を使うのが洗練されたやり方である。処理の内容によってはmutate_at()
とmutate()
を併用するのもいい。
マスタなどで全列factorに変換する場合、以下のようにすると実現できる。
x.dt %>%
mutate_all(funs(as.factor)) %>%
データの加工や分析で使うRの使い方 の記事一覧