ggplot2でX軸の大小を反転させる方法(factorの場合)

はじめに

ggplot2でX軸の大小を反転させる方法について

無指定の場合

ggplot2で描画する際にcoord_flip()を使用するとX軸とY軸を入れ替えることができる。
ただし、その場合には順番が小さい方が下にきてしまい、思い通りの図にならない。

library(ggplot2)

p <- ggplot(iris)
p + aes(x = Species, y = Sepal.Length) +
     geom_boxplot() +
     coord_flip()

plot of chunk unnamed-chunk-1

reorder関数とdplyr::desc関数を使用する場合

このサイトの内容を参考にしました。

reorder関数を使用することでfactorの順序を変えることができる。
この時dplyrパッケージのdesc関数で降順に変換する。

ただし、後に示しているが、
forcatsパッケージのfct_rev関数を使用する方法が最も簡単である。

library(ggplot2)

p + aes(x = reorder(Species, dplyr::desc(Species)),
        y = Sepal.Length) +
     geom_boxplot() +
    coord_flip()

plot of chunk unnamed-chunk-2

forcatsパッケージのfct_rev関数を使用する場合

ここではforcatsパッケージのfct_rev関数を使用した方法を示す。
この関数はfactorの順序を反転させるものである。

したがって、個人的にはこの方法を使用することにする。

library(ggplot2)
library(magrittr)
library(forcats)

p + aes(x = Species %>% fct_rev, y = Sepal.Length) +
     geom_boxplot() +
     coord_flip()

plot of chunk unnamed-chunk-3

forecatsパッケージを読み込まない場合には以下のようにする。

library(ggplot2)
library(magrittr)

p + aes(x = Species %>% forcats::fct_rev(), y = Sepal.Length) +
     geom_boxplot() +
     coord_flip()

カテゴリカルデータからダミー変数を作成するR関数を自作(複数列対応可)(CRANに登録)

以前、 このページ でカテゴリカルデータからダミー変数を作成するR関数を紹介し、 GitHub で公開しました。関数が1つだけの非常に簡単なものです。

時々検索されているようなので、英語に不安はありますが思い切ってCRANに投稿してみました。

対応して頂いたのはUwe Ligges氏でした。「パッケージの説明文(Description)が理解しにくい」と指摘を受けたため、少し改善して再投稿したところアクセプトされました。

パッケージの説明は このページ にあります。

Rからは

install.packages("makedummies")

でインストールできます。

使用方法はGitHubの例を参照して下さい。

Vine LinuxのRでR commanderを使用できるように変更

VineSeedのRではR commanderを使用することができましたが、 Vine Linux 6では使用することができませんでした。

R commanderを使用するためには tcl-8.5/tk-8.5 が必要なのですが、 Vine Linux 6ではバージョンが8.4だったためです。

そこでtcl85/tk85パッケージを作成することで R commanderを使用することができるようになりました。

※ただし、現状の6.3ではproposed-updatesを適用する必要があります。 6.5βではそのままで使用できます。

sudo apt-get install apt-sourceslist-proposed-updates # 6.3の場合に必要
sudo apt-get update
sudo apt-get install R

これで使用者が少しでも増えるといいです(願望)。

Vine Linuxでlittlerをインストールする

追記(2016.2.21)

Vine Linux 6 およびVineSeedに R-littler パッケージをアップロードしました。

したがって以下の記事は過去の記録程度の意味となりました。

経緯

Rのコマンドラインのインタフェースとして littler を使用する場合があります。

Vine Linuxでもlittlerパッケージを作成して使用できるようにしていますが、バージョンが0.1.5と古いです(バージョンを上げるとビルド時にエラーが出てしまったため放置していました)。

最近、何かを調べていて(忘れてしまいました)、 CRANにlittlerパッケージが登録されているのを知りました。早速インストールしたのでその時のメモです。

littlerのインストール

Vine Linuxの場合にはまずlibicu-develをインストールします。

sudo apt-get install libicu-devel

これのパッケージがないとlittlerのインストール時にエラーが出ます。

