データフレーム Tips 大全

R の多くの関数はデータフレームと呼ばれるオブジェクトを対象とする.データフレームは、同じ長さの複数の数値ベクトル,文字ベクトル等を成分とする、data.frame クラス属性を持つオブジェクト(実体はリスト)であるが,そのものとしては行列のような外見を持つ.各行・列はラベルを必ず持ち,それを用いた添字操作が可能である.データフレームの各行は一組の観測値(case)を表現する。データフレームの各列は一つの変数(項目)を表現する。


データフレームの成分をその成分名で参照できるようにする attach と with (2004.2.5)

attach 関数はデータフレームの成分を現在の環境中に登録する。detach は逆に抹消する。

> data(swiss)  # 組み込みデータ swiss を読み込み
> swiss            # swiss データは5成分からなるデータフレーム
             Fertility Agriculture Examination Education Catholic
Courtelary        80.2        17.0          15        12     9.96
Delemont          83.1        45.1           6         9    84.84
......  (以下略)  ..............................
> swiss$Fertility      # 成分 Fertility の表示 
 [1] 80.2 83.1 92.5 85.8 76.9 76.1 83.8 92.4 82.4 82.9 87.1 64.1 66.9 68.9 61.7
[16] 68.3 71.7 55.7 54.3 65.1 65.5 65.0 56.6 57.4 72.5 74.2 72.0 60.5 58.3 65.4
[31] 75.5 69.3 77.3 70.5 79.4 65.0 92.2 79.3 70.4 65.7 72.7 64.4 77.6 67.6 35.0
[46] 44.7 42.8
> Fertility
Error: Object "Fertility" not found  # Fertility という変数は無いのでエラー
> attach(swiss)  # swiss データの各成分を成分ラベルで参照できるようにする
> Fertility   # Fertility という変数ができた
 [1] 80.2 83.1 92.5 85.8 76.9 76.1 83.8 92.4 82.4 82.9 87.1 64.1 66.9 68.9 61.7
[16] 68.3 71.7 55.7 54.3 65.1 65.5 65.0 56.6 57.4 72.5 74.2 72.0 60.5 58.3 65.4
[31] 75.5 69.3 77.3 70.5 79.4 65.0 92.2 79.3 70.4 65.7 72.7 64.4 77.6 67.6 35.0
[46] 44.7 42.8
> detach(swiss)  # もし不要で邪魔なら成分名で参照できないようにする

attach 関数に代わる機能 with はデータフレーム等から専用の環境を作り、その中で評価を行なう。結果として attach 関数無しで、成分を参照できる。with 関数が終了すればこの環境もなくなる。
注意: ループ中等で同じデータフレームを何度も attach する場合は、一まとまりの処理が終り、不要になったらこまめに detach (例えば on.exit(detach(swiss)) を関数本体に入れておく)しておかないと処理時間が段々遅くなるという報告があるので注意(検索パスが段々長くなるためらしい)。with 利用ではそうした問題は起きない。

> library(MASS)  # アドオンパッケージ MASS 読み込み
> data(anorexia) # anorexia は三成分 Treat, Prewt, Postwt を持つデータフレーム
> with(anorexia, { # データフレーム anorexia から専用の環境を作り、その中で以下を評価
       anorex.1 <- glm(Postwt ~ Prewt + Treat + offset(Prewt), family = gaussian)
       summary(anorex.1)
      })

データフレームを作る

データファイルを read.table() 関数で読み込んでデータフレームを作る

データフレーム変数を得る基本は、特別の形式をもつデータファイルを read.table() 関数で読み込むことである。

行ラベルのないデータファイル (header=TRUE)

行ラベルの無いデータファイル "temp1.data" の内容

Price Floor Area Ch
52.0  111.0 830  yes
54.8  128.0 710  no
57.5  101.0 1000 yes
59.3  131.0 900  no

オプション header=TRUE 付きでデータフレームとして読み込む。最初の行は見出しで,列ラベルとされる。行ラベルは与えられておらず,自動的にヘッダー(通し番号 1,2,3,4)が付け加えられる

> HP <- read.table("temp1.data", header=TRUE)
> HP
  Price Floor Area  Ch   # 形式的に 4x4 行列.行・ラベルが自動的に付加される
