【问题标题】:How to match, replace and sum header rows from another dataset in R?如何匹配、替换和求和 R 中另一个数据集的标题行?
【发布时间】:2017-07-15 05:49:34
【问题描述】:

我有两个数据集:

一个。如下所示的数据框:

        SpeciesA  SpeciesB  SpeciesC  SpeciesD  SpeciesE  SpeciesF
Site1     1          0        4        6          2        5
Site2     1          0        4        6          2        5
Site3     1          0        4        6          2        5
Site4     1          0        4        6          2        5

(注意:行值不相同,这里只是为了表示的目的)

b.另一个看起来像这样的数据集:

Family          Species
Family1         SpeciesA
Family1         SpeciesB
Family1         SpeciesC
Family2         SpeciesD
Family3         SpeciesE
Family4         SpeciesF

我想将数据集 (2) 中的 Family 列与 data-frame(1) 中的相应 Species 相匹配,并将同一 Family 下的值(如果有多个物种)相加。我知道我可以使用merge 函数,但是我不知道如何使用它,或者如何在标题行中调用它然后将其全部汇总。

预决赛输出

         Family1    Family1   Family1  Family2  Family3  Family4
Site1     1          0        4        6          2        5 
Site2     1          0        4        6          2        5 
Site3     1          0        4        6          2        5 
Site5     1          0        4        6          2        5 

最终输出

         Family1      Family2    Family3   Family4
Site1     5             6          2        5           
Site2     5             6          2        5             
Site3     5             6          2        5             
Site4     5             6          2        5     

