行ごとにRデータフレームを作成する


107

Rで行ごとにデータフレームを構築したいと思います。いくつかの検索を実行しました。私が思いついたのは、空のリストを作成し、リストのインデックススカラーを保持し、毎回リストに追加するという提案です。単一行のデータフレームで、リストのインデックスを1つ進めます。最後do.call(rbind,)に、リストにあります。

これは機能しますが、非常に扱いにくいようです。同じ目標を達成する簡単な方法はありませんか?

明らかに、一部のapply関数を使用できず、データフレームを行ごとに明示的に作成する必要がある場合を参照しています。少なくとも、push最後に使用されたインデックスを明示的に追跡する代わりに、リストの最後に移動する方法はありますか?


1
ここでは役に立ちませんが、append()[おそらくinsertという名前の]を使用するかc()、リストの最後に項目を追加することができます。
Hatmatrix

戻りデータフレームは、あなたがそれらを返す場合を除きことRでの多くの機能はありません[行単位]からlapply()Map()などがありますが、また見てみましょうすることをお勧めしますaggregate()dapply() {heR.Misc}cast() {reshape}あなたのタスクはこれらによって処理することができないかどうかを確認するために関数(これらはすべてデータフレームを返します)。
Hatmatrix 2010

回答:


96

を追加または使用することにより、行ごとに拡張できますrbind()

それはあなたがすべきだという意味ではありません。動的に成長する構造は、Rでコーディングする最も効率の悪い方法の1つです。

可能であれば、data.frame全体を前もって割り当てます。

N <- 1e4  # total number of rows to preallocate--possibly an overestimate

DF <- data.frame(num=rep(NA, N), txt=rep("", N),  # as many cols as you need
                 stringsAsFactors=FALSE)          # you don't know levels yet

そして、操作中に一度に行を挿入します

DF[i, ] <- list(1.4, "foo")

これは任意のdata.frameで機能し、はるかに効率的です。Nをオーバーシュートした場合は、常に最後に空の行を縮小できます。


6
1.4を文字モードに強制しないように、10の代わりにNを、c(1.4、 "foo")の代わりにlist(1.4、 "foo")を配置するつもりでしたか?
Hatmatrix 2010

はい、data.frameの作成にNを使用するつもりでした。また、チャットへの強制を非常にうまくキャッチしました-私はそれを逃しました。
Dirk Eddelbuettel、2009

1
コメントに残すよりも回答を編集する方が良いでしょう。この答えを理解しようとして混乱しました。
ユーザー

4
data.tabledata.framesを使用した事前割り当てよりもさらに高速なようです。ここでのテスト:stackoverflow.com/a/11486400/636656
Ari B. Friedman

これはR 3.1でもまだ当てはまりますか?
userJT 2014

49

に行を追加できますNULL

df<-NULL;
while(...){
  #Some code that generates new row
  rbind(df,row)->df
}

例えば

df<-NULL
for(e in 1:10) rbind(df,data.frame(x=e,square=e^2,even=factor(e%%2==0)))->df
print(df)

3
データフレームではなく行列を出力します
Olga

1
@Olga等しいタイプの要素の行をバインドする場合のみ-その場合、BTWはsapply(またはベクトル化して)転置することをお勧めします。
mbq

1
@mbqまさに私がやっていること。また、df <-data.frame()で初期化すると、データフレームが出力されることもわかりました。
Olga

9

これは、[に似ています]のdo.call(rbind,)出力での使用方法の愚かな例ですMap()lapply()

> DF <- do.call(rbind,Map(function(x) data.frame(a=x,b=x+1),x=1:3))
> DF
  x y
1 1 2
2 2 3
3 3 4
> class(DF)
[1] "data.frame"

私はこの構造をよく使用します。


8

私がRcppをとても気に入っている理由は、R Coreの考え方を常に理解できるとは限らないためです。Rcppを使用すると、多くの場合、そうする必要はありません。

哲学的に言えば、あなたはすべての値他のすべての値から独立して見えることを保証しようとする機能的パラダイムに関して罪の状態にいます。ある値を変更しても、別の値に目に見える変化が生じることはありません。これは、Cでの表現を共有するポインターで得られる方法です。

問題は、関数型プログラミングが小さな船に邪魔にならないように信号を送るときに発生し、小さな船は「私は灯台です」と返信します。その間に処理したい大きなオブジェクトに長い一連の小さな変更を加えると、あなたは灯台の領土に入ります。

