No.13740 幅固定欄ファイルの読み込みと変数定義  【波音】 2010/11/07(Sun) 19:19

データフレームの変数の型をいっぺんに再定義する方法として何か良いアイディアはないでしょうか?

例えばVAR1, VAR2, VAR3が全てnumericである場合に,それぞれfactor, numeric, factorというように変数の型を再定義したいわけです。もちろん,3つくらいなら個々に

mydata$VAR1 <- as.factor(mydata$VAR1)

などとしていけばよいのですが,変数が何十個もある場合には面倒です(^_^;)

ち なみにread.***()関数類の引数でcolClasses=c("factor", "numeric", "factor")を指定することで簡単にできますが,この方法だとfactor型として定義したVAR1に空白(例えば半角スペースが2つ分)が含まれ ているとNAで置き換えられないので都合が悪いのです。

na.strings=c(" ")を用いても良いのですが,読み込むデータに複数個の半角スペースが含まれた空白部分が点在しているので一度numericとして読み込みNAで置き換えられた後に,変数を再定義した方が手っ取り早いのではないかと思うのですが・・・
# 幅 3, 2, 2, 3 である固定長データを読み込む

--- sample.txt ここから ---
0010918111
0021002222
00311233 3
0044 344
--- sample.txt ここまで ---

# 変数名,変数の型,幅の長さが書かれているテキストファイルを用意する

--- mylab.txt ここから ---
VAR1 numeric 3
VAR2 factor 2
VAR3 factor 2
VAR4 numeric 3
--- mylab.txt ここまで ---

# R上で以下のようにコマンドする
> mylab <- read.table("mylab.txt", colClasses=c("character", "character", "numeric"))
> mylab
V1 V2 V3
1 VAR1 numeric 3
2 VAR2 factor 2
3 VAR3 factor 2
4 VAR4 numeric 3

> #この方法だと元のデータにいくつの半角スペースが含まれているか確認できないので不都合(2つの半角スペースだけならよいが・・・)
> dat2 <- read.fwf("sample.txt", widths=mylab$V3,
+ col.names=mylab$V1, colClasses=mylab$V2, na.strings=c(" "))

> dat2
VAR1 VAR2 VAR3 VAR4
1 1 09 18 111
2 2 10 02 222
3 3 11 23 33
4 4 4 344

> #空白がそのまま読み込まれては不都合(NAにしたい)
> dat2 <- read.fwf("sample.txt", widths=mylab$V3,
+ col.names=mylab$V1, colClasses=mylab$V2)
> dat2
VAR1 VAR2 VAR3 VAR4
1 1 09 18 111
2 2 10 02 222
3 3 11 23 33
4 4 4 344

> #これがベターだが,変数の再定義が必要。でもどうやって?
> dat2 <- read.fwf("sample.txt", widths=mylab$V3,
+ col.names=mylab$V1, colClasses="numeric")
> dat2
VAR1 VAR2 VAR3 VAR4
1 1 9 18 111
2 2 10 2 222
3 3 11 23 33
4 4 4 NA 344

No.13741 Re: 幅固定欄ファイルの読み込みと変数定義  【青木繁伸】 2010/11/07(Sun) 22:45

dat2 <- read.fwf("sample.txt", widths=mylab$V3, 
col.names=mylab$V1, colClasses="numeric")
のあと,mylab$V2 が factor の変数のみ dat2 のその変数に factor( ) を作用させるのですか?
factor にすべき変数が dat2 の何列目かを表すベクトルを用意すれば,
for (i in c(2, 3)) dat2[,i] <- factor(dat2[,i])
のようにすればよいと思います。そのようなベクトルも mylab から作れます。
for (i in (1:nrow(mylab))[mylab$V2=="factor"]) {
dat2[,i] <- factor(dat2[,i])
}
あるいは,
for (i in 1:nrow(mylab)) {
if (mylab$V2[i] == "factor") {
dat2[,i] <- factor(dat2[,i])
}
}
も同じですね。
また,さらに面倒くさいですけど,
for (i in 1:nrow(mylab)) {
if (mylab$V2[i] == "factor") {
vname <- mylab$V1[i]
eval(parse(text=sprintf("dat2$%s <- factor(dat2$%s)", vname, vname)))
}
}
実行結果は
> mylab <- read.table("mylab.txt", colClasses=c("character", "character", "numeric"))
> dat2 <- read.fwf("sample.txt", widths=mylab$V3,
+ col.names=mylab$V1, colClasses="numeric")
> sapply(dat2, class)
VAR1 VAR2 VAR3 VAR4
"numeric" "numeric" "numeric" "numeric"
> for (i in 1:nrow(mylab)) {
+ if (mylab$V2[i] == "factor") {
+ vname <- mylab$V1[i]
+ eval(parse(text=sprintf("dat2$%s <- factor(dat2$%s)", vname, vname)))
+ }
+ }
> dat2
VAR1 VAR2 VAR3 VAR4
1 1 9 18 111
2 2 10 2 222
3 3 11 23 33
4 4 4 <NA> 344
> sapply(dat2, class)
VAR1 VAR2 VAR3 VAR4
"numeric" "factor" "factor" "numeric"
ま たは,na.strings はベクトルでよいので,na.strings=sapply(1:10, function(i) paste(rep(" ", i), collapse="")) などとしておくと 10 桁までの空白が NA にできるので都合がよいかもしれません。

No.13742 Re: 幅固定欄ファイルの読み込みと変数定義  【波音】 2010/11/08(Mon) 22:41

早速の回答ありがとうございます。

やはり基本的にはfor構文を用いて繰り返し処理をしていくの がベターのようですね。if文を用いたやり方のほうが馴染み深いものですが,(1:nrow(mylab))[mylab$V2=="factor"]と いう表現(書き方は)初めて知ったのでとても参考になりました。

na.strings=sapply(1:10, function(i) paste(rep(" ", i), collapse=""))で複数個の空白が格納されているベクトルを用意する方法も良いですが,forによる繰り返し処理であってもそれほど時間を要す るわけでもないので,とりあえず作業工程で都合のよい方をその都度使ってみようと思います。

● 「統計学関連なんでもあり」の過去ログ--- 044 の目次へジャンプ
● 「統計学関連なんでもあり」の目次へジャンプ
● 直前のページへ戻る