web-dev-qa-db-ja.com

dplyr結合はNA値を定義します

Dplyr結合でNAの「フィル」値を定義できますか?たとえば、結合で、すべてのNA値を1にする必要があると定義しますか?

require(dplyr)
lookup <- data.frame(cbind(c("USD","MYR"),c(0.9,1.1)))
names(lookup) <- c("rate","value")
fx <- data.frame(c("USD","MYR","USD","MYR","XXX","YYY"))
names(fx)[1] <- "rate"
left_join(x=fx,y=lookup,by=c("rate"))

上記のコードは、値「XXX」と「YYY」に対してNAを作成します。私の場合、私は多数の列を結合しており、多くの不一致があります。一致しないものはすべて同じ値にする必要があります。私はいくつかのステップでそれを実行できることを知っていますが、問題はすべて1つで実行できるのですか?ありがとう!

19
Triamus

まず、data.frame(cbind(...))の組み合わせを使用しないことをお勧めします。その理由は次のとおりです。アトミックベクトルのみを渡す場合、cbindはデフォルトでmatrixを作成します。そして、Rの行列は、1種類のデータのみを持つことができます(行列は、次元属性、つまり行と列の数を持つベクトルと考えてください)。したがって、あなたのコード

_cbind(c("USD","MYR"),c(0.9,1.1))
_

文字行列を作成します。

_str(cbind(c("USD","MYR"),c(0.9,1.1)))
# chr [1:2, 1:2] "USD" "MYR" "0.9" "1.1"
_

おそらく、文字列または因子列(レート)と数値列(値)を含む最終的なデータフレームを期待していました。しかし、あなたが得るものは:

_str(data.frame(cbind(c("USD","MYR"),c(0.9,1.1))))
#'data.frame':  2 obs. of  2 variables:
# $ X1: Factor w/ 2 levels "MYR","USD": 2 1
# $ X2: Factor w/ 2 levels "0.9","1.1": 1 2
_

これは、デフォルトで_data.frame_を使用すると文字列(文字)が因子に変換されるためです(data.frame()呼び出しで_stringsAsFactors = FALSE_を指定すると、これを回避できます)。

サンプルデータを作成するには、次の代替アプローチをお勧めします(同じ呼び出しで列名を簡単に指定できることにも注意してください)。

_lookup <- data.frame(rate = c("USD","MYR"), 
                     value = c(0.9,1.1))

fx <- data.frame(rate = c("USD","MYR","USD","MYR","XXX","YYY"))
_

さて、あなたの実際の質問について、私が正しく理解していれば、結合されたデータのすべてのNAsを_1_に置き換えたいと思います。それが正しい場合は、ここに_left_join_と_mutate_each_を使用してそれを行うカスタム関数があります。

_library(dplyr)
left_join_NA <- function(x, y, ...) {
  left_join(x = x, y = y, by = ...) %>% 
    mutate_each(funs(replace(., which(is.na(.)), 1)))
}
_

これを次のようにデータに適用できます。

_> left_join_NA(x = fx, y = lookup, by = "rate")
#  rate value
#1  USD   0.9
#2  MYR   1.1
#3  USD   0.9
#4  MYR   1.1
#5  XXX   1.0
#6  YYY   1.0
#Warning message:
#joining factors with different levels, coercing to character vector 
_

文字列(レート)と数値列(値)になり、すべてのNAが1に置き換えられることに注意してください。

_str(left_join_NA(x = fx, y = lookup, by = "rate"))
#'data.frame':  6 obs. of  2 variables:
# $ rate : chr  "USD" "MYR" "USD" "MYR" ...
# $ value: num  0.9 1.1 0.9 1.1 1 1
_
17

とにかくdplyrを使用している場合は、dplyr::coalesceを利用して、dplyr構文を使用して1または0に渡すこともできます。これは見栄えが良いと思います...

... %>%
mutate_if(is.numeric,coalesce,0)

ここで、0は、NAを置き換えるためにdplyr::coalesceに渡される引数です。

質問の例では、要素を持つデータフレームがあります。 FXレートを因子として使用したり、NAをゼロに置き換えたりする別のベクトルがないと確信しているので、以下のステップを追加して、提供された例の後に回答を実行可能にします。

# replace NAs with zeros for all numeric columns
#
# ... code from question above
left_join(x=fx,y=lookup,by=c("rate")) %>%
    # ignore if factors in value column are because it's a toy example
    mutate(value = as.numeric(as.character(value))) %>%
    # the good stuff here
    mutate_if(is.numeric,coalesce,0)
8
Rafael Zayas

私は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
}

元の回答: 左のテーブルで有効なNAを保持しながら、NAではなく0でRの左外部結合

2
Fernando Macedo