Dplyr加入:NA匹配任何

时间:2018-05-23 08:50:46

标签: r dplyr tidyverse

编辑我正在编辑这篇文章,以便在整个方法从一开始就错误的情况下提供更多的上下文。请参阅下面的“上下文”,试图更抽象地解释问题。

我已经看到了讨论在块中匹配NA的线程,并且选项是将它们与其他NA匹配,或者不将它们与任何内容相匹配:dplyr left_join matching NA

然而,我真的在寻找相反的行为。在连接操作期间,是否有一种方法可以使NA(或该案例中的任何缺失值)与任何其他值匹配?以下示例:


library(tidyverse)
# Removed output for brevity

tbl1 <- tibble(subj = 1, run = 1, session=1)

tbl2 <- tibble(subj = c(1, NA, 2), run = c(NA, 1, 2), session=c(NA, NA, 1), outcomedata = c(NA, NA, NA) )

tbl2$outcomedata[2][[1]] <- list(temperature=30)
tbl2$outcomedata[1][[1]] <- list(height=155, weight=80)
tbl2$outcomedata[3][[1]] <- list(temperature=20)

tbl1
#> # A tibble: 1 x 3
#>    subj   run session
#>   <dbl> <dbl>   <dbl>
#> 1  1.00  1.00    1.00
tbl2
#> # A tibble: 3 x 4
#>    subj   run session outcomedata
#>   <dbl> <dbl>   <dbl> <list>     
#> 1  1.00 NA      NA    <list [2]> 
#> 2 NA     1.00   NA    <list [1]> 
#> 3  2.00  2.00    1.00 <list [1]>

left_join(tbl1, tbl2)
#> Joining, by = c("subj", "run", "session")
#> # A tibble: 1 x 4
#>    subj   run session outcomedata
#>   <dbl> <dbl>   <dbl> <list>     
#> 1  1.00  1.00    1.00 <NULL>

我期望的最终结果是我可以将tbl2的第一行和第二行匹配到tbl1的单行,因为这些行匹配所有非NA属性。第三行不应与任何内容匹配,因为它与非NA值不同。因此,我试图让最终输出如下:

#> # A tibble: 2 x 4
#>    subj  run   session  outcomedata
#>   <dbl> <dbl>   <dbl>     <list>     
#> 1  1.00  1.00    1.00     <list [2]> 
#> 2  1.00  1.00    1.00     <list [1]> 

上下文

让我提供上下文,以防我出现在这里并用连接咆哮错误的树,这是一个更容易的选择。我有一堆嵌套的json文件(我在R中实例化为列表),其中包含我想要归因于数据中特定实例的各种信息。一个json可能包含与主题1的数据中的所有实例(即tbl2的第一行)有关的信息,而另一个json涉及运行1的数据中的所有实例(即tbl2的第二行)。

我希望能够将数据中每个参数星座的所有相关信息(其中一个在tbl1中,但计划是将它们全部都包含在单独的列表中)合并。我的计划是尝试将所有内容与相关的所有内容相匹配,然后对所有参数(即group_by(subj,run,session))使用group_by操作并合并列表(我的计划是使用rlist :: list .merge)。

任何帮助都会受到大力赞赏!

1 个答案:

答案 0 :(得分:2)

这是一个tidyverse解决方案:

tbl2 %>%
  split(seq(nrow(.))) %>%               # split into one row data frames
  map_dfr(~modify_if(.,is.na,~NULL) %>% # remove na columns
        inner_join(tbl1,.))             # inner join to table1

# # A tibble: 2 x 4
#    subj   run session outcomedata
#       <dbl> <dbl>   <dbl> <list>     
# 1     1     1       1 <list [2]> 
# 2     1     1       1 <list [1]>

我使用inner_join(tbl1,.)代替inner_join(tbl1)来保留列顺序。

基础R翻译:

df_list <- split(tbl2,seq(nrow(tbl2)))
df_list <- lapply(df_list,function(dfi){
  merge(tbl1, dfi[!sapply(dfi,is.na)])
})
do.call(rbind,df_list)
#   subj run session outcomedata
# 1    1   1       1     155, 80
# 2    1   1       1          30

<强>加成

使用group_by代替split的2 100%tidyverse方法。一个do,一个nestmapdo被软推荐为FYI,但在这里它提供了更紧凑和可读的语法:

tbl2 %>%
  group_by(n=seq(n())) %>%
  do(modify_if(.,is.na,~NULL) %>% # remove na columns
            inner_join(tbl1,.)) %>%
  ungroup %>%
  select(-n)

tbl2 %>%
  rowid_to_column("n") %>%
  group_by(n) %>%
  nest(.key="dfi") %>%
  mutate_at("dfi",~map(.,
                       ~ modify_if(.,is.na,~NULL) %>% # remove na columns
                         inner_join(tbl1,.))) %>%
  unnest %>%
  select(-n)