niszetの日記

アナログCMOS系雑用エンジニアが頑張る備忘録系日記

(R) 最頻値を求める

Rでも最頻値は求めることが出来る

modelr::typical()を使う。

For numeric vectors, it returns the median. For factors, characters, and logical vectors, it returns the most frequent value.

とあるように、数値と文字列・因子・論理型で挙動が異なるので注意。

modelr::typical(c("a", "a", "a", "b", "c"))
#> [1] "a"

数値型の場合

 modelr::typical(c(1, 1, 2, 3, 4))
#> [1] 2

最頻値にしたければ型を変えれば良い。

as.numeric(modelr::typical(as.character(c(1, 1, 2, 3, 4))))
#> [1] 1

こんな感じで。

まぁ、僕は最頻値あまり使わないのだけど。

Enjoy!!

(R) promisesパッケージがCRAN上でVersion 1.0.1 として公開されていた(メモ)

まだ触ってないけど…。

CRANはここ。 CRAN - Package promises

専用のページはココ。 rstudio.github.io

このパッケージの存在は認識していたんですが、CRANにリリースされるまではノータッチで良いかなと思っていたら意外と早くリリースされたので焦る…。

非同期プログラミング1について、これまでRではうまく扱えなかった。このパッケージはそれを可能とする、ということでR言語でのプログラミングにおいて、大きな変化点になる可能性もあるなぁ…ということで、↑のページにあるContentsを順に追っていこうと思います2。 説明に書いてあるように、「メンタルシフト」が必要ということなので、ちょっと時間をかけて頑張ろう。

Enjoy!!


  1. 訳語これであってるかな…

  2. 誰か教えt(ry

(R) ggplot2パッケージの+の話

正確には+.gg

この記事の続き?かな。

niszet.hatenablog.com

ggplot2パッケージではレイヤーを足していくということで、+のオペレータがggオブジェクトに対して定義されています

ggplot2:::`+.gg`
## function (e1, e2) 
## {
##     e2name <- deparse(substitute(e2))
##     if (is.theme(e1)) 
##         add_theme(e1, e2, e2name)
##     else if (is.ggplot(e1)) 
##         add_ggplot(e1, e2, e2name)
## }
## <environment: namespace:ggplot2>

こんな感じに。

↑のコードを見ると気づきますが、ggのclassを持つものとしてggplot以外にも実はthemeggを持っているんですね。

class(theme_bw())
## [1] "theme" "gg"   

ggplot2のほかの部品についても見てみます。

geomstatはご存知の通りLayerで、

class(stat_bin())
## [1] "LayerInstance" "Layer"         "ggproto"      
class(geom_point())
## [1] "LayerInstance" "Layer"         "ggproto"      

などとなります。

scaleはちょっと特殊ですが、基本はScaleとその発展形。

 class(scale_x_log10())
## [1] "ScaleContinuousPosition" "ScaleContinuous"         "Scale"                  
## [4] "ggproto"    

coordもちょっと複雑ですがScaleと同様、

class(coord_equal())
[1] "CoordFixed"     "CoordCartesian" "Coord"          "ggproto"       

xlabなどは

class(xlab("x"))
## [1] "labels"

となっています。こうしてみると、結構色々なclassがありますねぇ。

gg以外足せない

本題に戻りますが、ggplot2パッケージ内ではggクラスにのみ+が定義されています。

これは例えばgeomを足しておこうと思って以下のように書くとエラーになります。

geom_line()+geom_point()
## Error in geom_line() + geom_point() : 
##   non-numeric argument to binary operator

まぁそりゃそうだ。+はLayer用には定義されていないのですから。

これについては先の記事にあるように、list()で囲う(listにする)と良いです。

+の中身を見てみると、e1はthemeかggplotでないといけないことがわかります。逆順にしてはいけないわけです。

# こんなこと普通しないけど
geom_point()+ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width))
## NULL

と、e1がthemeでもないしggpplotでもない(Layer)なので、スルーされてしまい、NULLが返ってきます。
themeも同様。

geom_point()+theme_bw()
## NULL

なお、左辺がthemeの場合は右辺はthemeしか足せません。

theme_bw()+geom_abline()
## Error: Don't know how to add RHS to a theme object

View(theme_bw())などで見てみるとわかりますが、themeはただのlist(がS3 classとして扱われている、いわゆる普通のS3)なので、ggprotoのとそれとは異なります。

