クリップボードとdputでデータを共有する

Rのデータ整形について質問したいんだけどデータはExcel上にある、そして質問は今この瞬間に投げかけたい、ファイルに出力している暇などない、そんな事態、あると思います。
そんな時はdput関数を使ってください。

クリップボードにコピーした結果を共有する

たとえばこんなデータがExcel上にあったとします。

該当範囲のデータをまずコピーします。
その上で以下のコマンドを打ち込んでください。

dput(read.table("clipboard")) # Windowsの場合
dput(read.table(pipe("pbpaste"))) # Macの場合

こうするとコンソールに以下のような結果が表示されます。

> dput(read.table(pipe("pbpaste")))
structure(list(V1 = structure(c(3L, 1L, 2L), .Label = c("1", 
"2", "num"), class = "factor"), V2 = structure(c(3L, 1L, 2L), .Label = c("3", 
"4", "value"), class = "factor")), .Names = c("V1", "V2"), class = "data.frame", row.names = c(NA, 
-3L))

この出力結果(structure以下)を相手に共有してください(スタックオーバーフローとかRワカラングとか)。

どのように共有しているかは例えば以下のスタックオーバーフローの質問等を参考にしてください。
http://stackoverflow.com/questions/28391850/r-reverse-order-of-discrete-y-axis-in-ggplot2

出力結果を利用する

この出力結果を利用する時はstructure以下を実行してください。
上記の例であれば以下のような形になります。

df <- structure(list(V1 = structure(c(3L, 1L, 2L), .Label = c("1", 
                                                              "2", "num"), class = "factor"), V2 = structure(c(3L, 1L, 2L), .Label = c("3", 
                                                                                                                                       "4", "value"), class = "factor")), .Names = c("V1", "V2"), class = "data.frame", row.names = c(NA, 
                                                                                                                                                                                                                                      -3L))

ほぼ近い形で再現できます。

> df
   V1    V2
1 num value
2   1     3
3   2     4

パッケージビルド時に no packageと言われた時の対処法

パッケージビルド時に以下のようなメッセージが出た。

Error in loadNamespace(i, c(lib.loc, .libPaths()), versionCheck = vI[[i]]) : 
  there is no package called ‘bigrquery,dplyr’

パッケージが無いといわれているが、いずれのパッケージもインストール済みである。
以下のSOの回答等を参考に再インストールしてみたがメッセージは変わらない。
http://stackoverflow.com/questions/32720990/error-in-libraryrjson-there-is-no-package-called-rjson

途方に暮れてエラーメッセージをよく見ると、‘bigrquery,dplyr’となっている。

Rのドキュメント管理にはroxygen2パッケージを使っているが、はたしてスクリプトの@importを確認すると以下のようになっていた。

#' @import bigrquery,dplyr

正しくは以下の通りであり、区切り文字のカンマは不要。

#' @import bigrquery dplyr

単純ミスだが気づくにくいのでメモしておく。

Rで集中線を描く

写真から顔を検出したら集中線を描くのが紳士のたしなみ。
以下のアルゴリズムを参考にRでタカヤナギ=サンに集中線を描きます。
http://stamefusa.hateblo.jp/entry/20120115/1326636719
顔領域の検出については以前の記事を参考のこと。

ひとまずこんな感じになります。
まだ集中線とは言い難いのでここからいい感じのパラメータを探したい。

library("imager")
library("httr")
MS_FACE_KEY <- "あなたのスクリプトキー"

### 顔領域の検出
url_image <- "https://raw.githubusercontent.com/dichika/ojisan/master/takayanagi_dj.jpg" # タカヤナギ=サン
data_image <- load.image(url_image)
tmp <- tempfile(fileext = ".png")
save.image(data_image, tmp)
url_base <- "https://westus.api.cognitive.microsoft.com/face/v1.0/detect"
result <- POST(url_base, 
               body = upload_file(tmp), 
               query = list(returnFaceAttributes="age,gender,headPose,smile,facialHair,glasses,emotion", 
                            language="en"), 
               add_headers(.headers = c(`Content-Type`="application/octet-stream", 
                                        `Ocp-Apim-Subscription-Key`= MS_FACE_KEY
               )
               )
) %>% content()

### 検出された顔領域のデータを抽出して中心点を求める
bbox <- lapply(result, function(x)x$faceRectangle)
center <- data.frame(x = bbox[[1]]$left + bbox[[1]]$width * 0.5,
                     y = bbox[[1]]$top + bbox[[1]]$height * 0.5)

### 集中線の描画
line_width <- 10 # 線の幅
move <- line_width * 3 # 集中線の間隔

plot(data_image, axes = FALSE)

# 画像上下からの集中線
for(point_y in c(0, height(data_image))){
  for(point_x in seq(0, width(data_image), by = move)){
    p <- runif(1, 0.7, 0.8)
    a <- runif(1, 0.5, 1)
    polygon(x = c(point_x, point_x + line_width, point_x + p*(center$x - point_x)),
            y = c(point_y, point_y, point_y + p*(center$y - point_y)), 
            density = 1000, col = rgb(1, 1, 1, a))
  }
  
}

# 画像左右からの集中線
for(point_x in c(0, width(data_image))){
  for(point_y in seq(0, height(data_image), by = move)){
    p <- runif(1, 0.7, 0.8)
    a <- runif(1, 0.5, 1)
    polygon(x = c(point_x, point_x, point_x + p*(center$x - point_x)),
            y = c(point_y, point_y + line_width, point_y + p*(center$y - point_y)), 
            density = 1000, col = rgb(1, 1, 1, a))
  }
  
}

Enjoy !!

Rmd上でhtmlwidget系パッケージを用いて複数出力する

