web-dev-qa-db-ja.com

R左テーブルの有効なNAを維持しながら、NAの代わりに0で外部外部結合

左側のデータテーブルの有効なNA値を上書きせずに、NA(デフォルト)ではなく塗りつぶし値を0(またはその他の値)にして、2つのデータテーブル(dt1、dt2)で左外部結合を行う最も簡単な方法は何ですか?

このスレッド などの一般的な答えは、dplyr::left_joinまたはdata.table::mergeまたはdata.tableのdt2 [dt1]キー付き列ブラケット構文を使用して左外部結合を行うことです。 、続いて2番目のステップでは、結合されたデータテーブル内のすべてのNA値を0に置き換えるだけです。例えば:

library(data.table);
dt1 <- data.table(x=c('a', 'b', 'c', 'd', 'e'), y=c(NA, 'w', NA, 'y', 'z'));
dt2 <- data.table(x=c('a', 'b', 'c'), new_col=c(1,2,3));
setkey(dt1, x);
setkey(dt2, x);
merged_tables <- dt2[dt1];
merged_tables[is.na(merged_tables)] <- 0;

このアプローチでは、保存する必要のある有効なNA値がdt1にないことを必然的に想定しています。しかし、上記の例でわかるように、結果は次のとおりです。

   x new_col y
1: a       1 0
2: b       2 w
3: c       3 0
4: d       0 y
5: e       0 z

しかし、望ましい結果は次のとおりです。

   x new_col y
1: a       1 NA
2: b       2 w
3: c       3 NA
4: d       0 y
5: e       0 z

このような些細なケースでは、data.tableを使用する代わりに、上記のようにすべての要素が構文を置き換え、new_colのNA値だけを置き換えることができます。

library(dplyr);
merged_tables <- mutate(merged_tables, new_col = ifelse(is.na(new_col), 0, new_col));

ただし、このアプローチは、動的に作成された列名を使用して、数十または数百の新しい列がマージされる非常に大きなデータセットには実用的ではありません。列名がすべて事前にわかっていたとしても、すべての新しい列をリストアップして、それぞれに対して変更スタイルの置換を行うのは非常に醜いです。

もっと良い方法があるに違いない? dplyr::left_joindata.table::merge、またはdata.tableのブラケットのいずれかの構文により、ユーザーがNA以外のfill値を簡単に指定できる場合、この問題は簡単に解決されます。何かのようなもの:

merged_tables <- data.table::merge(dt1, dt2, by="x", all.x=TRUE, fill=0);

data.tabledcast関数を使用するとユーザーはfill値を指定できるので、これを行うためのもっと簡単な方法があるはずだと思います。

提案?

編集:@jangoreckiはコメントで、現在開いている機能要求があることを指摘しました data.table GitHugページ 今述べたことを正確に実行し、nomatch=0構文を更新します。 data.tableの次のリリースに含まれるはずです。

17
Mekki MacAulay

left_joinの場合のように、列インデックスを使用して新しい列のみを参照できますか?それらはすべて結果のdata.frameの右側にありますか?ここでそれはdplyrになります:

dt1 <- data.frame(x = c('a', 'b', 'c', 'd', 'e'),
                  y = c(NA, 'w', NA, 'y', 'z'),
                  stringsAsFactors = FALSE)
dt2 <- data.frame(x = c('a', 'b', 'c'),
                  new_col = c(1,2,3),
                  stringsAsFactors = FALSE)

merged <- left_join(dt1, dt2)
index_new_col <- (ncol(dt1) + 1):ncol(merged)
merged[, index_new_col][is.na(merged[, index_new_col])] <- 0

> merged
  x    y new_col
1 a <NA>       1
2 b    w       2
3 c <NA>       3
4 d    y       0
5 e    z       0
2
Sam Firke

私はdplyrで同じ問題に遭遇し、問題を解決する小さな関数を作成しました。 (ソリューションにはtidyrとdplyrが必要です)

left_join0 <- function(x, y, fill = 0L){
  z <- left_join(x, y)
  tmp <- setdiff(names(z), names(x))
  z <- replace_na(z, setNames(as.list(rep(fill, length(tmp))), tmp))
  z
}
6
Fernando Macedo

現在のところ最もクリーンな方法は、左側のテーブル(dt1)で結合する値を中間テーブルにシードし、dt2のマージをチェーンし、NA値を0に設定し、中間テーブルをdt1とマージすることです。完全にdata.tableで実行でき、data.frame構文に依存しません。中間ステップにより、2番目のマージでnomatchNAの結果が発生しないことが保証されます。

library(data.table);
dt1 <- data.table(x=c('a', 'b', 'c', 'd', 'e'), y=c(NA, 'w', NA, 'y', 'z'));
dt2 <- data.table(x=c('a', 'b', 'c'), new_col=c(1,2,3));
setkey(dt1, x);
setkey(dt2, x);
inter_table <- dt2[dt1[, list(x)]];
inter_table[is.na(inter_table)] <- 0;
setkey(inter_table, x);
merged <- inter_table[dt1];

> merged;
   x new_col  y
1: a       1 NA
2: b       2  w
3: c       3 NA
4: d       0  y
5: e       0  z

このアプローチの利点は、右側に追加される新しい列に依存せず、data.tableキー付き速度最適化の内部にとどまるということです。 @SamFirkeのソリューションも機能し、他のコンテキストでより役立つ可能性があるため、@ SamFirkeへの回答をクレジットします。

1
Mekki MacAulay