Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
892 views
in Technique[技术] by (71.8m points)

r - Divide all columns by a chosen column using mutate_all

I have a sample data frame that looks like this (my full dataframe has "d" plus 57 elements):

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"

The Detrital_Divisor can change based on the user input but will always be a column in the "example" dataframe. I would like to divide all the remaining columns by the Detrital_Divisor column, preferably using a pipe. Right now I have:

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

But I get the error:

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

I have also tried:

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

based on similar questions that have been asked on this forum but I just can't get it to work. I get the error

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

I know this question is somewhat repetitive but the other answers I have found are not working in my situation. My entire data frame has 57 elements so writing code to divide each column individually would be very long.

Thanks in advance for any advice.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Something like this perhaps:

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)

I know you said you'd like to see a mutate_all solution, but I guess you don't want to divide Zr by itself?

In this case mutate_at is more helpful, otherwise you can do mutate_all(funs(. / Zr)).

If you want to keep the mentioned vector:

Detrital_Divisor <- as.symbol("Zr")

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

UPDATE (dplyr 0.8.0)

Now that funs is deprecated as of dplyr 0.8.0, you can just use ~, e.g.:

Detrital_Divisor <- as.symbol("Zr")

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

On the other hand there's also list - useful for mutating in multiple ways or naming the output, e.g.:

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

UPDATE (dplyr 1.0.0)

As of dplyr 1.0.0, you would probably want to use across:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...