如何在R语言中为数据框不同形状行应用对应体积计算公式
问题描述
我需要创建一个R函数,输入是如下结构的数据框:
| Shape | Dim_a | Dim_b | Dim_c |
|---|---|---|---|
| Ellipsoid | 23 | 10 | 23 |
| Rectangular_box | 4 | 65 | 18 |
针对不同的Shape(Ellipsoid、Rectangular_box),用对应公式计算体积:
- Ellipsoid体积公式:
vol = (pi/6) * Dim_a * Dim_b * Dim_c - Rectangular_box体积公式:
vol = Dim_a * Dim_b * Dim_c
输出要新增volume列的数据框。我写了如下代码,但运行后Ellipsoid的体积计算错误,所有行都套用了同一个公式:
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) }
运行结果:
| Shape | Dim_a | Dim_b | Dim_c | vol |
|---|---|---|---|---|
| Ellipsoid | 23 | 10 | 23 | 5290 |
| Rectangular_box | 4 | 65 | 18 | 4680 |
Ellipsoid的正确体积应该是(pi/6)*23*10*23 ≈ 2767.7,但结果用了长方体的公式得到5290,怎么解决?
错误原因分析
- 全局覆盖问题:
any(sel_sp ==1)会检查数据框中是否存在任意一个Ellipsoid,一旦存在就给所有行计算椭球体积;接着any(sel_sp ==2)又检查是否存在长方体,存在的话就把所有行的体积覆盖成长方体公式的结果,最终所有行都用了第二个公式。 - 向量判断逻辑错误:
which(common_sp == Shape)在Shape是向量时,返回的是多个位置值,但你没有对每行做单独的条件判断,无法实现逐行匹配公式的需求。
正确解法
解法1:使用ifelse向量化判断
最直接的向量化方案,适合简单的条件分支:
Biovol3 <- function(data_frame) { # 逐行根据Shape选择对应公式计算体积 data_frame$vol <- ifelse( data_frame$Shape == "Ellipsoid", (pi/6) * data_frame$Dim_a * data_frame$Dim_b * data_frame$Dim_c, data_frame$Dim_a * data_frame$Dim_b * data_frame$Dim_c ) return(data_frame) }
解法2:使用dplyr::case_when(易扩展)
如果后续需要添加更多形状的计算规则,case_when的可读性和扩展性更好:
library(dplyr) Biovol3 <- function(data_frame) { data_frame <- data_frame %>% mutate( vol = case_when( Shape == "Ellipsoid" ~ (pi/6) * Dim_a * Dim_b * Dim_c, Shape == "Rectangular_box" ~ Dim_a * Dim_b * Dim_c, TRUE ~ NA_real_ # 对未定义的Shape返回NA,可根据需求修改 ) ) return(data_frame) }
解法3:循环逐行处理(适合理解逻辑)
如果想手动控制逐行判断,可用for循环:
Biovol3 <- function(data_frame) { # 初始化体积向量,长度与数据框行数一致 vol <- numeric(nrow(data_frame)) for(i in 1:nrow(data_frame)) { if(data_frame$Shape[i] == "Ellipsoid") { vol[i] <- (pi/6) * data_frame$Dim_a[i] * data_frame$Dim_b[i] * data_frame$Dim_c[i] } else if(data_frame$Shape[i] == "Rectangular_box") { vol[i] <- data_frame$Dim_a[i] * data_frame$Dim_b[i] * data_frame$Dim_c[i] } else { vol[i] <- NA_real_ } } data_frame$vol <- vol return(data_frame) }
测试验证
用示例数据测试函数:
test_data <- data.frame( Shape = c("Ellipsoid", "Rectangular_box"), Dim_a = c(23, 4), Dim_b = c(10, 65), Dim_c = c(23, 18) ) Biovol3(test_data)
输出结果:
Shape Dim_a Dim_b Dim_c vol 1 Ellipsoid 23 10 23 2767.701 2 Rectangular_box 4 65 18 4680.000
内容的提问来源于stack exchange,提问作者Kriss
相关产品推荐
相关产品推荐

