Использование коэффициента вариации в совокупности R - PullRequest
1 голос
/ 21 марта 2012

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

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

co.var <- function (x) ( 100 * сд (х) / средний (х) ) </p>

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

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

1 Ответ

4 голосов
/ 21 марта 2012

Предполагая, что я понимаю вашу проблему, я бы предложил использовать 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),]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...