如何从多个配对列传播/收集数据

时间:2018-03-08 17:41:15

标签: r tidyr

如何使用dplyr/tidyr来转换数据框,如下所示:

df <- data.frame(obj=c(1,1,2,2,3,3,3,4,4,4),
             S1=rep(c("a","b"),length.out=10),S1PR=rep(c(3,7),length.out=10),
             S2=rep(c("c","d"),length.out=10),S2PR=rep(c(7,3),length.out=10),
             Relsize=c(.4,.6,.4,.6,.2,.2,.6,.2,.2,.6))


   obj S1 S1PR S2 S2PR Relsize
1    1  a    3  c    7     0.4
2    1  b    7  d    3     0.6
3    2  a    3  c    7     0.4
4    2  b    7  d    3     0.6
5    3  a    3  c    7     0.2
6    3  b    7  d    3     0.2
7    3  a    3  c    7     0.6
8    4  b    7  d    3     0.2
9    4  a    3  c    7     0.2
10   4  b    7  d    3     0.6

然后把它变成这样的一个:

obj  a    b    c    d
 1  0.12 0.42 0.28 0.18
 2  0.12 0.42 0.28 0.18
 3  0.24 0.14 0.56 0.06

输出数据框中的值基于PR / 10 * Relsize。编辑:对于同一物种有多个条目,他们应该总结我一直试图通过传播和聚集的一些组合来做这个,但我不知道该怎么做。

4 个答案:

答案 0 :(得分:1)

使用基数R:

 df <- data.frame(stringsAsFactors = F,obj=c(1,1,2,2,3,3,3,4,4,4),
                                 S1=rep(c("a","b"),length.out=10),S1PR=rep(c(3,7),length.out=10),
                                   S2=rep(c("c","d"),length.out=10),S2PR=rep(c(7,3),length.out=10))
 df$Relsize=c(0.4,0.6,.4,.6,.2,.2,.6,.2,.2,.6)
 #Create the next two columns required:. I will call them `oo and pp`
 df1=transform(df,oo=S1PR*Relsize/10,pp=S2PR*Relsize/10)

按列obj,s1 and s2进行分组并对oo and pp执行总和,我们使用aggregate

m=aggregate(.~obj+S1+S2,df1,sum)#aggregate(cbind(oo,pp)~obj+S1+S2,df1,sum)

现在重新排列结果数据帧,如图所示,列S1,S2的内容应该是新的列名,而oo,pp的内容应该在这些列中传播。我们使用unstack

unstack(m,cbind(oo,pp)~cbind(S1,S2))
     a    b    c    d
1 0.12 0.42 0.28 0.18
2 0.12 0.42 0.28 0.18
3 0.24 0.14 0.56 0.06
4 0.06 0.56 0.14 0.24

答案 1 :(得分:1)

另一种选择可能是使用reshape2中的library(tidyverse) library(reshape2) df_mod <- df %>% mutate(S1PR = (S1PR/10)*Relsize, S2PR = (S2PR/10)*Relsize) %>% select(-Relsize) bind_rows(x = select(df_mod,obj, S := S1, PR := S1PR), y = select(df_mod, obj, S := S2, PR :=S2PR)) %>% dcast(obj ~ S, sum) # obj a b c d #1 1 0.12 0.42 0.28 0.18 #2 2 0.12 0.42 0.28 0.18 #3 3 0.24 0.14 0.56 0.06 #4 4 0.06 0.56 0.14 0.24 到达:

df <- data.frame(obj=c(1,1,2,2,3,3,3,4,4,4),
                 S1=rep(c("a","b"),length.out=10),S1PR=rep(c(3,7),length.out=10),
                 S2=rep(c("c","d"),length.out=10),S2PR=rep(c(7,3),length.out=10),
                 Relsize=c(.4, .6, .4, .6, .2, .2, .6, .2, .2, .6),
                 stringsAsFactors = FALSE)

数据

{{1}}

答案 2 :(得分:1)

使用dplyr和tidyr,但与MKR的解决方案相同。

OP没有说明求和是否正确。

也许bind_rows可能更优雅但似乎到目前为止所有的建议都做了类似的事情。

df %>% 
    as_data_frame %>% 
    mutate(Relsize=c(0.4,0.6,.4,.6,.2,.2,.6,.2,.2,.6)) %>% 
    mutate(S1PR = (S1PR/10)*Relsize, S2PR = (S2PR/10)*Relsize) %>%  
    {bind_rows(select(., obj, S = S1, PR = S1PR),
               select(., obj, S = S2, PR = S2PR)
               )
    } %>% 
    group_by(obj, S) %>% 
    summarise(PR=sum(PR)) %>% 
    spread(S, PR)

答案 3 :(得分:0)

我想出了一种避免使用bind_rows

的方法
  df %>% 
    unite(S1_S1PR, contains("S1")) %>% 
    unite(S2_S2PR, contains("S2")) %>% 
    gather(x, Species, S1_S1PR, S2_S2PR) %>% 
    separate(Species, into = c("Species","PR"), convert = T) %>% 
    group_by(obj, Species) %>% 
    mutate(PR = sum(PR/10*Relsize)) %>% 
    select(-x, -Relsize) %>% distinct() %>% 
    spread(Species, PR)

它更具可读性,但需要更多步骤。我发现我经常在生态学中看到这样的数据,其中每一行都是一个位置,并且有一组像SX和SXPR这样的列,它们被重复用于该位置的第一,第二和第三最常见的物种。能够使用dplyr的漂亮选择助手获得所有匹配的列对于许多列非常有用