【问题标题】:fill Na values in df according to other columns values根据其他列值填充df中的Na值
【发布时间】:2020-05-28 22:58:37
【问题描述】:

我需要 R 中的帮助并根据模式处理列边距信息。 为了不理解这里举个例子:

       Groups                    Names   COL1 COL2 COL3
1      G1 KB640596.1_2-BICs_-__SP1   <NA>   10   30
2      G1  KB640596.1_32-33_-__SP1  YP_98   NA   NA
3      G1  KB640596.1_32-33_-__SP1  YP_99   NA   NA
4      G1  KB640596.1_32-33_-__SP1 YP_100   NA   NA
5      G1  KB640596.1_32-33_-__SP1 YP_101   NA   NA
6      G1 KB640588.1_2-BICs_-__SP1   <NA>   89   28
7      G1  KB640596.1_38-39_-__SP1 YP_102   NA   NA
8      G1  KB640588.1_38-39_-__SP1 YP_103   NA   NA
9      G1  KB640596.1_21-90_-__SP1 YP_102   NA   NA
10     G1  KB640588.1_78-32_-__SP1 YP_102   NA   NA
11     G1  KB640596.1_89-90_-__SP2 YP_104   90   76
12     G2    LO640571_89-90_-__SP3 YP_100   30   90
13     G2    LO640571_89-90_-__SP3 YP_101   40   10
14     G3    LO640571_89-90_-__SP3   YP_2   29   29
15     G3    LO640571_10-20_-__SP3   YP_2   29   29
16     G3    LO640571_09-99_-__SP3   YP_2   29   29