1  52.0   111  830 yes
2  54.8   128  710  no
3  57.5   101 1000 yes
4  59.3   131  900  no
> HP$Price                   # 第一列.HP[[1]] でも良い。
[1] 52.0 54.8 57.5 59.3  # 数字は数値として読み込まれる
> HP[["Ch"]]                  # これも可.第4列
[1] yes no  yes no
Levels: no yes          # 文字列は因子として読み込まれる
> HP[1,]                 # 第一行.列ラベルが付く
  Price Floor Area  Ch
1    52   111  830 yes
> HP[2,]
  Price Floor Area Ch
2  54.8   128  710 no
> HP[2,2]               # 第2列第2行の要素
[1] 128
> HP[2,"Floor"]         # この形式も可
[1] 128
> dim(HP)               # 行列と同様次元を持つ
[1] 4 4

行ラベルつきのデータファイル (header=FALSE)

行ラベル "Am", "St", "Yo", "Ht" 付きのデータファイル "temp2.data" の内容

      Price  Floor  Area  Ch
Am 52.0   111.0 830    yes
St  54.8   128.0  710    no
Yo 57.5   101.0  1000  yes
Ht  59.3   131.0  900    no

(既定の) header=FALSE で読み込み

> HP <- read.table("temp2.data") 
> HP
  Price Floor Area  Ch
Am  52.0   111  830 yes
St  54.8   128  710  no
Yo  57.5   101 1000 yes
Ht  59.3   131  900  no
> HP[2,2]        # 第2行第2列成分
[1] 128
> HP["St","Area"] # 第2行第3列成分
[1] 710
> HP["St","Ch"] # 第2行第4列成分
[1] no
Levels: no yes

もう一つの行ラベル付きデータファイル "temp3.data"。行ラベルは文字列 "32", "13", "5", "71" と見なされる

     Price  Floor   Area  Ch
32 52.0   111.0  830    yes
13 54.8   128.0  710    no
5   57.5   101.0 1000   yes
71 59.3   131.0  900    no
> HP <- read.table("temp3.data")  # 既定値の header=FALSE で読み込み
> HP
   Price Floor Area  Ch
32  52.0   111  830 yes
13  54.8   128  710  no
5   57.5   101 1000 yes
71  59.3   131  900  no
> HP[32,2]     # エラー
[1] NA
> HP["32",2]   # 正しい.HP[1,2] でも良い
[1] 111

列(i.e. 変数名)ラベルの無いデータファイル

a  1  2 yes    # 列ラベルの無いデータファイル "temp.data"
b  2  3  no
c  5  7 yes
> x=read.table("temp.data")  # 既定の header=FALSE で読み込み
> x
  V1 V2 V3  V4    # 列(変数名)ラベルが自動的につけられる
1  a  1  2 yes
2  b  2  3  no
3  c  5  7 yes
> y=read.table("temp.data",header=TRUE)
> y
  a X1 X2 yes    # ナンセンスな結果
1 b  2  3  no
2 c  5  7 yes

データフレームを直接作る。関数 data.frame()

数値ベクトルからデータフレームを作る

> data.frame(vx = 1:4, vy = rnorm(4))   # 4x2 のデータフレーム。列ラベル vx,vy 
   vx          vy
1 1   -0.8481768
2 2    0.8831475
3 3    0.2178012
4 4    0.2753476

数値行列からデータフレームを作る

> x
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12
> data.frame(x)
  X1 X2 X3
1  1  5  9
2  2  6 10
3  3  7 11
4  4  8 12  
> data.frame(x,row.names=c("a","b","c","d"))  # 行ラベルを指定
  X1 X2 X3   # 列ラベルは後から変更するしかない(?)
a  1  5  9      # x が列ラベルを持つ行列なら、それを継承する
b  2  6 10
c  3  7 11
d  4  8 12

> x=matrix(1:4, c(2,2), dimnames=list(c("Ca","Cu"),c("Ag","Pt")))
> x           # 行・列ラベル付き行列
   Ag Pt
Ca  1  3
Cu  2  4
> data.frame(x)  # データフレームは行・列ラベルを継承する
   Ag Pt
