14

既存のテーブルに多くの大きなテーブルを追加する必要があるため、優れたパッケージdata.tableでrbindを使用します。ただし、後のテーブルの一部には、元のテーブル(含める必要がある)よりも多くの列があります。data.tableにrbind.fillに相当するものはありますか?

library(data.table)

aa <- c(1,2,3)
bb <- c(2,3,4)
cc <- c(3,4,5)

dt.1 <- data.table(cbind(aa, bb))
dt.2 <- data.table(cbind(aa, bb, cc))

dt.11 <- rbind(dt.1, dt.1)  # Works, but not what I need
dt.12 <- rbind(dt.1, dt.2)  # What I need, doesn't work
dt.12 <- rbind.fill(dt.1, dt.2)  # What I need, doesn't work either

すべてのテーブルを取得する前にrbindingを開始する必要があるため、将来どのような新しい列が呼び出されるかを知る方法はありません。欠落しているデータはNAで埋めることができます。

4

5 に答える 5

14

以来v1.9.2data.table'srbind関数はfill引数を取得しました。?rbind.data.tableドキュメントから:

TRUEの場合、欠落している列をNAで埋めます。デフォルトではFALSEです。TRUEの場合、use.namesはTRUEである必要があり、入力リストのすべての項目はnull以外の列名を持っている必要があります。

したがって、次のことができます(約v1.9.6より前)。

data.table::rbind(dt.1, dt.2, fill=TRUE) 
#    aa bb cc
# 1:  1  2 NA
# 2:  2  3 NA
# 3:  3  4 NA
# 4:  1  2  3
# 5:  2  3  4
# 6:  3  4  5

v1.9.6の更新:

これは現在直接機能します:

rbind(dt.1, dt.2, fill=TRUE)
#    aa bb cc
# 1:  1  2 NA
# 2:  2  3 NA
# 3:  3  4 NA
# 4:  1  2  3
# 5:  2  3  4
# 6:  3  4  5
于 2014-10-10T07:35:28.463 に答える
5

これは、の欠落している列を更新するアプローチです。

rbind.missing <- function(A, B) { 

  cols.A <- names(A)
  cols.B <- names(B)

  missing.A <- setdiff(cols.B,cols.A)
  # check and define missing columns in A
  if(length(missing.A) > 0L){
   # .. means "look up one level"
   class.missing.A <- lapply(B[, ..missing.A], class)
   nas.A <- lapply(class.missing.A, as, object = NA)
   A[,c(missing.A) := nas.A]
  }
  # check and define missing columns in B
  missing.B <- setdiff(names(A), cols.B)
  if(length(missing.B) > 0L){
    class.missing.B <- lapply(A[, ..missing.B], class)
    nas.B <- lapply(class.missing.B, as, object = NA)
    B[,c(missing.B) := nas.B]
  }
  # reorder so they are the same
  setcolorder(B, names(A))
  rbind(A, B)

}

rbind.missing(dt.1,dt.2)

##    aa bb cc
## 1:  1  2 NA
## 2:  2  3 NA
## 3:  3  4 NA
## 4:  1  2  3
## 5:  2  3  4
## 6:  3  4  5

これは、一度に2つしか機能しないため、多くの、または大きなdata.tablesでは効率的ではありません。

于 2013-02-22T05:05:30.443 に答える
4

答えは素晴らしいですが、私にとっては完璧に機能しているように見えるplyr::rbind.fillやgtools::smartbindなどのいくつかの関数がここで提案されているようです。

于 2015-10-09T19:02:30.380 に答える
2

master基本的な概念は、実行中のテーブルから、newTableおよびその逆の両方向に欠落している列を追加することです。

@menlがコメントで指摘しているように、NAを割り当てるだけでは問題が発生します。これは、の列全体が作成されるためですclass logical

1つの解決策は、単一のタイプ(つまりas.numeric(NA))のすべての列を強制することですが、それは制限が厳しすぎます。

代わりに、そのクラスの新しい各列を分析する必要があります。次に、新しい列に割り当てるベクトルとしてas(NA, cc)_(クラス)を使用できます。これをのステートメントでccラップし、を使用 して割り当てます。lapplyRHSeval(columnName)LHS

次に、これを関数でラップし、S3メソッドを使用して、単純に呼び出すことができます。

rbindFill(A, B)

以下はその機能です。

rbindFill.data.table <- function(master, newTable)  {
# Append newTable to master

    # assign to Master
    #-----------------#
      # identify columns missing
      colMisng     <- setdiff(names(newTable), names(master))

      # if there are no columns missing, move on to next part
      if (!identical(colMisng, character(0)))  {
           # identify class of each
            colMisng.cls <- sapply(colMisng, function(x) class(newTable[[x]]))

            # assign to each column value of NA with appropriate class 
            master[ , eval(colMisng) := lapply(colMisng.cls, function(cc) as(NA, cc))]
          }

    # assign to newTable
    #-----------------#
      # identify columns missing
      colMisng     <- setdiff(names(master), names(newTable))

      # if there are no columns missing, move on to next part
      if (!identical(colMisng, character(0)))  {
        # identify class of each
        colMisng.cls <- sapply(colMisng, function(x) class(master[[x]]))

        # assign to each column value of NA with appropriate class 
        newTable[ , eval(colMisng) := lapply(colMisng.cls, function(cc) as(NA, cc))]
      }

    # reorder columns to avoid warning about ordering
    #-----------------#
      colOrdering <- colOrderingByOtherCol(newTable, names(master))
      setcolorder(newTable,  colOrdering)

    # rbind them! 
    #-----------------#
      rbind(master, newTable)
  }

  # implement generic function
  rbindFill <- function(x, y, ...) UseMethod("rbindFill")


