2016-09-14 10 views
-8

のは、私は数値列と文字列を持つデータフレームを作りたいとしましょう:ループ内のデータフレームにすべての列を同じタイプにすることなく行を追加するにはどうすればよいですか?

df<-data.frame() 
for(i in 1:26) { 
    df<-rbind(df, cbind(x=i, y=toString(i))) 
} 
str(df) 
'data.frame': 26 obs. of 2 variables: 
$ x: Factor w/ 26 levels "1","2","3","4",..: 1 2 3 4 5 6 7 8 9 10 ... 
    ..- attr(*, "names")= chr "x" "x" "x" "x" ... 
$ y: Factor w/ 26 levels "1","2","3","4",..: 1 2 3 4 5 6 7 8 9 10 ... 
    ..- attr(*, "names")= chr "y" "y" "y" "y" ... 

おっと、私は要因をしたくありませんでした。

df2<-data.frame() 
for(i in 1:26) { 
    df2<-rbind(df2, cbind(x=i, y=toString(i)), stringsAsFactors=FALSE) 
    } 
str(df2) 
'data.frame': 26 obs. of 2 variables: 
$ x: chr "1" "2" "3" "4" ... 
$ y: chr "1" "2" "3" "4" ... 

すべてが文字です。

x<-NULL 
y<-NULL 
for(i in 1:26) { 
    x<-c(x, i) 
    y<-c(y, toString(i)) 
} 
df3<-data.frame(x, y, stringsAsFactors=FALSE) 
str(df3) 
'data.frame': 26 obs. of 2 variables: 
$ x: int 1 2 3 4 5 6 7 8 9 10 ... 
$ y: chr "1" "2" "3" "4" ... 

しかし、あなたが見ることができるように、これは余分なコードが必要です。私はこれを回避するために把握することができます唯一の方法は、最後にデータフレームを別々のベクターを構築し、その後形成することです。 20列のデータフレームがある場合は、ループの前に20個の初期化文が必要で、ループに20個の文が必要です。

これを達成するためのより簡潔な方法はありますか?

+0

タイプ変換を避けるために 'list'として持っている方が良いと思います – akrun

+0

すべてのステップでdfを割り当てる必要がありますか?非常に非効率なようです。なぜ、すべてのステップをlapplyしないで、 'do.call(rbind、list)'? – Shape

+8

**決して**ループ内のdata.frameに行を追加しないでください。これは、実際の問題を説明するのではなく、むしろ非常に悪い解決策を見つけて助けを求めているときに、典型的なXY問題のように思えます。どのように解決しようとしているのかを記述するのではなく、実際に達成しようとしていることを説明することをお勧めします。 –

答えて

3

これを行わないでください。ループの中でオブジェクトを成長させることは、メモリ管理のために非常に遅いです。コメントからは、行をループする必要はほとんどありません。ただし、これを行う必要がある場合は、ベクトルを事前に割り当て、ループに割り当てた後にdata.frameに結合する必要があります。ループ内で別々のベクトルを使用する理由は、data.frameのサブセットの割り当ても遅いためです。

x <- integer(26) 
y <- character(26) 
for(i in 1:26) { 
    x[i] <- i 
    y[i] <- toString(i) 
} 

df <- data.frame(x, y, stringsAsFactors = FALSE) 
str(df) 
#'data.frame': 26 obs. of 2 variables: 
# $ x: int 1 2 3 4 5 6 7 8 9 10 ... 
# $ y: chr "1" "2" "3" "4" ... 

多くの列をお持ちの場合は、少なくともそのクラスを知っている必要があります。

colclasses <- c("integer", "character") 
l <- lapply(colclasses, vector, length = 26) 
for(i in 1:26) { 
    l[[1]][i] <- i 
    l[[2]][i] <- toString(i) 
} 
names(l) <- c("x", "y") 
df <- as.data.frame(l, stringsAsFactors = FALSE) 

編集:あなたは簡潔な何かをしたいので

lapplyを使用することを検討して、あなたはこれを行うことができます。

l <- lapply(1:26, function(i) list(x = i, y = toString(i))) 
df <- do.call(rbind.data.frame, l) 
+0

パフォーマンスが心配していない場合(私のデータフレームは小さく、メモリ管理時間はループ内の計算に比べてマイナーです)、コードの簡潔さが気になりますが、コードなしでこれを達成する方法はありません個別の初期化とデータフレームの各列の行の追加? –

+0

簡潔なコードが必要な場合は、 'for'ループを使用しないでください。あなたは実際の問題に対しておそらくより優れた(より効率的でより洗練された)解決策があると繰り返し語られています。 PS:ループの中でオブジェクトを成長させる言い訳はありません。あなたは他の言語でそれをしません。その理由は、それが枢機卿的な業績の罪だからです。 – Roland

+0

一般的に、私は 'for'ループを避けますが、この場合、私はそれを回避する方法がありません。 –

-5

私は、これは忘却の彼方にdownvotedされます知っているが、ここに私の同僚が思いついた解決策があります:

df<-data.frame() 
for(i in 1:26) { 
    df<-rbind(df, data.frame(x=i, y=toString(i), stringsAsFactors=FALSE)) 
} 
str(df) 
'data.frame': 26 obs. of 2 variables: 
$ x: int 1 2 3 4 5 6 7 8 9 10 ... 
$ y: chr "1" "2" "3" "4" ... 

パフォーマンスはおそらく貧しいですが、それは私が探していた簡潔な解決策のようなものです。

関連する問題