Ca  1  3
Cu  2  4

データをファイルに記録するwrite.table()

MASS ライブラリ中の write.matrix 関数も write.table 関数と同様の機能を持つ。

> x <- matrix(1:12, ncol=3)  # 数値行列
> x
     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12

> write.table(x, file="temp.dataframe")  # x をファイルに書き出す(同時にデータフレームに強制変換される)
> xx <- read.table("temp.dataframe")   # 再び読み込み
> xx                                                     # データフレームになっている       
         
  X1 X2 X3                                           # 変数ラベルが付け加えられている  
1  1  5  9
2  2  6 10
3  3  7 11
4  4  8 12

ファイル temp.dataframe の中身は以下のようになっている.

"X1" "X2" "X3"         
"1" 1 5 9
"2" 2 6 10
"3" 3 7 11
"4" 4 8 12

ファイルへのデータの出力例

read.table() に対して関数 write.table() や write() で実現できる. 例えば以下の様なデータ data.txt が( C:/ に)あったとする.

0.9, 1.2, 1.9
1.3, 1.6, 2.7
2.0, 3.5, 3.7
1.8, 4.0, 3.1
0.9, 1.2, 1.9
1.3, 1.6, 2.7
2.0, 3.5, 3.7
1.8, 4.0, 3.1
2.2, 5.6, 3.5
2.2, 5.6, 3.5
3.5, 5.7, 7.5
1.9, 6.7, 1.2
2.7, 7.5, 3.7
2.1, 8.5, 0.6
3.6, 9.7, 5.1

このデータ data.txt を read.table() で読み込んで, write.table() でファイル output.txt に出力してみる.

x <- read.table("C:/data.txt")
x

     V1   V2  V3
1  0.9, 1.2, 1.9
2  1.3, 1.6, 2.7
3  2.0, 3.5, 3.7
4  1.8, 4.0, 3.1
5  0.9, 1.2, 1.9
6  1.3, 1.6, 2.7
7  2.0, 3.5, 3.7
8  1.8, 4.0, 3.1
9  2.2, 5.6, 3.5
10 2.2, 5.6, 3.5
11 3.5, 5.7, 7.5
12 1.9, 6.7, 1.2
13 2.7, 7.5, 3.7
14 2.1, 8.5, 0.6
15 3.6, 9.7, 5.1

write.table(x,"C:/output.txt") # quote=F にしないと,要素に "" がついてしまう
# append = F にするとファイルに上書きする
write.table(x,"C:/output.txt", append=T, quote=F, col.names=F) 

データフレームを出力する際は write.table() が使いやすいが,リストをファイルに出力する場合は write() が使いやすい.それぞれの関数の書式は以下のようになっている.『出力するファイルのパス』 は,空文字列 "" なら標準出力に出力される・

write(リスト名, "出力するファイルのパス", append = T, ncolumns = 一行の要素の数)

write.table(データフレーム名, "出力するファイルのパス", append=T, quote=F, col.names=F)

write() 関数について使い方の例

x <- matrix(1:12, ncol=3)
x

     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12

write(x, file="x.data")
scan("x.data")                       # scan 関数で再読み込み(結果はベクトルになっている)

Read 12 items
[1]  1  2  3  4  5  6  7  8  9 10 11 12

xx <- matrix(scan("x.data"), ncol=3) # また行列に変換

Read 12 items

xx

     [,1] [,2] [,3]
[1,]    1    5    9
[2,]    2    6   10
[3,]    3    7   11
[4,]    4    8   12

# ファイルそのものを直接編集したいのでなければ次のようにする方が
# x の構造を直接記録してくれるので世話がない
save(x, file="temp.data")            # ファイル temp.data はテキストデータではない!
rm(x)
load("temp.data")                    # オブジェクト x が復元される

区切り文字を付けたファイルへのデータ出力

リストに入ったデータを,例えばカンマ ,で区切ってファイルに出力する場合,{データ ,カンマ,データ ,カンマ,・・・} というリストを作っておいてファイルに出力すればよい.