从这个 df 我想为每个组和每个具有-BICs 模式的名称填充其COL2 COL3 values and remplace them to the other Names that have the same content part before the first'_'`

例如:

G1 中,只有KB640596.1_2-BICs_-__SP1-BICs 模式, 然后我提取第一个 '_' 模式之前的内容并得到:KB640596.1 KB640596.1 也存在于其他名称中,然后我将COL2COL3 值(分别为1030)添加到它们并得到:

Groups Names COL1 COL2 COL3
G1 KB640596.1_2-BICs_-__SP1 NA 10 30
G1 KB640596.1_2-BICs_-__SP1 YP_98 10 30
G1 KB640596.1_2-BICs_-__SP1 YP_99 10 30
G1 KB640596.1_2-BICs_-__SP1 YP_100 10 30
G1 KB640596.1_2-BICs_-__SP1 YP_101 10 30
G1 KB640588.1_2-BICs_-__SP1 NA 89 28
G1 KB640596.1_2-BICs_-__SP1 YP_102 10 30
G1 KB640588.1_2-BICs_-__SP1 YP_103 89 28
G1 KB640596.1_2-BICs_-__SP1 YP_102 10 30
G1 KB640588.1_2-BICs_-__SP1 YP_102 89 28
G1 KB640596.1_2-BICs_-__SP1 YP_104 90 76
G2 LO640571_89-90_-__SP3 YP_100 30 90
G2 LO640571_89-90_-__SP3 YP_101 40 10
G3 LO640571_89-90_-__SP3   YP_2   29   29
G3 LO640571_10-20_-__SP3   YP_2   29   29
G3 LO640571_09-99_-__SP3   YP_2   29   29

如果有人有想法,那就太好了

数据

   structure(list(Groups = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 2L, 2L, 3L, 3L, 3L), .Label = c("G1", "G2", "G3"
), class = "factor"), Names = structure(c(4L, 6L, 6L, 6L, 6L, 
1L, 7L, 2L, 5L, 3L, 8L, 11L, 11L, 11L, 10L, 9L), .Label = c("KB640588.1_2-BICs_-__SP1", 
"KB640588.1_38-39_-__SP1", "KB640588.1_78-32_-__SP1", "KB640596.1_2-BICs_-__SP1", 
"KB640596.1_21-90_-__SP1", "KB640596.1_32-33_-__SP1", "KB640596.1_38-39_-__SP1", 
"KB640596.1_89-90_-__SP2", "LO640571_09-99_-__SP3", "LO640571_10-20_-__SP3", 
"LO640571_89-90_-__SP3"), class = "factor"), COL1 = structure(c(NA, 
7L, 8L, 1L, 2L, NA, 3L, 4L, 3L, 3L, 5L, 1L, 2L, 6L, 6L, 6L), .Label = c("YP_100", 
"YP_101", "YP_102", "YP_103", "YP_104", "YP_2", "YP_98", "YP_99"
), class = "factor"), COL2 = c(10L, NA, NA, NA, NA, 89L, NA, 
NA, NA, NA, 90L, 30L, 40L, 29L, 29L, 29L), COL3 = c(30L, NA, 
NA, NA, NA, 28L, NA, NA, NA, NA, 76L, 90L, 10L, 29L, 29L, 29L
)), class = "data.frame", row.names = c(NA, -16L))

【问题讨论】:

    标签: r regex dataframe dplyr


    【解决方案1】:

    我们可以创建一个行号为separate 的新列,Name 列基于分隔符 (-) 分为两列。我们可以将数据分成两组,一组保留有"BIC" 值的组,另一组没有。我们将fillCOL2COL3 值分组并加入数据以获得最终数据帧。

    library(dplyr)
    library(tidyr)
    
    df1 <- df %>% mutate(row = row_number())
    df2 <- df1 %>%
             separate(Names, paste0('col', 1:2), sep = "-|\\.", extra = "merge") %>%
             group_by(Groups, col1) %>%
             filter(any(grepl('BIC', col2))) %>%
             fill(COL2, COL3) %>%
             mutate(col2 = first(col2)) %>%
             unite(Names, col1, col2, sep = "-")
    
    
    bind_rows(df2, df1 %>% filter(!row %in% df2$row)) %>%
              arrange(row) %>%
              select(-row)
    
    #   Groups Names                    COL1    COL2  COL3
    #   <fct>  <chr>                    <fct>  <int> <int>
    # 1 G1     KB640596-1_2-BICs_-__SP1 NA        10    30
    # 2 G1     KB640596-1_2-BICs_-__SP1 YP_98     10    30
    # 3 G1     KB640596-1_2-BICs_-__SP1 YP_99     10    30
    # 4 G1     KB640596-1_2-BICs_-__SP1 YP_100    10    30
    # 5 G1     KB640596-1_2-BICs_-__SP1 YP_101    10    30
    # 6 G1     KB640588-1_2-BICs_-__SP1 NA        89    28
    # 7 G1     KB640596-1_2-BICs_-__SP1 YP_102    10    30
    # 8 G1     KB640588-1_2-BICs_-__SP1 YP_103    89    28
    # 9 G1     KB640596-1_2-BICs_-__SP1 YP_102    10    30
    #10 G1     KB640588-1_2-BICs_-__SP1 YP_102    89    28
    #11 G1     KB640596-1_2-BICs_-__SP1 YP_104    90    76
    #12 G2     LO640571_89-90_-__SP3    YP_100    30    90
    #13 G2     LO640571_89-90_-__SP3    YP_101    40    10
    #14 G3     LO640571_89-90_-__SP3    YP_2      29    29
    #15 G3     LO640571_10-20_-__SP3    YP_2      29    29
    #16 G3     LO640571_09-99_-__SP3    YP_2      29    29
    

    【讨论】:

    • 谢谢,但它似乎也改变了其他值(我只想为Names做这件事,他们的名字中有-BICs pattenr,因为我可以有其他数据,例如:@ 987654331@ G3 LO640571_181-10_-__SP3 YP_2 29 29 G3 LO640571_2-78_-__SP3 YP_2 29 29 在这些情况下,您的代码似乎更改了它们的名称(而且不应该..)@Ronal Shah 我更新了帖子以向您展示
    • @chippycentra 为什么第 9 行和第 11 行没有变化?他们都有KB640596.1
    • @chippycentra 你能检查更新的答案吗?有帮助吗?
    • 你好,事实上我猜sep = "-|\\." 不匹配所有可能的情况,因为我也可以有contig_97606_2-HSPs_-__sp3_sp 模式'没有.
    • 我现在不完全记得上下文但是sep = "-|\\." 并不意味着您需要同时拥有"-"".',它被翻译为OR。所以他们中的任何一个也应该工作。
    【解决方案2】:

    我们可以通过'Groups'和'Names'的子字符串在删除后缀部分的基础上进行分组,然后mutate数字列通过将NA元素替换为'Names'具有-BICs

    library(dplyr)
    library(stringr)
    df %>% 
      group_by(Groups, grp = str_remove(Names, "_\\d+.*")) %>%
       mutate_if(is.numeric, ~         
          replace(., is.na(.), .[str_detect(Names, '-BICs')])) %>%
      ungroup %>%
      select(-grp)
    # A tibble: 13 x 5
    #   Groups Names                    COL1    COL2  COL3
    #   <fct>  <fct>                    <fct>  <int> <int>
    # 1 G1     KB640596.1_2-BICs_-__SP1 <NA>      10    30
    # 2 G1     KB640596.1_32-33_-__SP1  YP_98     10    30
    # 3 G1     KB640596.1_32-33_-__SP1  YP_99     10    30
    # 4 G1     KB640596.1_32-33_-__SP1  YP_100    10    30
    # 5 G1     KB640596.1_32-33_-__SP1  YP_101    10    30
    # 6 G1     KB640588.1_2-BICs_-__SP1 <NA>      89    28
    # 7 G1     KB640596.1_38-39_-__SP1  YP_102    10    30
    # 8 G1     KB640588.1_38-39_-__SP1  YP_103    89    28
    # 9 G1     KB640596.1_21-90_-__SP1  YP_102    10    30
    #10 G1     KB640588.1_78-32_-__SP1  YP_102    89    28
    #11 G1     KB640596.1_89-90_-__SP2  YP_104    90    76
    #12 G2     LO640571_89-90_-__SP3    YP_100    30    90
    #13 G2     LO640571_89-90_-__SP3    YP_101    40    10
    

    或者使用mutate/across

    df %>% 
         group_by(Groups, grp = str_remove(Names, "_\\d+.*")) %>%
         mutate(across(where(is.numeric), ~replace(., is.na(.), 
                 .[str_detect(Names, '-BICs')]))) %>% 
         ungroup %>%
         select(-grp)
    

    【讨论】:

    • 谢谢,但我更新了代码以说明第一个 _ 之前的模式的重要性。在新示例中,我们有 2 个不同的 -BICs
    • 您好,非常感谢您,我想我们已经接近了! :) 实际上,我想更改 Names 值,以便它们具有与模式 _ 相同的 Names 值,该模式给出了 COL2 和 COL3 值(检查预期输出的 Names 值。跨度>
    猜你喜欢
    • 2018-02-27
    • 2015-11-09
    • 1970-01-01
    • 2020-10-27
    • 1970-01-01
    • 1970-01-01
    • 2021-06-19
    • 2019-06-06
    • 2020-12-29
    相关资源
    最近更新 更多