Rmarkdown上でhtmlwidget系のパッケージを用いて出力する際、以下のようにforループを回して複数の出力を実現しようとするとうまくいかない。

```{r}
library(dplyr)
for(s in unique(iris$Species)){
  tmp <- iris %>% filter(Species == s)
  datatable(tmp)
}
```

そんなときはlapply()とhtmltoolsパッケージのtagList()を組み合わせると良い。

```{r}
library(DT)
htmltools::tagList(
  lapply(split(iris, iris[, 5]), datatable)
)
```

https://github.com/rstudio/DT/issues/67

ここにmanipulateWidgetパッケージを組み合わせて、各出力のレイアウト(上記例の場合は表の並べ方)も調整できると良いのだがうまくいかない。

コメントいただきました

たとえば2列に並べたいときは以下のようにすると良いとのことです。
kazutanさんありがとうございます!!!!!!!!!

library(DT)
manipulateWidget::combineWidgets(
  ncol = 2,
  list = lapply(split(iris, iris[, 5]), datatable)
)

http://d.hatena.ne.jp/dichika/20170412/p1#c1492086795

Rの良いところと悪いところうんぬんのメモ

たまに見かける「Rの良いところは統計家によって開発されたことだ。そしてRの悪いところは統計家によって開発されたことだ」という言葉、Bow Cowgillが言ったらしい。

I was on a panel back in 2009 where Bow Cowgill said, "The best thing about R is that it was written by statisticians. The worst thing about R is that it was written by statisticians."

https://www.r-bloggers.com/why-has-r-despite-quirks-been-so-successful/

引用しようとした時にいつも検索に迷うのでメモしておく。

集合写真で水中メガネの人に枠を付ける

前回の記事の集合写真を拡大すると、さらに細かくメガネの種類を検出できるらしい。
http://uribo.hatenablog.com/entry/2017/04/05/224401

ということでメガネの種類ごとに色分けした顔領域を描画したい。

画像の読み込みと拡大

画像の拡大には今回はmagickパッケージのimage_scale()を用いる。

library("httr")
library("magick")
library("dplyr")
MS_FACE_KEY <- "あなたのスクリプトキー"
url_image <- "https://henningsway.github.io/images/biginjapan_blog/tokyo_r.jpg"
# 画像を読み込んで、顔が検出できるように幅を5000pxに拡大する
pic <- image_read(url_image) %>% image_scale("5000")

ここで画像の情報を確認する。magickパッケージのimage_info()を用いる。
幅5000pxになっていることが確認できる。

# いったん画像の情報を確認する
image_info(pic)
#   format width height colorspace filesize
# 1   JPEG  5000   3328       sRGB        0

APIへのPOST

拡大した画像をファイル出力し、APIにPOSTする。

# APIにPOSTするために一時ファイルに出力する:出力しなくて良い方法があったら教えてください
tmp <- tempfile()
image_write(pic, tmp)

# MS Face APIにPOST
url_base <- "https://westus.api.cognitive.microsoft.com/face/v1.0/detect"
result <- POST(url_base, 
               body = upload_file(tmp), 
               query = list(returnFaceAttributes="age,gender,headPose,smile,facialHair,glasses,emotion", 
                            language="en"), 
               add_headers(.headers = c(`Content-Type`="application/octet-stream", 
                                        `Ocp-Apim-Subscription-Key`=MS_FACE_KEY
                                        )
                           )
               ) %>% content()

POSTした結果から検出されたメガネの種類を確認すると3種類あることがわかる。

# 検出されたメガネの種類を確認
result %>% lapply(function(x)x$faceAttributes$glasses) %>% unlist() %>% table()

# NoGlasses  ReadingGlasses SwimmingGoggles 
# 17              12               3 

メガネの種類によって色分けする

結果には検出された顔領域がfaceRectangleとして格納されている。
メガネの種類によって、これを塗り分けることにする。
いったん写真を描画して、rect()を用いて色分けした四角形を描画する。

# 検出された顔領域のデータを抽出
bbox <- lapply(result, function(x)x$faceRectangle)

# メガネの種類によって顔領域を塗り分けるために色分けする
# メガネなし:灰、通常のメガネ:オレンジ、水中メガネ:緑
glass <- result %>% lapply(function(x)x$faceAttributes$glasses) %>% 
  unlist() %>% 
  recode(ReadingGlasses="orange", SwimmingGoggles="green", .default=NA_character_)

# 描画
plot(pic)
for(i in seq(length(bbox))){
  rect(xleft=bbox[[i]]$left,
       ybottom=image_info(pic)$height-bbox[[i]]$top-bbox[[i]]$height,
       xright=bbox[[i]]$left+bbox[[i]]$width,
       ytop=image_info(pic)$height-bbox[[i]]$top, 
       lwd=2,
       border=glass[i]
       )
}

結果はこちら。

Enjoy!

sfパッケージのst_というプレフィックスの語源

sfパッケージの関数にはst_というプレフィックスがついているのだが、この由来がvignetteやreferenceにも書いておらずもやもやしていた。
sfパッケージなんだからsf_じゃないのかと。
st_as_sf()なんて、stオブジェクトをsfオブジェクトにする関数じゃないのかと(違う)。

で、色々調べてたらどうやらPostGISに行き着いた。
以下のページのNoteにこう書かれている。

As a result, most of the functions that you know and love have been renamed using the standard spatial type (ST) prefix.

https://postgis.net/docs/reference.html

standard spatial typeでstというわけですね。
かつてはst_ではなく大文字のST_だったとのことでこの由来で間違い無さそう。

すっきり。

と思ったらspatial and temporalの略でst_ということらしいです。
詳細は以下のPRをご確認ください。
https://github.com/edzer/sfr/pull/293
ユタニ=サンありがとうございます!!!!