次にスーパーユーザーでRを起動し、

install.packages("littler")

でlittlerをインストールします。

64-bit環境では /usr/lib64/R/library/littler/bin 以下に r がインストールされるため、 /usr/local/bin 以下にシンボリックリンクを貼ります。

sudo ln -s /usr/lib64/R/library/littler/bin/r /usr/local/bin

これで r を使用できるようになります。

$ r --version
r ('littler') version 0.3.0

using GNU R Version 3.2.3 (2015-12-10)

Copyright (C) 2006 - 2015  Jeffrey Horner and Dirk Eddelbuettel

r is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under the terms of the
GNU General Public License.  For more information about
these matters, see http://www.gnu.org/copyleft/gpl.html.

プログラムの1行目は

#!/usr/bin/env r

としておくといいでしょう。

カテゴリカルデータからダミー変数を作成するR関数を自作(複数列対応可)(その後)

追記(2017.1.3)

makedummiesパッケージがCRANに登録されました。ブログの このページ を参照して下さい。

内容

以前、 このページ でカテゴリカルデータからダミー変数を作成するR関数を紹介しました。

このブログ自体それほどアクセスがあるわけではありませんが、検索される際のキーワードとして「R ダミー変数」が最も多かったです。

そこでこの関数をGitHubで公開しました(https://github.com/toshi-ara/makedummies)。

Rからは

## install.packages("devtools") # パッケージをインストールしていない場合
library(devtools)
install_github("toshi-ara/makedummies")

でインストールできます。

使用方法はGitHubの例を参照して下さい。

org-modeで(require ‘ob-R)とするとエラーが出ていたのを解決(訂正)

経緯

Emacsのパッケージ管理をpackageで行っています。 2015.8.3より後のバージョンのorgをインストールした場合に、 org-bableでR-modeを使用するために

(require 'ob-R)

とすると

Debugger entered--Lisp error: (invalid-function org-babel-header-args-safe-fn)

のようにエラーが出ていました。

試行錯誤の結果、解決できたのでメモを残しておきます。

追記(2015.9.29)

以下の「方法」の内容は間違いの可能性があるため訂正します。従来のELPA(gnu)レポジトリでインストールできました。

org-modeのメーリングリストを見ていると同じエラーの投稿がありました( 質問 とそれに対する 回答 )。

回答には

When this error has been reported in the past, it has been due to
another version of Org being loaded during the update.  Please uninstall
and then reinstall before any version of Org is loaded.

と書かれていました。

つまり、

  1. 一度(新しいバージョンの)Orgをアンインストールする。
  2. Emacsを起動して古いバージョンのOrgがロードされる前に(新しいバージョンの)Orgをインストールする。

必要があるようです。

何回もインストールとアンインストールを繰り返して試行錯誤した結果、

  1. (念のため)Emacsをシャットダウンする。
  2. emacs -Q でまっさらな環境のEmacsを起動する(ここが重要)。
  3. M-x list-packages からorg(gnu版のみ表示される)をインストールする。
  4. Emacsを起動する。

でエラーが起こらなくなりました。

同じ症状で困っている方がいれば試してみて下さい。

方法(以下の内容は必要ありません)

このページ の内容を参考にしました。

.emacs.elに

;; (require 'package)   ;; 設定済のためコメントアウト
(add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/") t)

を追加し、

M-x list-packages

とすると、

org                20150914      available  gnu        Outline-based notes management and organizer
org                20150914      available  org        Outline-based notes management and organizer

のようにorg版のorgも表示されるようになるので、こちらをインストールします。

これで

(require 'ob-R)

としてもエラーが出なくなりました。

補足

このページ によると、開発版ではstan-modeに対応しているようです(2015.9.20閲覧)。 2015.9.3のgitのログ に載っていました。

近いうちに取り込まれて使用できるようになるでしょう。楽しみです。

カテゴリカルデータからダミー変数を作成するR関数を自作(複数列対応可)

追記(2017.1.3)

makedummiesパッケージがCRANに登録されました。ブログの このページ を参照して下さい。

追記(2015.12.26)

GitHubで関数を公開しました。ブログの このページ を参照して下さい。

経緯

Rのglm関数を用いて重回帰分析を行う際には、カテゴリカルデータを自動的にダミー変数に変換してくれるため、あまり苦労しません。

現在、個人的にRStanを勉強中であり、同じ解析を行うためには自分でダミー変数を作成する必要があります。さらにカテゴリカルデータと数値データが混在しているとそれだけで非常に大変です。

そこで群馬大学の青木先生が公開されているmake.dummy関数( http://aoki2.si.gunma-u.ac.jp/R/src/make.dummy.R )をもとにして関数を作成しました。

作成した関数

(2015.9.6追記)以下のプログラムを修正したものを記事の下に掲載しています。こちらを使用せずにそちらを参考にして下さい。

# http://aoki2.si.gunma-u.ac.jp/R/src/make.dummy.R
make.dummy <- function(dat, basal_level= FALSE, sep = "_") {
    name <- colnames(dat)
    level <- levels(dat[,1])
    if (!is.data.frame(dat))
        dat <- as.data.frame(dat)
    ncat <- ncol(dat)
    dat[, 1:ncat] <- lapply(dat, function(x) {
        if (is.factor(x)) {
            return(as.integer(x))
        } else {
            return(x)
        }
    })
    mx <- sapply(dat, max)
    start <- c(0, cumsum(mx)[1:(ncat-1)])
    nobe <- sum(mx)
    ## modified
    res <- t(apply(dat, 1, function(obs) 1:nobe %in% (start+obs))) + 0
    colnames(res) <- paste(name, level, sep = sep)
    if (basal_level == FALSE) res <- res[,-1]
    return(res)
}


make.dummys <- function(dat, ...) {
    n <- ncol(dat)
    res_list <- lapply(seq(n), function(i) {
        tmp <- as.data.frame(dat[,i])
        colnames(tmp) <- colnames(dat)[i]
        if (is.factor(dat[,i])) {       # factor or ordered
            make.dummy(tmp, ...)
        } else {
            tmp
        }
    })

    res <- NULL
    for (i in seq(n)) {
        res <- cbind(res, res_list[[i]])
    }
    return(res)
}

解説

make.dummy関数

青木先生が公開されているmake.dummy関数を少しだけ改変しました。データはデータフレーム形式で渡します。

変更点は以下の点です。

  1. 基準となるカテゴリーを削除できるように変更
    • basal_level引数が FALSE => 基準となるカテゴリーを削除する(デフォルト)
    • basal_level引数が TRUE => 基準となるカテゴリーを削除しない
  2. 列名を追加
    • sep引数で変数名とカテゴリー名を連結する文字列を設定(デフォルトは”_”)

(2015.9.6追記)新バージョンではこの関数は削除しました。ただし、引数の説明はこのまま使用できます。

make.dummys関数

元データが複数の列からなっている場合にも一度にダミー変数に変更するようにしました。

また、カテゴリカルデータ以外(主に数値データ)の場合にはそのまま出力するようにしました。

ですので make.dummys関数を使用すればOKです。引数sepとbasal_levelも使用可能です。

使用例

カテゴリカルデータの場合

基準となるカテゴリーを削除する場合

dat <- data.frame(x = factor(rep(c("a", "b", "c"), each = 3)))
dat$x
make.dummys(dat)
[1] a a a b b b c c c
Levels: a b c

      x_b x_c
 [1,]   0   0
 [2,]   0   0
 [3,]   0   0
 [4,]   1   0
 [5,]   1   0
 [6,]   1   0
 [7,]   0   1
 [8,]   0   1
 [9,]   0   1

基準となるカテゴリーを削除しない場合

make.dummys(dat, basal_level = TRUE)
     x_a x_b x_c
[1,]   1   0   0
[2,]   1   0   0
[3,]   1   0   0
[4,]   0   1   0
[5,]   0   1   0
[6,]   0   1   0
[7,]   0   0   1
[8,]   0   0   1
[9,]   0   0   1

変数名とカテゴリー名を連結する文字列を変更

make.dummys(dat, sep = ":")
     x:b x:c
[1,]   0   0
[2,]   0   0
[3,]   0   0
[4,]   1   0
[5,]   1   0
[6,]   1   0
[7,]   0   1
[8,]   0   1
[9,]   0   1

順序のあるカテゴリカルデータの場合

dat <- data.frame(x = factor(rep(c("a", "b", "c"), each = 3)))
dat$x <- ordered(dat$x, levels = c("a" ,"c" ,"b"))
dat$x
make.dummys(dat)
[1] a a a b b b c c c
Levels: a < c < b

      x_c x_b
 [1,]   0   0
 [2,]   0   0
 [3,]   0   0
 [4,]   0   1
 [5,]   0   1
 [6,]   0   1
 [7,]   1   0
 [8,]   1   0
 [9,]   1   0

カテゴリカル変数は意味のある語が使用されることが多いため、実際にはordered変数を使用して順序のあるカテゴリカルデータとして扱うことが多いと思います。

数値データの場合

dat <- data.frame(x = rep(1:3, each = 3))
dat$x
make.dummys(dat)
  x
1 1
2 1
3 1
4 2
5 2
6 2
7 3
8 3
9 3

数値データはそのまま出力されます。

複数の列をもつ場合

2つのカテゴリカルデータ

dat <- data.frame(
    x = factor(rep(c("a", "b", "c"), each = 3)),
    y = factor(rep(1:3, each = 3))
)
make.dummys(dat)
     x_b x_c y_2 y_3
[1,]   0   0   0   0
[2,]   0   0   0   0
[3,]   0   0   0   0
[4,]   1   0   1   0
[5,]   1   0   1   0
[6,]   1   0   1   0
[7,]   0   1   0   1
[8,]   0   1   0   1
[9,]   0   1   0   1

それぞれダミー変数として出力されます。

カテゴリカルデータと数値データ

dat <- data.frame(
    x = factor(rep(c("a", "b", "c"), each = 3)),
    y = rep(1:3, each = 3)
)
make.dummys(dat)
  x_b x_c y
1   0   0 1
2   0   0 1
3   0   0 1
4   1   0 2
5   1   0 2
6   1   0 2
7   0   1 3
8   0   1 3
9   0   1 3

カテゴリカルデータと数値データが混在してもカテゴリカルデータのみがダミー変数に変換されます。

追記

2015.9.6

プログラムを修正しました。

  • make.dummys関数の1つだけで動作するように改変しました。
  • ダミー変数に変換するプログラムも簡潔にしました。
  • 得られる結果は同じです。
  • ただし、元データの行ラベルも再現するように変更しました。

2015.9.11

プログラムを少し修正しました。

統計学関連なんでもあり のNo. 21771から始まるスレッドの青木先生の書き込みをもとに変更しました。

こちらの方が行数は増えますが、処理の内容が明確でした。

make.dummys <- function(dat, basal_level = FALSE, sep = "_") {
    n_col <- ncol(dat)
    name_col <- colnames(dat)
    name_row <- rownames(dat)

    result <- NULL
    for (i in seq(n_col)) {
        ## process each column
        tmp <- dat[,name_col[i]]
        if (is.factor(tmp)) {
            ## factor or ordered => convert dummy variables
            level <- levels(droplevels(tmp))
            ## http://aoki2.si.gunma-u.ac.jp/taygeta/statistics.cgi
            ## No. 21773
            m <- length(tmp)
            n <- length(level)
            res <- matrix(0, m, n)
            res[cbind(seq(m), tmp)] <- 1
            ## res <- sapply(level, function(j) ifelse(tmp == j, 1, 0))
            colnames(res) <- paste(name_col[i], level, sep = sep)
            if (basal_level == FALSE) {
                res <- res[,-1]
            }
        } else {
            ## non-factor or non-ordered => as-is
            res <- as.matrix(tmp)
            colnames(res) <- name_col[i]
        }
        result <- cbind(result, res)
    }
    rownames(result) <- name_row
    return(result)
}