加入数据但忽略缺失值
Join data but ignore missing values
我在使用 dplyr 连接数据帧时遇到了一些问题,我想忽略 NA。
我的数据量很大,但简化版如下:
id <- c("id1", "id2", "id3", "id4")
A <- c("E", "F", "G", NA)
B <- c("T", NA, "N", "T")
C <- c(NA, "T", "U", NA)
df <- data.frame(A, B, C)
id A B C
1 id1 E T NA
2 id2 F NA T
3 id3 G N U
4 id4 NA T NA
我有一个要与 df 匹配的条目,例如:
df2 <- data.frame(A = "E", B = "T", C = "M")
A B C
1 E T M
因此,我想从 df 中获取与 df2 匹配的所有行,但应忽略 NA。所以结果应该是这样的:
id A B C
1 id1 E T NA
2 id4 NA T NA
我试图用 semi_join 来做这件事,但到目前为止还没有成功:
result <- df %>%
group_by(n = seq(n())) %>%
do(modify_if(., is.na, ~NULL) %>%
semi_join(df2, by = c("A", "B", "C"))) %>%
ungroup %>%
select(-n)
这导致:
Error: `by` can't contain join column `C` which is missing from LHS
Call `rlang::last_error()` to see a backtrace
谁知道答案?
这是一个混合了 tidyverse 和 base R 的解决方案。我认为这很清楚,但我对一个并非完全人为设计的纯 tidyverse 实现感兴趣。
想法是首先展开 df
和 df2
中的所有条目,然后使用循环过滤所有列。
数据:
id <- c("id1", "id2", "id3", "id4")
A <- c("E", "F", "G", NA)
B <- c("T", NA, "N", "T")
C <- c(NA, "T", "U", NA)
df <- data.frame(id, A, B, C, stringsAsFactors = F) # Make sure to use strings not factors
df2 <- data.frame(A = "E", B = "T", C = "M", stringsAsFactors = F)
代码:
library(tidyr)
results <- crossing(df, df2)
select_columns <- c("A", "B", "C")
for(col in select_columns) {
keep <- is.na(results[[col]]) | results[[col]] == results[[paste0(col, 1)]]
results <- results[keep,, drop=F]
}
results <- results %>% dplyr::select(id, A:C) %>% distinct
results
id A B C
1 id1 E T <NA>
2 id4 <NA> T <NA>
如果您只需要对一组值执行此操作,这可能是最直接的方法:
d[A %in% c("E",NA) & B %in%c("T",NA) & C %in% c("M",NA),]
另一个使用 tidyverse 和 base (dplyr, tidyr, base) 的例子:
在这里,我将你的 df2 转换成一个数据框,其中包含你想要接受的所有值组合((E 或 NA)&(T 或 NA)&(M 或 NA)),然后我进行内部连接有了这个全套。还有其他方法可以创建所有可能组合的数据框,但这个使用 tidyr 相当容易。
library(dplyr)
library(tidyr)
id <- c("id1", "id2", "id3", "id4")
A <- c("E", "F", "G", NA)
B <- c("T", NA, "N", "T")
C <- c(NA, "T", "U", NA)
df <- data.frame(A, B, C, stringsAsFactors = FALSE)
df2 <- data.frame(A = "E", B = "T", C = "M",stringsAsFactors = FALSE)
df2_expanded <- df2 %>%
rowwise() %>%
mutate(combinations = list(expand.grid(A = c(A,NA),B = c(B,NA),C = c(C,NA),stringsAsFactors = FALSE))) %>%
select(-A,-B,-C) %>%
unnest(combinations)
# A tibble: 8 x 3
# A B C
# <chr> <chr> <chr>
# 1 E T M
# 2 NA T M
# 3 E NA M
# 4 NA NA M
# 5 E T NA
# 6 NA T NA
# 7 E NA NA
# 8 NA NA NA
df %>%
inner_join(df2_expanded)
# A B C
# 1 E T <NA>
# 2 <NA> T <NA>
我在使用 dplyr 连接数据帧时遇到了一些问题,我想忽略 NA。
我的数据量很大,但简化版如下:
id <- c("id1", "id2", "id3", "id4")
A <- c("E", "F", "G", NA)
B <- c("T", NA, "N", "T")
C <- c(NA, "T", "U", NA)
df <- data.frame(A, B, C)
id A B C
1 id1 E T NA
2 id2 F NA T
3 id3 G N U
4 id4 NA T NA
我有一个要与 df 匹配的条目,例如:
df2 <- data.frame(A = "E", B = "T", C = "M")
A B C
1 E T M
因此,我想从 df 中获取与 df2 匹配的所有行,但应忽略 NA。所以结果应该是这样的:
id A B C
1 id1 E T NA
2 id4 NA T NA
我试图用 semi_join 来做这件事,但到目前为止还没有成功:
result <- df %>%
group_by(n = seq(n())) %>%
do(modify_if(., is.na, ~NULL) %>%
semi_join(df2, by = c("A", "B", "C"))) %>%
ungroup %>%
select(-n)
这导致:
Error: `by` can't contain join column `C` which is missing from LHS
Call `rlang::last_error()` to see a backtrace
谁知道答案?
这是一个混合了 tidyverse 和 base R 的解决方案。我认为这很清楚,但我对一个并非完全人为设计的纯 tidyverse 实现感兴趣。
想法是首先展开 df
和 df2
中的所有条目,然后使用循环过滤所有列。
数据:
id <- c("id1", "id2", "id3", "id4")
A <- c("E", "F", "G", NA)
B <- c("T", NA, "N", "T")
C <- c(NA, "T", "U", NA)
df <- data.frame(id, A, B, C, stringsAsFactors = F) # Make sure to use strings not factors
df2 <- data.frame(A = "E", B = "T", C = "M", stringsAsFactors = F)
代码:
library(tidyr)
results <- crossing(df, df2)
select_columns <- c("A", "B", "C")
for(col in select_columns) {
keep <- is.na(results[[col]]) | results[[col]] == results[[paste0(col, 1)]]
results <- results[keep,, drop=F]
}
results <- results %>% dplyr::select(id, A:C) %>% distinct
results
id A B C
1 id1 E T <NA>
2 id4 <NA> T <NA>
如果您只需要对一组值执行此操作,这可能是最直接的方法:
d[A %in% c("E",NA) & B %in%c("T",NA) & C %in% c("M",NA),]
另一个使用 tidyverse 和 base (dplyr, tidyr, base) 的例子:
在这里,我将你的 df2 转换成一个数据框,其中包含你想要接受的所有值组合((E 或 NA)&(T 或 NA)&(M 或 NA)),然后我进行内部连接有了这个全套。还有其他方法可以创建所有可能组合的数据框,但这个使用 tidyr 相当容易。
library(dplyr)
library(tidyr)
id <- c("id1", "id2", "id3", "id4")
A <- c("E", "F", "G", NA)
B <- c("T", NA, "N", "T")
C <- c(NA, "T", "U", NA)
df <- data.frame(A, B, C, stringsAsFactors = FALSE)
df2 <- data.frame(A = "E", B = "T", C = "M",stringsAsFactors = FALSE)
df2_expanded <- df2 %>%
rowwise() %>%
mutate(combinations = list(expand.grid(A = c(A,NA),B = c(B,NA),C = c(C,NA),stringsAsFactors = FALSE))) %>%
select(-A,-B,-C) %>%
unnest(combinations)
# A tibble: 8 x 3
# A B C
# <chr> <chr> <chr>
# 1 E T M
# 2 NA T M
# 3 E NA M
# 4 NA NA M
# 5 E T NA
# 6 NA T NA
# 7 E NA NA
# 8 NA NA NA
df %>%
inner_join(df2_expanded)
# A B C
# 1 E T <NA>
# 2 <NA> T <NA>