久々に真面目に書きますよ…
前回はこの記事でちょっとだけ紹介したjantorパッケージですが、結構便利な関数が揃っていて実務でも使い始めているので、少しずつ紹介していこうと思います。
あうぇ…awesome1本で有名な前処理大全で知ったのですが、これはデータの前処理というよりはデータクレンジングに相当するのですね。
Twitter上での発言
すでに何度か呟いているのですが、これらも含めて少しずつやっていきましょうか。
spread、重複する行があると使えないが、janitor::get_dupes()によって検出できます。
— niszet* (@niszet0) 2018年4月12日
重複がない場合は空のtibbleが。便利です。
Enjoy!
janitor::clean_names() は日本語列名でも問題なく動くようですが、列名が日本語の場合、それらの文字を_で分けるようなので、ちょっと微妙…というか列名に日本語使うなって話かも。
— niszet* (@niszet0) 2018年4月12日
なお、indexとか全角でいれたら半角にしてくれるようですね。
Enjoy!
janitor::tabyl, 1列目を犠牲にするのでちょっと微妙かもしれない。
— niszet* (@niszet0) 2018年4月19日
が、アンケートの集計とかには使えそうなので
俺は使わないやつじゃん…
get_dupes()
get_dupes()
はデータフレームの重複のある行を見つけて返してくれます。返却されたときにはtibbleになってるけど…。
列名を指定しない場合、すべての列をみて、重複している行を返します。
みんな大好きirisデータ、さすがに全列で重複している行はないかなと思ってやってみると…
> janitor::get_dupes(iris) No variable names specified - using all columns. # A tibble: 2 x 6 Sepal.Length Sepal.Width Petal.Length Petal.Width Species dupe_count <dbl> <dbl> <dbl> <dbl> <fct> <int> 1 5.80 2.70 5.10 1.90 virginica 2 2 5.80 2.70 5.10 1.90 virginica 2
あるんだ…。重複がある場合、dupe_count列にその条件で重複した行数が入ります。この場合は重複した2行それぞれに2が入っていますね。
条件を指定する場合は、
> janitor::get_dupes(iris, Sepal.Length, Sepal.Width) # A tibble: 60 x 6 Sepal.Length Sepal.Width dupe_count Petal.Length Petal.Width Species <dbl> <dbl> <int> <dbl> <dbl> <fct> 1 4.70 3.20 2 1.30 0.200 setosa 2 4.70 3.20 2 1.60 0.200 setosa 3 4.80 3.00 2 1.40 0.100 setosa 4 4.80 3.00 2 1.40 0.300 setosa 5 4.80 3.40 2 1.60 0.200 setosa 6 4.80 3.40 2 1.90 0.200 setosa 7 4.90 3.10 2 1.50 0.100 setosa 8 4.90 3.10 2 1.50 0.200 setosa 9 5.00 3.40 2 1.50 0.200 setosa 10 5.00 3.40 2 1.60 0.400 setosa # ... with 50 more rows
のようになります。選択した列が左側にその順に来て、そのあとにget_dupes列が来る仕様のようです。必要ならselectなどで適宜整形しましょう。
なお、列名は""で囲ってはダメで、
> janitor::get_dupes(iris, "Sepal.Length", "Sepal.Width") Error in check_vars_in_df(dat, df_name, var_names) : These variables do not match column names in iris: "Sepal.Length", "Sepal.Width"
と、エラーになってしまいます。
Twitterでも呟いた通り、行の重複があるとtidyr::spread()
が使えないので、この関数で前もって重複行がないか確認すると良いです。重複がない場合は空のtibbleが返ってきます。
clean_names()
列名をいい感じのsnake_caseにしてくれる関数で、
- ' と " を削除、
- %はpercent_に置き換え
#
はnumber_に置き換え- 文字列先頭にある、空白か句読点ではない記号、(@*[]など)は削除
などをしたうえで、大文字を小文字にして、最終的に.などは_に置き換えてくれます。こんな感じ。
> head(janitor::clean_names(iris)) sepal_length sepal_width petal_length petal_width species 1 5.1 3.5 1.4 0.2 setosa 2 4.9 3.0 1.4 0.2 setosa 3 4.7 3.2 1.3 0.2 setosa 4 4.6 3.1 1.5 0.2 setosa 5 5.0 3.6 1.4 0.2 setosa 6 5.4 3.9 1.7 0.4 setosa
ただ、この関数は日本語名のついた列については
janitor::clean_names(data.frame(ほげ=1,ふが=2))あ ほ_げ ふ_が 1 1 2
のような挙動となってしまうのでイマイチ…。内部的にはsnakecase::to_any_case
を呼んでいるので、ここの挙動を理解できれば[^1]…。
なお、全角2文字で英数字を入れていた場合には半角にしてくれます。
janitor::clean_names(data.frame(index=1,123=2)) index 123 1 1 2
これは何気に便利ではないかな。なお、caseの引数を変えれば蛇さん以外にもできますので、詳しくはマニュアルなどを参照してください。
remove_empty()
空行、あるいは空列を削除できます。ここで空行あるいは空列は全てNA
であるような行、列を指します。
実際にやってみると、
# あまりよろしくはないが…空列を追加 iris$hoge <- NA # 確認 > head(iris) Sepal.Length Sepal.Width Petal.Length Petal.Width Species hoge 1 5.1 3.5 1.4 0.2 setosa NA 2 4.9 3.0 1.4 0.2 setosa NA 3 4.7 3.2 1.3 0.2 setosa NA 4 4.6 3.1 1.5 0.2 setosa NA 5 5.0 3.6 1.4 0.2 setosa NA 6 5.4 3.9 1.7 0.4 setosa NA
で、出来たdata.frameに対して、空列を削除してみます。
> head(janitor::remove_empty(iris, "cols")) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 1 5.1 3.5 1.4 0.2 setosa 2 4.9 3.0 1.4 0.2 setosa 3 4.7 3.2 1.3 0.2 setosa 4 4.6 3.1 1.5 0.2 setosa 5 5.0 3.6 1.4 0.2 setosa 6 5.4 3.9 1.7 0.4 setosa
出来ました。行の場合は第二引数を"rows"としてあげてください。
なお、列と行それぞれに対応したremove_empty_cols()
やremove_empty_rows()
もありますが、deprecatedだと警告が出ますので、使わないようにしましょう。
とりあえず1回目としてはこのくらいでいいかな…。
Enjoy!!