R dataframe - eiichiromomma/CVMLAB GitHub Wiki

(R) data.frame

Rでデータフレームを扱う際の色々

文字列

データフレーム中に文字列を使用する場合の注意

文字列を含むデータフレームの因子化

read.csvなどを含めて、データフレームを作成する場合に文字列が全てfactor扱いになる。そのため、

x$abc <- "new strings"

としたとき、"new strings"がlevels(x$abc)に含まれない新しい文字列の場合には、代入しようとするとエラーが発生する。

対処法

data.frameの場合

既存のデータをI()関数でくくって宣言すれば避けられる。

ファイルから読む場合

default.stringsAsFactors()

としてTRUEになっている場合、自動的に因子化される。 システムのデフォルトを変える場合には

options(stringsAsFactors=FALSE)

とする。

一時的な抑止をしたい場合にはstringsAsFactors=FALSEを読み込み関数のオプションに入れれば良い。

z<-read.csv("file", stringsAsFactors=FALSE)

levelsを拡張する

levelsを更新するだけだが、新しい単語が出現する度に対処が必要になるので、文字列として扱いたい場合には使わない方が良い。

泥縄データフレーム

予めデータのフォーマットが決まっていれば良いが、解析を行なおうとすると後から続々と項目が増えてくる。 画像の場合はループ内で特徴値を連続して求めるため、仕様変更が起きると面倒な事になる。 どの程度まで動的にデータ構造追加に耐えてくれるか試してみた。

行の追加

> a <- array(0,256)
> b <- array(0,256)
> z <- data.frame(A=a,B=b)
> dim(z)
[1] 256   2

であるとき、

> z[256,] <- list(10,20)
> z[256,]
     A  B
256 10 20

は当然成功する。

> z[257,] <- list(10,20)

エラー:dim<- : dims [product 256] は object [257] の長さに整合しま    せん

となりアウト。

リストに追加するデータが揃っている場合

> z <- rbind(z,list(10,20))
> z[257,]
     A  B
257 10 20

のようにrbindを使えば成功する。 データを部分的に追加できるかというと

> z <- rbind(z,1)
> z[259,]
    A B
259 1 1

のように一応だが行は増える。

泥縄用の結論としてはデータをキッカリ揃えてrbindをするという解が出たが、スマートでは無いので予めデータ数分を確保しておくのが良さそうだ。

項目の追加

こっちの方が状況としてありうる。

> a <- array(0,3)
> b <- array(0,3)
> z <- data.frame(A=a,B=b)
> z
  A B
1 0 0
2 0 0
3 0 0

としておき、新しい項目を追加する。

> z[1,"C"]=50
> z
  A B  C
1 0 0 50
2 0 0 NA
3 0 0 NA

のように勝手に項目は追加してくれる。

調子に乗って

> z[1,c("D","E")] <- list(1,2)

としてみるが

以下にエラー`*tmp*`[j](/eiichiromomma/CVMLAB/wiki/j) : 添え字が許される範囲外です

でアウト。 ムキになって

> z[1,c("D","E")] <- list(1,2,names=c("D","E"))

とするが

以下にエラー`*tmp*`[j](/eiichiromomma/CVMLAB/wiki/j) : 添え字が許される範囲外です
追加情報: Warning messages:
1: 置き換え要素 3 は 2 行を持ちますが、1 個の行を置き換えようとしています in: "[<-.data.frame"(`*tmp*`, 1, c("D",  "E"), value = list(1, 2,  
2: 3 個の変数を与えて、2 個の変数を置き換えようとしています in: "[<-.data.frame"(`*tmp*`, 1, c("D", "E"), value =  list(1, 2,  

でアウト。

> z[1,c("D","E")] <- as.data.frame(list(1,2,names=c("D","E")))

も 以下にエラー*tmp*j : 添え字が許される範囲外です 追加情報: Warning messages: 1: 置き換え要素 1 は 2 行を持ちますが、1 個の行を置き換えようとしています in: "[<-.data.frame"(*tmp*, 1, c("D","E"), value = list(X1 = c(1,
2: 置き換え要素 2 は 2 行を持ちますが、1 個の行を置き換えようとしています in: "[<-.data.frame"(*tmp*, 1, c("D","E"), value = list(X1 = c(1,
3: 置き換え要素 3 は 2 行を持ちますが、1 個の行を置き換えようとしています in: "[<-.data.frame"(*tmp*, 1, c("D","E"), value = list(X1 = c(1,
4: 3 個の変数を与えて、2 個の変数を置き換えようとしています in: "[<-.data.frame"(*tmp*, 1, c("D", "E"), value =list(X1 = c(1,

でアウト。

ちなみに既存の項目であれば

> z[1,c("A","B")] <- list(1,2)
> z
  A B  C
1 1 2 50
2 0 0 NA
3 0 0 NA

と、すんなり成功する。

というわけで、1項目だけ追加するのであれば、データフレーム[データ番号, "新規項目名"]に代入可能。

綺麗なソースにするには?

冗長かもしれないが各データに必要な入れ物を作っておいて、ループが終わった時点でdata.frameを使ってデータフレームにするのが他人が読んでも分かりやすいと思われる。 要するに泥縄は良くない。

> a <- array(0,3)
> b <- array(0,3)
> c <- array(0,3)
> d <- array(0,3)
> e <- array(0,3)
> x <- data.frame(D=d,E=e)
----データ1-3までループ処理
----ループ終了
> z <- data.frame(A=a, B=b,C=c,x)

とするのが良さそう。