CSVファイルを読み込む際「nullが埋め込まれている」とエラーが出た時はUTF-16LEを疑う

Windowsのもと作られたCSVファイルを読み込む際、CP932を指定しようというのは定石だが、それでもうまくいかないことがある。

エラーメッセージを読むと「nullが埋め込まれている」とある。

意味がわからない。

「nullが埋め込まれている」だから大方「R embedded null」あたりでググればなんかヒントあるだろと思って検索すると以下のSOがトップで出てくる。

stackoverflow.com

 

解決策を見ると、こういうファイルは大抵Windowsで作られたUTF-16LEのファイルだからそれを試してみろとある。

実際に試してみるとうまくいった。

 

ちなみにreadrパッケージのread.csv()でlocale = locale(encoding = "UTF-16LE")と指定してもうまくいかない。

ここに対応するのはなかなか大問題らしく未対応のようである。

 

github.com

いまどきの固定長データはread_fwf()を用いて読み込む

こんな感じのデータがあったとする。

library(readr)
fwf_sample <- readr_example("fwf-sample.txt")
cat(read_lines(fwf_sample))
John Smith          WA        418-Y11-4111 Mary Hartford       CA        319-Z19-4341 Evan Nolan          IL        219-532-c301

いわゆる固定長データであり、バイト数を指定して読み込むことになる。 Rだともともとread.fwf()という関数が用意されている。 https://dichika.hateblo.jp/entry/20120406/1333683931

が、いちいちバイト数を指定するのは面倒である。とにかく楽をしたい。データの読み込みなんぞで力を使いたくない。 空白のカラムからよしなにバイト数を推定して読み込んで欲しい。 こういう時はreadrパッケージのread_fwf()を利用する。

# 空白のカラムからよしなにバイト数を指定してもらうパターン
read_fwf(fwf_sample, fwf_empty(fwf_sample, col_names = c("first", "last", "state", "ssn")))

もちろんバイト数を指定するパターンも利用できるし、色々な指定法がある。

# バイト数を指定するパターン
read_fwf(fwf_sample, fwf_widths(c(20, 10, 12), c("name", "state", "ssn")))
# 上記を各列名と紐づけて指定するパターン
read_fwf(fwf_sample, fwf_cols(name = 20, state = 10, ssn = 12))

# 開始位置と終了位置を指定するパターン
# この場合、nameの開始位置は1 終了位置は20、ssnの開始位置は30 終了位置は42
read_fwf(fwf_sample, fwf_positions(c(1, 30), c(20, 42), c("name", "ssn")))
# 上記を各列名と紐づけて指定するパターン
read_fwf(fwf_sample, fwf_cols(name = c(1, 20), ssn = c(30, 42)))

いかがでしたか?

数字をアルファベットに変換したい時はchartr()を使う

数字をアルファベットに変換したい、もしくはその逆でアルファベットを数字に変換したいというときがたまにあります。

例えば、11, 12, 13 をAA, AB, ACに変換したいという時です。

こういう時はRではchartr()を利用します。

chartr("123456789", "ABCDEFGHI", 11:13)
[1] "AA" "AB" "AC"

第一・第二引数にそれぞれ対応表を与えて、最後に変換したいベクトルを与えるだけです。

0も加えて以下のような指定が楽かも。

chartr(paste(collapse="", 0:9), paste(collapse="", letters[1:10]), 11:13)
[1] "bb" "bc" "bd"

(追記)

確かにこっちの方が楽。

chartr("0-9", "a-z", 11:13)
[1] "bb" "bc" "bd"

いかがでしたか?

折れ線グラフで各系列にラベルをつける際はgghighlightを用いるのが楽なんじゃなかろうか

こういうデータがあるとする。

library(dplyr)
library(ggplot2)
library(gghighlight)
ChickWeight_diet <- ChickWeight %>% group_by(Diet, Time) %>% summarise(weight = mean(weight))
> ChickWeight_diet
# A tibble: 48 x 3
# Groups:   Diet [?]
   Diet   Time weight
   <fct> <dbl>  <dbl>
 1 1         0   41.4
 2 1         2   47.2
 3 1         4   56.5
 4 1         6   66.8
 5 1         8   79.7
 6 1        10   93.1
 7 1        12  109. 
 8 1        14  123. 
 9 1        16  145. 
10 1        18  159. 
# … with 38 more rows

折れ線グラフで各系列にラベルをつけたい。 いろいろやり方はあるが、gghighlightパッケージを用いるのが一番楽な印象。 gghighlight()の条件設定で全て該当するような条件を設定するのがポイント。 なお、筆者の環境はMacなので、日本語が文字化けするためlabel_paramsでMacの日本語フォントを指定している。

ggplot(ChickWeight_diet, aes(Time, weight, color=Diet)) + 
  geom_line() +
  gghighlight(max(weight)>0, label_params = list(family = "HiraKakuPro-W3"))

f:id:dichika:20190216193509p:plain

追記(2019/2/17) 開発者よりコメントいただき、条件設定は不要とのこと。

いかがでしたか?

Rで時刻の差をとるときは単位を指定する癖をつける(もしくはlubridate::time_length()を用いる)

時刻を入れたデータフレームがあるとする。

> smp <- data.frame(now=Sys.time(), then=Sys.time()-60) 
> smp 
   now                               then 
1 2019-02-09 10:30:15 2019-02-09 10:29:15 

で、時刻の差を計算すると、そこに単位も含まれてくる。

> smp$diff <- with(smp, now - then) 
> smp now then diff 
1 2019-02-09 10:30:15 2019-02-09 10:29:15 59.99999 secs 

これは煩わしいので、as.numeric()で数値に変える。

> smp$diff <- with(smp, as.numeric(now - then)) 
> smp 
    now                              then                              diff
 1 2019-02-09 10:30:15 2019-02-09 10:29:15 59.99999 

一見問題ないように見えるが、次のような時に困る。

> smp <- data.frame(now=Sys.time(), then=Sys.time()-3600) 
> smp$diff <- with(smp, as.numeric(now - then)) 
> smp 
   now                              then                                diff 
1 2019-02-09 10:38:55 2019-02-09 09:38:55 60 

これは時刻の差分を計算する時に呼び出されるdifftime()の引数unitsがデフォルトではautoとなっていることに起因する。 したがっていつも同じ単位で結果が欲しいときは、演算子ではなくdifftime()を用いて、unitsを指定するとよい。

> smp$diff <- with(smp, as.numeric(difftime(now, then, units = "secs"))) 
> smp                              
   now                              then                                diff 
1 2019-02-09 10:45:00 2019-02-09 09:45:00 3600 

もしくはlubridateパッケージでtime_length()を用いるという手もある。 こちらはデフォルトがsecsになっている。 なお、time_length()はIntervalクラスの値を求めるので、interval()してから渡してやる必要がある点に注意。

> smp$diff <- with(smp, time_length(interval(then, now))) 
> smp                              
   now                              then                                diff 
1 2019-02-09 10:45:00 2019-02-09 09:45:00 3600 

interval()の演算子として%--%も用意されているので、パイプを使いたいときはこちらもあり。

> smp <- smp %>% + mutate(diff = then %--% now %>% time_length()) 
> smp 
now then diff 
1 2019-02-09 10:49:53 2019-02-09 09:49:53 3600 

いかがでしたか????

ggplot2で複数の因子によるグループで折れ線プロット

各因子を結合した列を追加すればいいっちゃいいのだが、ggplot2上で指定する方法もあったよなと思いながら思い出せなかった+ググりづらかったのでこれも備忘。

interaction()を使う。


library(ggplot2)
library(dplyr)

# ChickWeightデータで初回の体重が43以上か否かのフラグを立てる

summarised_weight <- ChickWeight %>% 
group_by(Chick) %>% 
mutate(flag = weight[Time==0]>=43) %>% 
ungroup %>% 
group_by(Time, Diet, flag) %>% 
summarise(w_mean = mean(weight))

# Dietとflagを組みわせた折れ線プロットを描く
ggplot(summarised_weight, aes(Time, w_mean, color = interaction(Diet, flag, sep = "_"))) + geom_line()

f:id:dichika:20190208193207p:plain

でもこれ別にpaste()でも問題ないな。

 

R関係備忘録

最近本当に忘れっぽい。

Rのパッケージ名なんて、イメージは浮かぶものの正確な名称が思い出せない。

ふわっとググるんだけど当然出てこない。

仕方なく、よく見かけるブログの記事を総当たりしてやっと見つかることもままある。

ということでここにメモしていく。

順次更新。

  •  remotesパッケージ

    uribo.hatenablog.com

    install_github()ってdevtoolsじゃなくて別の軽量なパッケージで提供され始めてるんだよなという記憶だけがあった。
  • ggridgesパッケージdichika.hateblo.jp

    EXILE・ggplot2というイメージだけが頭の中にあった。こんなので検索して出てくるわけがない。記事アップ後、インデックス化されたらしく、「エグザイル ggplot2」みたいな雑なクエリで記事が出てくるようになった。
  • devtoolsパッケージ

    heavywatal.github.io

    パッケージ名を忘れた訳ではないが、とても綺麗にまとめていただいてるのでメモ。パッケージを作るときはここを見て思い出せ。
  • ggplot2パッケージのstrip周り

    uribo.hatenablog.com

    facet_wrapのstrip周りはまじで覚えてられないのでとにかくここを見る。 

  • .Last.Value

    uribo.hatenablog.com

    パッケージじゃないけど、最後の処理はここに格納される。こういうのは思い出せないのでメモメモ。