【问题讨论】:

    标签: r merge matching


    【解决方案1】:

    如果我理解正确,您可以将您的第一个 data.frame 从“宽”格式重塑为“长”格式,将 merge 与第二个 data.frame 重塑,然后使用适当的聚合将结果重新转换为宽格式:

    dfa$id <- row.names(dfa)
    mdfa <- reshape2::melt(dfa, id.vars = "id", variable.name = "Species")
    
    reshape2::dcast(
        merge(dfb, mdfa, by = "Species"), 
        id ~ Family, 
        fun.aggregate = sum
    )
    #      id Family1 Family2 Family3 Family4
    # 1 Site1       5       6       2       5
    # 2 Site2       5       6       2       5
    # 3 Site3       5       6       2       5
    # 4 Site4       5       6       2       5
    

    数据:

    dfa <- read.table(text = "SpeciesA  SpeciesB  SpeciesC  SpeciesD  SpeciesE  SpeciesF
    Site1     1          0        4        6          2        5
    Site2     1          0        4        6          2        5
    Site3     1          0        4        6          2        5
    Site4     1          0        4        6          2        5",
    header = TRUE, stringsAsFactors = FALSE)
    
    dfb <- read.table(text = "Family          Species
    Family1         SpeciesA
    Family1         SpeciesB
    Family1         SpeciesC
    Family2         SpeciesD
    Family3         SpeciesE
    Family4         SpeciesF",
    header = TRUE, stringsAsFactors = FALSE)
    

    【讨论】:

      【解决方案2】:

      你可以这样做:

      transform(dfa, Family1=SpeciesA+SpeciesB+SpeciesC, Family2=SpeciesD, Family3=SpeciesE, Family4=SpeciesF)[-(1:6)]
      

      结果如下:

      dfa <- read.table(text = "SpeciesA  SpeciesB  SpeciesC  SpeciesD  SpeciesE  SpeciesF
      Site1     1          0        4        6          2        5
      Site2     1          0        4        6          2        5
      Site3     1          0        4        6          2        5
      Site4     1          0        4        6          2        5",
                        header = TRUE, stringsAsFactors = FALSE)
      # > transform(dfa, Family1=SpeciesA+SpeciesB+SpeciesC, Family2=SpeciesD, Family3=SpeciesE, Family4=SpeciesF)[-(1:6)]
      #       Family1 Family2 Family3 Family4
      # Site1       5       6       2       5
      # Site2       5       6       2       5
      # Site3       5       6       2       5
      # Site4       5       6       2       5
      

      或者你可以做一个矩阵乘法:

      as.matrix(dfa) %*% matrix(c(1,1,1,0,0,0, 0,0,0,1,0,0, 0,0,0,0,1,0, 0,0,0,0,0,1), 6)
      # > as.matrix(dfa) %*% matrix(c(1,1,1,0,0,0, 0,0,0,1,0,0, 0,0,0,0,1,0, 0,0,0,0,0,1), 6)
      #       [,1] [,2] [,3] [,4]
      # Site1    5    6    2    5
      # Site2    5    6    2    5
      # Site3    5    6    2    5
      # Site4    5    6    2    5
      

      dat2 <- read.table(header=TRUE, text=
      "Family          Species
      Family1         SpeciesA
      Family1         SpeciesB
      Family1         SpeciesC
      Family2         SpeciesD
      Family3         SpeciesE
      Family4         SpeciesF")
      

      您可以将矩阵乘法的代码缩短为

      as.matrix(dfa) %*% t(table(dat2)) # or 
      tcrossprod(as.matrix(dfa), as.matrix(table(dat2)))
      

      (tnx 到 @alexis_laz 发表评论)
      .
      另一种基于 R 的解决方案:

      d <- cbind(rowSums(dfa[1:3]), dfa[-(1:3)])
      names(d) <- paste0("Family", 1:4)
      d
      

      【讨论】:

      • 矩阵乘积可以是as.matrix(dat1) %*% t(table(dat2))tcrossprod(as.matrix(dat1), as.matrix(table(dat2)))
      • @alexis_laz tnx 发表评论。我编辑了我的答案。
      • 你可以为几十个物种/地点/科制作一个版本
      • @Ferroao 是的,如果给定数据帧dat2,矩阵乘法可以做到这一点。
      【解决方案3】:

      我对 data.table 或 dplyr 的回答 2:

      data <- read.table(text="
      sites      SpeciesA  SpeciesB  SpeciesC  SpeciesD  SpeciesE  SpeciesF
      Site1     1          0        4        6          2        5
      Site2     1          0        4        6          2        5
      Site3     1          0        4        6          2        5
      Site4     1          0        4        6          2        5" ,  header=TRUE, stringsAsFactors=FALSE)
      famdf <- read.table(text="
      Family          Species
      Family1         SpeciesA
      Family1         SpeciesB
      Family1         SpeciesC
      Family2         SpeciesD
      Family3         SpeciesE
      Family4         SpeciesF" ,  header=TRUE, stringsAsFactors=FALSE)
      
      #My answer 1 with data.table:
      melted<-data.table::melt(data,id.vars="sites", variable.name= "Species")
      
      data.table::dcast(
        setDT(merge(famdf, melted, by = "Species"))[,c("sites","Family","value")], 
        ... ~ Family,
          fun = sum,
        value.var = "value", 
      )
      #end
      #My answer 2 with dplyr or data.table:
      transpose<-function(df){
        n<-df[,1]
        df <- as.data.frame(t(df[,-1]))
        colnames(df) <- n
        df$id<-factor(row.names(df))
        return(df)
        }
      data<-transpose(data)
      data$fam<-fam$Family[match(data$id, fam$Species)]
      data <- subset(data, select = -id )
      
      #Sum option 1 data.table
      library(data.table)
      transpose(setDF(setDT(data)[, lapply(.SD,sum), by = .(fam)]))
      #Sum option 2 dplyr
      library(dplyr)
      result<-as.data.frame(data %>%
        group_by(fam) %>%
        summarise_each(funs(sum))
      )
      transpose(result)
      

      【讨论】:

        【解决方案4】:

        这是另一个带有查找表(命名向量)和rowSums 的基本 R 解决方案。

        # get lookup table
        lookup <- setNames(dfb$Species, dfb$Family)
        # get corresponding column positions with match
        colPos <- names(lookup)[match(names(dfa), lookup)]
        
        # return data.frame with named columns
        setNames(data.frame(lapply(unique(names(lookup)),
                                   function(i) rowSums(dfa[i == colPos]))),
                 unique(names(lookup)))
        

        返回

              Family1 Family2 Family3 Family4
        Site1       5       6       2       5
        Site2       5       6       2       5
        Site3       5       6       2       5
        Site4       5       6       2       5
        

        在第二行中,match 用于查找对应的列位置。在第三行中,lapply 遍历唯一的家族名称并将rowSums 应用于与这些名称对应的列。这将返回一个列表,该列表被转换为data.frame,并以setNames 命名。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-03-21
          • 1970-01-01
          • 2015-10-24
          • 1970-01-01
          • 1970-01-01
          • 2020-09-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多