【问题标题】:Manipulating variable values using values from another data frame使用来自另一个数据帧的值来操作变量值
【发布时间】:2019-03-07 11:26:22
【问题描述】:

我有一个数据集df,其中的列由各种化学品组成,行由由id 标识的样本和每种化学品的浓度组成。

我需要使用在另一个数据集df2 中找到的每种化学品的唯一值来更正化学品浓度。

这是一个最小的df1 数据集:

df1 <- read.table(text="id,chem1,chem2,chem3,chemA,chemB
1,0.5,1,5,4,3
2,1.5,0.5,2,3,4
3,1,1,2.5,7,1
4,2,5,3,1,7
5,3,4,2.3,0.7,2.3",
header = TRUE,
sep=",")

这是一个df2 示例:

df2 <- read.table(text="chem,value
chem1,1.7
chem2,2.3
chem3,4.1
chemA,5.2
chemB,2.7",
header = TRUE,
sep = ",")

我需要做的是将df1chem1 的所有观察值除以df2chem1 提供的值,对每种化学物质重复。实际上,化学名称是不连续的,大约有 30 种化学物质。

以前我会使用 Excel 和索引/匹配来完成此操作,但我希望使我的方法更具可重复性,因此与 R 进行斗争。我主要使用 dplyr 进行数据操作,所以如果有一个 tidyverse 解决方案那里,那太好了!

感谢您的帮助

【问题讨论】:

    标签: r dplyr


    【解决方案1】:

    我们可以使用 'df2' 中的 'chem' 列对 'df1' 进行子集化,除以复制的 'df2' 的 'value' 列以使长度相同,并通过分配结果返回

    df1[as.character(df2$chem)] <- df1[as.character(df2$chem)]/df2$value[col(df1[-1])]
    

    【讨论】:

    • 在 OP chem1 中,id=1 = 0.5 和 df2 示例中 1.7 的值是 0.5/1.7=0.29 ...我在示例数据上运行您的解决方案并得到 0.17?
    • @Soren 不知道你是怎么得到它的。我收到(df1[as.character(df2$chem)]/df2$value[col(df1[-1])])$chem1[1] #[1] 0.2941176
    • 是的,检查很好,不知道我第一次做了什么! (可能是剩余的环境变量)。谢谢。
    【解决方案2】:

    使用 reshape2 包,可以将数据框更改为长格式以与 df2 合并,如下所示。 (请注意,示例 df 引入了一些在此解决方案中过滤的空格)

    library(reshape2)
    df1 <- read.table(text="id,chem1,chem2,chem3,chemA,chemB
    1,0.5,1,5,4,3
                      2,1.5,0.5,2,3,4
                      3,1,1,2.5,7,1
                      4,2,5,3,1,7
                      5,3,4,2.3,0.7,2.3",
                      header = TRUE,
                      sep=",",stringsAsFactors = F)
    
    df2 <- read.table(text="chem,value
    chem1,1.7
                      chem2,2.3
                      chem3,4.1
                      chemA,5.2
                      chemB,2.7",
                      header = TRUE,
                      sep = ",",stringsAsFactors = F)
    
    df2$chem <- gsub("\\s+","",df2$chem) #example introduces whitespaces in the names
    df1A <- melt(df1,id.vars=c("id"),variable.name="chem")
    
    combined <- merge(x=df1A,y=df2,by="chem",all.x=T)
    combined$div <- combined$value.x/combined$value.y
    head(combined)
    
       chem id value.x value.y       div
    1 chem1  1     0.5     1.7 0.2941176
    2 chem1  2     1.5     1.7 0.8823529
    3 chem1  3     1.0     1.7 0.5882353
    4 chem1  4     2.0     1.7 1.1764706
    5 chem1  5     3.0     1.7 1.7647059
    6 chem2  1     1.0     2.3 0.4347826
    

    或宽格式:

    > dcast(combined[,c("id","chem","div")],id ~ chem,value.var="div")
      id     chem1     chem2     chem3     chemA     chemB
    1  1 0.2941176 0.4347826 1.2195122 0.7692308 1.1111111
    2  2 0.8823529 0.2173913 0.4878049 0.5769231 1.4814815
    3  3 0.5882353 0.4347826 0.6097561 1.3461538 0.3703704
    4  4 1.1764706 2.1739130 0.7317073 0.1923077 2.5925926
    5  5 1.7647059 1.7391304 0.5609756 0.1346154 0.8518519
    

    【讨论】:

      【解决方案3】:

      这是tidyverse 解决方案。

      df3 <- df1 %>%
          # convert the data from wide to long to make the next step easier
          gather(key = chem, value = value, -id) %>%
          # do your math, using 'match' to map values from df2 to rows in df3
          mutate(value = value/df2$value[match(df3$chem, df2$chem)]) %>%
          # return the data to wide format if that's how you prefer to store it
          spread(chem, value)
      

      【讨论】:

      • 这在管道时似乎不起作用。完整的管道返回关于“值”长度的错误。可能是因为 mutate 需要最后创建的 df3 tibble。但是,该方法确实以非管道格式工作: df3
      • 对不起,我不小心把df3留在了最后一行的spread调用中。
      猜你喜欢
      • 2020-07-24
      • 1970-01-01
      • 2020-10-12
      • 1970-01-01
      • 2016-12-20
      • 1970-01-01
      • 2015-01-21
      • 1970-01-01
      • 2021-01-26
      相关资源
      最近更新 更多