自定义R函数结果无法正确保留两位小数问题求助
问题背景
数据示例
dput(per_stack[1:4,])
输出结果:
structure(list(articles_ponderats2_migpunts = c(20.2083333333333, 20.6666666666667, 23.8333333333333, 15.1666666666667), Tramspoblacio = structure(c(5L, 4L, 4L, 4L), .Label = c("1 - 999", "1000 - 4999", "5000 - 9999", "10000 - 19999", "20000 - 49999", "50000 - 99999", "100000 - 200000", "Mayor de 200000"), class = "factor")), row.names = c(NA, 4L), class = "data.frame")
自定义汇总函数
funcio_resum <-function(x) { n<-NROW(x) mean<-mean(x) median <- median (x) min<-min (x) max<-max(x) q1 <- quantile(x, .25) q3 <- quantile(x, .75) SD<- sd(x) IQR <- IQR(x) quantile <- quantile(x, probs=seq(.1,.9, by =.1)) hist<-hist(x) summary<-list(n=n,mean=mean, median = median, max=max,min=min, SD=SD, IQR = IQR) return(summary) }
执行代码与报错
生成汇总表的代码:
resum <- tapply(index_articles_migpunts$articles_ponderats2_migpunts, index_articles_migpunts$Tramspoblacio, funcio_resum) resum <- do.call (rbind, resum)
尝试用dplyr执行保留小数操作时报错:
resum %>% round(digits = 2)
错误信息:
Error in round(., digits = 2) : non-numeric argument to mathematical function
在函数内对均值、中位数等指标使用round后,结果仅显示整数(如显示8而非7.88),需排查原因。
问题原因与解决方法
1. round报错的核心原因
你猜测的hist对象并非关键问题(因为你没把它放进返回的summary列表),真正原因是:
tapply结合返回列表的函数后,得到的是分组列表;用do.call(rbind, resum)绑定后生成的是列表矩阵,每个单元格是单个数值的列表,而非直接的数值类型。这种结构下,round无法识别为可运算的数值向量,因此报错。
2. 函数内round只显示整数的原因
列表矩阵的元素是长度为1的列表,R在打印这类结构时会自动简化显示,导致原本保留两位小数的数值被截断为整数(实际值仍存在,但显示异常)。
3. 解决办法
方法一:修改自定义函数,返回数据框而非列表
将函数返回改为数据框,这样tapply后绑定得到的是标准数据框,可直接处理:
funcio_resum <-function(x) { n <- NROW(x) mean_val <- round(mean(x), 2) median_val <- round(median(x), 2) min_val <- round(min(x), 2) max_val <- round(max(x), 2) SD_val <- round(sd(x), 2) IQR_val <- round(IQR(x), 2) data.frame(n = n, mean = mean_val, median = median_val, max = max_val, min = min_val, SD = SD_val, IQR = IQR_val) }
执行代码:
resum <- tapply(index_articles_migpunts$articles_ponderats2_migpunts, index_articles_migpunts$Tramspoblacio, funcio_resum) resum <- do.call(rbind, resum) # 此时可直接使用round,或函数内已完成保留小数 resum <- resum %>% round(digits = 2)
方法二:将列表矩阵转换为数值矩阵
无需修改函数,直接转换现有结构:
# 提取列表矩阵中的数值,转为数值矩阵 resum_num <- apply(resum, c(1,2), function(x) x[[1]]) # 保留两位小数 resum_num <- round(resum_num, 2)
方法三:用dplyr分组汇总更简洁
直接使用dplyr的分组功能,避免结构问题:
library(dplyr) resum <- index_articles_migpunts %>% group_by(Tramspoblacio) %>% summarize( n = n(), mean = round(mean(articles_ponderats2_migpunts), 2), median = round(median(articles_ponderats2_migpunts), 2), min = round(min(articles_ponderats2_migpunts), 2), max = round(max(articles_ponderats2_migpunts), 2), SD = round(sd(articles_ponderats2_migpunts), 2), IQR = round(IQR(articles_ponderats2_migpunts), 2) )
内容的提问来源于stack exchange,提问作者FrancoBattiato
相关产品推荐
相关产品推荐

