Hatena::ブログ(Diary)

My Life as a Mock Quant このページをアンテナに追加 RSSフィード Twitter

2018-04-10

glue::glue()をちょっと便利に使う

| 23:02 | glue::glue()をちょっと便利に使うを含むブックマーク

glueパッケージのglue()は、いわばPythonでいう .format() を使えるようにするパッケージなわけで、以下のようにテンプレート文字列 (ここでは"a is {a}" )を、その”傍にある”*1 変数で勝手に埋めてくれるので便利に使えるわけです。

> a <- 123
> glue::glue("a is {a}")
a is 123

このテンプレート文字列に指定する変数関数引数になっててもよくて、以下のように使うこともできるのです、おお便利だ!

> f <- function(x)
+ {
+   hoge <- "aaa"
+   glue::glue("{hoge} + {x}")
+ }
> f(123)
aaa + 123

しかし、3連ドット(...)を引数にした場合、その中に所望の変数(ここではx)が入っていたとしても、うまく動きません。

> f <- function(...)
+ {
+   hoge <- "aaa"
+   glue::glue("{hoge} + {x}")
+ }
> f(x=23, y=32)
 Show Traceback
 
 Rerun with Debug
 Error in eval(parse(text = code, keep.source = FALSE), envir) : 
  object 'x' not found 

これを動かすには面倒ですが、

> f <- function(...)
+ {
+   args <- list(...)
+   for(name in names(args)){
+     assign(name, args[[name]])
+   }
+   hoge <- "aaa"
+   glue::glue("{hoge} + {x}")
+ }
> f(x=23, y=32)
aaa + 23

のように、一度3連ドット(...)が絡んでる変数を一度 "f()の環境の変数"としてassignしておく必要があります。

いやいや、これでうごいためでたい。

これを自動でやるようなPull Requestの1つでも出しましょうかねぇ。

*1:実際には (glue::glueの中から見た)parent.frame() = glueの呼び出しもとの環境

AtsushiAtsushi 2018/04/14 16:59 #glue_dataで幸せになれます

f <- function(...) {
hoge <- "aaa"
glue_data(list(...), "{hoge} + {x}")
}
f(x = 23, y = 32)

2018-04-02

Juliaでlogsumexp

| 22:02 | Juliaでlogsumexpを含むブックマーク

何も考えずにできた。

function logsumexp(x)
    xmax = maximum(x)
    xmax + log(sum(exp(x - xmax)))
end

> x = [1,2,3,10]
> log(sum(exp(x)))
> logsumexp(x)
> 10.001369815771387

Syntaxハイライトが効かないので、そろそろBLOG引越しの機運か。

2018-03-30

purrr::map_dfr = lapply + dplyr::bind_rows

| 22:54 | purrr::map_dfr = lapply + dplyr::bind_rowsを含むブックマーク

そういうことなんだよな〜シミュレーション系でよく使うのでメモ。

> dplyr::bind_rows(lapply(1:3, function(x){head(iris, 1)}))
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          5.1         3.5          1.4         0.2  setosa
3          5.1         3.5          1.4         0.2  setosa
> purrr::map_dfr(1:3, ~ head(iris, 1))
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          5.1         3.5          1.4         0.2  setosa
3          5.1         3.5          1.4         0.2  setosa

2018-03-04

fillは shallow copy (浅いコピー)作るので危険

| 23:55 | fillは shallow copy (浅いコピー)作るので危険を含むブックマーク

めちゃハマったのでメモ。

julia> mutable struct Hoge
           x::Int
       end

julia> xs = fill(Hoge(10), 2)
2-element Array{Hoge,1}:
 Hoge(10)
 Hoge(10)

julia> xs[1].x = 333
333

julia> xs[2].x
333

内包表現(でいいのか?)使うならおk。

julia> xs = [Hoge(10) for _ in 1:2]
2-element Array{Hoge,1}:
 Hoge(10)
 Hoge(10)

julia> xs[1].x = 333
333

julia> xs[2].x
10

2018-03-03

Sys.getenv()の結果をdata.frameとして扱いたい

09:05 | Sys.getenv()の結果をdata.frameとして扱いたいを含むブックマーク

Dlistというクラスのオブジェクトになっていて使いにくい。

> x <- Sys.getenv()
> class(x)
[1] "Dlist"

しょうがないんで、これをdata.frameとして返却する関数を書いた。

get_env <- function(x=NULL)
{
  env <- Sys.getenv(x)
  class(env) <- NULL
  env <- as.data.frame(env, stringsAsFactors=FALSE)
  env <- cbind(rownames(env), env)
  rownames(env) <- NULL
  names(env) <- c("key", "value")
  env  
}

これを使うと、環境変数をdata.frameとして取得でき、更にdplyr & stringrと組み合わせることで楽にフィルタリングできる。

> x <- get_env()
> class(x)
[1] "data.frame"
> dplyr::filter(x, stringr::str_detect(key, "(COMPUTERNAME|DISPLAY)"))
           key           value
1 COMPUTERNAME LAPTOP-S5NHVV53
2      DISPLAY              :0

このあたりの”tidy Sys"系関数はパッケージングされてるのかな?なければ作ってもよい気がしてきた。

おしまい。