使用例:

    # Sample Data: 
    #--------------------------------------------------#
    A  <- data.table(a=1:3, b=1:3, c=1:3)
    A2 <- data.table(a=6:9, b=6:9, c=6:9)
    B  <- data.table(b=1:3, c=1:3, d=1:3, m=LETTERS[1:3])
    C  <- data.table(n=round(rnorm(3), 2), f=c(T, F, T), c=7:9)
    #--------------------------------------------------#

    # Four iterations of calling rbindFill
    master <- rbindFill(A, B)
    master <- rbindFill(master, A2)
    master <- rbindFill(master, C)

    # Results:
    master
    #      a  b c  d  m     n     f
    #  1:  1  1 1 NA NA    NA    NA
    #  2:  2  2 2 NA NA    NA    NA
    #  3:  3  3 3 NA NA    NA    NA
    #  4: NA  1 1  1  A    NA    NA
    #  5: NA  2 2  2  B    NA    NA
    #  6: NA  3 3  3  C    NA    NA
    #  7:  6  6 6 NA NA    NA    NA
    #  8:  7  7 7 NA NA    NA    NA
    #  9:  8  8 8 NA NA    NA    NA
    # 10:  9  9 9 NA NA    NA    NA
    # 11: NA NA 7 NA NA  0.86  TRUE
    # 12: NA NA 8 NA NA -1.15 FALSE
    # 13: NA NA 9 NA NA  1.10  TRUE
于 2013-02-22T03:42:25.090 に答える
2

欠落している列を(正しいタイプとNAで)挿入するさらに別の方法は、2番目のdata.tableの構造を持つ空のdata.tableを使用しmerge()て最初のdata.tableに挿入することです。これにより、ユーザー関数にバグが発生する可能性がなくなります(自分のコードよりも信頼性が高いことはわかっています;))。上からmnelのテーブルを使用して、以下のコードのようなことを行います。AA2[0]merge()

また、をrbindlist()処理するときは、使用がはるかに高速になるはずdata.tablesです。

テーブルを定義します(上記のmnelのコードと同じ):

library(data.table)
A  <- data.table(a=1:3, b=1:3, c=1:3)
A2 <- data.table(a=6:9, b=6:9, c=6:9)
B  <- data.table(b=1:3, c=1:3, d=1:3, m=LETTERS[1:3])
C  <- data.table(n=round(rnorm(3), 2), f=c(T, F, T), c=7:9)

不足している変数をテーブルAに挿入します:(の使用に注意してくださいA2[0]

A <- merge(x=A, y=A2[0], by=intersect(names(A),names(A2)), all=TRUE)

欠落している列をテーブルA2に挿入します。

A2 <- merge(x=A[0], y=A2, by=intersect(names(A),names(A2)), all=TRUE)

これで、同じタイプの同じ列が必要になりAます。A2念のため、列の順序を一致するように設定します(おそらく不要であり、rbindlist()列名または列位置にバインドされているかどうかはわかりません)。

setcolorder(A2, names(A))
DT.ALL <- rbindlist(l=list(A,A2))
DT.ALL

他のテーブルについても繰り返します...手作業で繰り返すよりも、これを関数に入れる方がよいかもしれません...

DT.ALL <- merge(x=DT.ALL, y=B[0], by=intersect(names(DT.ALL), names(B)), all=TRUE)
B <- merge(x=DT.ALL[0], y=B, by=intersect(names(DT.ALL), names(B)), all=TRUE)
setcolorder(B, names(DT.ALL))
DT.ALL <- rbindlist(l=list(DT.ALL, B))

DT.ALL <- merge(x=DT.ALL, y=C[0], by=intersect(names(DT.ALL), names(C)), all=TRUE)
C <- merge(x=DT.ALL[0], y=C, by=intersect(names(DT.ALL), names(C)), all=TRUE)
setcolorder(C, names(DT.ALL))
DT.ALL <- rbindlist(l=list(DT.ALL, C))
DT.ALL

結果は、mnelsの出力と同じように見えます(乱数と列の順序を除く)。

PS1:元の作者は、一致する変数がある場合に何をすべきかを述べていません-本当にやりたいのですか、それともrbind()考えていmerge()ますか?

PS2 :(コメントするのに十分な評判がないので)質問の要点はこの質問の複製のようです。data.table大規模なデータセットを使用した場合と比較した場合のベンチマークにも重要ですplyr

于 2013-08-03T12:17:09.773 に答える