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)
とするのが良さそう。