左側のデータテーブルの有効な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_join
、data.table::merge
、またはdata.table
のブラケットのいずれかの構文により、ユーザーがNA以外のfill
値を簡単に指定できる場合、この問題は簡単に解決されます。何かのようなもの:
merged_tables <- data.table::merge(dt1, dt2, by="x", all.x=TRUE, fill=0);
data.table
のdcast
関数を使用するとユーザーはfill
値を指定できるので、これを行うためのもっと簡単な方法があるはずだと思います。
提案?
編集:@jangoreckiはコメントで、現在開いている機能要求があることを指摘しました data.table
GitHugページ 今述べたことを正確に実行し、nomatch=0
構文を更新します。 data.table
の次のリリースに含まれるはずです。
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
私は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
}
現在のところ最もクリーンな方法は、左側のテーブル(dt1)で結合する値を中間テーブルにシードし、dt2のマージをチェーンし、NA値を0に設定し、中間テーブルをdt1とマージすることです。完全にdata.table
で実行でき、data.frame
構文に依存しません。中間ステップにより、2番目のマージでnomatch
NAの結果が発生しないことが保証されます。
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への回答をクレジットします。