2012-03-21 5 views
1

У меня есть кадр данных с 50000 строк и 200 столбцов. В данных есть повторяющиеся строки, и я хочу агрегировать данные, выбирая строку с максимальным коэффициентом вариации среди дубликатов, используя агрегированную функцию в R. С помощью агрегата я могу использовать «средний», «сумма» по умолчанию, но не коэф. изменение. Например, aggregate (data, as.columnname, FUN = mean) Работает нормально.Использование коэффициента вариации в совокупности R

У меня есть пользовательская функция для вычисления коэффициента вариации, но не знаю, как использовать его с агрегатом.

< co.var - функция (х) ( 100 * сд (х)/среднее значение (х) )

Я попытался совокупности (данные, as.columnname, функция (х) макс (co.var (x, data [index (x),]))) , но он дает ошибку, так как объект x не найден.

Любые предложения!

+1

Что такое 'as.columnname'? – csgillespie

ответ

4

Предполагая, что я понимаю вашу проблему, я бы предложил использовать tapply() вместо aggregate() (см. ?tapply для получения дополнительной информации). Тем не менее, минимальный рабочий пример будет очень полезен.

co.var <- function(x) (100*sd(x)/mean(x)) 

## Data with multiple repeated measurements. 
## There are three things (ID 1, 2, 3) that 
## are measured two times, twice each (val1 and val2) 
myDF<-data.frame(ID=c(1,2,3,1,2,3),val1=c(20,10,5,25,7,2), 
    val2=c(19,9,4,24,4,1)) 

## Calculate coefficient of variation for each measurement set 
myDF$coVar<-apply(myDF[,c("val1","val2")],1,co.var) 

## Use tapply() instead of aggregate 
mySel<-tapply(seq_len(nrow(myDF)),myDF$ID,function(x){ 
    curSub<-myDF[x,] 
    return(x[which(curSub$coVar==max(curSub$coVar))]) 
}) 

## The mySel vector is then the vector of rows that correspond to the 
## maximum coefficient of variation for each ID 
myDF[mySel,] 

EDIT:

Есть более быстрые способы, один из которых находится ниже. Однако с набором данных 40000 на 100 приведенный выше код занял от 16 до 20 секунд на моей машине.

# Create a big dataset 

myDF <- data.frame(val1 = c(20, 10, 5, 25, 7, 2), 
    val2 = c(19, 9, 4, 24, 4, 1)) 
myDF <- myDF[sample(seq_len(nrow(myDF)), 40000, replace = TRUE), ] 
myDF <- cbind(myDF, rep(myDF, 49)) 
myDF$ID <- sample.int(nrow(myDF)/5, nrow(myDF), replace = TRUE) 

# Define a new function to work (slightly) better with large datasets 

co.var.df <- function(x) (100*apply(x,1,sd)/rowMeans(x)) 

# Create two datasets to benchmark the two methods 
# (A second method proved slower than the third, hence the naming) 

myDF.firstMethod <- myDF 
myDF.thirdMethod <- myDF 

Время оригинальный метод

startTime <- Sys.time() 
myDF.firstMethod$coVar <- apply(myDF.firstMethod[, 
    grep("val", names(myDF.firstMethod))], 1, co.var) 
mySel <- tapply(seq_len(nrow(myDF.firstMethod)), 
    myDF.firstMethod$ID, function(x) { 
    curSub <- myDF.firstMethod[x, ] 
    return(x[which(curSub$coVar == max(curSub$coVar))]) 
}, simplify = FALSE) 
endTime <- Sys.time() 

R> endTime-startTime 
Time difference of 17.87806 secs 

время второй метод

startTime3 <- Sys.time() 
coVar3<-co.var.df(myDF.thirdMethod[, 
    grep("val",names(myDF.thirdMethod))]) 
mySel3 <- tapply(seq_along(coVar3), 
    myDF[, "ID"], function(x) { 
    return(x[which(coVar3[x] == max(coVar3[x]))]) 
}, simplify = FALSE) 
endTime3 <- Sys.time() 

R> endTime3-startTime3 
Time difference of 2.024207 secs 

И проверьте, чтобы увидеть, что мы получаем те же результаты:

R> all.equal(mySel,mySel3) 
[1] TRUE 

Существует дополнительная изменить исходный пост, в что отредактированный код считает, что может быть более одной строки с самым высоким CV для данного идентификатора. Поэтому, чтобы получить результаты от редактируемого кода, вы должны unlist в mySel или mySel3 объектов:

myDF.firstMethod[unlist(mySel),] 

myDF.thirdMethod[unlist(mySel3),] 
+2

Thats работает красиво. С этим мы получаем строку с минимальным коэффициентом. var, просто изменив «min (curSub $ coVar)» на «max (curSub $ coVar)», сделает для максимума. Спасибо за помощь. – piyush

+0

Да, извините. Отредактировал ответ, чтобы вернуть максимум. Сожалею. – BenBarnes

+0

Есть ли более быстрый способ сделать это? Это занимает много времени для больших кадров данных со 100 колонками и 40000 строк. – piyush

Смежные вопросы