ひとつ注意なのが、themeの場合は右辺がlistであってもダメということです。つまり、

theme_bw()+list(theme_dark())
## Error: Don't know how to add RHS to a theme object

です。themeの場合はthemeのまま足してあげましょう。

ggplot2パッケージの+の正確な挙動はマニュアルを参照してください。

Add components to a plot — +.gg • ggplot2

あとはソース読んだ方が早いかも…(大体書いた…けど、unevalだけちょっと特殊かな。気が向いたら、いつか)

Enjoy~~

(R) ggplot2で複数のレイヤーをlistにして一気に足す

ggbode中でも使っていますが…

まぁ見た方が早いと思うので。これが

library(ggplot2)
ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width,color=Species))+list(geom_line(),geom_point())

こうなる。

f:id:niszet:20180415181914p:plain

解説。

ggplot2パッケージでは+によりレイヤーを重ねたり、軸の設定をしたりしてどんどんと設定を追加していくことが出来ます。この内部の実装を見てみると、

ggplot2:::`+.gg`
## function (e1, e2) 
## {
##     e2name <- deparse(substitute(e2))
##     if (is.theme(e1)) 
##         add_theme(e1, e2, e2name)
##     else if (is.ggplot(e1)) 
##         add_ggplot(e1, e2, e2name)
## }
## <environment: namespace:ggplot2>

となっていて、+の左辺がggplotオブジェクトの場合、add_ggplot()が呼ばれています。で、その中身を見てみると、

ggplot2:::add_ggplot
## 抜粋
##     else if (is.list(object)) {
##         for (o in object) {
##             p <- p %+% o
##         }
##     }

となっていて、つまりlistで渡せばその要素に対してそれぞれ+の操作をしてくれる、というわけですね。

なお、先の例のlist()c()で置き換えられます。つまり

ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width,color=Species))+c(geom_line(),geom_point())

でも同じ結果が得られます。これは、geom_*というよりはLayerのオブジェクトのベクトルを作ることが出来ないからで、実際に

is.list(c(geom_line(),geom_point()))
## [1] TRUE
class(c(geom_line(),geom_point()))
## [1] "list"

であることを確認できます。ベクトルは(多分)アトミックな型(integer, numeric, raw, character, complex, logical)しか作れないのだと思います。どこかに書いてありそうだけど…

+は調べてみると面白かったので時間があれば何か書く、かも。

追記

一応、ヘルプを読むと

You can also supply a list, in which case each element of the list will be added in turn.

とあって、書いてあるもんだなぁ…と。

Add components to a plot — +.gg • ggplot2

Enjoy!!

サンテ メディカル12の効き目がやばすぎてな…

しばらくお仕事忙しくてR率下げる…

そんなわけで、眼精疲労に悩んでいましたが、一時期ネットで話題になっていたこれを使ってみました

サンテメディカル 12|製品情報 | 参天製薬サンテメディカルシリーズ

これ、効き目がやばいですね。1日5-6回、1-2滴だったかな?推奨らしいですけども、3回、計四滴で快適…。

お値段が1500円くらいしますが、十分価値がある…が、これを常用するようになったら末期かな…。

とりあえず、直近技術書典4まではなんとかなりそうだけど、そのあとは完全に\(^o^)/な仕事のスケジュールになったので、しばらくはTwitter上でRの小ネタを書くくらいで日記はお休みしていく方向のつもり、です。

まぁ、どうなるかわからんですがね…。

(R) もう少し具体的な形での、Rmdを書くときのファイル等の階層構造についてのメモ

試行錯誤している

この前の記事、

niszet.hatenablog.com

Twitter上でuriboさんが反応してくれたので、現在のRmd内の構成とプロジェクト内でのファイル構造について書いてみる。

前回はまずはRファイルにまとめる、そのあとRファイル中の関数群をchunkと定義してRmdからそのchunkを呼び出す、という形で対応しているという話でした。

シンプルな、関数が2-3個くらいならまぁコレで良さそうなのですが、段々とあれも欲しいこれも欲しい…でファイルが成長していくことがままありまして、その途中経過について、ここでは書いています。

プロジェクト内の階層構造

ネットで見かけた、

R/
data/
output/
doc/

の構成が良さげなのでこれを採用しています。基本的にはパッケージ作るときの階層構造+data/、output/って感じですかね。
このあたりも試行錯誤していて、ガチの生データ(ログファイルとか)と、それをcsvにしたものは別にするとして、csvはoutputなのか…?という感じに(今はそうなっているが…)

