如何将唯一重复的列折叠为R中的唯一列?

时间:2019-04-13 21:46:24

标签: r dplyr

解决方案

我接受了下面@MauritsEvers和@akrun提供的解决方案。

问题

对于一个数据框,我只希望保留每组重复列中的1列。此外,保留的列采用的名称是重复列集中所有列名称的串联。数据框中有多组重复的列。数据帧包含数万列,因此使用for循环可能会花费太多时间。

我尝试了以下方法的组合:使用plicate(),summary(),aggregate(),lapply(),apply()和for循环。

输入数据帧(df_in):

0 1 2 3 4 5 6 7
0 1 0 0 1 0 1 1
0 1 0 1 1 0 0 0
1 0 1 0 0 1 1 0

输出数据帧(df_out):

0-2-5 1-4 3 6 7
0     1   0 1 1
0     1   1 0 0
1     0   0 1 0

2 个答案:

答案 0 :(得分:2)

这里是tidyverse的一个选项。我们将数据gather转换为“长”格式,将“值”转换为字符串,然后按“值”分组,paste将“键”列在一起,将“值”的行分开,然后spread的“值”列以获取预期的输出

library(tidyverse)
gather(df_in) %>% 
   group_by(key) %>%
   summarise(value = toString(value)) %>% 
   group_by(value) %>% 
   summarise(key = paste(key, collapse="-")) %>% 
   separate_rows(value) %>% 
   group_by(key) %>%
   mutate(n = row_number()) %>% 
   spread(key, value) %>%
   select(-n)
# A tibble: 3 x 5
#  `0-2-5` `1-4` `3`   `6`   `7`  
#  <chr>   <chr> <chr> <chr> <chr>
#1 0       1     0     1     1    
#2 0       1     1     0     0    
#3 1       0     0     1     0    

否则,带有tidyverse的另一个选项就是

t(df_in) %>%
    as.data.frame %>%
    mutate(grp = group_indices(., V1, V2, V3)) %>%
    mutate(rn = row_number() - 1) %>% 
    group_split(grp, keep = FALSE) %>% 
    map_dfc(~ .x %>% 
           mutate(rn = str_c(rn, collapse="-")) %>% 
           slice(1)  %>% 
           gather(key, val, -rn) %>% 
           rename(!! .$rn[1] := val) %>% 
           select(ncol(.)))
# A tibble: 3 x 5
#  `0-2-5`   `3`   `7`   `6` `1-4`
#    <int> <int> <int> <int> <int>
#1       0     0     1     1     1
#2       0     1     0     0     1
#3       1     0     0     1     0

或者我们也可以使用data.table方法

library(data.table)
dcast(melt(as.data.table(t(df_in))[, grp := .GRP, .(V1, V2, V3)][, 
     c(.SD[1], cn = paste(.I-1, collapse="-")) , .(grp)],
      id.var = c('cn', 'grp')), variable ~ cn, value.var = 'value')[, 
        variable := NULL][]
#    0-2-5 1-4 3 6 7
#1:     0   1 0 1 1
#2:     0   1 1 0 0
#3:     1   0 0 1 0

数据

df_in <- structure(list(`0` = c(0L, 0L, 1L), `1` = c(1L, 1L, 0L), `2` = c(0L, 
 0L, 1L), `3` = c(0L, 1L, 0L), `4` = c(1L, 1L, 0L), `5` = c(0L, 
 0L, 1L), `6` = c(1L, 0L, 1L), `7` = c(1L, 0L, 0L)),
  class = "data.frame", row.names = c(NA, -3L))

答案 1 :(得分:1)

您可以在基本R中执行以下操作

  1. 获取相同列的索引

    idx <- split(seq_along(names(df)), apply(df, 2, paste, collapse = "_"))
    
  2. 从低到高排序索引

    idx <- idx[order(sapply(idx, function(x) x[1]))]
    
  3. idx的名称与列名的关联

    names(idx) <- sapply(idx, function(x) paste(names(df)[x], collapse = "_"))
    
  4. 创建最终的matrix

    sapply(idx, function(x) df[, x[1]])
    #     col0_col2_col5 col1_col4 col3_col6 col7
    #[1,]              0         1         1    1
    #[2,]              0         1         0    0
    #[3,]              1         0         1    0
    

请注意,生成的对象是matrix,因此,如果需要data.frame,只需强制转换as.data.frame


样本数据

我对示例数据进行了一些更改,以使列名没有数字。

df <- read.table(text =
    "col0 col1 col2 col3 col4 col5 col6 col7
0 1 0 1 1 0 1 1
0 1 0 0 1 0 0 0
1 0 1 1 0 1 1 0", header = T)