如何将> 2列数据框转换为2列

时间:2017-08-02 09:51:35

标签: r dplyr

我在转换数据方面遇到了问题。

我有一个数据帧,它告诉我们进行了哪些转换,以及这个转换序列发生了多少次。不同的列对应于时段10,11和12中的情况(并且我的数据中有更多)。我想总结一下这些数据,并想知道人们从A到C,A到D,还有C到G等多少次。所以基本上我想根据第二列的每一列聚合这些数据。我的最终目标是将这些数据转换为sankey图。

举例说明:

df<-data.frame(s10=unlist(strsplit("AAAABBBBBC","")),
           s11=unlist(strsplit("CCDDEEFFFF","")),
           s12=unlist(strsplit("GHIGJKMNNN","")),
           freq=c(10,20,30,40,50,60,70, 40, 20, 20))
   s10 s11 s12 freq
1    A   C   G   10
2    A   C   H   20
3    A   D   I   30
4    A   D   G   40
5    B   E   J   50
6    B   E   K   60
7    B   F   M   70
8    B   F   N   40
9    B   F   N   20
10   C   F   N   20

我的目标是得到这个结果:

     colA  colB     freq    
1    A     C        30
2    A     D        70
3    B     E        110
4    B     F        130
5    C     F        20
6    C     G        10
7    C     H        20
8    D     G        40
9    D     I        30
10   E     J        50
11   E     K        60
12   F     M        70
13   F     N        80

我通过首先聚合s10和s11以及s11和s12的频率总和,然后更改列名并将它们绑定在一起来获得此结果。它适用于,但我打算用更多的列来做到这一点,所以我确信有一种更有效的方法来做到这一点。请参阅我在下面使用的代码:

bl1 <- df %>% 
  group_by(s10, s11) %>% 
  summarise(freq = sum(freq)) %>%
  as.data.frame()
bl2 <- df %>% 
  group_by(s11, s12) %>% 
  summarise(freq = sum(freq)) %>%
  as.data.frame()
colnames(bl1) <- c('colA', 'colB','freq' )
colnames(bl2) <- c('colA', 'colB','freq' )
rbind(bl1, bl2)

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:1)

您可以{data} rbind所选的data.frames列,然后使用aggregate。唯一的技巧是重命名列以使它们匹配。为此,我使用setNames

aggregate(freq ~ colA + colB,
          data=rbind(setNames(df[c("s10", "s11", "freq")], c("colA", "colB", "freq")),
                     setNames(df[c("s11", "s12", "freq")], c("colA", "colB", "freq"))),
          FUN=sum)

这会返回所需的结果。

   colA colB freq
1     A    C   30
2     A    D   70
3     B    E  110
4     B    F  130
5     C    F   20
6     C    G   10
7     D    G   40
8     C    H   20
9     D    I   30
10    E    J   50
11    E    K   60
12    F    M   70
13    F    N   80

答案 1 :(得分:0)

行。我试了一下,并在基准测试中获得了一些乐趣。另一种方法(我使用过)是使用aggregate()本身。有关实现,请参阅fun1。我已经使它适合这个特定的例子,当然它需要调整以处理其他宽度的数据帧

Edit: I have removed dataframe creation from functions and added Benchmarking output1

require(dplyr); require(microbenchmark)


df<-data.frame(s10=unlist(strsplit("AAAABBBBBC","")),
               s11=unlist(strsplit("CCDDEEFFFF","")),
               s12=unlist(strsplit("GHIGJKMNNN","")),
               freq=c(10,20,30,40,50,60,70, 40, 20, 20))

fun0<- function(){

  bl1 <- df %>% 
    group_by(s10, s11) %>% 
    summarise(freq = sum(freq)) %>%
    as.data.frame()
    bl2 <- df %>% 
    group_by(s11, s12) %>% 
    summarise(freq = sum(freq)) %>%
    as.data.frame()
    colnames(bl1) <- c('colA', 'colB','freq' )
    colnames(bl2) <- c('colA', 'colB','freq' )

    return(rbind(bl1, bl2))

}


fun1<- function(){

  a<- apply(df[,c(1,2)], 1, function(x)paste(x[1],x[2], sep="",collapse = "" ))
  b<- apply(df[,c(2,3)], 1, function(x)paste(x[1],x[2], sep="",collapse = "" ))
  z<-data.frame(x=c(a,b),f=rep(df$freq,2))

  return( aggregate(  f~x ,  data=z, FUN=sum) )

}

fun0()
fun1()

#benchmarking 


MB_res <- microbenchmark( fun0=fun0(), fun1=fun1() , times=1000)
MB_res

结果是:

Unit: milliseconds
 expr      min       lq     mean   median       uq      max neval
 fun0 2.218889 2.587820 2.773454 2.676921 2.785586 6.020277  1000
 fun1 1.472971 1.737751 1.908966 1.842152 1.910118 8.915407  1000