2016-08-06 4 views
-1

Много раз данные, такие как возраст, заданы диапазонами. Я хочу рассчитать среднее значение этих диапазонов. Я могу рассчитать его, но я чувствую, что есть более элегантный и, возможно, более быстрый способ.Преобразование данных диапазона в среднее значение в R

Вот рабочий пример:

age <- c("0-10", "11-20", "21-30", "31-40") # define the age vector in ranges 
age_split<-strsplit(age,"-") # gives the list with splits 

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" 

На основе предложений ЖИО- и Akron, вот код, который может быть эксплуатационные испытания различных методов:

irows = 100000 
data1 <- paste0(sample(1:10, irows, replace = TRUE),"-", sample(11:20, irows, replace = TRUE)) 
data2 <- data1; data3 <- data1; data4 <- data1 # replicated for testing different methods 

#--method 1 -- originally proposed 
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 

# method 2 (lmo suggestion) 
a2<-Sys.time() 
data2 <- sapply(strsplit(data2, split="-"), function(i) mean(as.numeric(i))) 
Sys.time()-a2 

# method 3 (cue from 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 

# method 4 (akron proposed) 
a4<-Sys.time() 
data4 <-rowMeans(read.table(text=data4, sep = "-")) 
Sys.time()-a4 

# validating if outputs match 
all.equal(as.numeric(data1),data2) 
all.equal(as.numeric(data1),data3) 
all.equal(as.numeric(data1),data4) 

Когда IRow = 100 К, время, взятое из метода 1 - 4, равно: (1) 2,5 с (2) 1,4 с (3) 0,34 с (4) 6,3 с. Когда irow = 1mil, время было (1) 23s (2) 14s (3) 6s (4) очень длинным. Когда irow = 10 мил, время составляло (1) 3,9 мин (2) 2,9 мин (3) очень долго. Это заставляет меня сделать вывод, что read.table действительно медленный. Метод 3 занимает много памяти.

+0

Комментарии о том, когда и если вы будете принимать ответы не относятся к вопросу. Если вы действительно думаете, что это нужно сказать, поместите его здесь в комментарии. Что касается скорости, кажется сомнительным, что это будет иметь значение здесь, если у людей не возрастет очень, очень высокий возраст. – Frank

ответ

0

Вот один вкладыш с sapply:

sapply(strsplit(age, split="-"), function(i) mean(as.numeric(i))) 
[1] 5.0 15.5 25.5 35.5 

strplit разбивает строки на «-» и возвращает список, который подается на sapply, который затем принимает каждый элемент списка, преобразует векторы в числовой и вычислить значение.

+0

lmo, я нашел ваш один вкладыш довольно быстрым по сравнению с циклом for, который я изначально упоминал. Также, используя кий из @akrun, я нашел rowMeans еще быстрее. Поскольку я нахожу это большим опытом обучения, я предоставляю полный пример, где производительность может быть проверена. –

+0

Я отредактировал свой вопрос, в котором я представил код для тестирования 4 разных методов. Они работают по-разному, и интересно узнать различные сценарии. –

1

Мы можем сделать с rowMeans после прочтения его в data.frame с read.table

rowMeans(read.table(text=age, sep="-")) 
#[1] 5.0 15.5 25.5 35.5 
Смежные вопросы