R语言 如何对数据框中同一列中的每一行执行不同的操作

nmpmafwu  于 2023-06-19  发布在  其他
关注(0)|答案(4)|浏览(157)

我想创建一个R函数,其中输入数据将是具有以下结构的 Dataframe :
| 形状|尺寸a|尺寸B| Dim_c|
| - -----|- -----|- -----|- -----|
| 椭球面|二十三|十个|二十三|
| 矩形箱|4|六十五|十八岁|
而且,对于每种不同的形状(即“椭圆形”、“矩形盒”),我想使用不同的方程来计算体积,使用各自的尺寸值(即“Dim_a”、“Dim_b”、“Dim_c”)。
例如,对于“椭球”形状,计算体积的公式为:
vol = (pi/6) * Dim_a * Dim_b * Dim_c(等式第一章
对于'Rectangular_box',等式为:
vol = Dim_a * Dim_b * Dim_c(等式2)
所以,在我的R函数中,我想做“如果椭球形状,那么使用eq。1,但如果是矩形形状,则使用eq. 2”。
输出是一个新列,其中包含每个不同形状的体积计算结果。
我想这么做

Biovol3 <- function(data_frame){ #The input is a data frame
  
# The variables are: 'Shape' and the different dimentions 'Dim_a', 'Dim_b', 'Dim_c' that must be included in the data frame

  Shape <- data_frame$Shape
  Dim_a <- data_frame$Dim_a
  Dim_b <- data_frame$Dim_b
  Dim_c <- data_frame$Dim_c

# Then I tried to use 'which' function to select the shape
 
common_sp <- c("Ellipsoid", "Rectangular_box") # common shapes that must be included in the 'shape' column                 in the data frame

  sel_sp <- which(common_sp == Shape)

# Using 'if' statement to calculate the volume for each different shape
  
  if(any(sel_sp == 1)){
      
      vol = (pi/6) * Dim_a * Dim_b * Dim_c
    }
    
  if(any(sel_sp == 2)){
    
    vol = Dim_a * Dim_b * Dim_c
    }
  
# The output must be a data frame with a new column 'volume'
 
 result_data_frame <- data.frame(data_frame,
                                  vol = unname(vol),
                                  Area = unname(Area)) 
  
  return(result_data_frame)
}

这将返回以下 Dataframe 作为结果:
| 形状|尺寸a|尺寸B| Dim_c|卷|
| - -----|- -----|- -----|- -----|- -----|
| 椭球面|二十三|十个|二十三|五二九零|
| 矩形箱|4|六十五|十八岁|四六八○|
但椭球体体积的计算结果是不正确的。我注意到,这是因为函数只使用其中一个方程(在本例中,方程。2),在两种形状中,我不知道如何使用对应于不同形状的不同方程。

5tmbdcev

5tmbdcev1#

在Base R中,你可以:

frac <- c(Ellipsoid = pi/6, Rectangular_box = 1)
df$vol <- frac[df$Shape] * df$Dim_a * df$Dim_b * df$Dim_c
df
            Shape Dim_a Dim_b Dim_c      vol
1       Ellipsoid    23    10    23 2769.838
2 Rectangular_box     4    65    18 4680.000
xytpbqjk

xytpbqjk2#

对于两个选项,ifelse是一个很好的选项。如果你想要更可扩展的东西,case_whencase_match更好。
mutatecase_whencase_match都来自dplyr封装,而case_match需要一个非常新的版本。
case_match可能更简洁一些,如果你的决定仅仅基于Shape,并且你有一个最新版本的dplyr

df %>%
  mutate(
    vol = case_match(Shape,
       "Ellipsoid"       ~ (pi/6) * Dim_a * Dim_b * Dim_c,
       "Rectangular_box" ~ Dim_a * Dim_b * Dim_c,
       "Pyramid" ~ Dim_a * Dim_b * Dim_c / 3,
       .default ~ NA # default behavior, but modifiable here
    )
  )

如果条件基于多个变量,则case_when更灵活

df %>%
  mutate(
    vol = case_when(
       Shape == "Ellipsoid"       ~ (pi/6) * Dim_a * Dim_b * Dim_c,
       Shape == "Rectangular_box" ~ Dim_a * Dim_b * Dim_c,
       Shape == "Pyramid"         ~ Dim_a * Dim_b * Dim_c / 3,
       TRUE                       ~ NA  # default behavior, but modifiable here
    )
  )

使用这两种功能中的任何一种,您都可以根据需要创建任意多个形状(例如我添加的金字塔示例)

jhkqcmku

jhkqcmku3#

您可以使用mutateifelse

df %>% mutate (
        vol = ifelse(df$Shape %in% 'Ellipsoid',
            (pi/6) * Dim_a * Dim_b * Dim_c),
            Dim_a * Dim_b * Dim_c
    )
sg2wtvxw

sg2wtvxw4#

虚拟数据:

library(tidyverse)
df1 <- tribble(~Shape,  ~Dim_a, ~Dim_b, ~Dim_c,
               "Ellipsoid", 23, 10, 23,
               "Rectangular_box",   4,  65, 18)

您可以创建一个包含函数的列表(与“shape”同名):

fun_list <- list(Ellipsoid = function(Dim_a, Dim_b, Dim_c) {(pi/6) * Dim_a * Dim_b * Dim_c},
                 Rectangular_box = function(Dim_a, Dim_b, Dim_c) {Dim_a * Dim_b * Dim_c})

使用purrr::transpose创建一个列表,其中 Dataframe 的每一行都是行:

transpose(select(df1, c(Dim_a,  Dim_b,  Dim_c))

现在,您可以使用purrr::map2do.call应用到fun_list[df1$Shape]和上面的行列表的每个组合:

map2_dbl(fun_list[df1$Shape], 
         transpose(select(df1, c(Dim_a, Dim_b,  Dim_c))),
         do.call)

   Ellipsoid       Rectangular_box 
   2769.838        4680.000

相关问题