dplyr join定义NA值

时间:2015-03-11 16:38:57

标签: r left-join dplyr na

我可以在dplyr join中为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。在我的情况下,我加入了大量的列,将会有很多不匹配。所有不匹配应具有相同的值。我知道我可以分几步完成,但问题是一切都可以完成吗? 谢谢!

3 个答案:

答案 0 :(得分:16)

首先,我建议不要使用组合data.frame(cbind(...))。原因如下:cbind默认情况下创建matrix,如果您只将原子矢量传递给它。并且R中的矩阵只能有一种类型的数据(将矩阵看作具有维度属性的向量,即行和列的数量)。因此,您的代码

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时字符串(字符)会转换为因子(您可以通过在stringsAsFactors = FALSE调用中指定data.frame()来避免这种情况。)

我建议使用以下替代方法来创建示例数据(另请注意,您可以在同一个调用中轻松指定列名称):

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

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

现在,对于您的实际问题,如果我理解正确,您希望将所有NA替换为已加入数据中的1。如果这是正确的,这是使用left_joinmutate_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 

请注意,您最终会得到一个字符列(rate)和一个数字列(value),所有NAs都会替换为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

答案 1 :(得分:7)

如果你正在使用dplyr,你也可以利用dplyr::coalesce,并使用dplyr语法传入1或0.我认为这看起来不错......

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

0是传递给dplyr::coalesce以取代NAs的arg。

在问题的示例中,存在具有因子的数据帧。我有信心不会将外汇汇率作为因素,或者你用NA替换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)

答案 2 :(得分:2)

我偶然发现了与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
}

最初回答:R Left Outer Join with 0 Fill Instead of NA While Preserving Valid NA's in Left Table