使用mutate_all将所有列除以所选列

16

我有一个示例数据框,它看起来像这样(我的完整数据框有"d"加上57个元素):

d <- seq(0, 100, 0.5) 
Fe <- runif(201, min = 0, max = 1000) 
Ca <- runif(201, min = 0, max = 1000) 
Zr <- runif(201, min = 0, max = 1000) 
Ti <- runif(201, min = 0, max = 1000) 
Al <- runif(201, min = 0, max = 1000) 
example <- data.frame(d, Fe, Ca, Zr, Ti, Al)
Ratio_Elements <- c("Fe", "Ti", "Zr", "d") #this subset of the 
dataframe is user defined
Detrital_Divisor <- "Zr"

Detrital_Divisor可能会根据用户输入而更改,但它将始终是“example”数据帧中的一列。 我想使用管道将所有剩余列除以Detrital_Divisor列。 目前我有:

Example_Ratio <- example %>%
select (Ratio_Elements) #to subset to the user selected elements
mutate_all(./Detrital_Divisor)

但是我收到了错误:

Error in Ops.data.frame(., Detrital_Divisor) : 
  ‘/’ only defined for equally-sized data frames.

我也尝试过:

Example_Ratio <- example %>%
select (Ratio_Elements)
sweep(., Detrital_Divisor, MARGIN = 1, '/')

基于在该论坛上类似的问题,但我就是无法让它工作。我收到了以下错误信息:

    `Error in Ops.data.frame(x, aperm(array(STATS, dims[perm]), order(perm)),  : 
  list of length 206340 not meaningful.`

我知道这个问题有点重复,但是其他我找到的答案在我的情况下都不起作用。我的整个数据框中有57个元素,因此编写将每列单独分开的代码会非常冗长。

提前感谢任何建议。


抱歉,第一个代码块中的注释应包括下一行文本,即整个注释应为#此数据框的子集是用户定义的。 - JJGabe
2个回答

27

也许类似这样:

library(tidyverse)

d <- seq(0, 100, 0.5) 
Fe <- runif(201, min = 0, max = 1000) 
Ca <- runif(201, min = 0, max = 1000) 
Zr <- runif(201, min = 0, max = 1000) 
Ti <- runif(201, min = 0, max = 1000) 
Al <- runif(201, min = 0, max = 1000) 
example <- data.frame(d, Fe, Ca, Zr, Ti, Al)
Ratio_Elements <- c("Fe", "Ti", "Zr", "d") #this subset of the 

Example_Ratio <- example %>%
  mutate_at(vars(-Zr), funs(. / Zr)) %>%
  select(Ratio_Elements)

我知道你说你想看到一个mutate_all的解决方案,但我猜你不想把Zr除以它本身?

在这种情况下,mutate_at更有帮助,否则你可以使用mutate(across(everything(), ~ . / Zr))

如果你想保留提到的向量,至少有两种选择。

要么通过as.symbol将其转换为名称,然后使用!!如下所示:

Detrital_Divisor <- as.symbol("Zr")

Example_Ratio <- example %>%
  mutate(across(-Detrital_Divisor, ~ . / !! Detrital_Divisor)) %>%
  select(all_of(Ratio_Elements))

或者使用.data代词并将其保留为字符/纯字符串:


Detrital_Divisor <- "Zr"

Example_Ratio <- example %>%
  mutate(across(-Detrital_Divisor, ~ . / .data[[Detrital_Divisor]])) %>%
  select(all_of(Ratio_Elements))

dplyr 版本 < 1.0.0

dplyr 版本小于 1.0.0 的情况下,您无法使用 across。 然而,在 0.81.0 中,您可以执行以下操作:

Detrital_Divisor <- as.symbol("Zr")

Example_Ratio <- example %>%
  mutate_at(vars(- !! Detrital_Divisor), ~ . / !! Detrital_Divisor) %>%
  select(Ratio_Elements)

另一方面,还有list-用于以多种方式进行突变或命名输出,例如:

Example_Ratio <- example %>%
  mutate_at(vars(- !! Detrital_Divisor), list(appended_name = ~ . / !! Detrital_Divisor))

0.8.0之前的版本中,存在已弃用的funs函数:

Detrital_Divisor <- as.symbol("Zr")

Example_Ratio <- example %>%
  mutate_at(vars(- !! Detrital_Divisor), funs(. / !! Detrital_Divisor)) %>%
  select(Ratio_Elements)

谢谢 @arg0naut,方法是行得通的。似乎只是我输入的顺序有误……应该先进行突变,然后再选择。你知道我怎样能够改变代码以使用我上面列出的 Detrital_Divisor 向量吗?像这样: mutate_at(vars(-Detrital_Divisor), funs(. / Detrital_Divisor)) - JJGabe
没错, 这样做就可以了。不过我好奇,您知道为什么我可以按照我写的那样在那个字符串上使用 select 函数,但是为了执行你的操作,您将 Detrital_Divisor 设置为 as.symbol 了吗?把 Ratio_Elements 也设置为 as.symbol 会更好吗? - JJGabe
1
你可以尝试并查看你会得到什么错误。很可能它会说你有一个一元运算符(即减号),而你不能否定一个字符串,这就是为什么要加引号。如果你想排除那些列,以同样的方式设置Ratio_Elements是有意义的。在你目前的情况下,我认为这不是必要的。 - arg0naut91
1
@arg0naut91 如果你使用 .data [[]],你可以将 "Zr" 保留为纯字符串。那么代码就变成了: example %>% mutate(across(-all_of(Detrital_Divisor), ~./.data[[Detrital_Divisor]])) %>% select(all_of(Ratio_Elements)) - Dan Adams
1
请查看rlang博客文章 - Dan Adams
显示剩余4条评论

3

以下是对 @arg0naut91 的回答进行的更新(dplyr 1.0.0 版本):

Example_Ratio <- example %>% 
  mutate(across(everything()), . / Zr) %>% 
  select(Ratio_Elements)

1
你还需要加上波浪线 ~,我想。 - Simon Woodward

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接