很多时候,数据如年龄是以范围形式给出的。我想计算这些范围的均值。我能够计算出来,但是我觉得可能有更优雅且可能更快的方法。
这是一个工作示例:
age <- c("0-10", "11-20", "21-30", "31-40") # 定义年龄范围向量
age_split<-strsplit(age,"-") # 按"-"分割,得到分割后的列表
for(ii in 1:length(age)){
age[ii] <- mean(as.numeric(unlist(age_split[ii])))}
print(age)
## [1] "5" "15.5" "25.5" "35.5"
根据lmo和akron的建议,这里是可以从各种方法中进行性能测试的代码:
irows = 100000
data1 <- paste0(sample(1:10, irows, replace = TRUE),"-", sample(11:20, irows, replace = TRUE))
data2 <- data1; data3 <- data1; data4 <- data1 # 复制用于测试不同方法
#--方法1 -- 最初提出的
a1<-Sys.time()
age_split<-strsplit(data1,"-")
for(ii in 1:length(data1)){
data1[ii] <- mean(as.numeric(unlist(age_split[ii])))}
Sys.time()-a1
# 方法2 (lmo建议)
a2<-Sys.time()
data2 <- sapply(strsplit(data2, split="-"), function(i) mean(as.numeric(i)))
Sys.time()-a2
# 方法3 (akron的提示)
a3<-Sys.time()
age_split_matrix <-do.call(rbind, strsplit(data3,"-"))
class(age_split_matrix) <- "numeric"
data3<-rowMeans(age_split_matrix)
Sys.time()-a3
# 方法4 (akron建议)
a4<-Sys.time()
data4 <-rowMeans(read.table(text=data4, sep = "-"))
Sys.time()-a4
# 验证输出是否匹配
all.equal(as.numeric(data1),data2)
all.equal(as.numeric(data1),data3)
all.equal(as.numeric(data1),data4)
当irow = 10万时,方法1到4所需的时间分别是:(1) 2.5秒 (2) 1.4秒 (3) 0.34秒 (4) 6.3秒。当irow = 100万时,时间为(1) 23秒 (2) 14秒 (3) 6秒 (4) 非常长。当irow=1000万时,时间为(1) 3.9分钟 (2) 2.9分钟 (3) 非常长。这让我得出结论,read.table确实很慢。方法3占用大量内存。
回答:
这里是一个使用sapply
的一行代码:
sapply(strsplit(age, split="-"), function(i) mean(as.numeric(i)))
[1] 5.0 15.5 25.5 35.5
strplit
按”-“分割字符串并返回一个列表,该列表被传递给sapply
,然后sapply
处理每个列表项,将向量转换为数值并计算均值。