根据第二个df将转换应用于df的特定行和列

时间:2018-05-24 12:13:24

标签: r dataframe dplyr purrr

我有两个巨大的df(特别是第一个),我在这里简化了。

library(tidyverse)
(thewhat <- tibble(sample = 1:10L, y= 1.0, z =2.0))

# A tibble: 10 x 3
   sample     y     z
    <int> <dbl> <dbl>
 1      1    1.    2.
 2      2    1.    2.
 3      3    1.    2.
 4      4    1.    2.
 5      5    1.    2.
 6      6    1.    2.
 7      7    1.    2.
 8      8    1.    2.
 9      9    1.    2.
10     10    1.    2.

(thewhere <- tibble(cond = c("a","a","b","c","a"),
     init_sample= c(1,3,4,5,7), 
     duration = c(1,2,2,1,3), 
     where = c(NA,"y","z","y","z")))

# A tibble: 5 x 4
  cond  init_sample duration where
  <chr>       <dbl>    <dbl> <chr>
1 a              1.       1. <NA> 
2 a              3.       2. y    
3 b              4.       2. z    
4 c              5.       1. y    
5 a              7.       3. z  

我想根据thewhat df的信息将thewhere df的一些单元“变”为NAs。重要的是,thewhat是宽格式的,我不想将其转换为长格式(因为我有数百万行)。

我想将thewhere中指示的样本转换为init_sample,直到duration所指示的列的where。 (如果where为NA,则表示它适用于除thewhat之外的sample的所有列;此处为yz。)

我创建了一个df,NAs,表示哪个是应该是NA的单元格:

# table with the elements that should be replaced by NA
NAs <- filter(thewhere, cond=="a") %>% 
      mutate( sample = map2(init_sample, init_sample + duration - 1,seq)) %>% 
      unnest %>%
      select(where, sample)

我尝试了不同的方法,这是我得到的最接近的方法。在下一个mutate中,我为一列进行了NA转换,我可以手动添加其余的相关列,但在我的实际场景中,我有30列。

# Takes into account the different columns but I need to manually add each relevant column
# and another case for mutate_all when the where is NA:
mutate(thewhat, y = if_else(sample %in% NAs$sample[NAs$where =="y"],  
        NA_real_, y  ))

预期输出如下:

# A tibble: 10 x 3
   sample     y     z
    <int> <dbl> <dbl>
 1      1   NA    NA
 2      2    1.    2.
 3      3   NA     2.
 4      4   NA     2.
 5      5    1.    2.
 6      6    1.    2.
 7      7    1.   NA 
 8      8    1.   NA 
 9      9    1.   NA 
10     10    1.    2.

也许mutate_atmutate_if可以在这里工作,但我不知道如何。或者map中的一些purrr函数可以拯救我,但我无法使其适用于此案例。

(布朗尼指出,如果解决方案仍然存在于整数中,但我也可以使用其他类型的解决方案)。

谢谢, 布鲁诺

1 个答案:

答案 0 :(得分:1)

根据说明,我们可以使用map

library(tidyverse)
lst <- NAs %>% 
         split(.$where)
set_names(names(lst), names(lst)) %>%
     map_df(., ~ thewhat[[.x]] %>%
                 replace(., thewhat$sample %in% lst[[.x]]$sample, NA_real_) ) %>%
     bind_cols(thewhat %>%
                 select(sample), .)
# A tibble: 10 x 3
#   sample     y     z
#    <int> <dbl> <dbl>
# 1      1     1     2
# 2      2     1     2
# 3      3    NA     2
# 4      4    NA     2
# 5      5     1     2
# 6      6     1     2
# 7      7     1    NA
# 8      8     1    NA
# 9      9     1    NA
#10     10     1     2