中間データとして、生データとも最終データとも分けておいた方が良い感じはしますね。分けよう…。

R/の下も似ている関数は全部まとめておきたいところですが最初のうちはどうなるのかわからん…。
ファイルが成長していくと、他のRファイルの関数を呼び始めるので、そこまで複雑になってきたらパッケージ化を考えた方が良いのかもしれないですね。

Rmd中の構造

  • setupチャンク これは普通のRmd中にも入れますね。

    • knitrのグローバルな設定
    • library類の読み込み
    • read_chunk()でRファイル内のchunkの読み込み。使用している関数の定義をしているもの(R/def/に入れている)とplotしているもの(R/plotに入れている)など、必要なRファイルは全部取り込んでおく必要がある。
  • definition系のchunkの実行

    • 自作関数の定義を有効にするためのchunk。この中では定義だけ有効にするように構成する(関数を実際に実行することはしない)
    • libraryなどもこの内部では実行せず。
  • chunk: data_path_definition

    • 内部で使用するファイルパスの定義のchunk
    • here("data" "data1.txt")で プロジェクトのtop dir/data/data1.txtになる。hereパッケージ便利。
    • Rmdをデータごとに作る場合、このファイルパスだけ対応するファイル名に変更すればよいように作っておくと、Rmdファイル量産が簡単にできる。プロットを並べて比較すような場合、データだけ入れ替えて図表は同じ構成ということがあるので、このファイルパスだけ更新すればよい、という形にしておくと結構楽にできる(本文が入るとダメだけど…それも外部からimport出来れば…)
  • データ前処理系のchunk

    • 生データに差異がない、あるいは整形したデータに変更を加えたくない、処理時間をかけたくない場合(ただし、この実行の結果如何で最終的な結果が変わらない場合に限る)はここをskip
  • data importのchunk

    • read_csv()とかでファイブのデータを読み込むchunk。ファイルパスは↑で定義。

以降は本文とplot系のchunk。もし、plot前になんらかの処理が必要であれば、それはplotのchunk内で行っている。 もし、変数等が共通で、オプションを変える必要がないのであれば、コード一式をRファイルに書き出すのもアリ。というよりはそうした方が良い。データパス依存のコードをRファイルに書き出してしまうと、Rmdを作るごとにRファイルが増えてしまうのでそれは避けるべき。変数名は同じにして、変数の中身は違うけど同じ処理をしている…という書き方がベターっぽい。

Rのコード単体でも動くようにしたかったのですが、依存関係の処理が結構面倒くさくて、「いや、そもそも複数のRのコードを管理するのはパッケージでは…?」と、思い直してそちらのスパゲッティ化は回避しました。ただ、単体のRファイルでも動作するというのは大事だと思っているのでこれはいずれ解決させたいと思っています(暫定解は他のファイル全部読む、パッケージ化する)

内部で使用するRのコードが増えてきたらパッケージ化を考えるのは良いと思いますが、初心者向きではないのと、外部パッケージの関数の使用をしている場合は割と面倒なので、このあたりのお作法を守って作るのはまだ「書き捨て」のつもりのRのコードを書いている段階ではちょっと書くコストに見合わないかなぁって思います。どこかに損益分岐点があるのですが、これがどこかわかっていない。
また、これは人によっても変わると思うので、一般論とするのは難しいかもしれない。

後からパッケージ化するためのバッドノウハウもあると思う。が、ある程度詳細を詰めることが出来たらそこから引いて、トップダウンで設計しなおした方が良い構造になるのではと思っています(が、現実にはそこに時間をかけること、難しく…)

前回よりもまとまっていませんが…こうやって情報?を出すことで、色々議論が出来ればいいなぁ…と思っています。

Reproducible Research with R and RStudio Second Editionに載ってるのかなー。やっぱり読むべきなんだろうか…

とりとめない…っ!!

Enjoy!!

SpringerのData Convertersって本を買ったのです

あれ?前にも買ってませんでした?

ほら・・・

niszet.hatenablog.com

そう、この時は(電子)を買ったのですが、こんかいは(物理)です。自分的には物理本が性に合っているのですよね。
そろそろ出るとか言われている、iPad Proの新型を手に入れたらこの限りではないことを期待していますが。

早く出ないかなぁ…。

そんなわけで結構読むようになって、用語は分かるようになってきました。半年くらいで頑張って読み切ろう…。