x <- c(1:9)
out <- NULL
for (i in 1:(length(x)-1)) {
  out <- cbind(out, x[i]) 
  out <- cbind(out, ",")
}
out <- cbind(out, x[length(x)])
write(out, file="

特定の条件を満たすデータを抽出する(2005/11/25)

NAを一つでも含む行を除いたデータフレームを作る(2005/10/18)

欠損値を除いたデータフレームを作るということ

> x <- c(1,3,2,1,NA,4)
> y <- c(2,NA,3,2,5,4)
> z <- c(5,3,2,3,2,1)
> df <- data.frame(x,y,z)
> df
   x  y z
1  1  2 5
2  3 NA 3
3  2  3 2
4  1  2 3
5 NA  5 2
6  4  4 1
> dfc <- subset(df, complete.cases(df))
> dfc
  x y z
1 1 2 5
3 2 3 2
4 1 2 3
6 4 4 1
> dfc2 <- df[complete.cases(df),]
> dfc2
  x y z
1 1 2 5
3 2 3 2
4 1 2 3
6 4 4 1

追記(2012-01-01)

> dfc3 <- na.omit(df)
> dfc3
  x y z
1 1 2 5
3 2 3 2
4 1 2 3
6 4 4 1

特定の条件を満たすデータを抽出する(2005/11/25)

条件の指定はいろいろあるが,
抽出されるデータフレーム <- 元のデータフレーム[条件, ]
とする。条件の後の「,」を忘れないように注意。
その意味では,上の例や次の例のように subset 関数を使うのがよい。
subset には,次に示すような別の利点もある。
条件としては例えば,
元のデータフレーム[項目] == 値
とか,単に 10:15 とかでもよい。

# テスト用のデータフレームを作る
> x <- c(1,3,2,1,NA,4)
> y <- c(2,NA,3,2,5,4)
> z <- c(5,3,2,3,2,1)
> df <- data.frame(x,y,z)
> df # 以下のような内容になる
   x  y z
1  1  2 5
2  3 NA 3
3  2  3 2
4  1  2 3
5 NA  5 2
6  4  4 1
# z が 3 であるデータ(行)を抽出
> z.eq.3 <- df[df["z"] == 3,]
> z.eq.3
  x  y z
2 3 NA 3
4 1  2 3
# z が 3 以外のデータ(行)を抽出
> z.ne.3 <- df[df["z"] != 3,]
> z.ne.3
   x y z
1  1 2 5
3  2 3 2
5 NA 5 2
6  4 4 1

特定の条件を満たすデータを抽出する subset を使う(2005/11/25)

# テスト用のデータフレームを作る
> x <- c(1,3,2,1,NA,4)
> y <- c(2,NA,3,2,5,4)
> z <- c(5,3,2,3,2,1)
> df <- data.frame(x,y,z)
# このような内容
> df
   x  y z
1  1  2 5
2  3 NA 3
3  2  3 2
4  1  2 3
5 NA  5 2
6  4  4 1
# y が 2 である行を取り出そうとすると
> df[df["y"]==2,]
    x  y  z
1   1  2  5
NA NA NA NA # わお,変なものも取り出される。しかも元の行とは内容が違うし。
4   1  2  3
# subset を使うと書き方もわかりやすいし,変なものも選ばれない
# つまり NA は NA として扱われる
> subset(df, df["y"]==2)
  x y z
1 1 2 5
4 1 2 3

空の因子レベルを除く

subsetを使ってデータセットの一部を取り出すと、以下のように空の因子レベルが残ってしまう。これを取り除くにはfactor()を使う。

IS2$spray <- droplevels(IS2$spray) でもよい。droplevels( ) は実際には factor( ) なのだけど。(覚えるためには,機能を表す関数名 droplevels の方がよいのだろう)

> IS2 <- subset(InsectSprays, InsectSprays$spray != "D")
> IS2$spray
 [1] A A A A A A A A A A A A B B B B B B B B B B B B C C C C C C
[31] C C C C C C E E E E E E E E E E E E F F F F F F F F F F F F
Levels: A B C D E F
> summary(IS2$spray)
 A  B  C  D  E  F 
12 12 12  0 12 12 
> IS2$spray <- factor(IS2$spray)
> summary(IS2$spray)
 A  B  C  E  F 
12 12 12 12 12 
> aq <- transform(airquality, Month = factor(Month, labels = month.abb[5:9]))
> aq <- subset(aq, Month != "Jul")
> table(aq$Month)

May Jun Jul Aug Sep 
 31  30   0  31  30 
> table(droplevels(aq)$Month)

May Jun Aug Sep 
 31  30  31  30 

データフレームにケース(行)を加える、置き換える (2007.05.03)

データフレームに新しいケースを加えたり、既存のケースを置き換える際には一寸注意がいる。各ケースに付値するオブジェクトは原則としてデータフレームと同じ構造を持つリストである必要がある。

> Df <- data.frame(A=1:3, B=c("a","b","c"))
> Df
  A B
1 1 a
2 2 b
3 3 c
> str(Df)
'data.frame':   3 obs. of  2 variables:
 $ A: int  1 2 3
 $ B: Factor w/ 3 levels "a","b","c": 1 2 3  # 文字変数は既定では因子(整数値コード)化される
> levels(Df$B)
[1] "a" "b" "c"
> Df[2,] <- list(4,"a")          # 第2ケースを置き換え
> Df
  A B
1 1 a
2 4 a                  # 問題無し
3 3 c

もし因子水準に無い文字列を含むリストで置き換えると問題が起きる。

> Df[2,] <- list(4,"d")     # 既存のケースを置き換える
Warning message: 
無効な因子水準です。NA が発生しました in: `[<-.factor`(`*tmp*`, iseq, value = "d") 
> Df
  A    B
1 1    a
2 4 <NA>               # 第2ケースは意図したようにはならない("d" は因子水準中にないから) 
3 3    c

一つの解決策は因子水準を拡大してやること。

> levels(Df$B) <- c(levels(Df$B),"d")
> levels(Df$B) 
[1] "a" "b" "c" "d"
> Df[2,] <- y
> Df
  A B
1 1 a
2 4 d         # 成功!
3 3 c

もう一つは、「そのまま関数」I() を用いて、因子化しないように指示すること。

> Df <- data.frame(A=1:3, B=I(c("a","b","c"))) # 文字列変数を因子化しないように指示
> str(Df)
'data.frame':   3 obs. of  2 variables:
 $ A: int  1 2 3
 $ B:Class 'AsIs'  chr [1:3] "a" "b" "c" # 文字列そのままが記録されている
> Df[2,] <- list(6,"e")
> Df
  A B
1 1 a
2 6 e
3 3 c

もしデータフレームの全ての変数が同じ型(数値、文字列、論理値)ならば、リストでなくベクトルで置き換えることができる。

> Df <- data.frame(A=1:3, B=runif(3))
> Df
  A         B
1 1 0.3963373
2 2 0.6295562
3 3 0.2628651
> Df[2,] <- c(4, 3.1415)   # 既存のケースを変更   
> Df
  A         B
1 1 0.3963373
2 4 3.1415000
3 3 0.2628651
> Df[4,] <- c(5, 2.71828)  # 新しいケースを加える
> Df
  A         B
1 1 0.3963373
2 4 3.1415000
3 3 0.2628651
4 5 2.7182800

文字列の場合は先の因子化問題に注意する必要がある。

> Df <- data.frame(A=I(c("x","y","z")), B=I(c("a","b","c")))
> Df[2,] <- c("foo", "bar")  # 既存のケースを置き換え
> Df[4,] <- c("yes", "no")   # 新しいケースを加える
> Df
    A   B
1   x   a
2 foo bar
3   z   c
4 yes  no
> Df[6,] <- c("male", "female") # 第5列無しに第6列を加えると:
> Df
     A      B
1    x      a
2  foo    bar
3    z      c
4  yes     no
5 <NA>   <NA>                 # (文字型の)NA値からなるケースが挿入される
6 male female

データフレームに新しい変数(列)を加えるいくつかの方法(2007.05.07)

> x <- data.frame(a=1:3, b=letters[1:3])
> x["c"] <- c(TRUE,TRUE,FALSE)
> x
  a b     c
1 1 a  TRUE
2 2 b  TRUE
3 3 c FALSE
> x <- data.frame(a=1:3, b=letters[1:3])
> x <- transform(x, c=c(TRUE,TRUE,FALSE))
> x
  a b     c
1 1 a  TRUE
2 2 b  TRUE
3 3 c FALSE
> x <- data.frame(a=1:3, b=letters[1:3])
> z <- cbind(x, c(TRUE,TRUE,FALSE))
> names(z) <- c("a","b","c")         # 変数ラベルを調整
> z
  a b     c
1 1 a  TRUE
2 2 b  TRUE
3 3 c FALSE
> x <- data.frame(a=1:3, b=letters[1:3])
> y <- data.frame(c=c(TRUE,TRUE,FALSE))
> cbind(x,y)
  a b     c
1 1 a  TRUE
2 2 b  TRUE
3 3 c FALSE

最後のに似ているけど,以下のようにやれば1ステップでできる(... 河童の屁 2009/10/20)

> x <- data.frame(a=1:3, b=letters[1:3])
> x <- data.frame(x, c=c(TRUE,TRUE,FALSE))
> x
  a b     c
1 1 a  TRUE
2 2 b  TRUE
3 3 c FALSE

二つのデータフレームを横につなぐ方法(2007.05.07)

> x <- data.frame(a=1:3, b=letters[1:3])
> y <- data.frame(c=c(TRUE,TRUE,FALSE), d=LETTERS[1:3])
> cbind(x,y)
  a b     c d
1 1 a  TRUE A
2 2 b  TRUE B
3 3 c FALSE C
> data.frame(x,y)
  a b     c d
1 1 a  TRUE A
2 2 b  TRUE B
3 3 c FALSE C
> c(x,y)         # リストとして結合される
$a
[1] 1 2 3
$b
[1] a b c
Levels: a b c
$c
[1]  TRUE  TRUE FALSE
$d
[1] A B C
Levels: A B C

特定の変数(列)を削除(2008.09.18)

> df<-data.frame(var1=c(4,1),var2=c(NA,2.0),var3=c("yes",NA)) # オリジナルのデータフレーム
> df[1,]  # 変数を確認
  var1 var2 var3
1    4   NA  yes
> df<-data.frame(var1=df$var1,var3=df$var3)  # データフレーム再定義:var2の列を削除
> df[1,]  # 変数を確認
  var1 var3
1    4  yes

特定の変数(列)を削除(別解追記、2009.10.19)

> df<-data.frame(var1=c(4,1),var2=c(NA,2.0),var3=c("yes",NA)) # オリジナルのデータフレーム
> df[1,]  # 変数を確認
  var1 var2 var3
1    4   NA  yes
> df$var2 <- NULL
> df[1,]  # 変数を確認
  var1 var3
1    4  yes

特定の変数(列)を削除(オーソドックスな方法を追記、2009.10.19 の 2)

特別に,妙な解を工夫して記載しているのだろうか(... 河童の屁)

2008.09.18 の方法は,元のデータフレームに列がいっぱいあったら,大変なタイプ量
2009.10.19 の方法は,列を削除して別のデータフレームを作りたいときに,まえもってコピーをして,そのデータフレームの特定の列を削除するということになり,面倒

オーソドックスな解がなぜ紹介されていないのか,気になるが以下のようにすれば問題なし

> df<-data.frame(var1=c(4,1),var2=c(NA,2.0),var3=c("yes",NA)) # オリジナルのデータフレーム
> df[1,]  # 変数を確認
  var1 var2 var3
1    4   NA  yes
> df <- df[, -2]              # 要するに,2 列目を除くということ
> df[1,]  # 変数を確認
  var1 var3
1    4  yes

何番目の列というのを数えるのが面倒だというなら,以下のようにも

> df<-data.frame(var1=c(4,1),var2=c(NA,2.0),var3=c("yes",NA)) # オリジナルのデータフレーム
> df[1,]  # 変数を確認
  var1 var2 var3
1    4   NA  yes
> df <- df[setdiff(colnames(df), "var2")] # "var2" ではない列を全部ということ
> df[1,]  # 変数を確認
  var1 var3
1    4  yes

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Google
WWW を検索 OKADAJP.ORG を検索
Last-modified: 2015-03-01 (日) 01:15:59 (1263d)