C ++ STLでは、push_back()は生き方です。機能的にすることはしませんが、一般的なプログラミングイディオムに効率的に対応しようとします

舞台裏の巧妙さを活かして、各世界に1本の足を持つように調整できる場合があります。スナップショットベースのファイルシステムは、良い例です(これは、ユニオンマウントなどの概念から発展したもので、両側にも適用されます)。

R Coreがこれを実行したい場合、基になるベクトルストレージがユニオンマウントのように機能する可能性があります。ベクトルストレージへの1つの参照は添え字に対して有効である可能性があります1:Nが、同じストレージへの別の参照は添え字に対して有効です1:(N+1)。まだ有効に参照されていない予約済みのストレージがあるかもしれませんpush_back()。既存の参照が有効であると見なす範囲外に追加する場合は、機能の概念に違反しません。

最終的に行を段階的に追加すると、予約済みストレージが不足します。すべての新しいコピーを作成し、ストレージに増分を掛ける必要があります。私が使用したSTL実装は、割り当てを拡張するときにストレージを2倍にする傾向があります。R Internalsを読んだところ、ストレージが20%増加するメモリ構造があると思いました。どちらの方法でも、追加された要素の総数を基準とした対数頻度で成長演算が行われます。償却ベースでは、これは通常許容されます。

舞台裏のトリックが進むにつれて、私はさらに悪いことを見てきました。たびにpush_back()新しい行がデータフレーム上に、トップレベルのインデックス構造をコピーする必要があります。新しい行は、古い関数値に影響を与えることなく、共有表現に追加できます。ガベージコレクタがそれほど複雑になるとは思いません。私はpush_front()すべての参照が割り当てられたベクトルストレージの前部へのプレフィックス参照であることを提案しているわけではないので。


2

ダーク・エデルビュッテルの答えは最高です。ここでは、データフレームのディメンションやデータ型を事前に指定しなくても済むようになっていることに注意してください。これは、複数のデータ型と多数の列がある場合に役立つことがあります。

row1<-list("a",1,FALSE) #use 'list', not 'c' or 'cbind'!
row2<-list("b",2,TRUE)  

df<-data.frame(row1,stringsAsFactors = F) #first row
df<-rbind(df,row2) #now this works as you'd expect.

もしかしてdf<-rbind(df, row2)
ティモシーC.クイン

1

マトリックスなしのrawでデータフレームを作成するこの方法を見つけました。

自動列名あり

df<-data.frame(
        t(data.frame(c(1,"a",100),c(2,"b",200),c(3,"c",300)))
        ,row.names = NULL,stringsAsFactors = FALSE
    )

列名あり

df<-setNames(
        data.frame(
            t(data.frame(c(1,"a",100),c(2,"b",200),c(3,"c",300)))
            ,row.names = NULL,stringsAsFactors = FALSE
        ), 
        c("col1","col2","col3")
    )

0

行になるベクトルがある場合はc()、を使用してそれらを連結し、行ごとに行列に渡して、その行列をデータフレームに変換します。

たとえば、行

dummydata1=c(2002,10,1,12.00,101,426340.0,4411238.0,3598.0,0.92,57.77,4.80,238.29,-9.9)
dummydata2=c(2002,10,2,12.00,101,426340.0,4411238.0,3598.0,-3.02,78.77,-9999.00,-99.0,-9.9)
dummydata3=c(2002,10,8,12.00,101,426340.0,4411238.0,3598.0,-5.02,88.77,-9999.00,-99.0,-9.9)

したがって、データフレームに変換できます。

dummyset=c(dummydata1,dummydata2,dummydata3)
col.len=length(dummydata1)
dummytable=data.frame(matrix(data=dummyset,ncol=col.len,byrow=TRUE))

確かに、2つの大きな制限があります。(1)これはシングルモードデータでのみ機能します。(2)これが機能するためには、最終的な#列を知っている必要があります(つまり、行の最大長が不明な不規則な配列(アプリオリ)。

この解決策は単純に思えますが、Rでの型変換に関する私の経験から、それは将来的に新しい課題を生み出すと確信しています。誰もがこれについてコメントできますか?


0

新しい行の形式によっては、tibble::add_row新しい行が単純で「値のペア」で指定できる場合に使用できます。またはdplyr::bind_rows、「do.call(rbind、dfs)の共通パターンの効率的な実装」を使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.