Tri*_*mus 17 r left-join na dplyr
我可以在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"))
Run Code Online (Sandbox Code Playgroud)
上面的代码将为值"XXX"和"YYY"创建NA.在我的情况下,我加入了大量的列,将会有很多不匹配.所有不匹配应具有相同的值.我知道我可以分几步完成,但问题是一切都可以完成吗?谢谢!
tal*_*lat 17
首先,我建议不要使用该组合data.frame(cbind(...)).原因如下:如果只传递原子向量,则默认cbind创建一个matrix.R中的矩阵只能有一种类型的数据(将矩阵看作具有维度属性的向量,即行数和列数).因此,你的代码
cbind(c("USD","MYR"),c(0.9,1.1))
Run Code Online (Sandbox Code Playgroud)
创建一个字符矩阵:
str(cbind(c("USD","MYR"),c(0.9,1.1)))
# chr [1:2, 1:2] "USD" "MYR" "0.9" "1.1"
Run Code Online (Sandbox Code Playgroud)
虽然您可能期望最终数据框具有字符或因子列(速率)和数字列(值).但你得到的是:
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
Run Code Online (Sandbox Code Playgroud)
因为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"))
Run Code Online (Sandbox Code Playgroud)
现在,对于你的实际问题,如果我理解正确,你想NA用1连接数据中的a 替换所有s .如果这是正确的,这是一个使用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)))
}
Run Code Online (Sandbox Code Playgroud)
现在您可以将它应用于您的数据,如下所示:
> 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
Run Code Online (Sandbox Code Playgroud)
请注意,最终会得到一个字符列(rate)和一个数字列(value),并且所有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
Run Code Online (Sandbox Code Playgroud)
如果您仍在使用dplyr,则不妨利用dplyr::coalesce,并使用dplyr语法将其传递为1或0。我认为这看起来不错...
... %>%
mutate_if(is.numeric,coalesce,0)
Run Code Online (Sandbox Code Playgroud)
哪里0是传递给dplyr::coalesceNA 的参数。
在问题的示例中,存在带有因子的数据框。我有信心不会将汇率作为因素,也不会将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)
Run Code Online (Sandbox Code Playgroud)
解决方案是在 join 之后tidyverse使用:tidyr::replace_na
left_join(x = fx, y = lookup, by = c("rate")) %>%
replace_na(list(value = 0))
Run Code Online (Sandbox Code Playgroud)
或者,对于更一般的情况:
left_join(x = fx, y = lookup, by = c("rate")) %>%
mutate(across(where(is.numeric), ~ replace_na(.x, 0)))
Run Code Online (Sandbox Code Playgroud)
小智 6
我偶然发现了与 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
}
Run Code Online (Sandbox Code Playgroud)
最初回答于:R Left Outer Join with 0 Fill 而不是 NA While Preserving Valid NA's in Left Table