【问题标题】:Name a column inside a loop on charactere vector with the current value of the loop用循环的当前值命名字符向量循环内的列
【发布时间】:2021-08-19 11:46:12
【问题描述】:

我有一个数据框 (data2),我想根据另一个选项卡 (data1) 中是否存在一些字符串来为其添加列 ("M1"、"M2"、"M3")。例如,对于“M1”值,如果该值与 data1 中的 M1 相关联,我想在 data2 中创建一个包含原始 TOT 值的列名称“M1”。 在某些情况下,我在 data2 中的值如下“t1;t4”,而我想在 data2 中比较的值是由 ; 分隔的。每一行。

为了更好地理解,下面有我想要的输出。

为了做到这一点,我尝试在包含所有模块值(“M1”...“M3”)的向量上创建一个循环,过滤该值的 data1,将相应的 GNE 值存储在向量中,并使用 mutate 函数在 data2 中添加列。我想知道如何在循环内用“M1”、“M2”或“M3”命名新列。

或者如果有人有更好的想法来使用另一种方法获得输出,我也会对我有用,因为我认为这不是最简单的方法。在我的真实数据中,我有 32 个新列要通过这种方式添加。

data1=data.frame(Module=c("M1", "M1", "M2", "M3", "M3", "M3", "M3"), GNE= c("t1", "t3", "t5", "t8", "t2", "t9", "t12"))


