简体   繁体   中英

R: Caculating new variable by category with a different equation for each category

I have been searching an answer to this for a while but nothing seems to fit me.

I have a dataframe called "data" that looks like this:

Species Length Weight
A 15 0
A 8 0
B 20 0
C 4 0
B 11 0
B 16 0
C 13 0

What I would like to do is to calculate the weight of each individual of a species based on their length ant fill the Weigth column with the results. For that purpose, I have already obtained an equation for each species, since each species has a different length-weight relation. Lets say those length-weight equations look as follows:

  • "A" species: weight=length*2
  • "B" species: weight=length^3
  • "C" species: weight=length/5

So, as a result, I would like to have have a dataframe that looks like this:

Species Length Weight
A 15 30
A 8 16
B 20 8000
C 4 0.8
B 11 1331
B 16 4096
C 13 3.6

I have tried to do it this way:

Species <- c("A", "A", "B", "C", "B","B","C")
Length <- c(15,8,20,4,11,16,13)
Weight <- c(0,0,0,0,0,0,0)
data <- data.frame(Species, Length, Weight)

for(i in 1:length(data$Length)){if(data$Species[i]=="A"){
data$Weight[i]<-data$Length[i]*2
}else if(data$Species[i]=="B"){
data$Weight[i]<-data$Length[i]^3
}else if(data$Species=="C"){
data$Weight[i]<-data$Length[i]/5
} else {data$Weight[i]<-"NA"}
}

The code runs without error, but the data$Weigth column is not filled with the results. However, when I tried the code without using for() and replacing [i] with a row number (for example [4]), it did the correct thing and fills the Weight column with the result for that row.

In reality I have 40 species and over 5000 observations, so running the code for each row individually is not an option.

Any suggestions? Maybe there is an easier way but I don´t see it? Any help will be much appreciated.

Thanks

In base R you could do:

transform(df, 
  Weight = Vectorize(\(x, type) switch(type, A = x*2, B= x^3, C =x/5))(Length, Species))

  Species Length Weight
1       A     15   30.0
2       A      8   16.0
3       B     20 8000.0
4       C      4    0.8
5       B     11 1331.0
6       B     16 4096.0
7       C     13    2.6

library(tidyverse)
df %>%
  mutate(Weight = case_when(Species == 'A' ~Length * 2,
                            Species == 'B' ~ Length ^ 3,
                            Species == 'C' ~ Length / 5))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM