R:使用行作为行和的分组向量

时间:2012-10-08 18:40:00

标签: r dataframe plyr rowsum

如果我的数据集如下:

Cohort Food1 Food2 Food 3 Food 4
--------------------------------
Group   1     1     2       3
 A      1     1     0       1
 B      0     0     1       0
 C      1     1     0       1
 D      0     0     0       1

我想对每一行求和,在那里我可以将食物组定义为不同的类别。所以我想使用Group行作为定义向量。

这意味着食物1和食物2在第1组中,食物3在第2组中,食物4在第3组中。

理想的输出类似于:

Cohort Group1 Group2 Group3
 A      2       0      1
 B      0       1      0
 C      2       0      1
 D      0       0      1

我尝试使用这个基于rowum()的函数,但没有运气,我是否需要使用ddply()?

评论中的示例数据:

dat <-
structure(list(species = c("group", "princeps", "bougainvillei", 
"hombroni", "lindsayi", "concretus", "galatea", "ellioti", "carolinae", 
"hydrocharis"), locust = c(1L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 0L, 
0L), grasshopper = c(1L, 0L, 0L, 1L, 0L, 0L, 1L, 0L, 1L, 0L), 
    snake = c(2L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L), fish = c(2L, 
    1L, 0L, 1L, 1L, 0L, 1L, 0L, 1L, 0L), frog = c(2L, 0L, 0L, 
    0L, 0L, 0L, 0L, 1L, 0L, 0L), toad = c(2L, 0L, 0L, 0L, 0L, 
    1L, 0L, 0L, 0L, 0L), fruit = c(3L, 0L, 0L, 0L, 0L, 1L, 1L, 
    0L, 0L, 0L), seed = c(3L, 0L, 0L, 0L, 0L, 1L, 0L, 0L, 0L, 
    0L)), .Names = c("species", "locust", "grasshopper", "snake", 
"fish", "frog", "toad", "fruit", "seed"), class = "data.frame", row.names = c(NA, 
-10L))

2 个答案:

答案 0 :(得分:2)

最有可能采用更直接的方法,但这是您可以尝试的方法:

  1. 首先,创建数据副本减去第二个标题行。

    dat2 <- dat[-1, ]
    
  2. 来自“reshape2”包的
  3. melt()dcast()等不能很好地处理重复的列名,所以让我们使列名更“适合reshape2”。

    Seq <- ave(as.vector(unlist(dat[1, -1])), 
               as.vector(unlist(dat[1, -1])), 
               FUN = seq_along)
    names(dat2)[-1] <- paste("group", dat[1, 2:ncol(dat)], 
                             ".", Seq, sep = "")
    
  4. melt()数据集

    m.dat2 <- melt(dat2, id.vars="species")
    
  5. 使用colsplit()功能正确拆分列。

    m.dat2 <- cbind(m.dat2[-2], 
                    colsplit(m.dat2$variable, "\\.", 
                             c("group", "time")))
    head(m.dat2)
    #         species value  group time
    # 1      princeps     0 group1    1
    # 2 bougainvillei     0 group1    1
    # 3      hombroni     1 group1    1
    # 4      lindsayi     0 group1    1
    # 5     concretus     0 group1    1
    # 6       galatea     0 group1    1
    
  6. 像往常一样继续dcast()

    dcast(m.dat2, species ~ group, sum)
    #         species group1 group2 group3
    # 1 bougainvillei      0      0      0
    # 2     carolinae      1      1      0
    # 3     concretus      0      2      2
    # 4       ellioti      0      1      0
    # 5       galatea      1      1      1
    # 6      hombroni      2      1      0
    # 7   hydrocharis      0      0      0
    # 8      lindsayi      0      1      0
    # 9      princeps      0      1      0
    
  7. 注意:已编辑,因为原始答案不正确。

    更新:基础R

    中更简单的方法

    如果您从转置数据开始,就可以轻松解决此问题

    dat3 <- t(dat[-1, -1])
    dat3 <- as.data.frame(dat3)
    names(dat3) <- dat[[1]][-1]
    t(do.call(rbind, lapply(split(dat3, as.numeric(dat[1, -1])), colSums)))
    #               1 2 3
    # princeps      0 1 0
    # bougainvillei 0 0 0
    # hombroni      2 1 0
    # lindsayi      0 1 0
    # concretus     0 2 2
    # galatea       1 1 1
    # ellioti       0 1 0
    # carolinae     1 1 0
    # hydrocharis   0 0 0
    

答案 1 :(得分:1)

你可以很容易地使用base R来做到这一点。这是一个例子。

首先,弄清楚哪些动物属于哪一组:

groupings <- as.data.frame(table(as.numeric(dat[1,2:9]),names(dat)[2:9]))

attach(groupings)
grp1 <- groupings[Freq==1 & Var1==1,2]
grp2 <- groupings[Freq==1 & Var1==2,2]
grp3 <- groupings[Freq==1 & Var1==3,2]
detach(groupings)

然后,使用这些组在正确的列上执行rowSums()

dat <- cbind(dat,rowSums(dat[as.character(grp1)]))
dat <- cbind(dat,rowSums(dat[as.character(grp2)]))
dat <- cbind(dat,rowSums(dat[as.character(grp3)]))

删除初始行和中间列:

dat <- dat[-1,-c(2:9)]

然后,只需正确重命名:

row.names(dat) <- rm()
names(dat) <- c("species","group_1","group_2","group_3")

你最终得到:

      species group_1 group_2 group_3
bougainvillei       0       0       0
    carolinae       1       1       0
    concretus       0       2       2
      ellioti       0       1       0
      galatea       1       1       1
     hombroni       2       1       0
  hydrocharis       0       0       0
     lindsayi       0       1       0
     princeps       0       1       0

已编辑:将排序顺序更改为按字母顺序排列,与其他答案一样。