data2=data.frame(ID=c("A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "A11"), TOT=c("t1;t4", "t2", "t3", "t4", "t5", "t6", "t7", "t8;t9", "t9", "t10", "t8-8"))


list=c("M1", "M2", "M3")

> data1
  Module GNE
1     M1  t1
2     M1  t3
3     M2  t5
4     M3  t8
5     M3  t2
6     M3  t9
7     M3 t12

> data2
    ID   TOT
1   A1 t1;t4
2   A2    t2
3   A3    t3
4   A4    t4
5   A5    t5
6   A6    t6
7   A7    t7
8   A8 t8;t9
9   A9    t9
10 A10   t10
11 A11  t8-8
for (a in list) {
 
 data1_int=data1 %>% filter(Module=={{a}})
 
 data1_int=data1_int$GNE
 
 data2_int=data2 %>% mutate(New1 = map_chr(strsplit(TOT, ";"), ~ str_c(intersect(., data1_int), collapse = ";"))) %>% select(New1)
 
 data2=cbind(data2, data2_int)
 
}
out=data2=data.frame(ID=c("A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "A10", "A11"), 
                     TOT=c("t1;t4", "t2", "t3", "t4", "t5", "t6", "t7", "t8;t9", "t9", "t10", "t8-8"),
                     M1=c("t1", "", "t3", "", "", "", "", "", "", "", ""),
                     M2=c("", "", "", "", "t5", "", "", "", "", "", ""),
                     M3=c("", "t2", "", "", "", "", "", "t8;t9", "t9", "", ""))

     ID   TOT M1 M2    M3
1   A1 t1;t4 t1         
2   A2    t2          t2
3   A3    t3 t3         
4   A4    t4            
5   A5    t5    t5      
6   A6    t6            
7   A7    t7            
8   A8 t8;t9       t8;t9
9   A9    t9          t9
10 A10   t10            
11 A11  t8-8                 

【问题讨论】:

    标签: r dataframe loops dplyr


    【解决方案1】:

    这是一种不使用for 循环的不同方法。

    library(dplyr)
    library(tidyr)
    
    data1 %>%
      filter(GNE %in% data2$TOT) %>%
      mutate(col = GNE) %>%
      complete(Module, GNE = data2$TOT, fill = list(col = '')) %>%
      pivot_wider(names_from = Module, values_from = col) %>%
      left_join(data2, by = c('GNE' = 'TOT')) %>%
      select(ID, GNE, everything()) %>%
      arrange(order(gtools::mixedorder(ID)))
    
    #    ID    GNE   M1    M2    M3   
    #   <chr> <chr> <chr> <chr> <chr>
    # 1 A1    t1    "t1"  ""    ""   
    # 2 A2    t2    ""    ""    "t2" 
    # 3 A3    t3    "t3"  ""    ""   
    # 4 A4    t4    ""    ""    ""   
    # 5 A5    t5    ""    "t5"  ""   
    # 6 A6    t6    ""    ""    ""   
    # 7 A7    t7    ""    ""    ""   
    # 8 A8    t8    ""    ""    "t8" 
    # 9 A9    t9    ""    ""    "t9" 
    #10 A10   t10   ""    ""    ""   
    

    【讨论】:

    • 感谢这个解决方案。这是在处理这些数据,但我意识到我的数据有点复杂,这对它不起作用。原因是在 data2 中,我的一些值被视为两个(或更多)值(对我而言),就像“t1;14”一样。如果 t1 与 data1 中的 M1 一起存在,我希望 t1 在输出的 M1 列中。这里“t1;t4”中data2中的t1被认为与data1中的t1不同。我要比较的是用 ; 分隔的内容。在 data2 中,在 data1 中具有 GNE 的值。这就是我使用 str_split() 的原因。我将用这个案例和另一个案例来更新我的帖子
    【解决方案2】:

    尝试使用data.table(或reshape2)中的dcast

    library(dplyr)
    library(data.table)
    data1 <- data1 %>% as.data.table()
    data2 <- data2 %>% as.data.table()
    
    data2 %>% 
      left_join(data1, by = c("TOT" = "GNE")) %>%   
      dcast(ID + TOT ~ Module, value.var = "TOT", fill = "")
    
    out:
         ID TOT  NA M1 M2 M3
     1:  A1  t1     t1      
     2: A10 t10 t10         
     3:  A2  t2           t2
     4:  A3  t3     t3      
     5:  A4  t4  t4         
     6:  A5  t5        t5   
     7:  A6  t6  t6         
     8:  A7  t7  t7         
     9:  A8  t8           t8
    10:  A9  t9           t9
    

    如果您需要保持ID 的顺序(并删除NA 列):

    data2 %>% 
      left_join(data1, by = c("TOT" = "GNE")) %>%   
      dcast(ID + TOT ~ Module, value.var = "TOT", fill = "") %>% 
      select(-`NA`) %>%
      arrange(order(gtools::mixedorder(ID)))
    
    out:
         ID TOT M1 M2 M3
     1:  A1  t1 t1      
     2:  A2  t2       t2
     3:  A3  t3 t3      
     4:  A4  t4         
     5:  A5  t5    t5   
     6:  A6  t6         
     7:  A7  t7         
     8:  A8  t8       t8
     9:  A9  t9       t9
    10: A10 t10         
    

    编辑后有点复杂:

    data2 %>% 
      tidyr::separate(TOT, into = c("TOT1","TOT2"), sep = "\\;", remove = F) %>% 
      left_join(data1, by = c("TOT1" = "GNE")) %>%
      left_join(data1, by = c("TOT2" = "GNE")) %>%
      
      mutate(TOT2 = ifelse(is.na(Module.y), NA,  TOT2),
             TOT1 = ifelse(is.na(Module.x), NA,  TOT1)) %>%
      tidyr::unite("tmp", c(TOT1, TOT2), na.rm = T, sep = ";") %>%
      mutate(Module = coalesce(Module.x, Module.y)) %>% 
      
      dcast(ID + TOT ~ Module, value.var = "tmp", fill = "") %>%
      select(-`NA`) %>%
      arrange(order(gtools::mixedorder(ID)))
    
    out:
         ID   TOT M1 M2    M3
     1:  A1 t1;t4 t1         
     2:  A2    t2          t2
     3:  A3    t3 t3         
     4:  A4    t4            
     5:  A5    t5    t5      
     6:  A6    t6            
     7:  A7    t7            
     8:  A8 t8;t9       t8;t9
     9:  A9    t9          t9
    10: A10   t10            
    11: A11  t8-8     
    

    【讨论】:

    • 非常感谢这个解决方案。这是在处理这些数据,但我意识到我的数据有点复杂,这对它不起作用。原因是在 data2 中,我的一些值被视为两个值(对我而言),就像“t1;14”一样。如果 t1 与 data1 中的 M1 一起存在,我希望 t1 在输出的 M1 列中。这里“t1;t4”中data2中的t1被认为与data1中的t1不同。我要比较的是用 ; 分隔的内容。在 data2 中,在 data1 中具有 GNE 的值。这就是我使用 str_split() 的原因。我用这个案例和另一个案例更新了我的帖子
    • 检查添加的解决方案
    猜你喜欢
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-10
    • 1970-01-01
    • 2011-03-19
    • 1970-01-01
    • 2021-09-10
    相关资源
    最近更新 更多